share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua
changeset 13087 aa9e871f9685
parent 12776 957e4e2e2802
child 13099 ffa5cdc75826
equal deleted inserted replaced
13086:dce9f0b84a18 13087:aa9e871f9685
     1 --Created by Patrick Nielsen
     1 --[[
     2 --It's been so fun to create this, your welcome to contact me at Trivkz@gmail.com
     2 	Basic Rope Training
     3 --
     3 	Teaches the player how to rope! No advanced tricks, just the basics. But fun! (I hope)
     4 --I've tried to keep the code as clear as possible and with comments.
     4 
     5 --But as English is not my first language there may be spelling / grammar mistakes.
     5 	Lesson plan:
     6 --
     6 	- Select rope
     7 --I know there need to be more "tutorial" specefic messages, but I had a hard timer figuring out what to type / what would be the best technical description.
     7 	- Shoot rope, attach, detach
     8 
     8 	- Extend, retract, swing to reach easy target
       
     9 	- Multiple shots / rope re-use to go over water hazard
       
    10 	- Drop grenade from rope
       
    11 	- Special rules when you only got 1 rope (i.e. when the rope is officially used up)
       
    12 	- Rope around obstacles and mines
       
    13 ]]
     9 
    14 
    10 HedgewarsScriptLoad("/Scripts/Locale.lua")
    15 HedgewarsScriptLoad("/Scripts/Locale.lua")
    11 HedgewarsScriptLoad("/Scripts/Utils.lua") -- For the gearIsInBox function, wrote my own, but decided it was a waste to include it
    16 HedgewarsScriptLoad("/Scripts/Utils.lua")
    12 
    17 
    13 local Player = nil -- Pointer to hog created in: onGameInit
    18 -- Map definition automatically converted from HWMAP file by hwmap2lua.sh
    14 local Target = nil -- Pointer to target hog
    19 local map =
    15 local GameLost = false -- You lost the game
    20 {'\2\30\7\126\135\2\28\5\52\0\1\211\6\203\135\3\207\6\189\0\3\1\5\205\135\4\120\5\203\0\2\30\5\31\135\2\35\4\173\0\1\170\4\216\135\4\150\4\248\0\3\230\4\138\135\4\54\6\22\0\3\205\6\189\135\4\154\7\91\0\4\154\7\91\135\6\57\7\41\0\4\79\6\38\135\4\221\6\112\0\4\221\6\112\135\6\27\6\70\0\3\175\6\196\135\4\51\5\235\0\3\17\6\178\135\3\161\5\226\0\4\33\7\4\135\4\191\6\93\0\4\200\7\75\135\5\45\6\137\0\6\29\6\66\135\6\98\5\123\0\6\107\7\32\135\6\237\5\249\0\6\102\5\95\135\7\169\5\6\0\7\0\5\237\135\7\235\6\20\0\7\233\6\13\135\7\226\8\43\0\13\66\6\47\135\13\100\8\57\0\7\167\5\15\135\7\164\4\51\0\7\71\4\109\135\13\235\4\132\0\13\4\6\75\135\14\242\6\57\0\14\169\6\166\135\15\183\4\86\0',
    16 local Objective = false -- Get to the target
    21 '\15\208\5\13\135\15\96\2\248\0\15\206\3\104\135\13\175\2\88\0\14\171\5\17\140\14\219\4\77\138\14\166\3\136\136\13\219\3\31\136\13\184\4\228\136\13\173\3\250\0\14\2\4\19\136\7\36\3\211\0\14\52\2\85\137\7\57\2\76\0\12\196\2\245\137\11\195\3\127\137\10\174\2\223\137\9\174\3\113\137\8\160\2\211\137\8\11\3\111\137\6\249\3\218\131\6\66\3\209\0\5\88\3\202\131\4\38\3\193\0\5\33\3\207\131\5\31\5\31\0\4\235\4\228\131\6\125\4\251\0\6\98\3\214\131\6\80\5\1\0\7\41\2\104\136\3\253\2\72\0\4\31\3\207\133\1\149\3\166\0\2\243\4\15\133\1\117\2\202\0\1\149\3\60\133\1\211\1\87\0\1\138\1\138\133\3\42\0\71\0\2\131\0\96\133\4\168\0\149\0\5\116\1\124\141\7\41\0\204\141\8\252\2\42\141\10\39\0\135\141\11\40\1\124\141\10\17\1\186\141',
    17 local RopeMaster = false -- Achievement
    22 '\12\104\0\151\141\4\29\0\156\137\14\160\0\69\0\13\182\1\133\137\13\171\2\78\0\13\201\0\78\137\13\189\0\197\0\13\194\1\195\137\15\148\2\147\0\14\189\0\59\137\15\222\0\217\0\15\226\0\215\137\15\164\2\145\0\13\217\1\211\137\15\167\1\220\0\14\208\2\37\164\8\89\1\92\139\6\146\1\211\139\8\174\2\39\203\10\19\2\7\203\11\56\1\167\203\12\106\0\217\203\7\36\1\12\203\5\182\1\163\203\6\141\1\165\203\8\71\1\135\203\8\151\3\19\203\8\7\3\70\203\9\227\3\118\203\13\66\3\113\133\13\54\4\104\0\11\200\3\26\133\11\191\4\84\0\9\160\2\255\133\9\160\4\84\0\8\16\3\163\133\8\18\4\109\0\9\108\3\53\197\10\19\3\70\0\14\25\5\228\132\14\43\4\253\130\13\237\3\241\210\13\217\3\225\210\13\95\4\74\140\7\137\4\40\0\2\209\6\75\207\3\255\6\102\0\4\1\6\107\207',
    18 local StatsSent = false -- Remember whether the stats have been sent already
    23 '\4\182\6\228\0\4\182\6\226\207\6\36\6\189\0\6\36\6\201\207\6\166\5\191\0\4\138\4\100\158\1\183\4\68\0\4\145\5\8\158\4\203\5\201\0\5\141\5\198\158\5\180\5\139\0\7\116\4\230\142\5\49\5\52\0\6\185\4\47\148\6\182\4\186\0\7\64\4\88\153\4\216\4\10\143\13\255\2\42\146\15\100\2\216\0\4\1\6\20\199\2\142\6\29\0\3\255\6\22\199\5\22\6\224\0\7\231\5\198\133\7\235\6\31\0\13\70\6\68\133\13\54\5\237\0\14\36\4\253\197\4\90\2\223\133\4\239\3\97\0\2\181\2\252\133\3\95\2\156\0\2\216\1\90\133\3\113\1\218\0\4\200\1\32\133\4\122\1\167\0\7\169\1\106\133\4\10\4\106\213\1\30\4\86\0\4\58\5\54\219\1\119\5\6\139\1\119\5\157\0\1\238\5\189\139\0\85\5\164\0\0\105\6\63\139\0\119\3\182\0\0\37\3\188\134\1\231\3\195\0',
    19 
    24 '\1\142\5\13\145\1\188\5\102\0\1\199\5\59\145\3\209\5\198\134\5\59\5\102\0\4\63\5\111\134\0\121\3\225\134\4\111\3\234\0\2\255\4\106\134\3\12\4\228\0\2\58\4\120\132\13\148\2\60\132\13\146\1\106\0'}
    20 local WaitTime = 1000 -- Wait 1sec before quit
    25 
    21 local FollowTime = 1500 -- For use with FollowGear
    26 local function drawMap()
    22 local FollowingGear = false
    27 	for m=1, #map do
    23 local BaseballIntro = false -- Fail safe for ticker
    28 		ParseCommand("draw "..map[m])
    24 local TargetNumber = 0 -- The current target number
    29 	end
    25 
    30 end
    26 local TargetPos = {} -- Tabel of targets
    31 
    27 local Timers = {}
    32 -- Gears
    28 local GetTime = 0
    33 local hog
    29 
    34 local ropeGear
    30 TargetPos[ 1 ] = { X = 1100, Y = 1100, Message = loc("Now find the next target! |Tip: Normally you lose health by falling down, so be careful!") }
    35 local mines = {}
    31 TargetPos[ 2 ] = { X = 1500, Y = 1490, Message = loc("You're getting pretty good! |Tip: When you shorten you rope, you move faster!|And when you lengthen it, you move slower.") }
    36 
    32 TargetPos[ 3 ] = { X = 2200, Y = 800, Message = loc("The next one is pretty hard! |Tip: You have to do multiple swings!") }
    37 -- Status vars
    33 TargetPos[ 4 ] = { X = 2870, Y = 400, Message = loc("I don't know how you did that. But good work!|The next one should be easy as cake for you!") }
    38 local ropeSelected = false	-- rope was selected the first time, used for msg
    34 TargetPos[ 5 ] = { X = 4000, Y = 1750, Message = "" }
    39 local ropeAttached = false	-- rope was attached, used for msg
    35 TargetPos[ 6 ] = { Modifier = true, Func = function() -- Last target is ALWAYS the "winning" target!
    40 local target1Reached = false	-- hog near 1st first target
    36 	Info( loc("Congratulations"), loc("Congratulations! You've completed the Basic Rope Training!"), 0 ) -- Congrats
    41 local barrelsBoom = false	-- barrels exploded
    37 	PlaySound( sndVictory, Player )
    42 local wasFirstTurn = false	-- first turn msg was displayed
    38 
    43 local gameOver = false		-- game over (only victory possible)
    39 	AddCaption( loc( "Victory!" ), 0xFFFFFFFF, capgrpGameState)
    44 local currentTarget = 0		-- current target ID. First target = 1
    40 	if TurnTimeLeft >= 250000 then -- If you very fast, unlock the ahievement "Rope Master!"
    45 
    41 		RopeMaster = true
    46 local cpX, cpY = 208, 1384	-- hog checkpoint, initialized with start coords
    42 		AddCaption( string.format(loc("Achievement gotten: %s"), loc("Rope Master") ), 0xffba00ff, capgrpMessage2)
    47 
    43 		PlaySound( sndHomerun )
    48 -- "Constants"
    44 	end
    49 local initHogHealth = 50
    45 	Objective = true
    50 local teamName = loc("Wannabe Ropers")
    46 end }
    51 
    47 
    52 local girderData = {
    48 function Info( Title, Text, Icon ) -- I made a small wrapper to ease the process
    53 	{2012, 1366, 6}, -- water gate
    49 	ShowMission( loc("Rope Training"), Title, Text, Icon, 0 )
    54 	{1156, 678, 2}, -- post-barrel gate
    50 end
    55 	{1206, 905, 2}, -- post-barrel gate
    51 
    56 	{1064, 288, 6}, -- top level gate
    52 function NewFollowGear( Gear )
    57 	{1064, 455, 6}, -- top level gate
    53 	FollowingGear = true
    58 	{1557, 1009, 0}, -- barrel pit protection
    54 	FollowGear( Gear )
    59 	{1436, 1003, 4}, -- barrel pit protection
    55 end
    60 	{3607, 1307, 4}, -- post-water gate
    56 
    61 	{3809, 1375, 0}, -- post-water gate
    57 function SpawnTarget( PosX, PosY )
    62 }
    58 	Target = AddGear( 0, 0, gtTarget, 0, 0, 0, 0 ) -- Create a new target
    63 
    59 	SetGearPosition( Target, PosX, PosY ) -- Set the position of the target
    64 local mineData = {
    60 	NewFollowGear( Target )
    65 	{1261, 549},
    61 end
    66 	{1395, 554},
    62 
    67 	{1719, 458},
    63 function AutoSpawn() -- Auto spawn the next target after you've killed the current target!
    68 	{1489, 558},
    64 	TargetNumber = TargetNumber + 1
    69 	{1686, 565},
    65 
    70 	{1581, 561},
    66 	if TargetPos[ TargetNumber ].Modifier then -- If there is a modifier, run the function, only used in the winning target!
    71 	{1904, 539},
    67 		TargetPos[ TargetNumber ].Func()
    72 	{2047, 539},
    68 		return true
    73 	{2226, 608},
    69 	end
    74 	{2387, 541},
    70 
    75 	{2523, 396},
    71 	if TargetNumber > 1 then
    76 	{2899, 324},
    72 		Info(loc("Training"), TargetPos[ TargetNumber - 1 ].Message, -amRope )
    77 	{3428, 546},
    73 	end
    78 	{3373, 546},
    74 
    79 	{3271, 546},
    75 	SpawnTarget( TargetPos[ TargetNumber ].X, TargetPos[ TargetNumber ].Y ) -- Spawn target on the next position
    80 	{3123, 545},
    76 end
    81 	{3012, 544},
    77 
    82 	{2907, 544},
    78 function InRange( Gear, PosX, PosY, Distance ) -- Fix as the default function didn't do quite what I needed
    83 	{2793, 543},
    79 	GearX, GearY = GetGearPosition( Gear )
    84 }
    80 
    85 
    81     return GearX >= PosX - Distance and GearX <= PosX + Distance and GearY >= PosY and GearY - Distance <= PosY + Distance
    86 local targetData = {
    82 end
    87 	-- 1: Start
    83 
    88 	{504, 1215},
    84 function CheckPosition( Hog, Distance ) -- Show a message when you get close to the current target!
    89 	-- 2: Start 2
    85 	if (not BaseballIntro and not Objective) and (CurrentHedgehog ~= nil) then --Fail safe check
    90 	{1082, 1348},
    86 		if InRange( Hog, 1100, 1100, Distance ) then -- Check if the player is within predefined position of the first target
    91 	-- 3: Before the water
    87 			BaseballIntro = true
    92 	{1941, 1490},
    88 			Info(loc("Training"), loc("Great work! Now hit it with your Baseball Bat! |Tip: You can change weapon with 'Right Click'!"), -amRope ) -- Guide them
    93 	-- 4: After the water
    89 			Timer( 10000, loc("Remember: The rope only bend around objects, |if it doesn't hit anything it's always stright!"))
    94 	{3504, 1557},
    90 		end
    95 	-- 5: Barrel pit
    91 	end
    96 	{2060, 885},
    92 end
    97 	-- 6: Grand Finale
    93 
    98 	{757, 679},
    94 function Timer( Delay, Message )
    99 	-- 7: Goal
    95 	local Timer = {}
   100 	{3802, 356},
    96 	Timer.End = GetTime + Delay
   101 }
    97 	Timer.Message = Message
   102 
    98 
   103 function onGameInit()
    99 	table.insert( Timers, Timer )
   104 
   100 end
   105 	ClearGameFlags()
   101 
   106 	EnableGameFlags(gfDisableGirders, gfDisableLandObjects, gfOneClanMode, gfInfAttack, gfSolidLand, gfDisableWind)
   102 function onGameInit() -- Called when the game loads
   107 	Seed = "{386439b4-748a-48b1-945a-eba6a817ca83}"
   103 	Seed = 1 -- The base number for the random number generator
   108 	Theme = "Bamboo"
   104 	GameFlags = gfInfAttack + gfOneClanMode + gfSolidLand + gfInvulnerable + gfBorder -- Game settings and rules, going with a border to make it easier
   109 	MapGen = mgDrawn
   105 	TurnTime = 300000 -- Player can move for 5min each round
   110 	MapFeatureSize = 12
   106 	CaseFreq = 0 -- No random crate drops
   111 	TemplateFilter = 0
   107 	MinesNum = 0 -- Never place any mines on the map
   112 	TemplateNumber = 0
   108 	Explosives = 0 -- Never place any explosives
   113 	TurnTime = 9999000
   109 	Delay = 1 -- We don't wont to wait between each round ( as the only is one )
   114 	Explosives = 0
   110 	Map = "Ropes" -- Map name
   115 	MinesNum = 0
   111 	Theme = "Nature" -- Map theme
   116 	CaseFreq = 0
   112 	-- Disable Sudden Death
   117 	MinesTime = 0
   113 	SuddenDeathTurns = 50
       
   114 	WaterRise = 0
   118 	WaterRise = 0
   115 	HealthDecrease = 0
   119 	HealthDecrease = 0
   116 
   120 
   117 	AddTeam( loc( "Rope Team" ), 14483456, "Simple", "Island", "Default", "cm_shoppa" ) -- Lets make the team
   121 	AddTeam(teamName, 0xFF0204, "Plinko", "Snail", "Default", "cm_yinyang")
   118 	Player = AddHog( loc( "Hunter" ), 0, 1, "StrawHat" ) -- Add a hog for it, and name it "Hunter"
   122 	hog = AddHog(loc("Roper"), 0, initHogHealth, "StrawHat")
   119 	SetGearPosition( Player, 420, 1750 ) -- Set player position
   123 	SetGearPosition(hog, cpX, cpY)
   120 
   124 	SetEffect(hog, heResurrectable, 1)
   121 	SetEffect( Player, heResurrectable, 1 ) -- By Suggestion :)
   125 
   122 end
   126 	drawMap()
   123 
   127 
   124 function onGameStart() -- Called when the game starts
       
   125 	SendHealthStatsOff()
   128 	SendHealthStatsOff()
   126 	AutoSpawn() -- Spawn our 1st target using the wrapper function
   129 
   127 
   130 end
   128 	SetHealth( Player, 100 ) -- Give the player 100 Health points
   131 
   129 
   132 -- The final challenge is to rope through a mined obstacle course with only 1 rope.
   130 	PlaceGirder(46,1783, 0) -- Place a girder to prevent the player falling into the water
   133 -- If the player screws up, this functinon will restart it.
   131 
   134 local function resetMineChallenge(setPos)
   132 	local message = loc("Get to the target using your rope!") .. "|" .. loc("Controls: Hold the Attack key (space by default) to|fire the rope, then, once attached use:|Left and Right to swing the rope;|Up and Down to contract and expand.")
   135 	if setPos == nil then
   133 	Info(loc("Training"), message, -amRope ) -- Short intro to tell the player what to do
   136 		setPos = true
   134 	Timer( 10000, message .. "|" .. loc("Tip: The rope physics are different than in the real world, |use it to your advantage!") ) -- After 15 sec, give them more help
   137 	end
       
   138 	SetHealth(hog, initHogHealth)
       
   139 	AddAmmo(hog, amRope, 1)
       
   140 	for gear, _ in pairs(mines) do
       
   141 		DeleteGear(gear)
       
   142 	end
       
   143 
       
   144 	for m=1, #mineData do
       
   145 		AddGear(mineData[m][1], mineData[m][2], gtMine, 0, 0, 0, 0)
       
   146 	end
       
   147 	if setPos then
       
   148 		SetGearPosition(hog, cpX, cpY)
       
   149 		FollowGear(hog)
       
   150 	end
       
   151 end
       
   152 
       
   153 -- Deletes girder with given girderData ID
       
   154 local function eraseGirder(id)
       
   155 	EraseSprite(girderData[id][1], girderData[id][2], sprAmGirder, girderData[id][3], false, false, false, false)
       
   156 	PlaySound(sndVaporize)
       
   157 	AddVisualGear(girderData[id][1], girderData[id][2], vgtSteam, false, 0)
       
   158 	AddCaption(loc("Barrier unlocked!"))
       
   159 end
       
   160 
       
   161 local function loadGearData()
       
   162 	------ GIRDERS ------
       
   163 	for g=1, #girderData do
       
   164 		PlaceGirder(unpack(girderData[g]))
       
   165 	end
       
   166 
       
   167 	------ BARRELS ------
       
   168 	local barrels = {}
       
   169 	table.insert(barrels, AddGear(1370, 1223, gtExplosives, 0, 0, 0, 0))
       
   170 	table.insert(barrels, AddGear(1430, 1226, gtExplosives, 0, 0, 0, 0))
       
   171 	table.insert(barrels, AddGear(1489, 1218, gtExplosives, 0, 0, 0, 0))
       
   172 	table.insert(barrels, AddGear(1537, 1211, gtExplosives, 0, 0, 0, 0))
       
   173 	table.insert(barrels, AddGear(1578, 1206, gtExplosives, 0, 0, 0, 0))
       
   174 	for b=1, #barrels do
       
   175 		SetHealth(barrels[b], 1)
       
   176 	end
       
   177 
       
   178 	------ MINES ------
       
   179 	for m=1, #mineData do
       
   180 		AddGear(mineData[m][1], mineData[m][2], gtMine, 0, 0, 0, 0)
       
   181 	end
       
   182 
       
   183 	------ FIRST TARGET ------
       
   184 	currentTarget = 1
       
   185 	AddGear(targetData[currentTarget][1], targetData[currentTarget][2], gtTarget, 0, 0, 0, 0)
       
   186 end
       
   187 
       
   188 function onGameStart()
       
   189 	loadGearData()
       
   190 
       
   191 	ShowMission(loc("Basic Rope Training"), loc("Basic Training"),
       
   192 	loc("Use the rope to complete the obstacle course!"), -amRope, 0)
       
   193 	FollowGear(hog)
   135 end
   194 end
   136 
   195 
   137 function onNewTurn()
   196 function onNewTurn()
   138 	SetWeapon(amRope) -- Set the default weapon to Rope
   197 	if not wasFirstTurn then
       
   198 		ShowMission(loc("Basic Rope Training"), loc("Select Rope"),
       
   199 		loc("Select the rope to begin!").."|"..
       
   200 		loc("Open ammo menu: [Right click]"), 2, 7500)
       
   201 		wasFirstTurn = true
       
   202 	end
       
   203 	if isInMineChallenge then
       
   204 		resetMineChallenge()
       
   205 	end
       
   206 end
       
   207 
       
   208 function onGameTick()
       
   209 	if gameOver or (not CurrentHedgehog) then
       
   210 		return
       
   211 	end
       
   212 
       
   213 	-- First rope selection
       
   214 	if not ropeSelected and GetCurAmmoType() == amRope then
       
   215 		ShowMission(loc("Basic Rope Training"), loc("Getting Started"),
       
   216 		loc("You can use the rope to reach new places.").."|"..
       
   217 		loc("Aim at the ceiling and hold [Attack] pressed until the rope attaches.").."|"..
       
   218 		loc("Aim: [Up]/[Down]").."|"..
       
   219 		loc("Attack: [Space]"), 2, 15000)
       
   220 		ropeSelected = true
       
   221 	-- Rope attach
       
   222 	elseif ropeGear and band(GetState(ropeGear), gstCollision) ~= 0 then
       
   223 		-- First rope attach
       
   224 		if not ropeAttached and not target1Reached then
       
   225 			ShowMission(loc("Basic Rope Training"), loc("How to Rope"),
       
   226 			loc("Great!").."|"..
       
   227 			loc("Use the rope to get to the target!").."|"..
       
   228 			loc("Extend/Retract rope: [Up]/[Down]").."|"..
       
   229 			loc("Swing: [Left]/[Right]").."|"..
       
   230 			loc("Release rope: [Attack]"), 2, 15000)
       
   231 			ropeAttached = true
       
   232 		elseif currentTarget > 1 then
       
   233 			HideMission()
       
   234 		end
       
   235 	end
       
   236 
       
   237 	-- Prevent grenade being thrown by hand (must use from rope instead)
       
   238 	local allowAttack = true
       
   239 	if GetCurAmmoType() == amGrenade and ropeGear == nil then
       
   240 		allowAttack = false
       
   241 	end
       
   242 	if allowAttack then
       
   243 		SetInputMask(bor(GetInputMask(), gmAttack))
       
   244 	else
       
   245 		SetInputMask(band(GetInputMask(), bnot(gmAttack)))
       
   246 	end
   139 end
   247 end
   140 
   248 
   141 function onGameTick20()
   249 function onGameTick20()
   142 	if TurnTimeLeft < 40 and TurnTimeLeft > 0 then -- Round starts at 0, so we check if the round is finished by using 1
   250 	if not gameOver and not target1Reached and CurrentHedgehog and gearIsInCircle(CurrentHedgehog, targetData[1][1], targetData[1][2], 48, false) then
   143 		GameLost = true -- You lost the game
   251 		ShowMission(loc("Basic Rope Training"), loc("Target Puncher"),
   144 		Info(loc("Training"), loc("You did not make it in time, try again!"), -amSkip )
   252 		loc("Okay, now destroy the target|using the baseball bat.").."|"..
   145 		if not StatsSent then
   253 		loc("Release rope: [Attack]"), 2, 9000)
   146 			SendStat(siGameResult, loc("You failed!"))
   254 		target1Reached = true
   147 			SendStat(siCustomAchievement, loc("You did not make it in time, try again!"))
   255 	end
   148 			StatsSent = true
   256 end
   149 		end
   257 
   150 		SetHealth( Player, 0 ) -- Kill the player so he can't keep moving!
   258 function onGearAdd(gear)
   151 
   259 	if GetGearType(gear) == gtRope then
   152 		SetEffect( Player, heResurrectable, 0 )
   260 		ropeGear = gear
   153 
   261 	elseif GetGearType(gear) == gtMine then
   154 	end
   262 		mines[gear] = true
   155 
   263 	elseif GetGearType(gear) == gtGrenade then
   156 	-- If the player gets to the last target, they win OR
   264 		if not ropeGear then
   157 	-- If round is finished and your not at the target you lose
   265 			DeleteGear(gear)
   158 	-- in either case, end the game
   266 		end
   159 	if (Objective == true) or (GameLost == true) then
   267 	end
   160 		if (WaitTime == 0 and not StatsSent) then
   268 end
       
   269 
       
   270 function onGearResurrect(gear)
       
   271 	-- Teleport hog to previous checkpoint
       
   272 	if gear == hog then
       
   273 		SetGearPosition(hog, cpX, cpY)
       
   274 		FollowGear(hog)
       
   275 		AddCaption(loc("Your hedgehog has been revived!"))
       
   276 		if isInMineChallenge then
       
   277 			resetMineChallenge(false)
       
   278 		end
       
   279 	end
       
   280 end
       
   281 
       
   282 function onGearDelete(gear)
       
   283 	if GetGearType(gear) == gtTarget then
       
   284 		-- Update checkpoint
       
   285 		cpX, cpY = GetGearPosition(gear)
       
   286 
       
   287 		-- New message
       
   288 		if currentTarget == 1 then
       
   289 			ShowMission(loc("Basic Rope Training"), loc("Obstacle"),
       
   290 			loc("Well done! Let's destroy the next target!").."|"..
       
   291 			loc("The targets will guide you through the training.").."|"..
       
   292 			loc("Use your rope to get to the next target, then destroy it!"), 2, 8000)
       
   293 		elseif currentTarget == 2 then
       
   294 			ShowMission(loc("Basic Rope Training"), loc("Speed Roping"),
       
   295 			loc("Try to reach and destroy the next target quickly.").."|"..
       
   296 			loc("Hint: When you shorten the rope, you move faster!|And when you lengthen it, you move slower."), 2, 15000)
       
   297 		elseif currentTarget == 3 then
       
   298 			ShowMission(loc("Basic Rope Training"), loc("Over the Water"),
       
   299 			loc("When you're in mid-air, you can continue to aim|and fire another rope if you're not attached.").."|"..
       
   300 			loc("To get over the water, you have to do multiple|rope shots and swings.").."|"..
       
   301 			loc("It needs some practice, but you have infinite lives.").."|"..
       
   302 			loc("Good luck!"), 2, 22500)
       
   303 			eraseGirder(1)
       
   304 		elseif currentTarget == 4 then
       
   305 			ShowMission(loc("Basic Rope Training"), loc("Little Obstacle Course"),
       
   306 			loc("Well done! The next target awaits.").."|"..
       
   307 			loc("Hint: The rope only bends around objects.|When it doesn't hit anything, it's always straight."), 2, 7000)
       
   308 			eraseGirder(8)
       
   309 			eraseGirder(9)
       
   310 		elseif currentTarget == 5 then
       
   311 			ShowMission(loc("Basic Rope Training"), loc("Rope Weapons"),
       
   312 			loc("Some weapons can be dropped from the rope.").."|"..
       
   313 			loc("Collect the weapon crate and drop|a grenade from rope to destroy the barrels.").."|"..
       
   314 			loc("Step 1: Start roping").."|"..
       
   315 			loc("Step 2: Select grenade").."|"..
       
   316 			loc("Step 3: Drop the grenade").."| |"..
       
   317 			loc("Drop weapon (while on rope): [Long Jump]"), 2, 20000)
       
   318 			AddAmmo(hog, amBaseballBat, 0)
       
   319 			SpawnAmmoCrate(1849, 920, amGrenade, 100)
       
   320 		elseif currentTarget == 6 then
       
   321 			ShowMission(loc("Basic Rope Training"), loc("Finite Ropes"),
       
   322 			loc("So far, you had infinite ropes, but in the|real world, ropes are usually limited.").."|"..
       
   323 			loc("Rules:").." |"..
       
   324 			loc("As long you don't touch the ground, you can|re-use the same rope as often as you like.").."|"..
       
   325 			loc("If you miss a shot while trying to|re-attach, your rope is gone, too!").."| |"..
       
   326 			loc("Final Challenge:").." |"..
       
   327 			loc("Reach and destroy the final target to win.").."|"..
       
   328 			loc("You only get 1 rope this time, don't waste it!").."|"..
       
   329 			loc("Avoid the mines!").."|"..
       
   330 			loc("Skip your turn to try again."), 2, 25000)
       
   331 			eraseGirder(4)
       
   332 			eraseGirder(5)
       
   333 			AddAmmo(hog, amRope, 1)
       
   334 			AddAmmo(hog, amSkip, 100)
       
   335 			isInMineChallenge = true
       
   336 		elseif currentTarget == 7 then
       
   337 			ShowMission(loc("Basic Rope Training"), loc("Training complete!"),
       
   338 			loc("Congratulations!"), 0, 0)
       
   339 			PlaySound(sndVictory, hog)
       
   340 			AddAmmo(hog, amBaseballBat, 0)
       
   341 			AddAmmo(hog, amGrenade, 0)
       
   342 			AddAmmo(hog, amRope, 0)
       
   343 			SendStat(siCustomAchievement, loc("Oh yeah! You sure know how to rope!"))
   161 			SendStat(siGameResult, loc("You have finished the Basic Rope Training!"))
   344 			SendStat(siGameResult, loc("You have finished the Basic Rope Training!"))
   162 			SendStat(siCustomAchievement, loc("Good job!"))
   345 			SendStat(siPlayerKills, "0", teamName)
   163 			SendStat(siPlayerKills, "0", loc("Rope Team"))
       
   164 			if RopeMaster then
       
   165 				SendStat(siCustomAchievement, loc("You earned the \"Rope Master\" achievement for finishing in under 50 seconds."))
       
   166 			end
       
   167 			StatsSent = true
       
   168 			EndGame()
   346 			EndGame()
   169 		else
   347 			gameOver = true
   170 			WaitTime = WaitTime - 20
   348 			SetInputMask(0)
   171 		end
   349 		end
   172 	end
   350 		currentTarget = currentTarget + 1
   173 
   351 
   174 	if FollowingGear == true then
   352 		if currentTarget <= #targetData then
   175 		if FollowTime == 0 then
   353 			AddGear(targetData[currentTarget][1], targetData[currentTarget][2], gtTarget, 0, 0, 0, 0)
   176 			FollowingGear = false
   354 		end
   177 			FollowTime = 1500
   355 
   178 			FollowGear( Player )
   356 	elseif GetGearType(gear) == gtExplosives then
   179 		else
   357 		if not barrelsBoom then
   180 			FollowTime = FollowTime - 20
   358 			barrelsBoom = true
   181 		end
   359 			AddAmmo(hog, amGrenade, 0)
   182 	end
   360 			AddAmmo(hog, amBaseballBat, 100)
   183 
   361 			eraseGirder(2)
   184 	for k, v in pairs( Timers ) do
   362 			eraseGirder(3)
   185 		if v.End <= GetTime then
   363 		end
   186 			Info(loc("Training"), v.Message, -amRope )
   364 	elseif GetGearType(gear) == gtRope then
   187 			Timers[ k ] = nil
   365 		ropeGear = nil
   188 		end
   366 		if ropeAttached and not target1Reached then
   189 	end
   367 			ShowMission(loc("Basic Rope Training"), loc("How to Rope"),
   190 
   368 			loc("Go to the target.").."|"..
   191 	GetTime = GetTime + 20
   369 			loc("Hold [Attack] to attach the rope.").."|"..
   192 
   370 			loc("Aim: [Up]/[Down]").."|"..
   193 	CheckPosition( Player, 70 ) -- Run the CheckPosition function to check if the player is close to a target
   371 			loc("Attack: [Space]"), 2, 13000)
       
   372 			ropeAttached = false
       
   373 		end
       
   374 	elseif GetGearType(gear) == gtMine then
       
   375 		mines[gear] = nil
       
   376 	elseif GetGearType(gear) == gtCase then
       
   377 		eraseGirder(6)
       
   378 		eraseGirder(7)
       
   379 	end
   194 end
   380 end
   195 
   381 
   196 function onAmmoStoreInit()
   382 function onAmmoStoreInit()
   197 	SetAmmo( amRope, 9, 2, 0, 0 ) -- Player ammo, Rope
   383 	SetAmmo(amRope, 9, 0, 0, 1)
   198 	SetAmmo( amBaseballBat, 9, 2, 0, 0 ) --Baseball bat
   384 	SetAmmo(amBaseballBat, 9, 0, 0, 1)
   199 end
   385 end
   200 
   386 
   201 function onGearDelete( Gear )
   387 function onHogAttack(ammoType)
   202 	if GetGearType( Gear ) == gtTarget then
   388 	-- Allow to manually reset final challenge with skip
   203 		AutoSpawn() -- When a target is deleted / destroyed, spawn a new one!
   389 	if ammoType == amSkip then
   204 	end
   390 		resetMineChallenge()
   205 end
   391 	end
       
   392 end
       
   393 
       
   394 function onAttack()
       
   395 	if GetCurAmmoType() == amGrenade and not ropeGear then
       
   396 		AddCaption(loc("You have to drop the grenade from rope!"), 0xFF4000FF, capgrpMessage)
       
   397 		PlaySound(sndDenied)
       
   398 	end
       
   399 end