|
1 --[=[ |
|
2 Target Practice Mission Framework for Hedgewars |
|
3 |
|
4 This is a simple library intended to make setting up simple training missions a trivial |
|
5 task requiring just. The library has been created to reduce redundancy in Lua scripts. |
|
6 |
|
7 The training framework generates complete and fully usable training missions by just |
|
8 one function call. |
|
9 |
|
10 The missions generated by this script are all the same: |
|
11 - The player will get a team with a single hedgehog. |
|
12 - The team gets a single predefined weapon infinitely times. |
|
13 - A fixed sequence of targets will spawn at predefined positions. |
|
14 - When a target has been destroyed, the next target of the target sequence appears |
|
15 - The mission ends successfully when all targets have been destroyed |
|
16 - The mission ends unsuccessfully when the time runs out or the hedgehog dies |
|
17 - When the mission ends, a score is awarded, based on the performance (hit targets, |
|
18 accuracy and remaining time) of the hedgehog. When not all targets are hit, there |
|
19 will be no accuracy and time bonuses. |
|
20 |
|
21 To use this library, you first have to load it and to call TrainingMission once with |
|
22 the appropriate parameters. Really, that’s all! |
|
23 See the comment of TrainingMission for a specification of all parameters. |
|
24 |
|
25 Below is a template for your convenience, you just have to fill in the fields and delete |
|
26 optional arguments you don’t want. |
|
27 ----- snip ----- |
|
28 HedgewarsScriptLoad("/Scripts/Training.lua") |
|
29 params = { |
|
30 missionTitle = , |
|
31 map = , |
|
32 theme = , |
|
33 time = , |
|
34 ammoType = , |
|
35 gearType = , |
|
36 targets = { |
|
37 { x = , y = }, |
|
38 { x = , y = }, |
|
39 -- etc. |
|
40 }, |
|
41 |
|
42 wind = , |
|
43 solidLand = , |
|
44 artillery = , |
|
45 hogHat = , |
|
46 hogName = , |
|
47 teamName = , |
|
48 teamGrave = , |
|
49 clanColor = , |
|
50 goalText = , |
|
51 shootText = |
|
52 } |
|
53 TargetPracticeMission(params) |
|
54 ----- snip ----- |
|
55 ]=] |
|
56 |
|
57 HedgewarsScriptLoad("/Scripts/Locale.lua") |
|
58 |
|
59 local player = nil |
|
60 local scored = 0 |
|
61 local shots = 0 |
|
62 local end_timer = 1000 |
|
63 local game_lost = false |
|
64 local time_goal = 0 |
|
65 local total_targets |
|
66 local targets |
|
67 |
|
68 --[[ |
|
69 TrainingMission(params) |
|
70 |
|
71 This function sets up the *entire* training mission and needs one argument: params. |
|
72 The argument “params” is a table containing fields which describe the training mission. |
|
73 mandatory fields: |
|
74 - missionTitle: the name of the mission |
|
75 - map: the name map to be used |
|
76 - theme: the name of the theme (does not need to be a standalone theme) |
|
77 - time: the time limit in milliseconds |
|
78 - ammoType: the ammo type of the weapon to be used |
|
79 - gearType: the gear type of the gear which is fired (used to count shots) |
|
80 - targets: The coordinates of where the targets will be spawned. |
|
81 It is a table containing tables containing coordinates of format |
|
82 { x=value, y=value }. The targets will be spawned in the same |
|
83 order as specified the coordinate tables appear. Example: |
|
84 targets = { |
|
85 { x = 324, y = 43 }, |
|
86 { x = 123, y = 56 }, |
|
87 { x = 6, y = 0 }, |
|
88 } |
|
89 There must be at least 1 target. |
|
90 |
|
91 optional fields: |
|
92 - wind: the initial wind (-100 to 100) (default: 0 (no wind)) |
|
93 - solidLand: weather the terrain is indestructible (default: false) |
|
94 - artillery: if true, the hog can’t move (default: false) |
|
95 - hogHat: hat of the hedgehog (default: "NoHat") |
|
96 - hogName: name of the hedgehog (default: "Trainee") |
|
97 - teamName: name of the hedgehog’s team (default: "Training Team") |
|
98 - teamGrave: name of the hedgehog’s grave |
|
99 - clanColor: color of the (only) clan (default: 0xFF0204, which is a red tone) |
|
100 - goalText: A short string explaining the goal of the mission |
|
101 (default: "Destroy all targets within the time!") |
|
102 - shootText: A string which says how many times the player shot, “%d” is replaced |
|
103 by the number of shots. (default: "You have shot %d times.") |
|
104 ]] |
|
105 function TargetPracticeMission(params) |
|
106 if params.hogHat == nil then params.hogHat = "NoHat" end |
|
107 if params.hogName == nil then params.hogName = loc("Trainee") end |
|
108 if params.teamName == nil then params.teamName = loc("Training Team") end |
|
109 if params.goalText == nil then params.goalText = loc("Eliminate all targets before your time runs out.|You have unlimited ammo for this mission.") end |
|
110 if params.shootText == nil then params.shootText = loc("You have shot %d times.") end |
|
111 if params.clanColor == nil then params.clanColor = 0xFF0204 end |
|
112 if params.teamGrave == nil then params.teamGrave= "Statue" end |
|
113 if params.wind == nil then params.wind = 0 end |
|
114 |
|
115 local solid, artillery |
|
116 if params.solidLand == true then solid = gfSolidLand else solid = 0 end |
|
117 if params.artillery == true then artillery = gfArtillery else artillery = 0 end |
|
118 |
|
119 targets = params.targets |
|
120 |
|
121 total_targets = #targets |
|
122 |
|
123 _G.onAmmoStoreInit = function() |
|
124 SetAmmo(params.ammoType, 9, 0, 0, 0) |
|
125 end |
|
126 |
|
127 _G.onGameInit = function() |
|
128 Seed = 1 |
|
129 GameFlags = gfDisableWind + gfInfAttack + gfOneClanMode + solid + artillery |
|
130 TurnTime = params.time |
|
131 Map = params.map |
|
132 Theme = params.theme |
|
133 Goals = params.goalText |
|
134 CaseFreq = 0 |
|
135 MinesNum = 0 |
|
136 Explosives = 0 |
|
137 |
|
138 SetWind(params.wind) |
|
139 |
|
140 AddTeam(loc(params.teamName), params.clanColor, params.teamGrave, "Island", "Default", "Flowerhog") |
|
141 |
|
142 player = AddHog(loc(params.hogName), 0, 1, params.hogHat) |
|
143 SetGearPosition(player, params.hog_x, params.hog_y) |
|
144 end |
|
145 |
|
146 _G.onGameStart = function() |
|
147 SendHealthStatsOff() |
|
148 ShowMission(params.missionTitle, loc("Aiming practice"), params.goalText, -params.ammoType, 5000) |
|
149 spawnTarget() |
|
150 end |
|
151 |
|
152 _G.onNewTurn = function() |
|
153 -- TODO: Remove the else branch when 0.9.21 has been released |
|
154 if SetWeapon ~= nil then |
|
155 SetWeapon(params.ammoType) |
|
156 else |
|
157 ParseCommand("/setweap "..string.char(params.ammoType)) |
|
158 end |
|
159 end |
|
160 |
|
161 _G.spawnTarget = function() |
|
162 gear = AddGear(0, 0, gtTarget, 0, 0, 0, 0) |
|
163 |
|
164 x = targets[scored+1].x |
|
165 y = targets[scored+1].y |
|
166 |
|
167 SetGearPosition(gear, x, y) |
|
168 end |
|
169 |
|
170 _G.onGameTick20 = function() |
|
171 if TurnTimeLeft < 40 and TurnTimeLeft > 0 and scored < total_targets and game_lost == false then |
|
172 game_lost = true |
|
173 AddCaption(loc("Time’s up!"), 0xFFFFFFFF, capgrpGameState) |
|
174 ShowMission(params.missionTitle, loc("Aiming practice"), loc("Oh no! Time's up! Just try again."), -amSkip, 0) |
|
175 SetHealth(player, 0) |
|
176 time_goal = 1 |
|
177 end |
|
178 |
|
179 if band(GetState(player), gstDrowning) == gstDrowning and game_lost == false and scored < total_targets then |
|
180 game_lost = true |
|
181 time_goal = 1 |
|
182 AddCaption(loc("You lose!"), 0xFFFFFFFF, capgrpGameState) |
|
183 ShowMission(params.missionTitle, loc("Aiming practice"), loc("Oh no! You failed! Just try again."), -amSkip, 0) |
|
184 end |
|
185 |
|
186 if scored == total_targets or game_lost then |
|
187 if end_timer == 0 then |
|
188 generateStats() |
|
189 EndGame() |
|
190 else |
|
191 TurnTimeLeft = time_goal |
|
192 end |
|
193 end_timer = end_timer - 20 |
|
194 end |
|
195 end |
|
196 |
|
197 _G.onGearAdd = function(gear) |
|
198 if GetGearType(gear) == params.gearType then |
|
199 shots = shots + 1 |
|
200 end |
|
201 end |
|
202 |
|
203 _G.onGearDamage = function(gear, damage) |
|
204 if GetGearType(gear) == gtTarget then |
|
205 scored = scored + 1 |
|
206 if scored < total_targets then |
|
207 AddCaption(string.format(loc("Targets left: %d"), (total_targets-scored)), 0xFFFFFFFF, capgrpMessage) |
|
208 spawnTarget() |
|
209 else |
|
210 if not game_lost then |
|
211 AddCaption(loc("You have destroyed all targets!"), 0xFFFFFFFF, capgrpGameState) |
|
212 ShowMission(params.missionTitle, loc("Aiming practice"), loc("Congratulations! You have destroyed all targets within the time."), 0, 0) |
|
213 PlaySound(sndVictory, player) |
|
214 SetState(player, bor(GetState(player), gstWinner)) |
|
215 time_goal = TurnTimeLeft |
|
216 end |
|
217 end |
|
218 end |
|
219 |
|
220 if GetGearType(gear) == gtHedgehog then |
|
221 if not game_lost then |
|
222 game_lost = true |
|
223 AddCaption(loc("You lose!", 0xFFFFFFFF, capgrpGameState)) |
|
224 ShowMission(params.missionTitle, loc("Aiming practice"), loc("Oh no! You failed! Just try again."), -amSkip, 0) |
|
225 |
|
226 SetHealth(player, 0) |
|
227 time_goal = 1 |
|
228 end |
|
229 end |
|
230 end |
|
231 |
|
232 _G.generateStats = function() |
|
233 local accuracy = (scored/shots)*100 |
|
234 local end_score_targets = scored * math.ceil(6000/#targets) |
|
235 local end_score_overall |
|
236 if not game_lost then |
|
237 local end_score_time = math.ceil(time_goal/(params.time/6000)) |
|
238 local end_score_accuracy = math.ceil(accuracy * 60) |
|
239 end_score_overall = end_score_time + end_score_targets + end_score_accuracy |
|
240 |
|
241 SendStat(siGameResult, loc("You have finished the target practice!")) |
|
242 |
|
243 SendStat(siCustomAchievement, string.format(loc("You have destroyed %d of %d targets (+%d points)."), scored, total_targets, end_score_targets)) |
|
244 SendStat(siCustomAchievement, string.format(params.shootText, shots)) |
|
245 SendStat(siCustomAchievement, string.format(loc("Your accuracy was %.1f%% (+%d points)."), accuracy, end_score_accuracy)) |
|
246 SendStat(siCustomAchievement, string.format(loc("You had %.1fs remaining on the clock (+%d points)."), (time_goal/1000), end_score_time)) |
|
247 else |
|
248 SendStat(siGameResult, loc("You lose!")) |
|
249 |
|
250 SendStat(siCustomAchievement, string.format(loc("You have destroyed %d of %d targets (+%d points)."), scored, total_targets, end_score_targets)) |
|
251 SendStat(siCustomAchievement, string.format(params.shootText, shots)) |
|
252 if(shots > 0) then |
|
253 SendStat(siCustomAchievement, string.format(loc("Your accuracy was %.1f%%."), accuracy)) |
|
254 end |
|
255 end_score_overall = end_score_targets |
|
256 end |
|
257 SendStat(siPlayerKills, tostring(end_score_overall), loc(params.teamName)) |
|
258 SendStat(siPointType, loc("points")) |
|
259 end |
|
260 end |