# HG changeset patch # User Wuzzy # Date 1520016186 -3600 # Node ID 730db0a3eb4318d2db95b1c0e27830a23e1b8e82 # Parent e69cb8d5512c8fc79d8398892926b14d5a793370 Completely redo Basic Grenade Training Lesson plan: - Select grenade - Throw grenade - Aim, set timer, set bounciness - Destroy targets diff -r e69cb8d5512c -r 730db0a3eb43 ChangeLog.txt --- a/ChangeLog.txt Fri Mar 02 13:57:37 2018 +0100 +++ b/ChangeLog.txt Fri Mar 02 19:43:06 2018 +0100 @@ -23,7 +23,7 @@ Content: + New scenarios: Bazooka Battlefield, Tentacle Terror + New basic training mission: Movement - + Completely redo Basic Bazooka Training + + Completely redo basic training missions: Bazooka, Grenade + Major overhaul of Sudden Death visuals in most themes + New flag: uk_scotland + New voice: Default_pl (Polish) diff -r e69cb8d5512c -r 730db0a3eb43 share/hedgewars/Data/Graphics/Missions/Training/Basic_Training_-_Grenade.png Binary file share/hedgewars/Data/Graphics/Missions/Training/Basic_Training_-_Grenade.png has changed diff -r e69cb8d5512c -r 730db0a3eb43 share/hedgewars/Data/Graphics/Missions/Training/Basic_Training_-_Grenade@2x.png Binary file share/hedgewars/Data/Graphics/Missions/Training/Basic_Training_-_Grenade@2x.png has changed diff -r e69cb8d5512c -r 730db0a3eb43 share/hedgewars/Data/Locale/missions_de.txt --- a/share/hedgewars/Data/Locale/missions_de.txt Fri Mar 02 13:57:37 2018 +0100 +++ b/share/hedgewars/Data/Locale/missions_de.txt Fri Mar 02 19:43:06 2018 +0100 @@ -5,7 +5,7 @@ Basic_Training_-_Bazooka.desc="Lern, wie man die Bazooka benutzt, lern über den Wind und zerstöre alle Ziele." Basic_Training_-_Grenade.name=Grundlagentraining: Granate -Basic_Training_-_Grenade.desc="Wirf ein paar Granaten, um 5 zufällige Zielscheiben zu zerstören. Vergiss nicht: Stift ziehen UND werfen!" +Basic_Training_-_Grenade.desc="Lern alles, was du über Granaten wissen solltest und zerstöre alle Ziele. Vergiss nicht: Stift ziehen UND werfen!" Basic_Training_-_Sniper_Rifle.name=Zielübung: Scharfschützengewehr Basic_Training_-_Sniper_Rifle.desc="Das ist der perfekte Schießstand für Scharfschützen! Zerstöre alle Ziele so schnell und treffsicher du kannst und werd zur Legende!" diff -r e69cb8d5512c -r 730db0a3eb43 share/hedgewars/Data/Locale/missions_en.txt --- a/share/hedgewars/Data/Locale/missions_en.txt Fri Mar 02 13:57:37 2018 +0100 +++ b/share/hedgewars/Data/Locale/missions_en.txt Fri Mar 02 19:43:06 2018 +0100 @@ -5,7 +5,7 @@ Basic_Training_-_Bazooka.desc="Learn how to use the bazooka, learn about the wind and destroy all targets." Basic_Training_-_Grenade.name=Basic Grenade Training -Basic_Training_-_Grenade.desc="Throw some grenades to destroy 5 random targets. Remember: You pull the pin AND throw!" +Basic_Training_-_Grenade.desc="Learn everything you need to know about grenades and destroy all targets. Remember: You pull the pin AND throw!" Basic_Training_-_Rope.name=Basic Rope Training Basic_Training_-_Rope.desc="The rope is one of the most versatile utilities you can get, but it needs a lot of practice. Here you learn the basics of roping." diff -r e69cb8d5512c -r 730db0a3eb43 share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua Fri Mar 02 13:57:37 2018 +0100 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua Fri Mar 02 19:43:06 2018 +0100 @@ -1,193 +1,222 @@ --- Hedgewars Grenade Training --- Scripting Example +--[[ + Basic Grenade Training --- Lines such as this one are comments - they are ignored --- by the game, no matter what kind of text is in there. --- It's also possible to place a comment after some real --- instruction as you see below. In short, everything --- following "--" is ignored. - ---------------------------------------------------------------- --- At first we implement the localization library using loadfile. --- This allows us to localize strings without needing to think --- about translations. --- We can use the function loc(text) to localize a string. + This training mission teaches players how to use the grenade. + Lesson plan: + - Selecting grenade + - Aiming and shooting + - Timer + - No wind + - Bounciness +]] HedgewarsScriptLoad("/Scripts/Locale.lua") --- This variable will hold the number of destroyed targets. -local score = 0 --- This variable represents the number of targets to destroy. -local score_goal = 5 --- This variable controls how many milliseconds/ticks we'd --- like to wait before we end the round once all targets --- have been destroyed. -local end_timer = 4000 -- 5000 ms = 5 s --- This variable is set to true if the game is lost (i.e. --- time runs out). -local game_lost = false --- This variable ensures that the death function isn't called --- repeatedly when game is over. -local team_death = false --- This variable will point to the hog's gear -local player = nil --- This variable will grab the time left at the end of the round -local time_goal = 0 +local hog -- Hog gear +local weaponSelected = false -- Player has selected the weapon +local gamePhase = 0 -- Used to track progress +local targetsLeft = 0 -- # of targets left in this round +local targetGears = {} -- list of target gears +local gameOver = false -- If true, game has ended +local shotsFired = 0 -- Total # of grenades fired +local maxTargets = 0 -- Target counter, used together with flawless +local flawless = true -- track flawless victory (100% accuracy, no hurt, no death) +local missedTauntTimer = -1 -- Wait timer for playing sndMissed. -1 = no-op + +function onGameInit() + + ClearGameFlags() + EnableGameFlags(gfDisableWind, gfOneClanMode, gfInfAttack, gfSolidLand, gfArtillery) + Map = "Mushrooms" + Seed = 0 + Theme = "Nature" + TurnTime = 9999000 + Explosives = 0 + MinesNum = 0 + CaseFreq = 0 + WaterRise = 0 + HealthDecrease = 0 + + ------ TEAM LIST ------ + + AddTeam(loc("Grenade Team"), 0xFF0204, "Flower", "Earth", "Default", "cm_grenade") + hog = AddHog(loc("Greenhorn"), 0, 1, "NoHat") + SetGearPosition(hog, 570, 157) + SetEffect(hog, heResurrectable, 1) --- This is a custom function to make it easier to --- spawn more targets with just one line of code --- You may define as many custom functions as you --- like. -function spawnTarget() - -- add a new target gear - gear = AddGear(0, 0, gtTarget, 0, 0, 0, 0) - - -- move it to a random position within 0 and - -- LAND_WIDTH - the width of the map - FindPlace(gear, true, 0, LAND_WIDTH-326) - - -- move the target to a higher vertical position - -- to ensure it's not somewhere down below - x, y = GetGearPosition(gear) - SetGearPosition(gear, x, 0) + SendHealthStatsOff() +end + +function onGearResurrect(gear) + if gear == hog then + flawless = false + SetGearPosition(hog, 570, 157) + AddCaption(loc("Your hedgehog has been revived!")) + end +end + +local function placeGirders() + PlaceGirder(918, 248, 1) + PlaceGirder(888, 129, 6) + PlaceGirder(844, 35, 1) + PlaceGirder(932, 37, 3) + PlaceGirder(926, 148, 6) + PlaceGirder(73, 812, 5) + PlaceGirder(189, 930, 5) + PlaceGirder(15, 669, 6) + PlaceGirder(15, 507, 6) + PlaceGirder(15, 344, 6) + PlaceGirder(62, 27, 0) + PlaceGirder(229, 115, 0) + PlaceGirder(1195, 250, 7) + PlaceGirder(1285, 205, 1) + PlaceGirder(1358, 201, 3) + PlaceGirder(1756, 415, 6) + PlaceGirder(1893, 95, 6) + PlaceGirder(1005, 333, 5) + PlaceGirder(1860, 187, 0) end --- This function is called before the game loads its --- resources. --- It's one of the predefined function names that will --- be called by the game. They give you entry points --- where you're able to call your own code using either --- provided instructions or custom functions. -function onGameInit() - -- At first we have to overwrite/set some global variables - -- that define the map, the game has to load, as well as - -- other things such as the game rules to use, etc. - -- Things we don't modify here will use their default values. +local function spawnTargets() + -- Warm-up + if gamePhase == 0 then + AddGear(233, 97, gtTarget, 0, 0, 0, 0) + AddGear(333, 255, gtTarget, 0, 0, 0, 0) + AddGear(753, 225, gtTarget, 0, 0, 0, 0) + -- No Wind + elseif gamePhase == 2 then + AddGear(61, 9, gtTarget, 0, 0, 0, 0) + AddGear(882, 39, gtTarget, 0, 0, 0, 0) + AddGear(945, 498, gtTarget, 0, 0, 0, 0) + -- Bounciness + elseif gamePhase == 3 then + AddGear(323, 960, gtTarget, 0, 0, 0, 0) + AddGear(1318, 208, gtTarget, 0, 0, 0, 0) + AddGear(1697, 250, gtTarget, 0, 0, 0, 0) + AddGear(1852, 100, gtTarget, 0, 0, 0, 0) + -- Grand Final + elseif gamePhase == 4 then + AddGear(186, 473, gtTarget, 0, 0, 0, 0) + AddGear(950, 250, gtTarget, 0, 0, 0, 0) + AddGear(1102, 345, gtTarget, 0, 0, 0, 0) + AddGear(1556, 297, gtTarget, 0, 0, 0, 0) + end +end - -- The base number for the random number generator - Seed = 1 - -- Game settings and rules - GameFlags = gfInfAttack + gfOneClanMode - -- The time the player has to move each round (in ms) - TurnTime = 60000 - -- The frequency of crate drops - CaseFreq = 0 - -- The number of mines being placed - MinesNum = 0 - -- The number of explosives being placed - Explosives = 0 - -- The delay between each round - Delay = 1 - -- The map to be played - Map = "Battlefield" - -- The theme to be used - Theme = "Castle" - -- Setting these 2 values to 0 is the official way to disable Sudden Death cleanly - HealthDecrease = 0 -- Sudden Death damage - WaterRise = 0 -- Water rise in Sudden Death - - -- Create the player team - AddTeam(loc("Grenadiers"), 14483456, "Simple", "Island", "Default", "cm_grenade") - -- And add a hog to it - player = AddHog(loc("Nade Boy"), 0, 1, "war_grenadier1") - SetGearPosition(player, 506, 76) +function onGameStart() + placeGirders() + spawnTargets() + ShowMission(loc("Basic Grenade Training"), loc("Basic Training"), loc("Destroy all the targets!"), -amGrenade, 0) end --- This function is called when the round starts --- it spawns the first target that has to be destroyed. --- In addition it shows the scenario goal(s). -function onGameStart() - -- Spawn the first target. - spawnTarget() - - -- Show some nice mission goals. - -- Parameters are: caption, sub caption, description, - -- extra text, icon and time to show. - -- A negative icon parameter (-n) represents the n-th weapon icon - -- A positive icon paramter (n) represents the (n+1)-th mission icon - -- A timeframe of 0 is replaced with the default time to show. - ShowMission(loc("Grenade Training"), loc("Aiming Practice"), loc("Eliminate all targets before your time runs out.|You have unlimited ammo for this mission."), -amGrenade, 0) +function newGamePhase() + -- Spawn targets, update wind and ammo, show instructions + if gamePhase == 0 then + ShowMission(loc("Basic Grenade Training"), loc("Select Weapon"), loc("To begin with the training, select the grenade from the ammo menu!").."|".. + loc("Open ammo menu: [Right click]").."|".. + loc("Select weapon: [Left click]"), 2, 5000) + elseif gamePhase == 1 then + ShowMission(loc("Basic Grenade Training"), loc("Warming Up"), + loc("Throw some grenades to destroy the targets!").."|".. + loc("Hold the Attack key pressed for more power.").."|".. + loc("Grenades explode after 1 to 5 seconds (you decide).").."|".. + loc("Attack: [Space]").."|".. + loc("Aim: [Up]/[Down]").."|".. + loc("Set detonation timer: [1]-[5]").."|".. + loc("Change direction: [Left]/[Right]"), 2, 20000) + spawnTargets() + elseif gamePhase == 2 then + ShowMission(loc("Basic Grenade Training"), loc("No Wind Influcence"), loc("Unlike bazookas, grenades are not influenced by wind.").."|".. + loc("Destroy the targets!"), 2, 6000) + SetWind(50) + spawnTargets() + elseif gamePhase == 3 then + ShowMission(loc("Basic Grenade Training"), loc("Bounciness"), + loc("You can set the bounciness of grenades (and grenade-like weapons).").."|".. + loc("Grenades with high bounciness bounce a lot and behave chaotic.").."|".. + loc("With low bounciness, it barely bounces at all, but it is much more predictable.").."|".. + loc("Try out different bounciness levels to reach difficult targets.").."|".. + loc("Set bounciness: [Left Shift] + [1]-[5]"), + 2, 20000) + spawnTargets() + elseif gamePhase == 4 then + ShowMission(loc("Basic Grenade Training"), loc("Final Targets"), loc("Good job! Now destroy the final targets to finish the training.").."|".. + loc("Precise Aim: [Left Shift] + [Up]/[Down]"), + 2, 7000) + spawnTargets() + elseif gamePhase == 5 then + ShowMission(loc("Basic Grenade Training"), loc("Training complete!"), loc("Congratulations!"), 0, 0) + SetInputMask(0) + AddAmmo(CurrentHedgehog, amGrenade, 0) + if shotsFired > maxTargets then + flawless = false + end + if flawless then + PlaySound(sndFlawless, hog) + else + PlaySound(sndVictory, hog) + end + SendStat(siCustomAchievement, loc("Good job!")) + SendStat(siGameResult, loc("You have completed the Basic Grenade Training!")) + SendStat(siPlayerKills, "0", loc("Grenade Team")) + EndGame() + gameOver = true + end + gamePhase = gamePhase + 1 end function onNewTurn() - SetWeapon(amGrenade) + if gamePhase == 0 then + newGamePhase() + end +end + +function onSetWeapon(ammoType) + if ammoType == amGrenade and not weaponSelected and gamePhase == 1 then + newGamePhase() + weaponSelected = true + end +end + +function onSlot(msgParam) + if msgParam <= 1 and not weaponSelected and gamePhase == 1 then + newGamePhase() + weaponSelected = true + end end --- This function is called every game tick. --- Note that there are 1000 ticks within one second. --- You shouldn't try to calculate too complicated --- code here as this might slow down your game. -function onGameTick20() - -- If time's up, set the game to be lost. - -- We actually check the time to be "1 ms" as it - -- will be at "0 ms" right at the start of the game. - if TurnTimeLeft < 40 and TurnTimeLeft > 0 and score < score_goal then - game_lost = true - -- ... and show a short message. - ShowMission(loc("Grenade Training"), loc("Aiming Practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0) - -- How about killing our poor hog due to his poor performance? - SetHealth(player, 0) - -- Just to be sure set the goal time to 1 ms - time_goal = 1 +function onHogAttack(ammoType) + if ammoType == amGrenade then + HideMission() end - -- If the goal is reached or we've lost ... - if score == score_goal or game_lost then - -- ... check to see if the time we'd like to - -- wait has passed and then ... - if end_timer == 0 then - -- Override the 'Draw' message with the appropriate message. - if game_lost then - AddCaption(loc("Mission lost!"), 0xffba00ff,capgrpGameState) - else - AddCaption(loc("Mission won!"), 0xffba00ff,capgrpGameState) - end - -- Remove the team to end the game. Only do this once. - if team_death == false then - team_death = true - DismissTeam(loc("Grenadiers")) - end - else - -- ... or just lower the timer by 1. - end_timer = end_timer - 20 - -- Reset the time left to stop the timer - TurnTimeLeft = time_goal +end + +function onGearAdd(gear) + if GetGearType(gear) == gtTarget then + targetsLeft = targetsLeft + 1 + maxTargets = maxTargets + 1 + targetGears[gear] = true + elseif GetGearType(gear) == gtGrenade then + shotsFired = shotsFired + 1 + end +end + +function onGearDelete(gear) + if GetGearType(gear) == gtTarget then + targetsLeft = targetsLeft - 1 + targetGears[gear] = nil + if targetsLeft <= 0 then + newGamePhase() end end end --- This function is called when the game is initialized --- to request the available ammo and probabilities -function onAmmoStoreInit() - -- add an unlimited supply of bazooka ammo - SetAmmo(amGrenade, 9, 0, 0, 0) +function onGearDamage(gear) + if gear == hog then + flawless = false + end end --- This function is called when a new gear is added. --- We don't need it for this training, so we can --- keep it empty. --- function onGearAdd(gear) --- end - --- This function is called before a gear is destroyed. --- We use it to count the number of targets destroyed. -function onGearDelete(gear) - -- We're only interested in target gears. - if GetGearType(gear) == gtTarget then - -- Add one point to our score/counter - score = score + 1 - -- If we haven't reached the goal ... - if score < score_goal then - -- ... spawn another target. - spawnTarget() - else - if not game_lost then - -- Otherwise show that the goal was accomplished - ShowMission(loc("Grenade Training"), loc("Aiming Practice"), loc("Congratulations! You've eliminated all targets|within the allowed time frame."), 0, 0) - -- Also let the hogs shout "victory!" - PlaySound(sndVictory) - -- Save the time left so we may keep it. - time_goal = TurnTimeLeft - end - end - end +function onAmmoStoreInit() + SetAmmo(amGrenade, 9, 0, 0, 0) end