Remove checkpoints in ASA: Getting to the device
This means the player now must win this mission in one go.
Justification: There were many ways for the mission to be saved in an unwinnable state,
there are many ways to win this mission and the checkpoints try to "force" one
particular way. Also, this mission isn't too long anyway.
------------------- ABOUT ----------------------
--
-- In the desert planet Hero will have to explore
-- the dunes below the surface and find the hidden
-- crates. It is told that one crate contains the
-- lost part.
-- Idea: game will be successfully end when the 2 lower crates are collected
-- it would be more defficult (and sadistic) if one should collect *all* the crates
HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/Animate.lua")
HedgewarsScriptLoad("/Scripts/Utils.lua")
HedgewarsScriptLoad("/Missions/Campaign/A_Space_Adventure/global_functions.lua")
----------------- VARIABLES --------------------
-- globals
local campaignName = loc("A Space Adventure")
local missionName = loc("Searching in the dust")
local heroIsInBattle = false
local ongoingBattle = 0
local cratesFound = 0
local checkPointReached = 1 -- 1 is normal spawn
-- dialogs
local dialog01 = {}
-- mission objectives
local goals = {
[dialog01] = {missionName, loc("Getting ready"), loc("The device part is hidden in one of the crates! Go and get it!").."|"..
loc("Most of the destructible terrain in marked with blue color").."|"..loc("Mines time: 0 seconds"), 1, 4500},
}
-- crates
local btorch1Y = 60
local btorch1X = 2700
local btorch2Y = 1900
local btorch2X = 2150
local btorch3Y = 980
local btorch3X = 3260
local rope1Y = 970
local rope1X = 3200
local rope2Y = 1900
local rope2X = 680
local rope3Y = 1850
local rope3X = 2460
local portalY = 480
local portalX = 1465
local girderY = 1630
local girderX = 3350
-- win crates
local btorch2 = {}
local girder = {}
-- hogs
local hero = {}
local ally = {}
local smuggler1 = {}
local smuggler2 = {}
local smuggler3 = {}
-- teams
local teamA = {}
local teamB = {}
local teamC = {}
-- hedgehogs values
hero.name = loc("Hog Solo")
hero.x = 1740
hero.y = 40
hero.dead = false
ally.name = loc("Chief Sandologist")
ally.x = 1660
ally.y = 40
smuggler1.name = loc("Sandy")
smuggler1.x = 400
smuggler1.y = 235
smuggler2.name = loc("Spike")
smuggler2.x = 736
smuggler2.y = 860
smuggler3.name = loc("Sandstorm")
smuggler3.x = 1940
smuggler3.y = 1625
teamA.name = loc("PAotH")
teamA.color = tonumber("FF0000",16) -- red
teamB.name = loc("Smugglers")
teamB.color = tonumber("0072FF",16) -- blues
teamC.name = loc("Hog Solo")
teamC.color = tonumber("38D61C",16) -- green
-------------- LuaAPI EVENT HANDLERS ------------------
function onGameInit()
Seed = 1
TurnTime = 20000
CaseFreq = 0
MinesNum = 0
MinesTime = 1
Explosives = 0
Delay = 3
HealthCaseAmount = 30
-- Disable Sudden Death
HealthDecrease = 0
WaterRise = 0
Map = "desert01_map"
Theme = "Desert"
-- get the check point
checkPointReached = initCheckpoint("desert01")
-- get hero health
local heroHealth = 100
if checkPointReached > 1 and tonumber(GetCampaignVar("HeroHealth")) then
heroHealth = tonumber(GetCampaignVar("HeroHealth"))
end
-- Hog Solo
AddTeam(teamC.name, teamC.color, "Bone", "Island", "HillBilly", "hedgewars")
hero.gear = AddHog(hero.name, 0, heroHealth, "war_desertgrenadier1")
AnimSetGearPosition(hero.gear, hero.x, hero.y)
HogTurnLeft(hero.gear, true)
-- PAotH undercover scientist and chief Sandologist
AddTeam(teamA.name, teamA.color, "Bone", "Island", "HillBilly", "cm_galaxy")
ally.gear = AddHog(ally.name, 0, 100, "Cowboy")
AnimSetGearPosition(ally.gear, ally.x, ally.y)
-- Smugglers
AddTeam(teamB.name, teamB.color, "Bone", "Island", "HillBilly", "cm_bloodyblade")
smuggler1.gear = AddHog(smuggler1.name, 1, 100, "hair_orange")
AnimSetGearPosition(smuggler1.gear, smuggler1.x, smuggler1.y)
smuggler2.gear = AddHog(smuggler2.name, 1, 100, "lambda")
AnimSetGearPosition(smuggler2.gear, smuggler2.x, smuggler2.y)
smuggler3.gear = AddHog(smuggler3.name, 1, 100, "beefeater")
AnimSetGearPosition(smuggler3.gear, smuggler3.x, smuggler3.y)
if checkPointReached == 1 then
-- Start of the game
elseif checkPointReached == 2 then
AnimSetGearPosition(hero.gear, 1050, 615)
HogTurnLeft(hero.gear, true)
elseif checkPointReached == 3 then
AnimSetGearPosition(hero.gear, 1680, 920)
HogTurnLeft(hero.gear, true)
elseif checkPointReached == 4 then
AnimSetGearPosition(hero.gear, 1160, 1180)
elseif checkPointReached == 5 then
local positions = GetCampaignVar("HogsPosition")
positions = split(positions,",")
local x
local y
if positions[1] then
x = positions[1]
y = positions[2]
else
-- this should *NEVER* happen, remove?
x = girderX+40
y = girderY-30
end
AnimSetGearPosition(hero.gear, x, y)
end
AnimInit()
AnimationSetup()
end
function onGameStart()
AnimWait(hero.gear, 3000)
FollowGear(hero.gear)
AddEvent(onHeroDeath, {hero.gear}, heroDeath, {hero.gear}, 0)
AddEvent(onHeroAtFirstBattle, {hero.gear}, heroAtFirstBattle, {hero.gear}, 1)
AddEvent(onHeroAtCheckpoint4, {hero.gear}, heroAtCheckpoint4, {hero.gear}, 0)
AddEvent(onHeroAtThirdBattle, {hero.gear}, heroAtThirdBattle, {hero.gear}, 0)
AddEvent(onCheckForWin1, {hero.gear}, checkForWin1, {hero.gear}, 0)
AddEvent(onCheckForWin2, {hero.gear}, checkForWin2, {hero.gear}, 0)
AddEvent(onCrateDestroyed, {hero.gear}, crateDestroyed, {hero.gear}, 0)
-- smugglers ammo
AddAmmo(smuggler1.gear, amBazooka, 2)
AddAmmo(smuggler1.gear, amGrenade, 2)
AddAmmo(smuggler1.gear, amDEagle, 2)
AddAmmo(smuggler3.gear, amRope, 2)
-- spawn crates
SpawnAmmoCrate(btorch2X, btorch2Y, amBlowTorch)
SpawnAmmoCrate(btorch3X, btorch3Y, amBlowTorch)
SpawnUtilityCrate(rope1X, rope1Y, amRope)
SpawnUtilityCrate(rope2X, rope2Y, amRope)
SpawnUtilityCrate(rope3X, rope3Y, amRope)
SpawnUtilityCrate(portalX, portalY, amPortalGun)
SpawnUtilityCrate(girderX, girderY, amGirder)
SpawnHealthCrate(3300, 970)
-- adding mines - BOOM!
AddGear(1280, 460, gtMine, 0, 0, 0, 0)
AddGear(270, 460, gtMine, 0, 0, 0, 0)
AddGear(3460, 60, gtMine, 0, 0, 0, 0)
AddGear(3500, 240, gtMine, 0, 0, 0, 0)
AddGear(3410, 670, gtMine, 0, 0, 0, 0)
AddGear(3450, 720, gtMine, 0, 0, 0, 0)
local x = 800
while x < 1630 do
AddGear(x, 900, gtMine, 0, 0, 0, 0)
x = x + GetRandom(13)+8
end
x = 1890
while x < 2988 do
AddGear(x, 760, gtMine, 0, 0, 0, 0)
x = x + GetRandom(13)+8
end
x = 2500
while x < 3300 do
AddGear(x, 1450, gtMine, 0, 0, 0, 0)
x = x + GetRandom(13)+8
end
x = 1570
while x < 2900 do
AddGear(x, 470, gtMine, 0, 0, 0, 0)
x = x + GetRandom(13)+8
end
if checkPointReached == 1 then
AddEvent(onHeroFleeFirstBattle, {hero.gear}, heroFleeFirstBattle, {hero.gear}, 1)
AddEvent(onHeroAtCheckpoint2, {hero.gear}, heroAtCheckpoint2, {hero.gear}, 0)
AddEvent(onHeroAtCheckpoint3, {hero.gear}, heroAtCheckpoint3, {hero.gear}, 0)
-- crates
SpawnAmmoCrate(btorch1X, btorch1Y, amBlowTorch)
SpawnHealthCrate(680, 460)
-- hero ammo
AddAmmo(hero.gear, amRope, 2)
AddAmmo(hero.gear, amBazooka, 3)
AddAmmo(hero.gear, amParachute, 1)
AddAmmo(hero.gear, amGrenade, 6)
AddAmmo(hero.gear, amDEagle, 4)
AddAmmo(hero.gear, amRCPlane, tonumber(getBonus(1)))
AddAnim(dialog01)
elseif checkPointReached == 2 or checkPointReached == 3 then
ShowMission(campaignName, missionName, loc("The device part is hidden in one of the crates! Go and get it!"), -amSkip, 0)
loadHeroAmmo()
secondBattle()
elseif checkPointReached == 4 or checkPointReached == 5 then
ShowMission(campaignName, missionName, loc("The part device is hidden in one of the crates! Go and get it!"), -amSkip, 0)
loadHeroAmmo()
end
SendHealthStatsOff()
end
function onNewTurn()
if CurrentHedgehog ~= hero.gear and not heroIsInBattle then
EndTurn(true)
elseif CurrentHedgehog == hero.gear and not heroIsInBattle then
TurnTimeLeft = -1
elseif (CurrentHedgehog == smuggler2.gear or CurrentHedgehog == smuggler3.gear) and ongoingBattle == 1 then
AnimSwitchHog(hero.gear)
EndTurn(true)
elseif (CurrentHedgehog == smuggler1.gear or CurrentHedgehog == smuggler3.gear) and ongoingBattle == 2 then
AnimSwitchHog(hero.gear)
EndTurn(true)
elseif (CurrentHedgehog == smuggler1.gear or CurrentHedgehog == smuggler2.gear) and ongoingBattle == 3 then
AnimSwitchHog(hero.gear)
EndTurn(true)
elseif CurrentHedgehog == ally.gear then
EndTurn(true)
end
end
function onGameTick()
AnimUnWait()
if ShowAnimation() == false then
return
end
ExecuteAfterAnimations()
CheckEvents()
end
function onAmmoStoreInit()
SetAmmo(amBlowTorch, 0, 0, 0, 1)
SetAmmo(amRope, 0, 0, 0, 1)
SetAmmo(amPortalGun, 0, 0, 0, 1)
SetAmmo(amGirder, 0, 0, 0, 3)
SetAmmo(amSkip, 9, 0, 0, 1)
end
function onGearAdd(gear)
if GetGearType(gear) == gtCase then
if GetX(gear) == btorch2X and GetY(gear) == btorch2Y then
btorch2.gear = gear
btorch2.destroyed = false
btorch2.deleted = false
elseif GetX(gear) == girderX and GetY(gear) == girderY then
girder.gear = gear
girder.destroyed = false
girder.deleted = false
end
end
end
function onGearDamage(gear, damage)
if gear == girder.gear then
girder.destroyed = true
elseif gear == btorch2.gear then
btorch2.destroyed = true
end
end
function onGearDelete(gear)
if gear == girder.gear then
girder.deleted = true
elseif gear == btorch2.gear then
btorch2.deleted = true
end
if gear == hero.gear then
hero.dead = true
elseif (gear == smuggler1.gear or gear == smuggler2.gear or gear == smuggler3.gear) and heroIsInBattle then
heroIsInBattle = false
ongoingBattle = 0
end
end
function onPrecise()
if GameTime > 3000 then
SetAnimSkip(true)
end
end
-------------- EVENTS ------------------
function onHeroDeath(gear)
if hero.dead then
return true
end
return false
end
function onHeroAtFirstBattle(gear)
if not hero.dead and not heroIsInBattle and GetHealth(smuggler1.gear) and GetX(hero.gear) <= 1450 and GetX(hero.gear) > 80
and GetY(hero.gear) <= GetY(smuggler1.gear)+5 and GetY(hero.gear) >= GetY(smuggler1.gear)-40 and StoppedGear(hero.gear) then
return true
end
return false
end
function onHeroFleeFirstBattle(gear)
if GetHealth(hero.gear) and GetHealth(smuggler1.gear) and heroIsInBattle
and not gearIsInCircle(smuggler1.gear, GetX(hero.gear), GetY(hero.gear), 1400, false)
and StoppedGear(hero.gear) then
return true
end
return false
end
-- saves the location of the hero and prompts him for the second battle
function onHeroAtCheckpoint2(gear)
if not hero.dead and GetX(hero.gear) > 1000 and GetX(hero.gear) < 1100
and GetY(hero.gear) > 590 and GetY(hero.gear) < 700 and StoppedGear(hero.gear) then
return true
end
return false
end
function onHeroAtCheckpoint3(gear)
if not hero.dead and GetX(hero.gear) > 1610 and GetX(hero.gear) < 1680
and GetY(hero.gear) > 850 and GetY(hero.gear) < 1000 and StoppedGear(hero.gear) then
return true
end
return false
end
function onHeroAtCheckpoint4(gear)
if not hero.dead and GetX(hero.gear) > 1110 and GetX(hero.gear) < 1300
and GetY(hero.gear) > 1100 and GetY(hero.gear) < 1220 then
return true
end
return false
end
function onHeroAtThirdBattle(gear)
if not hero.dead and GetX(hero.gear) > 2000 and GetX(hero.gear) < 2200
and GetY(hero.gear) > 1430 and GetY(hero.gear) < 1670 then
return true
end
return false
end
function onCheckForWin1(gear)
if not hero.dead and not btorch2.destroyed and btorch2.deleted then
return true
end
return false
end
function onCheckForWin2(gear)
if not hero.dead and not girder.destroyed and girder.deleted then
return true
end
return false
end
function onCrateDestroyed(gear)
if not hero.dead and girder.destroyed or btorch2.destroyed then
return true
end
return false
end
-------------- ACTIONS ------------------
function heroDeath(gear)
lose()
end
function heroAtFirstBattle(gear)
AnimCaption(hero.gear, loc("A smuggler! Prepare for battle"), 5000)
EndTurn(true)
heroIsInBattle = true
ongoingBattle = 1
AnimSwitchHog(smuggler1.gear)
EndTurn(true)
end
function heroFleeFirstBattle(gear)
AnimSay(smuggler1.gear, loc("Run away, you coward!"), SAY_SHOUT, 4000)
EndTurn(true)
heroIsInBattle = false
ongoingBattle = 0
end
function heroAtCheckpoint2(gear)
if GetAmmoCount(hero.gear, amRope) > 0 or GetAmmoCount(hero.gear, amParachute) > 0 then
saveCheckPointLocal("2")
end
secondBattle()
end
function heroAtCheckpoint3(gear)
if GetAmmoCount(hero.gear, amRope) > 0 then
saveCheckPointLocal("3")
end
secondBattle()
end
function heroAtCheckpoint4(gear)
saveCheckPointLocal("4")
end
function heroAtThirdBattle(gear)
heroIsInBattle = true
ongoingBattle = 3
AnimSay(smuggler3.gear, loc("Who's there?! I'll get you!"), SAY_SHOUT, 5000)
AnimSwitchHog(smuggler3.gear)
EndTurn(true)
end
function crateDestroyed(gear)
lose()
end
-- for some weird reson I couldn't call the same action for both events
function checkForWin1(gear)
checkForWin()
end
function checkForWin2(gear)
-- ok lets place one more checkpoint as next part seems challenging without rope
if cratesFound == 0 then
saveCheckPointLocal("5")
SaveCampaignVar("HogsPosition", GetX(hero.gear)..","..GetY(hero.gear))
end
checkForWin()
end
-------------- ANIMATIONS ------------------
function Skipanim(anim)
if goals[anim] ~= nil then
ShowMission(unpack(goals[anim]))
end
AnimSwitchHog(hero.gear)
if anim == dialog01 then
startMission()
end
end
function AnimationSetup()
-- DIALOG 01 - Start, getting info about the device
AddSkipFunction(dialog01, Skipanim, {dialog01})
table.insert(dialog01, {func = AnimWait, args = {hero.gear, 3000}})
table.insert(dialog01, {func = AnimCaption, args = {hero.gear, loc("On the Planet of Sand, you have to double check your moves ..."), 5000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Finally you are here!"), SAY_SAY, 2000}})
table.insert(dialog01, {func = AnimWait, args = {hero.gear, 2000}})
table.insert(dialog01, {func = AnimSay, args = {hero.gear, loc("Thank you for meeting me on such a short notice!"), SAY_SAY, 3000}})
table.insert(dialog01, {func = AnimWait, args = {ally.gear, 4000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("No problem, I would do anything for H!"), SAY_SAY, 4000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Now listen carefully! Below us there are tunnels that have been created naturally over the years"), SAY_SAY, 4000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("I have heard that the local tribes say that many years ago some PAotH scientists were dumping their waste here."), SAY_SAY, 5000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("H confirmed that there isn't such a PAotH activity logged."), SAY_SAY, 4000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("So, I believe that it's a good place to start."), SAY_SAY, 3000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Beware, though! Many smugglers come often to explore these tunnels and scavenge whatever valuable items they can find."), SAY_SAY, 5000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("They won't hesitate to attack you in order to rob you!"), SAY_SAY, 4000}})
table.insert(dialog01, {func = AnimWait, args = {hero.gear, 6000}})
table.insert(dialog01, {func = AnimSay, args = {hero.gear, loc("Okay, I'll be extra careful!"), SAY_SAY, 4000}})
table.insert(dialog01, {func = AnimWait, args = {ally.gear, 2000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("The tunnel entrance is over there."), SAY_SAY, 3000}})
table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Good luck!"), SAY_SAY, 3000}})
table.insert(dialog01, {func = AnimWait, args = {hero.gear, 500}})
table.insert(dialog01, {func = startMission, args = {hero.gear}})
end
--------------- OTHER FUNCTIONS ------------------
function startMission()
AnimSwitchHog(ally.gear)
EndTurn(true)
end
function secondBattle()
-- second battle
if heroIsInBattle and ongoingBattle == 1 then
AnimSay(smuggler1.gear, loc("Get him, Spike!"), SAY_SHOUT, 4000)
end
heroIsInBattle = true
ongoingBattle = 2
AnimSay(smuggler2.gear, loc("This is seems like a wealthy hedgehog, nice ..."), SAY_THINK, 5000)
AnimSwitchHog(smuggler2.gear)
EndTurn(true)
end
function saveCheckPointLocal(cpoint)
-- save checkpoint
saveCheckpoint(cpoint)
SaveCampaignVar("HeroHealth", GetHealth(hero.gear))
-- bazooka - grenade - rope - parachute - deagle - btorch - construct - portal - rcplane
SaveCampaignVar("HeroAmmo", GetAmmoCount(hero.gear, amBazooka)..GetAmmoCount(hero.gear, amGrenade)..
GetAmmoCount(hero.gear, amRope)..GetAmmoCount(hero.gear, amParachute)..GetAmmoCount(hero.gear, amDEagle)..
GetAmmoCount(hero.gear, amBlowTorch)..GetAmmoCount(hero.gear, amGirder)..
GetAmmoCount(hero.gear, amPortalGun)..GetAmmoCount(hero.gear, amRCPlane))
AnimCaption(hero.gear, loc("Checkpoint reached!"), 5000)
end
function loadHeroAmmo()
-- hero ammo
local ammo = GetCampaignVar("HeroAmmo")
AddAmmo(hero.gear, amRope, tonumber(ammo:sub(3,3)))
AddAmmo(hero.gear, amBazooka, tonumber(ammo:sub(1,1)))
AddAmmo(hero.gear, amParachute, tonumber(ammo:sub(4,4)))
AddAmmo(hero.gear, amGrenade, tonumber(ammo:sub(2,2)))
AddAmmo(hero.gear, amDEagle, tonumber(ammo:sub(5,5)))
AddAmmo(hero.gear, amBlowTorch, tonumber(ammo:sub(6,6)))
-- weird, if 0 bazooka isn't displayed in the weapons menu
if tonumber(ammo:sub(7,7)) > 0 then
AddAmmo(hero.gear, amGirder, tonumber(ammo:sub(7,7)))
end
AddAmmo(hero.gear, amPortalGun, tonumber(ammo:sub(8,8)))
AddAmmo(hero.gear, amRCPlane, tonumber(ammo:sub(9,9)))
end
function checkForWin()
if cratesFound == 0 then
-- have to look more
AnimSay(hero.gear, loc("Haven't found it yet ..."), SAY_THINK, 5000)
cratesFound = cratesFound + 1
elseif cratesFound == 1 then
-- end game
saveCompletedStatus(5)
AnimSay(hero.gear, loc("Hooray!"), SAY_SHOUT, 5000)
SendStat(siGameResult, loc("Congratulations, you won!"))
SendStat(siCustomAchievement, loc("To win the game you had to collect the 2 crates with no specific order."))
SendStat(siPlayerKills,'1',teamC.name)
SendStat(siPlayerKills,'0',teamB.name)
EndGame()
end
end
function lose()
SendStat(siGameResult, loc("Hog Solo lost, try again!"))
SendStat(siCustomAchievement, loc("To win the game you have to find the right crate."))
SendStat(siCustomAchievement, loc("You can avoid some battles."))
SendStat(siCustomAchievement, loc("Use your ammo wisely."))
SendStat(siCustomAchievement, loc("Don't destroy the device crate!"))
SendStat(siPlayerKills,'1',teamB.name)
SendStat(siPlayerKills,'0',teamC.name)
EndGame()
end