--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Scripts/RopeKnocking.lua Mon Oct 28 20:40:07 2019 +0100
@@ -0,0 +1,441 @@
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Utils.lua")
+
+local hhs = {}
+local deadHogs = {}
+local missionWon = nil
+local endTimer = 1000
+local hogsKilled = 0
+local totalEnemies = 0
+local finishTime
+local playerFail = false
+local ropeGear = nil
+local endGameCalled = false
+local missionEndHandled = false
+local valkyriesTimer = -1
+
+local valkyriesDuration = 20000
+local timeBonus = 6000
+local killBonus = 6000
+local playValkyries = false
+
+local extraTime
+
+local playerTeamName
+local missionName = loc("Rope-knocking Challenge")
+-- Mission type:
+-- 0 = none (no special handling)
+-- 1 = challenge (saves mission vars)
+local missionType = 1
+
+local function getKillScore()
+ return div(hogsKilled * killBonus, totalEnemies)
+end
+
+local function protectEnemies()
+ -- Protect enemy hogs
+ for i=1, totalEnemies do
+ if hhs[i] and GetHealth(hhs[i]) then
+ SetEffect(hhs[i], heInvulnerable, 1)
+ SetEffect(hhs[i], heResurrectable, 1)
+ end
+ end
+end
+
+local function killStr(killed, total, score)
+ if total == 16 then
+ return string.format(loc("You have killed %d of 16 hedgehogs (+%d points)."), killed, score)
+ else
+ return string.format(loc("You have killed %d of %d hedgehogs (+%d points)."), killed, total, score)
+ end
+end
+
+local function gameOver()
+ StopMusicSound(sndRideOfTheValkyries)
+ valkyriesTimer = -1
+ missionWon = false
+ SendStat(siGameResult, loc("Challenge over!"))
+ local score = getKillScore()
+ SendStat(siCustomAchievement, killStr(hogsKilled, totalEnemies, score))
+ SendStat(siPointType, "!POINTS")
+ SendStat(siPlayerKills, tostring(score), playerTeamName)
+ protectEnemies()
+ if not endGameCalled then
+ EndGame()
+ endGameCalled = true
+ end
+ if missionType == 1 then
+ -- Update highscore
+ updateChallengeRecord("Highscore", score)
+ end
+end
+
+local function victory(onVictory)
+ missionWon = true
+ local e = 0
+ if extraTime then
+ e = extraTime
+ end
+ local totalTime = TurnTime + e * totalEnemies
+ local completeTime = (totalTime - finishTime) / 1000
+ ShowMission(missionName, loc("Challenge completed!"), loc("Congratulations!") .. "|" .. string.format(loc("Completion time: %.2fs"), completeTime), 0, 0)
+ PlaySound(sndHomerun)
+ -- Protect player hog
+ if hhs[0] and GetHealth(hhs[0]) then
+ SetEffect(hhs[0], heInvulnerable, 1)
+ SetEffect(hhs[0], heResurrectable, 1)
+ end
+ SendStat(siGameResult, loc("Challenge completed!"))
+ local hogScore = getKillScore()
+ local timeScore = div(finishTime * timeBonus, totalTime)
+ local score = hogScore + timeScore
+ SendStat(siCustomAchievement, killStr(hogsKilled, totalEnemies, hogScore))
+ SendStat(siCustomAchievement, string.format(loc("You have completed this challenge in %.2f s (+%d points)."), completeTime, timeScore))
+ SendStat(siPointType, "!POINTS")
+ SendStat(siPlayerKills, tostring(score), playerTeamName)
+ SetTeamLabel(playerTeamName, tostring(score))
+ SetTurnTimeLeft(MAX_TURN_TIME)
+
+ if missionType == 1 then
+ -- Update highscore
+ updateChallengeRecord("Highscore", score)
+ end
+ if onVictory then
+ onVictory()
+ end
+end
+
+local function knockTaunt()
+ local r = math.random(0,23)
+ local taunt
+ if r == 0 then taunt = loc("%s has been knocked out.")
+ elseif r == 1 then taunt = loc("%s hit the ground.")
+ elseif r == 2 then taunt = loc("%s splatted.")
+ elseif r == 3 then taunt = loc("%s was smashed.")
+ elseif r == 4 then taunt = loc("%s felt unstable.")
+ elseif r == 5 then taunt = loc("%s exploded.")
+ elseif r == 6 then taunt = loc("%s fell from a high cliff.")
+ elseif r == 7 then taunt = loc("%s goes the way of the lemming.")
+ elseif r == 8 then taunt = loc("%s was knocked away.")
+ elseif r == 9 then taunt = loc("%s was really unlucky.")
+ elseif r == 10 then taunt = loc("%s felt victim to rope-knocking.")
+ elseif r == 11 then taunt = loc("%s had no chance.")
+ elseif r == 12 then taunt = loc("%s was a good target.")
+ elseif r == 13 then taunt = loc("%s spawned at a really bad position.")
+ elseif r == 14 then taunt = loc("%s was doomed from the beginning.")
+ elseif r == 15 then taunt = loc("%s has fallen victim to gravity.")
+ elseif r == 16 then taunt = loc("%s hates Newton.") -- Isaac Newton
+ elseif r == 17 then taunt = loc("%s had it coming.")
+ elseif r == 18 then taunt = loc("%s is eliminated!")
+ elseif r == 19 then taunt = loc("%s fell too fast.")
+ elseif r == 20 then taunt = loc("%s flew like a rock.")
+ elseif r == 21 then taunt = loc("%s stumbled.")
+ elseif r == 22 then taunt = loc("%s was shoved away.")
+ elseif r == 23 then taunt = loc("%s didn't expect that.")
+ end
+ return taunt
+end
+
+local function declareEnemyKilled(gear, onVictory)
+ if deadHogs[gear] or playerFail then
+ return
+ end
+ deadHogs[gear] = true
+ hogsKilled = hogsKilled + 1
+
+ -- Award extra time, if available
+ if extraTime and extraTime ~= 0 then
+ SetTurnTimeLeft(TurnTimeLeft + extraTime)
+ AddCaption(string.format(loc("+%d seconds!"), div(extraTime, 1000)), 0xFFFFFFFF, capgrpMessage2)
+ end
+
+ SetTeamLabel(playerTeamName, tostring(getKillScore()))
+
+ if hogsKilled == totalEnemies - 1 then
+ if playValkyries then
+ PlayMusicSound(sndRideOfTheValkyries)
+ valkyriesTimer = valkyriesDuration
+ end
+ elseif hogsKilled == totalEnemies then
+ finishTime = TurnTimeLeft
+ victory(onVictory)
+ end
+end
+
+--[[
+RopeKnocking function!
+
+This creates a rope-knocking challenge.
+The player spawns with one hog and a rope and must kill all other hogs
+by rope-knocking before the time runs out.
+The player wins points for each kill and gets a time bonus for killing
+all enemies.
+
+params is a table with all the required parameters.
+Fields of the params table:
+
+ MANDATORY:
+ - map: Map name
+ - theme: Theme name
+ - turnTime: Turn time
+ - playerTeam: Player team info:
+ {
+ x, y: Start position
+ faceLeft: If true, hog faces left
+ }
+ - enemyTeams: Table of enemy team tables. each enemy team table has this format:
+ {
+ name: Team name
+ flag: Flag
+ hogs: Hogs table:
+ {
+ x, y: Position
+ faceLeft: If true, hog faces left
+ hat: Hat name
+ name: Hog name
+ }
+ }
+
+ OPTIONAL:
+ - missionName: Mission name
+ - missionType:
+ 0: None/other: No special handling
+ 1: Challenge: Will save mission variables at end (default)
+ - killBonus: Score for killing all hogs (one hog scores ca. (killBonus/<number of enemies)) (default: 6000)
+ - timeBonus: Maximum theoretically possible time bonus (default: 6000)
+ - gameFlags: List of game flags, if you want to set your own
+ - extraTime: Extra time awarded for each kill, in milliseconds (default: 0)
+ - valkyries: If true, play "Ride of the Valkyries" at final enemy (default: false)
+ - onGameInit: Custom onGameInit callback
+ - onGameStart: Custom onGameStart callback
+ - onVictory: Function that is called when the mission is won.
+
+ Hint: Use onGameInit and onGameStart to place custom gears and girders
+ Hint: Use onVictory to save campaign variables if using this in a campaign
+
+]]
+function RopeKnocking(params)
+ if params.missionName then
+ missionName = params.missionName
+ end
+ if params.extraTime then
+ extraTime = params.extraTime
+ end
+ if params.valkyries then
+ playValkyries = params.valkyries
+ end
+ if params.missionType then
+ missionType = params.missionType
+ end
+ if params.killBonus then
+ killBonus = params.killBonus
+ end
+ if params.timeBonus then
+ timeBonus = params.timeBonus
+ end
+
+ _G.onGameInit = function()
+
+ if params.gameFlags then
+ for g=1, #params.gameFlags do
+ EnableGameFlags(params.gameFlags[g])
+ end
+ end
+
+ EnableGameFlags(gfBorder, gfSolidLand)
+
+ TurnTime = params.turnTime
+ Delay = 500
+ Map = params.map
+ Theme = params.theme
+
+ -- Disable Sudden Death
+ WaterRise = 0
+ HealthDecrease = 0
+
+ CaseFreq = 0
+ MinesNum = 0
+ Explosives = 0
+
+ -- Player team
+ playerTeamName = AddMissionTeam(-1)
+ hhs[0] = AddMissionHog(1)
+ SetGearPosition(hhs[0], params.playerTeam.x, params.playerTeam.y)
+ if params.playerTeam.faceLeft == true then
+ HogTurnLeft(hhs[0], true)
+ end
+
+ -- Enemy teams
+ for t=1, #params.enemyTeams do
+ local team = params.enemyTeams[t]
+ params.enemyTeams[t].name = AddTeam(team.name, -2, "Simple", "Tank", "Default_qau", team.flag)
+ for h=1, #team.hogs do
+ local hogData = team.hogs[h]
+ local name = hogData.name
+ local hat = hogData.hat
+ if not hat then
+ hat = "NoHat"
+ end
+ local hog = AddHog(name, 0, 1, hat)
+ SetGearPosition(hog, hogData.x, hogData.y)
+ if hogData.faceLeft == true then
+ HogTurnLeft(hog, true)
+ end
+ table.insert(hhs, hog)
+
+ totalEnemies = totalEnemies + 1
+ end
+ end
+
+ if params.onGameInit then
+ params.onGameInit()
+ end
+ end
+
+ _G.onGameStart = function()
+ SendHealthStatsOff()
+
+ local timeTxt = ""
+ local displayTime = 4000
+ if extraTime and extraTime ~= 0 then
+ timeTxt = string.format(loc("For each kill you win %d seconds."), div(extraTime, 1000))
+ displayTime = 5000
+ end
+ local recordInfo = getReadableChallengeRecord("Highscore")
+ if recordInfo == nil then
+ recordInfo = ""
+ else
+ recordInfo = "|" .. recordInfo
+ end
+ ShowMission(
+ missionName,
+ loc("Challenge"),
+ loc("Use the rope to knock your enemies to their doom.") .. "|" ..
+ loc("Finish this challenge as fast as possible to earn bonus points.") .. "|" ..
+ timeTxt .. recordInfo, -amRope, displayTime)
+
+ SetTeamLabel(playerTeamName, "0")
+
+ if params.onGameStart then
+ params.onGameStart()
+ end
+ end
+
+ _G.onGameTick = function()
+
+ if (TurnTimeLeft == 1) and (missionWon == nil) then
+ PlaySound(sndBoring, CurrentHedgehog)
+ gameOver()
+ end
+
+ if missionWon ~= nil then
+
+ endTimer = endTimer - 1
+ if endTimer == 1 then
+ if not endGameCalled then
+ EndGame()
+ endGameCalled = true
+ end
+ end
+
+ if not missionEndHandled then
+ if missionWon == true then
+ AddCaption(loc("Victory!"), 0xFFFFFFFF, capgrpGameState)
+ if missionType == 1 then
+ SaveMissionVar("Won", "true")
+ end
+ else
+ AddCaption(loc("Challenge over!"), 0xFFFFFFFF, capgrpGameState)
+ end
+ missionEndHandled = true
+ end
+
+ end
+
+ end
+
+ _G.onGameTick20 = function()
+ if (valkyriesTimer > 0) then
+ valkyriesTimer = valkyriesTimer - 20
+ if valkyriesTimer <= 0 then
+ StopMusicSound(sndRideOfTheValkyries)
+ end
+ end
+ local drown = (hhs[0]) and (band(GetState(hhs[0]), gstDrowning) ~= 0)
+ if drown and missionWon == nil then
+ -- Player hog drowns
+ playerFail = true
+ return
+ end
+ for i=1, totalEnemies do
+ local hog = hhs[i]
+ drown = (hog) and (not deadHogs[hog]) and (band(GetState(hhs[i]), gstDrowning) ~= 0)
+ if drown then
+ declareEnemyKilled(hog, params.onVictory)
+ end
+ end
+
+ if ropeGear and not missionWon and band(GetState(ropeGear), gstCollision) ~= 0 then
+ -- Hide mission on first rope attach
+ HideMission()
+ end
+ end
+
+ _G.onGearDamage = function(gear, damage)
+
+ if gear == hhs[0] then
+ -- Player hog hurts itself
+ playerFail = true
+ StopMusicSound(sndRideOfTheValkyries)
+ valkyriesTimer = -1
+ protectEnemies()
+ end
+
+ if gear ~= hhs[0] and GetGearType(gear) == gtHedgehog and not deadHogs[gear] and missionWon == nil and playerFail == false then
+ -- Enemy hog took damage
+ AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+ DeleteGear(gear)
+ PlaySound(sndExplosion)
+ AddCaption(string.format(knockTaunt(), GetHogName(gear)), 0xFFFFFFFF, capgrpMessage)
+
+ declareEnemyKilled(gear, params.onVictory)
+ end
+
+ end
+
+ _G.onGearAdd = function(gear)
+ if GetGearType(gear) == gtRope then
+ ropeGear = gear
+ end
+ end
+
+ _G.onGearDelete = function(gear)
+
+ if (gear == hhs[0]) and (missionWon == nil) then
+ playerFail = true
+ gameOver()
+ end
+
+ if GetGearType(gear) == gtHedgehog and gear ~= hhs[0] and not deadHogs[gear] then
+ declareEnemyKilled(gear, params.onVictory)
+ end
+
+ if GetGearType(gear) == gtRope then
+ ropeGear = nil
+ end
+
+ end
+
+ if params.onAmmoStoreInit then
+ _G.onAmmoStoreInit = params.onAmmoStoreInit
+ else
+ _G.onAmmoStoreInit = function()
+ SetAmmo(amRope, 9, 0, 0, 0)
+ end
+
+ _G.onNewTurn = function()
+ SetWeapon(amRope)
+ end
+ end
+
+end