# HG changeset patch # User Wuzzy # Date 1572291607 -3600 # Node ID 0039baa9895e827eecc22406846c1fa1b9aee8d6 # Parent 3c0a3c824c4913a8bc60e82a03262c9b5bcfd1cc Add RopeKnocking library (generalized ropeknock challenges) diff -r 3c0a3c824c49 -r 0039baa9895e share/hedgewars/Data/Scripts/RopeKnocking.lua --- /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/ 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