1-----------------------------------------------------------
2--- HEDGE EDITOR (for use with Hedgewars 0.9.22 and up) ---
3-----------------------------------------------------------
4-- A not-so-horrible mission editor.
5-- Place gears like a boss!
6
7-- Original author: mikade
8
9-- feel free to shower me with your adoration and/or hate mail
10-- more info can be found at https://hedgewars.org/HedgeEditor
11
12-- special thanks to nemo, unC0Rr, sheepluva and koda for their assistance
13
14---------------------------------------
15-- GETTING STARTED (for best results!)
16---------------------------------------
17-- create a weaponset that has NO DELAYS on any weapons, and that gives you 1 ammo per crate
18
19-- (optional) copy GameLogExtractor.html, jquery-1.js
20-- into your Documents/Hedgewars/Logs folder
21
22-- (optional) copy hwpmapconverter somewhere easily accessible
23
24-- (optional) profit??
25
26---------------------------------------
27-- CORE FEATURES as of latest version
28---------------------------------------
29-- togglable help (press PRECISE + 1, while you have a tool (e.g. airstrike) selected)
30
31-- place girders, rubberbands and custom sprites anywhere on the map.
32-- the above objects may be destructible, indestructible, icy, or bouncy.
33
34-- place mines, sticky mines, air mines, barrels, weapon crates, utility crates,
35-- health crates, targets, and cleavers anywhere on the map.
36
37-- select, reposition, modify, or delete placed objects.
38
39-- read in data from a previously generated map and allow the map to be edited/saved again
40
41-- contextual cursor and menu graphics
42-- placement sounds that are slightly more soothing
43
44-- upon saving, all level data will be output to logs/game0.log.
45-- game0.log also includes a lot of other data so if you only want to see the relevant lines of code
46-- you can use GameLogExtractor.html to extract and prune the log into a cleaner form of data,
47-- specifically: either as an automagically generated template mission, just core data, or hwmap points.
48-- from there, please copy and paste any lines relevant to your interest into an existing
49-- (or totally empty!) script and edit them according to taste.
50
51--------------------------
52-- MODE SPECIFIC SUPPORT
53--------------------------
54-- FOR CUSTOM MISSIONS/CAMPAIGN LEVELS:
55-- the names/hats/flags/voices/graves of any teams/hogs that you use to play this script can be saved,
56-- as can (most of) the settings from your scheme and weapons selection.
57-- HOWEVER, you can also use the 'hog identity' tool to give hogs preset names/hats/weapons/health
58-- or use the 'team identity' tool to give an entire team themed names/hats.
59-- give hogs differing health by using the health modification tool
60-- create goals by tagging gears with victory/defeat/collection markers (somewhat implemented)
61-- flavor text, as well as victory/defeat conditions will be generated based on these tags.
62
63-- SHOPPA BALANCE / CONSTRUCTION MODE (partial and/or possibly decremented):
64-- Press 1-5 while repositioning hogs with the reposition tool to assign them (their position) a rank.
65-- This value will be expressed as a colour that is intended to represent how "good" or "bad"
66-- a position on the map is. These ranks/points will be output along with other game data to game0.log
67-- This data could be pasted into the ShoppaBalance script to create balances for additional maps.
68
69-- TECH RACER / HEDGE EDITOR / POINT INTERPRETER:
70-- place/remove waypoints/special points
71-- use the ScriptParameter in the frontend scheme editor to set additional options, e.g.
72-- ufoFuel=1000 (Flying Saucer will start with half the normal fuel. A value of 2000 is infinite fuel)
73-- portalDistance=15 (This is the distance portals can travel before fizzling)
74-- m=3 (load a particular map from the map library of Data/Scripts/TechMaps
75
76-- when saving data, points for conversion to HWMAP are also generated and placed inside block comments.
77-- copy paste/these points at the START of a converted HWMAP and then convert the map back to HWMAP format.
78-- following the above procedure it is then possible to load the map in frontend and play it using a
79-- script like TechRacer (or HedgeEditor itself) that can interpret the points using InterpretPoints()
80
81---------------------------------------
82-- MIKADE'S DISCLAIMER
83---------------------------------------
84-- well, I really just made this for myself, so it's usage might be a little complicated for others.
85-- it also probably has a million errors, and has grown rather bloated over time due to the addition of
86-- more and more features that my initial design didn't take into account.
87
88-- anyway, I've tried to make it more user-friendly by including more comments and gradually adding
89-- some basic guidelines such as those listed above, and also the in-game Help displays for each tool.
90
91-----------------------------------------
92-- GIANT "TO DO" LIST / OTHER NOTES
93-----------------------------------------
94
95-- try to prune waypoint list and portal/ufo fuel in the mission template
96-- for gamelog extractor
97
98-- I should probably check if there are tagged gears on save
99-- and if there are enable gfOneClanMode so that user can't
100-- just destroy all hogs to win map.
101-- (what happens if we lose all our hogs?)
102
103-- I might be able to make the flavor text even better (assassinate hogName) by
104-- checking if there is only 1 hog, etc.
105
106-- possibly try show landflag addcaption constantly like we do for superdelete when
107-- using girders / rubbers.
108
109-- How about a weapons profile tool that is used with team ammo
110-- and then hog identity tool would only be available if gfPerHogAmmo is set
111
112-- [high]       check if we lose a mission when the enemy collects our crate (we should)
113
114-- [high] 	waypoints don't reload yet
115
116-- [high] 	add missing ammo types as they appear
117
118-- [med] 	add a limited form of save/load within level before mass-output
119
120-- [med]	maybe incorporate portal effects / ufo tracking into the template generated script if
121-- 			you want the missions to use it
122
123-- [med]	improve ammo handling (if possible, take more scheme settings into account)
124
125-- [low] 	break up the division of labor of the tools into airstrike, minestrike, napalm, etc.
126			--[[
127			girder =		"Girder Placement Mode",
128			rubber =		"Rubber Placement Mode",
129
130			airstrike =		(target sprite) (gear placement)
131							"Mine Placement Mode",
132							"Sticky Mine Placement Mode",
133							"Air Mine Placement Mode",
134							"Barrel Placement Mode",
135							"Target Placement Mode",
136							"Cleaver Placement Mode",
137
138			drillstrike =	crate sprite (crate placement mode)
139							"Health Crate Placement Mode",
140							"Weapon Crate Placement Mode",
141							"Utility Crate Placement Mode",
142
143
144			napalm =		arrow sprite (selection/modification/deletion mode)
145							"Repositioning Mode",  -- also include a delete
146							"Goal Editing Mode",
147							"Hog Identity Mode",
148							"Team Identity Mode",
149							"Health Modification Mode",
150							"Sprite Testing Mode",
151							"Sprite Modification Mode",
152							"Sprite Placement Mode",
153							"Waypoint Editing Mode"
154							}]]
155
156-- [low]	improve support for ShoppaBalance and ConstructionMode, see ranking)
157
158-- [low]	eventually incorporate scripted structures into the editor / mission mode
159
160-- [low] 	some kind of support for single team training missions
161-- 			we could possibly add gfOneClanMode and kill the other team we're playing with?
162
163-- [never?] more detailed goal tagging and multi-stage triggers
164
165-- [never?]	add a pulsing glow thing for sprites you have selected,
166--			kind of like the invaders in SpaceInvader (currently they are just displayed as purple)
167
168-- [never?]	add GUIs for editing ammo, init settings, additional gear attributes
169-- 			perhaps using precise with timer to enable/disable certain features
170
171--[[ gui menu ideas that have long since been abandoned
172INITIALISATION MENU
173	--gameFlags, etc
174
175	Map
176	Theme
177	TurnTime
178	Explosives
179	MinesNum
180	CaseFreq
181	Delay
182
183	HealthCaseProb
184	HealthCaseAmount
185	DamagePercent
186	MinesTime
187	MineDudPercent
188	SuddenDeathTurns
189	WaterRise
190	HealthDecrease
191HOG MENU
192	health
193	name (can be randomly generated from the list of hog names already in localisation)
194	poisoned (true/false)
195	hat
196	hog level?
197TEAM MENU
198	name (can be randomly generated as above?) should there be an array of teams with an array of names
199	colour
200	grave
201	fort
202	voicepack
203	flag
204
205-- this below stuff is less important
206STICKY MINE MENU
207	timer?
208MINE MENU
209	timer / dud
210MEDKIT MENU / EXPLOSIVE MENU
211	health amount
212WEP AND UTIL CRATE MENU
213	contents
214
215----------------------------------------
216-- MAP IDEAS
217----------------------------------------
218-- try to create a portal race (limit portal distance)
219-- for portal race, include barriers that you need to drill shoot through to get lazer site crates
220
221-- try make a map that uses sinegun to jump between bouncy boxes (not easy until we get better control over landflags)
222
223-- how about a mission where you have to trap / freeze all the enemy hogs
224-- and aren't allowed to kill them?
225-- can set it on the islands map.
226-- landgun
227-- girder
228-- mudball
229-- hammer
230-- seduction? (call a hog who has firepunch into a ditch
231-- icegun (do this so you can freeze guys in an area and then blowtorch/explode an obstacle)
232-- jump across a bridge that has been mined and then bat the enemy to the other side.
233
234-- possibly the same as part of the above, possibly different, what about a heist mission
235-- the objective is to steal 3 enemy crates
236-- the first one you have to fall through an invul tunnel of sticky mines and then parachute.
237-- the second one you have to drill rocket / portal.
238-- the third one you have to underwater ufo into, but only after opening it up with an underwater bee.
239
240]]
241
242---------------------------------------------------------
243-- HEDGE EDITOR, SCRIPT BEGINS (Hey yo, it's about time)
244---------------------------------------------------------
245
246-- Tell other scripts that we exist
247HedgeEditor = true
248
249HedgewarsScriptLoad("/Scripts/Locale.lua")
250HedgewarsScriptLoad("/Scripts/Tracker.lua")
251HedgewarsScriptLoad("/Scripts/Params.lua")
252HedgewarsScriptLoad("/Scripts/TechMaps.lua")
253
254-- Fake ammo type for the gear placement tool
255local amCMGearPlacementTool = amAirAttack
256
257-- Special frames in Ammos.png/Ammos_bw.png
258local ammoFrameAirAttack = 63
259
260-- Caption colors
261local colorErrorMessage = 0xFFFFFFFF
262local colorInfoMessage = 0xFFFFFFFF
263local colorPlaceMode1 = 0xFFBA00FF -- Main placement mode
264local colorPlaceMode2 = 0xFFDE85FF -- Secondary mode
265
266-----------------------------------------
267-- tracking vars for save/load purposes
268-----------------------------------------
269
270local teamCounter = 0
271local lastRecordedTeam = ""
272local hhs = {}
273
274local waypointList = {}
275local girderList = {}
276local rubberList = {}
277local spriteList = {}
278
279local mineList = {}
280local sMineList = {}
281local airMineList = {}
282local targetList = {}
283local knifeList = {}
284local explosivesList = {}
285local healthCrateList = {}
286local wepCrateList = {}
287local utilCrateList = {}
288local hogDataList = {}
289local AIHogDataList = {}
290local hFlagList = {}
291local previewDataList = {}
292
293local shoppaPointList = {}
294local shoppaPX = {}
295local shoppaPY = {}
296local shoppaPR = {}
297
298-- Misc. state variables
299local hedgeEditorMissionPanelShown = false
300
301local tagCursorX, tagCursorY
302
303---------------------------------
304-- crates are made of this stuff
305---------------------------------
306
307local atkArray =
308				{
309
310				{amBazooka, 	"amBazooka"},
311				{amBee, 	"amBee"},
312				{amMortar, 	"amMortar"},
313				{amDrill, 	"amDrill"},
314				{amSnowball, 	"amSnowball"},
315				{amKnife,	"amKnife"},
316
317				{amGrenade,	"amGrenade"},
318				{amClusterBomb,	"amClusterBomb"},
319				{amWatermelon, 	"amWatermelon"},
320				{amHellishBomb,	"amHellishBomb"},
321				{amMolotov, 	"amMolotov"},
322				{amGasBomb, 	"amGasBomb"},
323
324				{amShotgun,	"amShotgun"},
325				{amDEagle,	"amDEagle"},
326				{amSniperRifle,	"amSniperRifle"},
327				{amSineGun, 	"amSineGun"},
328				{amIceGun, 	"amIceGun"},
329				{amMinigun, 	"amMinigun"},
330
331				{amFirePunch, 	"amFirePunch"},
332				{amWhip,	"amWhip"},
333				{amBaseballBat, "amBaseballBat"},
334				{amKamikaze, 	"amKamikaze"},
335				{amSeduction, 	"amSeduction"},
336				{amHammer,	"amHammer"},
337
338				{amMine, 	"amMine"},
339				{amDynamite, 	"amDynamite"},
340				{amCake, 	"amCake"},
341				{amBallgun, 	"amBallgun"},
342				{amRCPlane,	"amRCPlane"},
343				{amSMine,	"amSMine"},
344
345				{amAirAttack,	"amAirAttack", ammoFrameAirAttack}, -- overwritten icon in Ammos.png
346				{amMineStrike,	"amMineStrike"},
347				{amNapalm, 	"amNapalm"},
348				{amPiano,	"amPiano"},
349				{amDrillStrike,	"amDrillStrike"},
350				{amAirMine,	"amAirMine"},
351
352				{amPickHammer,	"amPickHammer"},
353				{amBlowTorch, 	"amBlowTorch"},
354				{amFlamethrower,"amFlamethrower"},
355
356				{amBirdy,	"amBirdy"},
357
358				}
359
360local utilArray =
361				{
362				{amGirder, 	"amGirder"},
363				{amLandGun,	"amLandGun"},
364				{amRubber, 	"amRubber"},
365
366				{amRope, 	"amRope"},
367				{amParachute, 	"amParachute"},
368				{amTeleport,	"amTeleport"},
369				{amJetpack,	"amJetpack"},
370				{amPortalGun,	"amPortalGun"},
371
372				{amInvulnerable,"amInvulnerable"},
373				{amLaserSight,	"amLaserSight"},
374				{amVampiric,	"amVampiric"},
375				{amResurrector, "amResurrector"},
376				{amTardis, 	"amTardis"},
377
378				{amSwitch,	"amSwitch"},
379				{amLowGravity, 	"amLowGravity"},
380				{amExtraDamage, "amExtraDamage"},
381				{amExtraTime,	"amExtraTime"},
382
383				}
384
385				--skiphog is 6
386
387local effectArray = { heInvulnerable, hePoisoned, heResurrectable, heResurrected, heFrozen, heArtillery }
388local effectStr = { "heInvulnerable", "hePoisoned", "heResurrectable", "heResurrected", "heFrozen", "heArtillery" }
389
390----------------------------
391-- hog and map editing junk
392----------------------------
393
394local preMadeTeam = 	{
395
396				{
397				loc_noop("Clowns"),
398				{"WhySoSerious","clown-copper","clown-crossed","clown","Joker"},
399				{loc_noop("Baggy"),loc_noop("Bingo"),loc_noop("Bobo"),loc_noop("Bozo"),loc_noop("Buster"),loc_noop("Chester"),loc_noop("Copper"),loc_noop("Heckles"),loc_noop("Giggles"),loc_noop("Jingo"),loc_noop("Molly"),loc_noop("Loopy"),loc_noop("Patches"),loc_noop("Tatters")},
400				"R","cm_balls","Mobster","Rubberduck","Castle"
401				},
402
403				{
404				loc_noop("Street Fighters"),
405				{"sf_balrog","sf_blanka","sf_chunli","sf_guile","sf_honda","sf_ken","sf_ryu","sf_vega"},
406				{loc_noop("Balrog"),loc_noop("Blanka"),loc_noop("Chunli"),loc_noop("Guile"),loc_noop("Honda"),loc_noop("Ken"),loc_noop("Ryu"),loc_noop("Vega")},
407				"F","cm_balrog","Surfer","dragonball","Castle"
408				},
409
410				{
411				loc_noop("Cybernetic Empire"),
412				{"cyborg1","cyborg2"},
413				{loc_noop("Unit 189"),loc_noop("Unit 234"),loc_noop("Unit 333"),loc_noop("Unit 485"),loc_noop("Unit 527"),loc_noop("Unit 638"),loc_noop("Unit 709"),loc_noop("Unit 883")},
414				"R","cm_binary","Robot","Grave","Castle"
415				},
416
417				{
418				loc_noop("Color Squad"),
419				{"hair_blue","hair_green","hair_red","hair_yellow","hair_purple","hair_grey","hair_orange","hair_pink"},
420				{loc_noop("Blue"),loc_noop("Green"),loc_noop("Red"),loc_noop("Yellow"),loc_noop("Purple"),loc_noop("Grey"),loc_noop("Orange"),loc_noop("Pink")},
421				"F","mauritius","Singer","Grave","Castle"
422				},
423
424				{
425				loc_noop("Fruit"),
426				{"fr_apple","fr_banana","fr_lemon","fr_orange","fr_pumpkin","fr_tomato"},
427				{loc_noop("Juicy"),loc_noop("Squishy"),loc_noop("Sweet"),loc_noop("Sour"),loc_noop("Bitter"),loc_noop("Ripe"),loc_noop("Rotten"),loc_noop("Fruity")},
428				"R","cm_mog","Default","Cherry","Castle"
429				},
430
431				{
432				loc_noop("The Police"),
433				{"bobby","bobby2v","policecap","policegirl","royalguard"},
434				{loc_noop("Hightower"),loc_noop("Lassard"),loc_noop("Callahan"),loc_noop("Jones"),loc_noop("Harris"),loc_noop("Thompson"),loc_noop("Mahoney"),loc_noop("Hooks"),loc_noop("Tackleberry")},
435				"R","cm_star","British","Statue","Castle"
436				},
437
438				{
439				loc_noop("The Ninja-Samurai Alliance"),
440				{"NinjaFull","NinjaStraight","NinjaTriangle","Samurai","StrawHat","StrawHatEyes","StrawHatFacial","naruto"},
441				{loc_noop("Bushi"),loc_noop("Tatsujin"),loc_noop("Itami"),loc_noop("Arashi"),loc_noop("Shinobi"),loc_noop("Ukemi"),loc_noop("Godai"),loc_noop("Kenshi"),loc_noop("Ninpo")},
442				"R","japan","Default","octopus","Castle"
443				},
444
445				{
446				loc_noop("Pokémon"),
447				{"poke_ash","poke_charmander","poke_chikorita","poke_jigglypuff","poke_lugia","poke_mudkip","poke_pikachu","poke_slowpoke","poke_squirtle","poke_voltorb"},
448				{loc_noop("Ash"),loc_noop("Charmander"),loc_noop("Chikorita"),loc_noop("Jigglypuff"),loc_noop("Lugia"),loc_noop("Mudkip"),loc_noop("Pikachu"),loc_noop("Slowpoke"),loc_noop("Squirtle"),loc_noop("Voltorb")},
449				"FR","cm_pokemon","Default","pokeball","Castle"
450				},
451
452				{
453				loc_noop("The Zoo"),
454				{"zoo_Bat","zoo_Beaver","zoo_Bunny","zoo_Deer","zoo_Hedgehog","zoo_Moose","zoo_Pig","zoo_Porkey","zoo_Sheep","zoo_chicken","zoo_elephant","zoo_fish","zoo_frog","zoo_snail","zoo_turtle"},
455				{loc_noop("Batty"),loc_noop("Tails"),loc_noop("Bunny"),loc_noop("Deer"),loc_noop("Spikes"),loc_noop("Horns"),loc_noop("Bacon"),loc_noop("Porkey"),loc_noop("Sheepy"),loc_noop("Chicken"),loc_noop("Trunks"),loc_noop("Fishy"),loc_noop("Legs"),loc_noop("Slimer"),loc_noop("Roshi")},
456				"FR","cm_birdy","Default","Bone","Castle"
457				},
458
459				{
460				loc_noop("The Devs"),
461				{"ushanka","zoo_Sheep","bb_bob","Skull","poke_mudkip","lambda","WizardHat","sf_ryu","android","fr_lemon","mp3"},
462				{loc_noop("unC0Rr"), loc_noop("sheepluva"), loc_noop("nemo"), loc_noop("mikade"), loc_noop("koda"), loc_noop("burp"),loc_noop("HeneK"),loc_noop("Tiyuri"),loc_noop("Xeli"),loc_noop("Displacer"),loc_noop("szczur")},
463				"FR","cm_hw","Classic","Statue","Castle"
464				},
465
466				{
467				loc_noop("Mushroom Kingdom"),
468				{"sm_daisy","sm_luigi","sm_mario","sm_peach","sm_toad","sm_wario","NoHat","NoHat"},
469				{loc_noop("Daisy"),loc_noop("Luigi"),loc_noop("Mario"),loc_noop("Princess Peach"),loc_noop("Toad"),loc_noop("Wario"),loc_noop("Yoshi"),loc_noop("Waluigi")},
470				"FR","comoros","Default","Badger","Castle"
471				},
472
473				{
474				loc_noop("Pirates"),
475				{"pirate_jack","pirate_jack_bandana"},
476				{loc_noop("Rusted Diego"),loc_noop("Fuzzy Beard"),loc_noop("Al.Kaholic"),loc_noop("Morris"),loc_noop("Yumme Gunpowder"),loc_noop("Cutlass Cain"),loc_noop("Jim Morgan"),loc_noop("Silver"),loc_noop("Dubloon Devil"),loc_noop("Ugly Mug"),loc_noop("Fair Wind"),loc_noop("Scallywag"),loc_noop("Salty Dog"),loc_noop("Bearded Beast"),loc_noop("Timbers"),loc_noop("Both Barrels"),loc_noop("Jolly Roger")},
477				"R","cm_pirate","Pirate","chest","Castle"
478				},
479
480				{
481				loc_noop("Gangsters"),
482				{"Moustache","Cowboy","anzac","Bandit","thug","Jason","NinjaFull","chef"},
483				{loc_noop("The Boss"),loc_noop("Jimmy"),loc_noop("Frankie"),loc_noop("Morris"),loc_noop("Mooney"),loc_noop("Knives"),loc_noop("Tony"),loc_noop("Meals")},
484				"F","cm_anarchy","Mobster","deadhog","Castle"
485				},
486
487
488				{
489				loc_noop("Twenty-Twenty"),
490				{"Glasses","lambda","SunGlasses","Sniper","Terminator_Glasses","Moustache_glasses","doctor","punkman","rasta"},
491				{loc_noop("Specs"),loc_noop("Speckles"),loc_noop("Spectator"),loc_noop("Glasses"),loc_noop("Glassy"),loc_noop("Harry Potter"),loc_noop("Goggles"),loc_noop("Clark Kent"),loc_noop("Goggs"),loc_noop("Lightbender"),loc_noop("Specs Appeal"),loc_noop("Four Eyes")},
492				"R","cm_face","Default","eyecross","Castle"
493				},
494
495
496				{
497				loc_noop("Monsters"),
498				{"Skull","Jason","ShaggyYeti","Zombi","cyclops","Mummy","hogpharoah","vampirichog"},
499				{loc_noop("Bones"),loc_noop("Jason"),loc_noop("Yeti"),loc_noop("Zombie"),loc_noop("Old One Eye"),loc_noop("Ramesses"),loc_noop("Xerxes"),loc_noop("Count Hogula")},
500				"FR","cm_vampire","Default","octopus","Castle"
501				},
502
503				{
504				loc_noop("The Iron Curtain"),
505				{"ushanka","war_sovietcomrade1","war_sovietcomrade1","ushanka"},
506				{loc_noop("Alex"),loc_noop("Sergey"),loc_noop("Vladimir"),loc_noop("Andrey"),loc_noop("Dimitry"),loc_noop("Ivan"),loc_noop("Oleg"),loc_noop("Kostya"),loc_noop("Anton"),loc_noop("Eugene")},
507				"R","cm_soviet","Russian","skull","Castle"
508				},
509
510				{
511				loc_noop("Desert Storm"),
512				{"war_desertofficer","war_desertgrenadier1","war_desertmedic","war_desertsapper1","war_desertgrenadier2","war_desertgrenadier4","war_desertsapper2","war_desertgrenadier5"},
513				{loc_noop("Brigadier Briggs"),loc_noop("Lt. Luke"),loc_noop("Sgt. Smith"),loc_noop("Corporal Calvin"),loc_noop("Frank"),loc_noop("Joe"),loc_noop("Sam"),loc_noop("Donald")},
514				"F","bhutan","Default","Grave","Castle"
515				},
516
517				{
518				loc_noop("The Hospital"),
519				{"doctor","nurse","war_britmedic","war_desertmedic","war_germanww2medic"},
520				{loc_noop("Dr. Blackwell"),loc_noop("Dr. Drew"),loc_noop("Dr. Harvey"),loc_noop("Dr. Crushing"),loc_noop("Dr. Jenner"),loc_noop("Dr. Barnard"),loc_noop("Dr. Parkinson"),loc_noop("Dr. Banting"),loc_noop("Dr. Horace"),loc_noop("Dr. Hollows"),loc_noop("Dr. Jung")},
521				"R","cm_firstaid","Default","heart","Castle"
522				}
523
524				}
525
526local preMadeTeamNamesTranslated = {}
527local preMadeTeamNamesOriginal = {}
528for i=1, #preMadeTeam do
529	table.insert(preMadeTeamNamesOriginal, preMadeTeam[i][1])
530	table.insert(preMadeTeamNamesTranslated, loc(preMadeTeam[i][1]))
531end
532
533local gameFlagList =	{
534			{"gfOneClanMode", false, gfOneClanMode},
535			{"gfMultiWeapon", false, gfMultiWeapon},
536			{"gfSolidLand", false, gfSolidLand},
537			{"gfBorder", false, gfBorder},
538			{"gfDivideTeams", false, gfDivideTeams},
539			{"gfLowGravity", false, gfLowGravity},
540			{"gfLaserSight", true, gfLaserSight},
541			{"gfInvulnerable", false, gfInvulnerable},
542			{"gfResetHealth", false, gfResetHealth},
543			{"gfVampiric", false, gfVampiric},
544			{"gfKarma", false, gfKarma},
545			{"gfArtillery", false, gfArtillery},
546			{"gfSwitchHog", false, gfSwitchHog},
547			{"gfRandomOrder", false, gfRandomOrder},
548			{"gfKing", false, gfKing},
549			{"gfPlaceHog", false, gfPlaceHog},
550			{"gfSharedAmmo", false, gfSharedAmmo},
551			{"gfDisableGirders", false, gfDisableGirders},
552			{"gfDisableLandObjects", false, gfDisableLandObjects},
553			{"gfAISurvival", false, gfAISurvival},
554			{"gfInfAttack", true, gfInfAttack},
555			{"gfResetWeps", false, gfResetWeps},
556			{"gfPerHogAmmo", false, gfPerHogAmmo},
557			{"gfDisableWind", false, gfDisableWind},
558			{"gfMoreWind", false, gfMoreWind},
559			{"gfTagTeam", false, gfTagTeam},
560			{"gfShoppaBorder", false, gfShoppaBorder},
561			}
562
563 local reducedSpriteIDArray = {
564  sprTargetBee, sprAmGirder, sprAmRubber, sprIceTexture, sprHHTelepMask,
565  sprAMAmmos, sprAMAmmosBW, sprAMSlot, sprAMCorners, sprTurnsLeft, sprBotlevels,
566  sprSpeechCorner, sprSpeechEdge, sprSpeechTail, sprThoughtCorner, sprThoughtEdge, sprThoughtTail,
567  sprShoutCorner, sprShoutEdge, sprShoutTail, }
568
569 -- Set in onGameInit
570 local reducedSpriteIDArrayFrames
571
572 local reducedSpriteTextArray = {
573  "sprTargetBee", "sprAmGirder", "sprAmRubber", "sprIceTexture", "sprHHTelepMask",
574  "sprAMAmmos", "sprAMAmmosBW", "sprAMSlot",  "sprAMCorners", "sprTurnsLeft", "sprBotlevels",
575  "sprSpeechCorner", "sprSpeechEdge", "sprSpeechTail", "sprThoughtCorner", "sprThoughtEdge", "sprThoughtTail",
576  "sprShoutCorner", "sprShoutEdge", "sprShoutTail", }
577
578----------------------------
579-- placement shite
580----------------------------
581
582local landType = 0
583local superDelete = false
584local ufoGear = nil
585ufoFuel = 0
586mapID = 1
587local portalDistance = 5000/5
588local helpDisabled = false  --determines whether help popups pop up
589local CG = nil -- this is the visual gear displayed at CursorX, CursorY
590local crateSprite = nil-- this is a visual gear aid for crate placement
591local crateSpriteBorer = nil
592local waypointPreviewSprite = nil
593
594local cGear = nil -- detects placement of girders and objects (using airattack)
595local cGearPlacementDone = false
596local curWep = amNothing
597local leftHeld = false
598local rightHeld = false
599local preciseOn = false
600
601-- primary placement categories
602local cIndex = 1 -- category index
603local cat = 	{
604				loc("Girder Placement Mode"),
605				loc("Rubber Placement Mode"),
606				loc("Mine Placement Mode"),
607				loc("Dud Mine Placement Mode"),
608				loc("Sticky Mine Placement Mode"),
609				loc("Air Mine Placement Mode"),
610				loc("Barrel Placement Mode"),
611				loc("Health Crate Placement Mode"),
612				loc("Weapon Crate Placement Mode"),
613				loc("Utility Crate Placement Mode"),
614				loc("Target Placement Mode"),
615				loc("Cleaver Placement Mode"),
616				loc("Repositioning Mode"),
617				loc("Goal Definition Mode"),
618				loc("Hog Identity Mode"),
619				loc("Team Identity Mode"),
620				loc("Health Modification Mode"),
621				loc("Sprite Placement Mode"),
622				loc("Sprite Modification Mode"),
623				loc("Waypoint Editing Mode")
624				}
625
626
627local pMode = {}	-- pMode contains custom subsets of the main categories
628local pIndex = 1
629local sFrame = 0	-- frame in sprite placement mode
630
631local genTimer = 0
632
633local CGR = 1 -- current girder rotation, we actually need this as HW remembers what rotation you last used
634
635local placedX = {} -- x coord of placed object
636local placedY = {} -- y coord of placed object
637local placedSpec = {} -- this is different depending on what was placed, for mines it is their time, for crates it is their content, (for girders/rubbers it used to be their rotation, and for sprites, their name, but this has been moved to different variables to allow more complex / smooth editing)
638local placedType = {} -- what kind of object was placed: mine, crate, girder, rubber, barrel, etc.
639
640local placedTint = {} -- only girders/rubbers/sprites use this, it is their tint / colouration
641local placedSprite = {} -- what sprite was placed
642local placedFrame = {} -- what frame of sprite was placed (rotation for girders / rubber)
643local placedLandFlags = {}
644local placedHWMapFlag = {} -- this is what HWMapConverter uses
645local placedCount = 0 -- do we really need this?
646
647local sSprite -- sprite overlay that glows to show selected sprites
648local sCirc -- circle that appears around selected gears
649local sGear = nil
650local closestDist
651local closestGear = nil
652local closestSpriteID = nil
653
654local wpRadius = 450
655
656------------------------
657-- SOME GENERAL METHODS
658------------------------
659
660function BoolToString(boo)
661	if boo == true then
662		return("true")
663	else
664		return("false")
665	end
666end
667
668function GetDistFromGearToXY(gear, g2X, g2Y)
669
670	g1X, g1Y = GetGearPosition(gear)
671	q = g1X - g2X
672	w = g1Y - g2Y
673
674	return ( (q*q) + (w*w) )
675
676end
677
678------------------------------------------------------------
679-- STUFF FOR LOADING SPECIAL POINTS / HWMAP CONVERSION
680------------------------------------------------------------
681
682local specialPointsX = {}
683local specialPointsY = {}
684local specialPointsFlag = {}
685local specialPointsCount = 0
686
687function onSpecialPoint(x,y,flag)
688    specialPointsX[specialPointsCount] = x
689    specialPointsY[specialPointsCount] = y
690	specialPointsFlag[specialPointsCount] = flag
691    specialPointsCount = specialPointsCount + 1
692end
693
694-- you know you could probably add multiple layers to this to get more points
695-- after the first set is expended have the last 1 be 127
696-- and then increment some other counter so like
697
698-- this function interprets special points that have been embedded into an HWPMAP
699function InterpretPoints()
700
701	-- flags run from 0 to 127
702	for i = 0, (specialPointsCount-1) do
703
704		-- Mines
705		if specialPointsFlag[i] == 1 then
706			SetTimer(AddGear(specialPointsX[i], specialPointsY[i], gtMine, 0, 0, 0, 0), 1)
707		elseif specialPointsFlag[i] == 2 then
708			SetTimer(AddGear(specialPointsX[i], specialPointsY[i], gtMine, 0, 0, 0, 0), 1000)
709		elseif specialPointsFlag[i] == 3 then
710			SetTimer(AddGear(specialPointsX[i], specialPointsY[i], gtMine, 0, 0, 0, 0), 2000)
711		elseif specialPointsFlag[i] == 4 then
712			SetTimer(AddGear(specialPointsX[i], specialPointsY[i], gtMine, 0, 0, 0, 0), 3000)
713		elseif specialPointsFlag[i] == 5 then
714			SetTimer(AddGear(specialPointsX[i], specialPointsY[i], gtMine, 0, 0, 0, 0), 4000)
715		elseif specialPointsFlag[i] == 6 then
716			SetTimer(AddGear(specialPointsX[i], specialPointsY[i], gtMine, 0, 0, 0, 0), 5000)
717
718		-- Sticky Mines
719		elseif specialPointsFlag[i] == 7 then
720			AddGear(specialPointsX[i], specialPointsY[i], gtSMine, 0, 0, 0, 0)
721
722		-- Air Mines
723		elseif specialPointsFlag[i] == 8 then
724			AddGear(specialPointsX[i], specialPointsY[i], gtAirMine, 0, 0, 0, 0)
725
726		-- Health Crates
727		elseif specialPointsFlag[i] == 9 then
728			SetHealth(SpawnHealthCrate(specialPointsX[i],specialPointsY[i]),25)
729		elseif specialPointsFlag[i] == 10 then
730			SetHealth(SpawnHealthCrate(specialPointsX[i],specialPointsY[i]),50)
731		elseif specialPointsFlag[i] == 11 then
732			SetHealth(SpawnHealthCrate(specialPointsX[i],specialPointsY[i]),75)
733		elseif specialPointsFlag[i] == 12 then
734			SetHealth(SpawnHealthCrate(specialPointsX[i],specialPointsY[i]),100)
735
736		-- Cleaver
737		elseif specialPointsFlag[i] == 13 then
738			AddGear(specialPointsX[i], specialPointsY[i], gtKnife, 0, 0, 0, 0)
739
740		-- Target
741		elseif specialPointsFlag[i] == 14 then
742			AddGear(specialPointsX[i], specialPointsY[i], gtTarget, 0, 0, 0, 0)
743
744		--Barrels
745		elseif specialPointsFlag[i] == 15 then
746			SetHealth(AddGear(specialPointsX[i], specialPointsY[i], gtExplosives, 0, 0, 0, 0),1)
747		elseif specialPointsFlag[i] == 16 then
748			SetHealth(AddGear(specialPointsX[i], specialPointsY[i], gtExplosives, 0, 0, 0, 0),25)
749		elseif specialPointsFlag[i] == 17 then
750			SetHealth(AddGear(specialPointsX[i], specialPointsY[i], gtExplosives, 0, 0, 0, 0),50)
751		elseif specialPointsFlag[i] == 18 then
752			SetHealth(AddGear(specialPointsX[i], specialPointsY[i], gtExplosives, 0, 0, 0, 0),75)
753		elseif specialPointsFlag[i] == 19 then
754			SetHealth(AddGear(specialPointsX[i], specialPointsY[i], gtExplosives, 0, 0, 0, 0),100)
755
756		-- There are about 58+- weps / utils
757		-- Weapon Crates
758		elseif (specialPointsFlag[i] >= 20) and (specialPointsFlag[i] < (#atkArray+20)) then
759			tempG = SpawnAmmoCrate(specialPointsX[i],specialPointsY[i],atkArray[specialPointsFlag[i]-19][1])
760			setGearValue(tempG,"contents",atkArray[specialPointsFlag[i]-19][2])
761
762
763		-- Utility Crates
764		elseif (specialPointsFlag[i] >= (#atkArray+20)) and (specialPointsFlag[i] < (#atkArray+20+#utilArray)) then
765			tempG = SpawnUtilityCrate(specialPointsX[i],specialPointsY[i],utilArray[specialPointsFlag[i]-19-#atkArray][1])
766			setGearValue(tempG,"contents",utilArray[specialPointsFlag[i]-19-#atkArray][2])
767
768		--79-82 (reserved for future wep crates)
769		--89,88,87,86 and 85,84,83,82 (reserved for the 2 custom sprites and their landflags)
770
771		--90-99 reserved for scripted structures
772
773		elseif specialPointsFlag[i] == 98 then
774			portalDistance = div(specialPointsX[i],5)
775			ufoFuel = specialPointsY[i]
776
777		-- Normal Girders
778		elseif specialPointsFlag[i] == 100 then
779			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 0, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
780		elseif specialPointsFlag[i] == 101 then
781			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 1, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
782		elseif specialPointsFlag[i] == 102 then
783			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 2, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
784		elseif specialPointsFlag[i] == 103 then
785			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 3, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
786		elseif specialPointsFlag[i] == 104 then
787			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 4, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
788		elseif specialPointsFlag[i] == 105 then
789			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 5, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
790		elseif specialPointsFlag[i] == 106 then
791			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 6, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
792		elseif specialPointsFlag[i] == 107 then
793			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 7, U_LAND_TINT_NORMAL, nil, nil, nil, lfNormal)
794
795		-- Invulnerable Girders
796		elseif specialPointsFlag[i] == 108 then
797			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 0, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
798		elseif specialPointsFlag[i] == 109 then
799			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 1, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
800		elseif specialPointsFlag[i] == 110 then
801			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 2, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
802		elseif specialPointsFlag[i] == 111 then
803			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 3, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
804		elseif specialPointsFlag[i] == 112 then
805			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 4, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
806		elseif specialPointsFlag[i] == 113 then
807			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 5, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
808		elseif specialPointsFlag[i] == 114 then
809			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 6, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
810		elseif specialPointsFlag[i] == 115 then
811			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 7, U_LAND_TINT_INDESTRUCTIBLE, nil, nil, nil, lfIndestructible)
812
813		-- Icy Girders
814		elseif specialPointsFlag[i] == 116 then
815			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 0, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
816		elseif specialPointsFlag[i] == 117 then
817			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 1, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
818		elseif specialPointsFlag[i] == 118 then
819			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 2, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
820		elseif specialPointsFlag[i] == 119 then
821			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 3, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
822		elseif specialPointsFlag[i] == 120 then
823			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 4, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
824		elseif specialPointsFlag[i] == 121 then
825			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 5, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
826		elseif specialPointsFlag[i] == 121 then
827			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 6, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
828		elseif specialPointsFlag[i] == 123 then
829			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmGirder, 7, U_LAND_TINT_ICE, nil, nil, nil, lfIce)
830
831		-- Rubber Bands
832		elseif specialPointsFlag[i] == 124 then
833			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmRubber, 0, U_LAND_TINT_NORMAL, nil, nil, nil, lfBouncy)
834		elseif specialPointsFlag[i] == 125 then
835			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmRubber, 1, U_LAND_TINT_NORMAL, nil, nil, nil, lfBouncy)
836		elseif specialPointsFlag[i] == 126 then
837			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmRubber, 2, U_LAND_TINT_NORMAL, nil, nil, nil, lfBouncy)
838		elseif specialPointsFlag[i] == 127 then
839			PlaceSprite(specialPointsX[i], specialPointsY[i], sprAmRubber, 3, U_LAND_TINT_NORMAL, nil, nil, nil, lfBouncy)
840
841		-- Waypoints
842		else -- 0 / no value
843			PlaceWaypoint(specialPointsX[i],specialPointsY[i])
844		end
845
846	end
847
848end
849
850--shoppabalance crap
851function AddShoppaPoint(x,y,c)
852	table.insert(shoppaPX, x)
853	table.insert(shoppaPY, y)
854	table.insert(shoppaPR, c)
855end
856
857function GetRankedColour(r)
858	if r == 1 then
859		return(0xFF0000FF)
860	elseif r == 2 then
861		return(0xFFFF00FF)
862	elseif r == 3 then
863		return(0x00FF00FF)
864	elseif r == 4 then
865		return(0x0000FFFF)
866	elseif r == 5 then
867		return(0xFF00FFFF)
868	end
869end
870
871-----------------------------------------
872-- PRIMARY HEDGE EDITOR PLACEMENT STUFF
873-----------------------------------------
874
875function GetClosestGear()
876	closestDist = 999999999
877	closestGear = nil
878	runOnGears(SelectGear)
879	return(closestGear)
880end
881
882function SelectGear(gear)
883
884	d = GetDistFromGearToXY(gear, placedX[placedCount], placedY[placedCount])
885
886	if d < closestDist then
887		closestDist = d
888		closestGear = gear
889	end
890
891end
892
893function PlaceWaypoint(x,y)
894
895	placedX[placedCount] = x
896	placedY[placedCount] = y
897	placedType[placedCount] = loc("Waypoint Editing Mode")
898	placedLandFlags[placedCount] = nil -- use this to specify waypoint type maybe
899	placedHWMapFlag[placedCount] = 0
900
901	placedSprite[placedCount] = vgtCircle
902	placedSpec[placedCount] = AddVisualGear(x,y,vgtCircle,0,true)
903	placedTint[placedCount] = 0xFF0000FF
904	placedFrame[placedCount] = 1
905	SetVisualGearValues(placedSpec[placedCount], x, y, 164, 224, 1, 10, 0, wpRadius, 5, placedTint[placedCount])
906	placedCount = placedCount +1
907
908end
909
910function LoadSprite(pX, pY, pSprite, pFrame, pTint, p1, p2, p3, pLandFlags)
911
912	placedX[placedCount] = pX
913	placedY[placedCount] = pY
914	placedSpec[placedCount] = nil
915
916	if pSprite == sprAmGirder then
917
918		placedType[placedCount] = loc("Girder Placement Mode")
919
920		--newHWMapStuff
921		if pLandFlags == lfIndestructible then	specialMod = 1
922		elseif pLandFlags == lfIce then	specialMod = 2
923		else specialMod = 0
924		end
925		placedHWMapFlag[placedCount] = pFrame+100+(8*specialMod)
926
927
928	elseif pSprite == sprAmRubber then
929
930		placedType[placedCount] = loc("Rubber Placement Mode")
931
932		--newHWMapStuff
933		if pFrame == 0 then placedHWMapFlag[placedCount] = 124
934		elseif pFrame == 1 then placedHWMapFlag[placedCount] = 125
935		elseif pFrame == 2 then placedHWMapFlag[placedCount] = 126
936		elseif pFrame == 3 then placedHWMapFlag[placedCount] = 127
937		end
938
939	else
940		placedType[placedCount] = loc("Sprite Placement Mode")
941	end
942
943	if pLandFlags == lfIce then
944		placedLandFlags[placedCount] = "lfIce"
945	elseif pLandFlags == lfIndestructible then
946		placedLandFlags[placedCount] = "lfIndestructible"
947	elseif pLandFlags == lfBouncy then
948		placedLandFlags[placedCount] = "lfBouncy"
949	else
950		placedLandFlags[placedCount] = "lfNormal"
951	end
952
953	placedTint[placedCount] = pTint
954	placedFrame[placedCount] = pFrame
955
956	placedSprite[placedCount] = pSprite
957
958	local success = PlaceSprite(pX, pY, pSprite, pFrame, pTint, nil, nil, nil, pLandFlags)
959	if succcess then
960		placedCount = placedCount + 1
961	end
962
963end
964
965function CallPlaceSprite(pID, silent)
966
967	if silent == nil then
968		silent = false
969	end
970
971	if landType == lfIce then
972		placedLandFlags[pID] = "lfIce"
973		placedTint[pID] = U_LAND_TINT_ICE
974	elseif landType == lfIndestructible then
975		placedLandFlags[pID] = "lfIndestructible"
976		placedTint[pID] = U_LAND_TINT_INDESTRUCTIBLE
977	elseif landType == lfBouncy then
978		placedLandFlags[pID] = "lfBouncy"
979		placedTint[pID] = U_LAND_TINT_BOUNCY
980	else
981		placedLandFlags[pID] = "lfNormal"
982		placedTint[pID] = U_LAND_TINT_NORMAL
983	end
984
985	-- Special case: Placing amAirAttack of the ammos sprite (since this one is overwritten)
986	local actualDisplayedImage = placedFrame[pID]
987	if (placedSprite[pID] == sprAMAmmos or placedSprite[pID] == sprAMAmmosBW) and (actualDisplayedImage == (amAirAttack - 1)) then
988		actualDisplayedImage = ammoFrameAirAttack
989	end
990
991	local success = PlaceSprite(placedX[pID], placedY[pID], placedSprite[pID], actualDisplayedImage,
992		placedTint[pID],
993		nil, -- overrite existing land
994		nil, nil, -- this stuff specifies flipping
995		landType)
996
997	if not silent then
998		if success then
999			PlaySound(sndPlaced)
1000		else
1001			PlaySound(sndDenied)
1002		end
1003	end
1004
1005	return success
1006
1007end
1008
1009function SelectClosestSprite()
1010
1011	closestDist = 999999999
1012	closestSpriteID = nil -- just in case
1013
1014	for i = 0, (placedCount-1) do
1015		if (placedType[i] == loc("Girder Placement Mode"))
1016			or (placedType[i] == loc("Rubber Placement Mode"))
1017			or (placedType[i] == loc("Sprite Placement Mode"))
1018		then
1019				q = placedX[i] - placedX[placedCount]
1020				w = placedY[i] - placedY[placedCount]
1021				d = ( (q*q) + (w*w) )
1022				if d < closestDist then
1023					closestDist = d
1024					closestSpriteID = i
1025
1026					newTint = 0xFF00FFFF
1027
1028					SetVisualGearValues(sSprite, placedX[i], placedY[i], 0, 0, nil, placedFrame[i], 10000, placedSprite[i], 10000, newTint )
1029
1030				end
1031		end
1032	end
1033
1034end
1035
1036function EraseClosestSprite()
1037	if closestSpriteID ~= nil then
1038		EraseSprite(placedX[closestSpriteID], placedY[closestSpriteID], placedSprite[closestSpriteID], placedFrame[closestSpriteID],
1039                    nil, -- erase land only where the pixels match the land flag provided
1040                    nil, -- only erase the provided land flags. don't touch other land flags or LandPixels
1041                    nil, -- flip sprite horizontally
1042                    nil, -- flip sprite vertically
1043                    placedLandFlags[closestSpriteID])
1044
1045                PlaySound(sndBump)
1046
1047		placedX[closestSpriteID] = nil
1048		placedY[closestSpriteID] = nil
1049		placedSpec[closestSpriteID] = nil
1050		placedType[closestSpriteID] = nil
1051		placedTint[closestSpriteID] = nil
1052		placedSprite[closestSpriteID] = nil
1053		placedFrame[closestSpriteID] = nil
1054		placedLandFlags[closestSpriteID] = nil
1055		closestSpriteID = nil
1056		SetVisualGearValues(sSprite, 0, 0, 0, 0, 0, 1, 10000, sprAmGirder, 10000, 0x00000000 )
1057	else
1058		PlaySound(sndDenied)
1059	end
1060end
1061
1062-- work this into the above two functions and edit them, later
1063function EraseClosestWaypoint()
1064
1065	closestDist = 999999999
1066	closestSpriteID = nil -- just in case
1067
1068	for i = 0, (placedCount-1) do
1069		if (placedType[i] == loc("Waypoint Editing Mode")) then
1070			local q = placedX[i] - placedX[placedCount]
1071			local w = placedY[i] - placedY[placedCount]
1072			local d = ( (q*q) + (w*w) )
1073			if d < closestDist then
1074				closestDist = d
1075				closestSpriteID = i
1076
1077				SetVisualGearValues(sSprite, placedX[i], placedY[i], 0, 0, nil, placedFrame[i], 10000, placedSprite[i], 10000, newTint )
1078			end
1079		end
1080	end
1081
1082	if closestSpriteID ~= nil then
1083		DeleteVisualGear(placedSpec[closestSpriteID])
1084		placedX[closestSpriteID] = nil
1085		placedY[closestSpriteID] = nil
1086		placedSpec[closestSpriteID] = nil
1087		placedType[closestSpriteID] = nil
1088		placedTint[closestSpriteID] = nil
1089		placedSprite[closestSpriteID] = nil
1090		placedFrame[closestSpriteID] = nil
1091		placedLandFlags[closestSpriteID] = nil
1092		closestSpriteID = nil
1093		SetVisualGearValues(sSprite, 0, 0, 0, 0, 0, 1, 10000, sprAmGirder, 10000, 0x00000000 )
1094		PlaySound(sndBump)
1095	else
1096		PlaySound(sndDenied)
1097	end
1098end
1099
1100
1101-- essentially called when user clicks the mouse
1102-- with girders or an airattack
1103function PlaceObject(x,y)
1104
1105	placedX[placedCount] = x
1106	placedY[placedCount] = y
1107	placedType[placedCount] = cat[cIndex]
1108	placedSpec[placedCount] = pMode[pIndex]
1109	placedTint[placedCount] = nil
1110	placedFrame[placedCount] = nil
1111	placedLandFlags[placedCount] = nil
1112	placedSprite[placedCount] = nil
1113	placedHWMapFlag[placedCount] = nil
1114	placementSucceeded = true		-- We assume success unless the placement logic said otherwise
1115
1116	if cat[cIndex] == loc("Girder Placement Mode") then
1117
1118		if superDelete == false then
1119			--lfObject and lfBasic
1120			placedFrame[placedCount] = CGR
1121			placedSprite[placedCount] = sprAmGirder
1122			placementSucceeded = CallPlaceSprite(placedCount)
1123
1124			if placementSucceeded then
1125				if landType == lfIndestructible then	specialMod = 1
1126				elseif landType == lfIce then	specialMod = 2
1127				else specialMod = 0
1128				end
1129				placedHWMapFlag[placedCount] = CGR+100+(8*specialMod)
1130			else
1131				placedType[placedCount] = "bogus"
1132			end
1133		else
1134			placedType[placedCount] = "bogus" -- we need this so we don't think we've placed a new girder and are trying to erase the things we just placed??
1135			SelectClosestSprite()
1136			EraseClosestSprite()
1137		end
1138
1139	elseif cat[cIndex] == loc("Rubber Placement Mode") then
1140
1141		if superDelete == false then
1142			placedFrame[placedCount] = CGR
1143			placedSprite[placedCount] = sprAmRubber
1144
1145			--new ermagerd
1146			placedLandFlags[placedCount] = "lfBouncy"
1147			placedTint[placedCount] = U_LAND_TINT_NORMAL
1148			placementSucceeded = PlaceSprite(placedX[placedCount], placedY[placedCount], placedSprite[placedCount], placedFrame[placedCount],
1149				placedTint[placedCount],
1150				nil,
1151				nil, nil,
1152				landType)
1153
1154			if placementSucceeded then
1155				if CGR == 0 then placedHWMapFlag[placedCount] = 124
1156				elseif CGR == 1 then placedHWMapFlag[placedCount] = 125
1157				elseif CGR == 2 then placedHWMapFlag[placedCount] = 126
1158				elseif CGR == 3 then placedHWMapFlag[placedCount] = 127
1159				end
1160				PlaySound(sndPlaced)
1161			else
1162				placedType[placedCount] = "bogus"
1163				PlaySound(sndDenied)
1164			end
1165		else
1166			placedType[placedCount] = "bogus"
1167			SelectClosestSprite()
1168			EraseClosestSprite()
1169		end
1170
1171	elseif cat[cIndex] == loc("Target Placement Mode") then
1172		gear = AddGear(x, y, gtTarget, 0, 0, 0, 0)
1173	elseif cat[cIndex] == loc("Cleaver Placement Mode") then
1174		gear = AddGear(x, y, gtKnife, 0, 0, 0, 0)
1175	elseif cat[cIndex] == loc("Health Crate Placement Mode") then
1176		gear = SpawnHealthCrate(x,y)
1177		SetHealth(gear, pMode[pIndex])
1178	elseif cat[cIndex] == loc("Weapon Crate Placement Mode") then
1179		gear = SpawnAmmoCrate(x, y, atkArray[pIndex][1])
1180		placedSpec[placedCount] = atkArray[pIndex][2]
1181		setGearValue(gear,"contents",atkArray[pIndex][2])
1182	elseif cat[cIndex] == loc("Utility Crate Placement Mode") then
1183		gear = SpawnUtilityCrate(x, y, utilArray[pIndex][1])
1184		placedSpec[placedCount] = utilArray[pIndex][2]
1185		setGearValue(gear,"contents",utilArray[pIndex][2])
1186	elseif cat[cIndex] == loc("Barrel Placement Mode") then
1187		gear = AddGear(x, y, gtExplosives, 0, 0, 0, 0)
1188		SetHealth(gear, pMode[pIndex])
1189	elseif cat[cIndex] == loc("Mine Placement Mode") then
1190		gear = AddGear(x, y, gtMine, 0, 0, 0, 0)
1191		SetTimer(gear, pMode[pIndex])
1192	elseif cat[cIndex] == loc("Dud Mine Placement Mode") then
1193		gear = AddGear(x, y, gtMine, 0, 0, 0, 0)
1194		SetHealth(gear, 0)
1195		SetGearValues(gear, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 36 - pMode[pIndex])
1196	elseif cat[cIndex] == loc("Sticky Mine Placement Mode") then
1197		gear = AddGear(x, y, gtSMine, 0, 0, 0, 0)
1198		SetTimer(gear, pMode[pIndex])
1199	elseif cat[cIndex] == loc("Air Mine Placement Mode") then
1200		gear = AddGear(x, y, gtAirMine, 0, 0, 0, 0)
1201		SetTimer(gear, pMode[pIndex])
1202		SetGearValues(gear, nil, nil, pMode[pIndex])
1203	elseif cat[cIndex] == loc("Repositioning Mode") then
1204
1205		if pMode[pIndex] == loc("Selection Mode") then
1206			sGear = GetClosestGear()
1207			if sGear ~= nil then
1208				PlaySound(sndPortalSwitch)
1209			end
1210		elseif pMode[pIndex] == loc("Placement Mode") then
1211			if sGear ~= nil then
1212				SetGearPosition(sGear, x, y)
1213				PlaySound(sndWarp)
1214			end
1215		elseif pMode[pIndex] == loc("Deletion Mode") then
1216			sGear = GetClosestGear()
1217			if (sGear == nil) then
1218				AddCaption(loc("Please click on a gear."), colorErrorMessage, capgrpVolume)
1219				PlaySound(sndDenied)
1220			elseif (GetGearType(sGear) == gtHedgehog) then
1221				AddCaption(loc("Hedgehogs can not be deleted."), colorErrorMessage, capgrpVolume)
1222				PlaySound(sndDenied)
1223			else
1224				DeleteGear(sGear)
1225				PlaySound(sndBump)
1226			end
1227			sGear = nil
1228		end
1229
1230	elseif (cat[cIndex] == loc("Hog Identity Mode")) or (cat[cIndex] == loc("Team Identity Mode")) then
1231
1232		sGear = GetClosestGear()
1233		if (sGear ~= nil) and (GetGearType(sGear) == gtHedgehog) then
1234			if (cat[cIndex] == loc("Hog Identity Mode")) then
1235				SetHogProfile(sGear, pMode[pIndex])
1236			else -- set for the whole team
1237				SetTeamIdentity(sGear)
1238			end
1239			PlaySound(sndHello, sGear)
1240		else
1241			AddCaption(loc("Please click on a hedgehog."), colorErrorMessage, capgrpVolume)
1242			PlaySound(sndDenied)
1243		end
1244
1245
1246
1247	elseif cat[cIndex] == loc("Health Modification Mode") then
1248
1249		sGear = GetClosestGear()
1250		local gt = GetGearType(sGear)
1251		if gt == gtHedgehog or gt == gtExplosives or (gt == gtCase and GetGearPos(sGear) == 0x2) then
1252			local oldHealth, hDiff = GetHealth(sGear)
1253			if pMode[pIndex][2] == "set" then
1254				SetHealth(sGear, pMode[pIndex][1])
1255				hDiff = pMode[pIndex][1] - oldHealth
1256			elseif pMode[pIndex][2] == "mod" then
1257				local min
1258				if gt == gtCase then min = 0 else min = 1 end
1259				local newHealth = math.max(min, GetHealth(sGear) + tonumber(pMode[pIndex][1]))
1260				SetHealth(sGear, newHealth)
1261				hDiff = newHealth - oldHealth
1262			end
1263			PlaySound(sndPortalSwitch)
1264			if gt == gtHedgehog and hDiff < 0 then
1265				local snd = { sndOw1, sndOw2, sndOw3 }
1266				PlaySound(snd[math.random(1, #snd)], sGear)
1267			end
1268		elseif gt == gtMine and GetHealth(sGear) == 0 then
1269			local newHealth
1270			if pMode[pIndex][2] == "set" then
1271				newHealth =  pMode[pIndex][1]
1272			elseif pMode[pIndex][2] == "mod" then
1273				local _, oldHealth
1274				_,_,_,_,_,_,_,_,_,_,_, oldHealth = GetGearValues(sGear)
1275				oldHealth = 36 - oldHealth
1276				newHealth = math.max(1, oldHealth + tonumber(pMode[pIndex][1]))
1277			end
1278			if newHealth ~= nil then
1279				SetGearValues(sGear, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 36 - newHealth)
1280				PlaySound(sndPortalSwitch)
1281			end
1282		else
1283			AddCaption(loc("Please click on a hedgehog, barrel, health crate or dud mine."), colorErrorMessage, capgrpVolume)
1284			PlaySound(sndDenied)
1285		end
1286
1287	elseif cat[cIndex] == loc("Sprite Modification Mode") then
1288
1289		SelectClosestSprite()
1290
1291		if closestSpriteID ~= nil then
1292			if pMode[pIndex] == loc("LandFlag Modification Mode") then
1293				EraseSprite(placedX[closestSpriteID], placedY[closestSpriteID], placedSprite[closestSpriteID], placedFrame[closestSpriteID], nil, nil, nil, nil, placedLandFlags[closestSpriteID])
1294				placementSucceeded = CallPlaceSprite(closestSpriteID, true)
1295				if placementSucceeded then
1296					closestSpriteID = nil
1297					SetVisualGearValues(sSprite, 0, 0, 0, 0, 0, 1, 10000, sprAmGirder, 10000, 0x00000000 )
1298					PlaySound(sndPortalSwitch)
1299				else
1300					PlaySound(sndDenied)
1301				end
1302			elseif pMode[pIndex] == loc("Sprite Erasure Mode") then
1303
1304				EraseClosestSprite()
1305
1306			end
1307		else
1308			PlaySound(sndDenied)
1309		end
1310
1311
1312	elseif cat[cIndex] == loc("Goal Definition Mode") then
1313
1314		sGear = GetClosestGear()
1315		if sGear ~= nil then  -- used to be closestGear
1316
1317			if getGearValue(sGear,"tag") == nil then
1318
1319				if pMode[pIndex] == loc("Victory Condition: Collect") then
1320					if GetGearType(sGear) == gtCase then
1321						setGearValue(sGear, "tag","collection")
1322						PlaySound(sndPortalSwitch)
1323					else
1324						AddCaption(loc("Please click on a crate."), colorErrorMessage, capgrpVolume)
1325						PlaySound(sndDenied)
1326					end
1327				else
1328					if pMode[pIndex] == loc("Victory Condition: Destroy") then
1329						setGearValue(sGear, "tag","victory")
1330						PlaySound(sndPortalSwitch)
1331					elseif pMode[pIndex] == loc("Losing Condition: Destroy") then
1332						setGearValue(sGear, "tag","failure")
1333						PlaySound(sndPortalSwitch)
1334					end
1335				end
1336
1337			else
1338				-- remove tag and delete circ
1339				setGearValue(sGear, "tag", nil)
1340				DeleteVisualGear(getGearValue(sGear,"tCirc"))
1341				setGearValue(sGear, "tCirc", nil)
1342				PlaySound(sndBump)
1343			end
1344
1345
1346
1347		end
1348
1349
1350	elseif cat[cIndex] == loc("Sprite Placement Mode") then
1351
1352		if superDelete == false then
1353			placedFrame[placedCount] = sFrame
1354			placedSprite[placedCount] = reducedSpriteIDArray[pIndex]
1355			placementSucceeded = CallPlaceSprite(placedCount)
1356		else
1357			placedType[placedCount] = "bogus"
1358			SelectClosestSprite()
1359			EraseClosestSprite()
1360		end
1361
1362	elseif cat[cIndex] == loc("Waypoint Editing Mode") then
1363
1364
1365		if pMode[pIndex] == loc("Delete Waypoint") then
1366			placedType[placedCount] = "bogus"
1367			EraseClosestWaypoint()
1368		else
1369			PlaceWaypoint(x,y)
1370			placedCount = placedCount - 1
1371			PlaySound(sndPlaced)
1372		end
1373
1374	end
1375
1376	placedCount = placedCount + 1
1377end
1378
1379-- called when user changes primary selection
1380-- either via up/down keys
1381-- or selecting girder/airattack
1382function RedefineSubset()
1383
1384	superDelete = false -- fairly new addition
1385	landType = 0 --- fairly new addition
1386	pIndex = 1
1387	pMode = {}
1388
1389	if cat[cIndex] == loc("Girder Placement Mode") then
1390		pIndex = CGR
1391		pMode = {loc("Girder")}
1392	elseif cat[cIndex] == loc("Rubber Placement Mode") then
1393		pIndex = CGR
1394		pMode = {loc("Rubber")}
1395		landType = lfBouncy -- for now, let's not allow anything else (-- fairly new addition)
1396	elseif cat[cIndex] == loc("Target Placement Mode") then
1397		pMode = {loc("Target")}
1398	elseif cat[cIndex] == loc("Cleaver Placement Mode") then
1399		pMode = {loc("Cleaver")}
1400	elseif cat[cIndex] == loc("Barrel Placement Mode") then
1401		pMode = {60,80,100,120,160,200,240,1,10,20,30,40,50}
1402	elseif cat[cIndex] == loc("Health Crate Placement Mode") then
1403		pMode = {25,30,40,50,75,100,150,200,0,5,10,15,20}
1404	elseif cat[cIndex] == loc("Weapon Crate Placement Mode") then
1405		for i = 1, #atkArray do
1406			pMode[i] = GetAmmoName(atkArray[i][1], true)
1407		end
1408	elseif cat[cIndex] == loc("Utility Crate Placement Mode") then
1409		for i = 1, #utilArray do
1410			pMode[i] = GetAmmoName(utilArray[i][1], true)
1411		end
1412	elseif cat[cIndex] == loc("Mine Placement Mode") then
1413		pMode = {3000,4000,5000,0,1000,2000}
1414	elseif cat[cIndex] == loc("Dud Mine Placement Mode") then
1415		pMode = {36,48,60,72,96,1,6,12,18,24}
1416	elseif cat[cIndex] == loc("Mine Placement Mode") then
1417		pMode = {3000,4000,5000,0,1000,2000}
1418	elseif cat[cIndex] == loc("Sticky Mine Placement Mode") then
1419		pMode = {500,1000,1500,2000,2500,0}
1420	elseif cat[cIndex] == loc("Air Mine Placement Mode") then
1421		pMode = {750,1000,1250,0,250,500}
1422	elseif cat[cIndex] == loc("Repositioning Mode") then
1423		pMode = {loc("Selection Mode"),loc("Placement Mode"), loc("Deletion Mode")}
1424	elseif cat[cIndex] == loc("Goal Definition Mode") then
1425		pMode = {loc("Victory Condition: Destroy"),loc("Losing Condition: Destroy"),loc("Victory Condition: Collect")}
1426	elseif cat[cIndex] == loc("Hog Identity Mode") then
1427		pMode = {loc("Soldier"),loc("Grenadier"),loc("Sniper"),loc("Pyro"),loc("Ninja"),loc("Commander"),loc("Chef"),loc("Engineer"),loc("Physicist"),loc("Trapper"),loc("Saint"),loc("Clown")}
1428	elseif cat[cIndex] == loc("Team Identity Mode") then
1429		pMode = preMadeTeamNamesTranslated
1430	elseif cat[cIndex] == loc("Health Modification Mode") then
1431		pMode = { {100, "set"}, {125, "set"}, {150, "set"}, {200, "set"}, {300, "set"}, {1000, "set"},
1432			{"-100", "mod"}, {"-10", "mod"}, {"-1", "mod"}, {"+1", "mod"}, {"+10", "mod"}, {"+100", "mod"},
1433			{1, "set"}, {10, "set"}, {15, "set"}, {20, "set"}, {25, "set"}, {30, "set"}, {40, "set"}, {50, "set"}, {75, "set"},
1434}
1435	elseif cat[cIndex] == loc("Sprite Modification Mode") then
1436		pMode = {loc("LandFlag Modification Mode"),loc("Sprite Erasure Mode")}
1437	elseif cat[cIndex] == loc("Sprite Testing Mode") or cat[cIndex] == loc("Sprite Placement Mode") then
1438		for i = 1, #reducedSpriteTextArray do
1439			pMode[i] = reducedSpriteTextArray[i]
1440		end
1441		sFrame = 0
1442	elseif cat[cIndex] == loc("Waypoint Editing Mode") then
1443		pMode = {loc("Place Waypoint"), loc("Delete Waypoint")}
1444	end
1445
1446end
1447
1448------------------------------------------------
1449-- LOADING AND SAVING DATA STUFF
1450------------------------------------------------
1451
1452-- paste data you have saved previously here
1453function LoadLevelData()
1454
1455	if (mapID == nil) or (mapID == 0) then
1456		LoadMap(1)
1457	else
1458		LoadMap(mapID)
1459	end
1460
1461	for i = 1, techCount-1 do
1462		PlaceWaypoint(techX[i],techY[i])
1463	end
1464
1465end
1466
1467-- When you save your level, this function
1468-- generates the AddTeam and AddHog function calls for onGameInit()
1469function GetDataForSavingHogs(gear)
1470
1471	--this is a quick hack so that the human team(s) will always be
1472	--given the first move ahead of the AI
1473	local tempDataList = {}
1474	if GetHogLevel(gear) == 0 then
1475		tempDataList = hogDataList
1476	else
1477		tempDataList = AIHogDataList
1478	end
1479
1480	if GetHogTeamName(gear) ~= lastRecordedTeam then
1481
1482		teamCounter = teamCounter + 1
1483		if teamCounter == 9 then
1484			teamCounter = 1
1485		end
1486
1487		-- Color argument for AddTeam; using the
1488		-- default clan color format.
1489		local tColor = -(GetHogClan(gear)+1)
1490
1491		local tFort, tGrave, tFlag, tVoice
1492		if getGearValue(gear,"grave") == nil then
1493			tFort = GetHogFort(gear)
1494			tGrave = GetHogGrave(gear)
1495			tFlag = GetHogFlag(gear)
1496			tVoice = GetHogVoicepack(gear)
1497		else
1498			tGrave = getGearValue(gear,"grave")
1499			tFort = getGearValue(gear,"fort")
1500			tFlag = getGearValue(gear,"flag")
1501			tVoice = getGearValue(gear,"voice")
1502		end
1503		if not tFort then tFort = "Castle" end
1504		if not tGrave then tGrave = "Statue" end
1505		if not tFlag then tFlag= "hedgewars" end
1506		if not tVoice then tVoice = "Default" end
1507
1508		lastRecordedTeam = GetHogTeamName(gear)
1509
1510		table.insert(tempDataList, "")
1511
1512		local oTeamName = getGearValue(gear, "originalTeamName")
1513		if oTeamName == nil or oTeamName == "" then
1514			oTeamName = GetHogTeamName(gear)
1515		end
1516		table.insert	(tempDataList,
1517						"	AddTeam(loc(\"" ..
1518						oTeamName  .. "\")" ..
1519						", " .. tColor ..
1520						", " .. "\"" .. tGrave .. "\"" ..
1521						", " .. "\"" .. tFort .. "\"" ..
1522						", " .. "\"" .. tVoice .. "\"" ..
1523						", " .. "\"" .. tFlag .. "\"" ..
1524						")"
1525						)
1526
1527	end
1528
1529	table.insert(hhs, gear)
1530
1531	local oName = getGearValue(gear, "originalName")
1532	if oName == nil or oName == "" then
1533		oName = GetHogName(gear)
1534	end
1535	table.insert	(tempDataList,	"	hhs[" .. #hhs .."] = AddHog(loc(\"" ..
1536					oName .. "\"), " ..
1537					GetHogLevel(gear) .. ", " ..
1538					GetHealth(gear) .. ", \"" ..
1539					GetHogHat(gear) .. "\"" ..
1540					")"
1541			)
1542
1543	table.insert	(tempDataList,"	SetGearPosition(hhs[" .. #hhs .. "], " .. GetX(gear) .. ", " .. GetY(gear) .. ")")
1544
1545	for e=1, #effectArray do
1546		if GetEffect(gear, effectArray[e]) ~= 0 then
1547			table.insert	(tempDataList,"	SetEffect(hhs[" .. #hhs .. "], " .. effectStr[e] .. ", " .. GetEffect(gear, effectArray[e]) .. ")")
1548		end
1549	end
1550	local dX, _ = GetGearVelocity(gear)
1551	if dX < 0 then
1552		table.insert	(tempDataList,"	HogTurnLeft(hhs[" .. #hhs .. "], true)")
1553	end
1554
1555	if getGearValue(gear,"tag") ~= nil then
1556		table.insert	(tempDataList,"	setGearValue(hhs[" .. #hhs .. "], \"tag\", \"" .. getGearValue(gear,"tag") .. "\")")
1557	end
1558
1559	-- save the ammo values for each gear, we will call this later
1560	-- when we want to output it to console
1561
1562	if getGearValue(gear,"ranking") ~= nil then
1563		table.insert(shoppaPointList, "AddShoppaPoint(" .. GetX(gear) .. ", " .. GetY(gear) .. ", " .. getGearValue(gear,"ranking") .. ")")
1564	end
1565
1566	for i = 1, #atkArray do
1567		setGearValue(gear, atkArray[i][1], GetAmmoCount(gear, atkArray[i][1]))
1568	end
1569
1570	for i = 1, #utilArray do
1571		setGearValue(gear, utilArray[i][1], GetAmmoCount(gear, utilArray[i][1]))
1572	end
1573
1574	if GetHogLevel(gear) == 0 then
1575		hogDataList = tempDataList
1576	else
1577		AIHogDataList = tempDataList
1578	end
1579
1580end
1581
1582-- output hog and team data to the console
1583function SaveHogData()
1584
1585	teamCounter = 0
1586	lastRecordedTeam = ""
1587	hhs = {}
1588
1589	runOnHogs(GetDataForSavingHogs)
1590
1591	WriteLnToConsole("	------ TEAM LIST ------")
1592
1593	for i = 1, #hogDataList do
1594		WriteLnToConsole(hogDataList[i])
1595	end
1596
1597	for i = 1, #AIHogDataList do
1598		WriteLnToConsole(AIHogDataList[i])
1599	end
1600
1601	WriteLnToConsole("")
1602
1603	if #shoppaPointList > 0 then
1604		WriteLnToConsole("	------ SHOPPA POINT LIST ------")
1605		for i = 1, #shoppaPointList do
1606			WriteLnToConsole(shoppaPointList[i])
1607		end
1608	end
1609
1610
1611end
1612
1613-- generates an onGameInit() template with scheme data, team adds, and hogs
1614function SaveConfigData()
1615
1616	WriteLnToConsole("function onGameInit()")
1617	WriteLnToConsole("")
1618
1619	temp = "	EnableGameFlags(gfDisableWind"
1620	for i = 1, #gameFlagList do
1621		if gameFlagList[i][2] == true then
1622			temp = temp .. ", ".. gameFlagList[i][1]
1623		end
1624	end
1625
1626	WriteLnToConsole("	ClearGameFlags()")
1627	WriteLnToConsole(temp .. ")")
1628
1629	WriteLnToConsole("	Map = \"" .. Map .. "\"")
1630	WriteLnToConsole("	Seed = \"" .. Seed .. "\"")
1631	WriteLnToConsole("	Theme = \"" .. Theme .. "\"")
1632	WriteLnToConsole("	MapGen = " .. MapGen)
1633	WriteLnToConsole("	MapFeatureSize = " .. MapFeatureSize)
1634	WriteLnToConsole("	TemplateFilter = " .. TemplateFilter)
1635	WriteLnToConsole("	TemplateNumber = " .. TemplateNumber)
1636	WriteLnToConsole("	TurnTime = " .. TurnTime)
1637	WriteLnToConsole("	Explosives = " .. Explosives)
1638	WriteLnToConsole("	MinesNum = " .. MinesNum)
1639	WriteLnToConsole("	CaseFreq = " .. CaseFreq)
1640	WriteLnToConsole("	Delay = " .. Delay)
1641
1642	WriteLnToConsole("	HealthCaseProb = " .. HealthCaseProb)
1643	WriteLnToConsole("	HealthCaseAmount = " .. HealthCaseAmount)
1644	WriteLnToConsole("	DamagePercent = " .. DamagePercent)
1645	WriteLnToConsole("	RopePercent = " .. RopePercent)
1646	WriteLnToConsole("	MinesTime = " .. MinesTime)
1647	WriteLnToConsole("	MineDudPercent  = " .. MineDudPercent)
1648	WriteLnToConsole("	SuddenDeathTurns = " .. SuddenDeathTurns)
1649	WriteLnToConsole("	WaterRise = " .. WaterRise)
1650	WriteLnToConsole("	HealthDecrease = " .. HealthDecrease)
1651
1652	WriteLnToConsole("	Ready = " .. Ready)
1653	WriteLnToConsole("	AirMinesNum = " .. AirMinesNum)
1654	WriteLnToConsole("	GetAwayTime = " .. GetAwayTime)
1655	WriteLnToConsole("	WorldEdge = " .. WorldEdge)
1656
1657	-- ScriptParam intentionally left out, it doesn't make sense for missions.
1658
1659	WriteLnToConsole("")
1660
1661	SaveHogData()
1662
1663	WriteLnToConsole("")
1664	WriteLnToConsole("end")
1665
1666end
1667
1668-- output gear data as special points to be placed in a converted HWMAP, readable by InterpretPoints()
1669function ConvertGearDataToHWPText()
1670
1671	WriteLnToConsole("")
1672	WriteLnToConsole("--BEGIN HWMAP CONVERTER POINTS--")
1673	WriteLnToConsole("-- You can paste this data into the HWMAP converter if needed.")
1674	WriteLnToConsole("--[[")
1675	WriteLnToConsole("")
1676
1677	for i = 1, #hFlagList do
1678		WriteLnToConsole(hFlagList[i])
1679	end
1680
1681	WriteLnToConsole("")
1682	WriteLnToConsole("]]")
1683	WriteLnToConsole("--END HWMAP CONVERTER POINTS--")
1684	WriteLnToConsole("")
1685
1686end
1687
1688-- sigh
1689-- gradually got more bloated with the addition of hwpoint tracking and
1690-- distinction betweeen the need to track victory/win conditions or not
1691function GetDataForGearSaving(gear)
1692
1693	local temp = nil
1694	local specialFlag = nil
1695	local arrayList = nil
1696
1697	if GetGearType(gear) == gtMine then
1698
1699		temp = 	"	tempG = AddGear(" ..
1700			GetX(gear) .. ", " ..
1701			GetY(gear) .. ", gtMine, 0, 0, 0, 0)"
1702		table.insert(mineList, temp)
1703		table.insert(mineList, "	SetTimer(tempG, " .. GetTimer(gear) .. ")")
1704		if (GetHealth(gear) == 0) then
1705			table.insert(mineList, "	SetHealth(tempG, 0)")
1706			local _, damage
1707			_,_,_,_,_,_,_,_,_,_,_,damage = GetGearValues(gear)
1708			if damage ~= 0 then
1709				table.insert(mineList, "	SetGearValues(tempG, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "..damage..")")
1710			end
1711		end
1712		if (getGearValue(gear, "tag") ~= nil) then
1713			table.insert(mineList, "	setGearValue(tempG, \"tag\", \"" .. getGearValue(gear,"tag") .. "\")")
1714		end
1715
1716		if 		GetTimer(gear) == 0 then specialFlag = 1
1717		elseif	GetTimer(gear) == 1000 then specialFlag = 2
1718		elseif	GetTimer(gear) == 2000 then specialFlag = 3
1719		elseif	GetTimer(gear) == 3000 then specialFlag = 4
1720		elseif	GetTimer(gear) == 4000 then specialFlag = 5
1721		elseif	GetTimer(gear) == 5000 then specialFlag = 6
1722		end
1723
1724	elseif GetGearType(gear) == gtSMine then
1725
1726		arrayList = sMineList
1727		temp = 	"	tempG = AddGear(" ..
1728				GetX(gear) .. ", " ..
1729				GetY(gear) .. ", gtSMine, 0, 0, 0, 0)"
1730		table.insert(sMineList, temp)
1731		table.insert(sMineList, "	SetTimer(tempG, " .. GetTimer(gear) .. ")")
1732		specialFlag = 7
1733
1734	elseif GetGearType(gear) == gtAirMine then
1735
1736		temp = 	"	tempG = AddGear(" ..
1737			GetX(gear) .. ", " ..
1738			GetY(gear) .. ", gtAirMine, 0, 0, 0, 0)"
1739		table.insert(airMineList, temp)
1740		table.insert(airMineList, "	SetTimer(tempG, " .. GetTimer(gear) .. ")")
1741		table.insert(airMineList, "	SetGearValues(tempG, nil, nil, " .. GetTimer(gear) .. ")")
1742		if (getGearValue(gear, "tag") ~= nil) then
1743			table.insert(airMineList, "	setGearValue(tempG, \"tag\", \"" .. getGearValue(gear,"tag") .. "\")")
1744		end
1745
1746		table.insert(previewDataList, "	PreviewPlacedGear(" .. GetX(gear) ..", " ..	GetY(gear) .. ")")
1747		specialFlag = 8
1748
1749	elseif GetGearType(gear) == gtExplosives then
1750
1751		temp = 	"	tempG = AddGear(" ..
1752			GetX(gear) .. ", " ..
1753			GetY(gear) .. ", gtExplosives, 0, 0, 0, 0)"
1754		table.insert(explosivesList, temp)
1755		table.insert(explosivesList, "	SetHealth(tempG, " .. GetHealth(gear) .. ")")
1756		if (getGearValue(gear, "tag") ~= nil) then
1757			table.insert(explosivesList, "	setGearValue(tempG, \"tag\", \"" .. getGearValue(gear,"tag") .. "\")")
1758		end
1759
1760		table.insert(previewDataList, "	PreviewPlacedGear(" .. GetX(gear) ..", " ..	GetY(gear) .. ")")
1761
1762		if 		GetHealth(gear) == 1 then specialFlag = 15
1763		elseif	GetHealth(gear) == 25 then specialFlag = 16
1764		elseif	GetHealth(gear) == 50 then specialFlag = 17
1765		elseif	GetHealth(gear) == 75 then specialFlag = 18
1766		elseif	GetHealth(gear) == 100 then specialFlag = 19
1767		end
1768
1769	elseif GetGearType(gear) == gtTarget then
1770
1771		arrayList = targetList
1772		temp = 	"	tempG = AddGear(" ..
1773				GetX(gear) .. ", " ..
1774				GetY(gear) .. ", gtTarget, 0, 0, 0, 0)"
1775		table.insert(targetList, temp)
1776		specialFlag = 14
1777
1778	elseif GetGearType(gear) == gtKnife then
1779
1780		arrayList = knifeList
1781		temp = 	"	tempG = AddGear(" ..
1782				GetX(gear) .. ", " ..
1783				GetY(gear) .. ", gtKnife, 0, 0, 0, 0)"
1784		table.insert(knifeList, temp)
1785		specialFlag = 13
1786
1787	elseif GetGearType(gear) == gtCase then
1788
1789		table.insert(previewDataList, "	PreviewPlacedGear(" .. GetX(gear) ..", " ..	GetY(gear) .. ")")
1790
1791		-- Health crate
1792		if band(GetGearPos(gear), 0x2) ~= 0 then
1793
1794			temp = 	"	tempG = SpawnHealthCrate(" ..
1795				GetX(gear) ..", " ..
1796				GetY(gear) ..", " ..
1797				GetHealth(gear) .. ")"
1798			table.insert(healthCrateList, temp)
1799			if (getGearValue(gear, "tag") ~= nil) then
1800				table.insert(healthCrateList, "	setGearValue(tempG, \"tag\", \"" .. getGearValue(gear,"tag") .. "\")")
1801			end
1802
1803			if 		GetHealth(gear) == 25 then specialFlag = 9
1804			elseif	GetHealth(gear) == 50 then specialFlag = 10
1805			elseif	GetHealth(gear) == 75 then specialFlag = 11
1806			elseif	GetHealth(gear) == 100 then specialFlag = 12
1807			end
1808
1809		-- Ammo crate
1810		elseif band(GetGearPos(gear), 0x1) ~= 0 then
1811
1812			arrayList = wepCrateList
1813			temp = 	"	tempG = SpawnAmmoCrate(" ..
1814					GetX(gear) ..", " ..
1815					GetY(gear) ..", " ..
1816					getGearValue(gear,"contents") ..
1817					")"
1818			table.insert(wepCrateList, temp)
1819
1820			tempV = getGearValue(gear,"contents")
1821			for i = 1, #atkArray do
1822				if tempV == atkArray[i][2] then
1823					specialFlag = i + 19
1824				end
1825			end
1826
1827			--dammit, we probably need more entries if we want to allow editing of existing maps
1828			table.insert(wepCrateList, "	setGearValue(tempG, \"contents\", \"" .. getGearValue(gear,"contents") .. "\")")
1829
1830		-- Utility crate
1831		elseif band(GetGearPos(gear), 0x4) ~= 0 then
1832
1833			arrayList = utilCrateList
1834			temp = 	"	tempG = SpawnUtilityCrate(" ..
1835					GetX(gear) ..", " ..
1836					GetY(gear) ..", " ..
1837					getGearValue(gear,"contents") ..
1838					")"
1839			table.insert(utilCrateList, temp)
1840
1841			tempV = getGearValue(gear,"contents")
1842			for i = 1, #utilArray do
1843				if tempV == utilArray[i][2] then
1844					specialFlag = i + 19 + #atkArray
1845				end
1846			end
1847
1848			--dammit, we probably need more entries if we want to allow editing of existing maps
1849			table.insert(utilCrateList, "	setGearValue(tempG, \"contents\", \"" .. getGearValue(gear,"contents") .. "\")")
1850
1851		end
1852
1853	end
1854
1855	-- add tracking of simple win/lose for simpler gears that have a tempG = listed above
1856	if (getGearValue(gear, "tag") ~= nil) and (arrayList ~= nil) then
1857		table.insert(arrayList, "	setGearValue(tempG, \"tag\", \"" .. getGearValue(gear,"tag") .. "\")")
1858	end
1859
1860	-- this creates a big, messy list of special flags for use in hwmaps
1861	if specialFlag ~= nil then
1862		table.insert(hFlagList, "	" .. GetX(gear) .. " " .. GetY(gear) .. " " .. specialFlag)
1863	end
1864
1865end
1866
1867-- generate a title and list all the gears if there is at least 1 of them in the list
1868function AppendGearList(gearList, consoleLine)
1869	if #gearList > 0 then
1870		WriteLnToConsole(consoleLine)
1871		for i = 1, #gearList do
1872			WriteLnToConsole(gearList[i])
1873		end
1874		WriteLnToConsole("")
1875	end
1876end
1877
1878-- new attempt at doing shit a bit cleaner:
1879-- it may be a bit verbose, but this should generate a comprehensive, human-readable
1880-- list of gears, broken up into sections and output it to the console
1881function SaveGearData()
1882
1883	runOnGears(GetDataForGearSaving)
1884
1885	AppendGearList(healthCrateList, "	------ HEALTH CRATE LIST ------")
1886	AppendGearList(wepCrateList, "	------ AMMO CRATE LIST ------")
1887	AppendGearList(utilCrateList, "	------ UTILITY CRATE LIST ------")
1888	AppendGearList(explosivesList, "	------ BARREL LIST ------")
1889	AppendGearList(mineList, "	------ MINE LIST ------")
1890	AppendGearList(sMineList, "	------ STICKY MINE LIST ------")
1891	AppendGearList(airMineList, "	------ AIR MINE LIST ------")
1892	AppendGearList(targetList, "	------ TARGET LIST ------")
1893	AppendGearList(knifeList, "	------ CLEAVER LIST ------")
1894
1895end
1896
1897function DoAmmoLoop(i)
1898
1899	for x = 1, #atkArray do
1900		if getGearValue(hhs[i],atkArray[x][1]) ~= 0 then
1901			WriteLnToConsole("	AddAmmo(hhs[" .. i .. "], " .. atkArray[x][2] .. ", " .. getGearValue(hhs[i],atkArray[x][1]) .. ")")
1902		end
1903	end
1904
1905	for x = 1, #utilArray do
1906		if getGearValue(hhs[i],utilArray[x][1]) ~= 0 then
1907			WriteLnToConsole("	AddAmmo(hhs[" .. i .. "], " .. utilArray[x][2] .. ", " .. getGearValue(hhs[i],utilArray[x][1]) .. ")")
1908		end
1909	end
1910
1911	WriteLnToConsole("")
1912
1913end
1914
1915-- this is called when a tagged gear is deleted during a mission
1916-- it determines if the game is ready to conclude in victory/defeat
1917function CheckForConclusion(gear)
1918
1919	-- failure gears must always all be protected, so if any of them are destroyed the player loses
1920	if getGearValue(gear,"tag") == "failure" then
1921		EndGameIn("failure")
1922	else
1923
1924		-- the presence of other tagged gears means that the goal of this mission is not
1925		-- simply to kill every hedgehog. Thus, we need to count the remaining tagged objects
1926		-- to see how close we are to completing the mission successfully.
1927		victoryObj = 0
1928		failObj = 0
1929		collectObj = 0
1930		runOnGears(CheckForConditions)
1931
1932		if GetGearType(gear) ~= gtCase then
1933
1934			-- non-crates can only be tagged as victory or failure, and as this wasn't tagged
1935			-- "failure" in our earlier check, this must be a victory tagged gear. Let's adust
1936			-- the number of objects accordingly as it's in the process of being destroyed.
1937			victoryObj = victoryObj - 1
1938
1939			-- if there are no objectives left to complete, end the game in victory
1940			if (victoryObj == 0) and (collectObj == 0) then
1941				EndGameIn("victory")
1942			end
1943
1944		else
1945			-- this crate was deleted, but was it collected or destroyed, and how does that match
1946			-- the goals of our mission?
1947			if (GetGearMessage(gear) == 256) and (getGearValue(gear,"tag") == "collection") then
1948				if GetHogLevel(CurrentHedgehog) == 0 then
1949					-- the enemy stole our crate
1950					EndGameIn("failure")
1951				else
1952					collectObj = collectObj - 1
1953					if (victoryObj == 0) and (collectObj == 0) then
1954						EndGameIn("victory")
1955					end
1956				end
1957			elseif (GetGearMessage(gear) == 0) and (getGearValue(gear,"tag") == "victory") then
1958				victoryObj = victoryObj - 1
1959				if (victoryObj == 0) and (collectObj == 0) then
1960					EndGameIn("victory")
1961				end
1962			else
1963				-- unfortunately, we messed up our mission.
1964				EndGameIn("failure")
1965			end
1966
1967		end
1968
1969	end
1970
1971end
1972
1973---------------------------------
1974-- THE BIG ONE
1975---------------------------------
1976-- saving process starts here
1977-- saves all level data to logs/game0.log and generates a simple script template
1978function SaveLevelData()
1979
1980	waypointList = {}
1981	girderList = {}
1982	rubberList = {}
1983	spriteList = {}
1984	mineList = {}
1985	sMineList = {}
1986	airMineList = {}
1987	targetList = {}
1988	knifeList = {}
1989	explosivesList = {}
1990	healthCrateList = {}
1991	wepCrateList = {}
1992	utilCrateList = {}
1993	hFlagList = {}
1994	previewDataList = {}
1995	shoppaPointList = {}
1996	hogDataList = {}
1997	AIHogDataList = {}
1998
1999	WriteLnToConsole("------ BEGIN SCRIPT ------")
2000	WriteLnToConsole("-- Copy and Paste this text into an empty text file, and save it as")
2001	WriteLnToConsole("-- YOURTITLEHERE.lua, in your Data/Missions/Training/ folder.")
2002
2003	WriteLnToConsole("")
2004
2005	WriteLnToConsole("HedgewarsScriptLoad(\"/Scripts/Locale.lua\")")
2006	WriteLnToConsole("HedgewarsScriptLoad(\"/Scripts/Tracker.lua\")")
2007	WriteLnToConsole("HedgewarsScriptLoad(\"/Scripts/Utils.lua\")")
2008
2009	WriteLnToConsole("")
2010	WriteLnToConsole("local hhs = {}")
2011	WriteLnToConsole("")
2012
2013	SaveConfigData()
2014
2015
2016	WriteLnToConsole("")
2017	WriteLnToConsole("function LoadHogWeapons()")
2018	WriteLnToConsole("")
2019
2020	if band(GameFlags, gfPerHogAmmo) ~= 0 then -- per hog ammo
2021		for i = 1, #hhs do
2022			DoAmmoLoop(i)
2023		end
2024
2025	else	-- team-based ammo
2026
2027		teamCounter = 0
2028		lastRecordedTeam = ""
2029		for i = 1, #hhs do
2030
2031			if GetHogTeamName(hhs[i]) ~= lastRecordedTeam then
2032				lastRecordedTeam = GetHogTeamName(hhs[i])
2033				teamCounter = teamCounter + 1
2034				if teamCounter == 9 then
2035					teamCounter = 1
2036				end
2037				DoAmmoLoop(i)
2038			end
2039
2040		end
2041
2042	end
2043
2044
2045	WriteLnToConsole("end")
2046	WriteLnToConsole("")
2047
2048	WriteLnToConsole("")
2049	WriteLnToConsole("function LoadSprite(pX, pY, pSprite, pFrame, pTint, p1, p2, p3, pLandFlags)")
2050	WriteLnToConsole("	PlaceSprite(pX, pY, pSprite, pFrame, pTint, p1, p2, p3, pLandFlags)")
2051	WriteLnToConsole("end")
2052	WriteLnToConsole("")
2053
2054	WriteLnToConsole("")
2055	WriteLnToConsole("function LoadGearData()")
2056	WriteLnToConsole("")
2057
2058	WriteLnToConsole("	--BEGIN CORE DATA--")
2059	WriteLnToConsole("")
2060
2061	WriteLnToConsole("	------ PORTAL DISTANCE and UFO FUEL ------")
2062	WriteLnToConsole("	ufoFuel = " .. ufoFuel)
2063	WriteLnToConsole("	portalDistance = " .. portalDistance*5)
2064	table.insert(hFlagList, "	" .. portalDistance*5 .. " " .. ufoFuel .. " " .. 98)
2065	WriteLnToConsole("")
2066
2067	for i = 0, (placedCount-1) do
2068		if placedType[i] == loc("Waypoint Editing Mode") then
2069			--[[ TODO/FIXME: Somehow incorporate the waypoints in an actual useful manner.
2070			The functions AddWayPoint and PreviewWayPoint do not exist and will thus be commented-out
2071			in the output code. They are added anyway so the user sees the coordinates
2072			]]
2073			table.insert(waypointList,
2074			"--	AddWayPoint(" ..
2075				placedX[i] ..", " ..
2076				placedY[i] ..")"
2077				)
2078			table.insert(hFlagList, "	" .. placedX[i] .. " " .. placedY[i] .. " " .. "0")
2079			table.insert(previewDataList, "--	PreviewWayPoint(" .. placedX[i] ..", " ..	placedY[i] .. ")")
2080		end
2081	end
2082
2083	-- Helper table to convert tint color value to printable string
2084	local tint2String = {
2085		[U_LAND_TINT_INDESTRUCTIBLE] = "U_LAND_TINT_INDESTRUCTIBLE",
2086		[U_LAND_TINT_ICE] = "U_LAND_TINT_ICE",
2087		[U_LAND_TINT_BOUNCY] = "U_LAND_TINT_BOUNCY",
2088		[U_LAND_TINT_NORMAL] = "U_LAND_TINT_NORMAL",
2089	}
2090	for i = 0, (placedCount-1) do
2091		if placedType[i] == loc("Girder Placement Mode") then
2092			table.insert(girderList,
2093			"	LoadSprite(" ..
2094				placedX[i] ..", " ..
2095				placedY[i] ..", sprAmGirder, " ..
2096				placedFrame[i] ..			-- the rotation/frame
2097				", " ..
2098				tint2String[placedTint[i]] ..", " .. -- color
2099				"nil, nil, nil, " ..
2100				placedLandFlags[i] .. ")" --the landType
2101				)
2102			table.insert(hFlagList, "	" .. placedX[i] .. " " .. placedY[i] .. " " .. placedHWMapFlag[i])
2103			table.insert(previewDataList, "	PreviewGirder(" .. placedX[i] ..", " ..	placedY[i] .. ", " .. placedFrame[i] .. ")")
2104		end
2105	end
2106
2107	for i = 0, (placedCount-1) do
2108		if placedType[i] == loc("Rubber Placement Mode") then
2109			table.insert(rubberList,
2110				"	LoadSprite(" ..
2111				placedX[i] ..", " ..
2112				placedY[i] ..", sprAmRubber, " ..
2113				placedFrame[i] ..
2114				", " ..
2115				tint2String[placedTint[i]] ..", " .. -- color
2116				"nil, nil, nil, " ..
2117				"lfBouncy)" --the landType
2118				)
2119			table.insert(hFlagList, "	" .. placedX[i] .. " " .. placedY[i] .. " " .. placedHWMapFlag[i])
2120			table.insert(previewDataList, "	PreviewRubber(" .. placedX[i] ..", " ..	placedY[i] .. ", " .. placedFrame[i] .. ")")
2121		end
2122	end
2123
2124	for i = 0, (placedCount-1) do
2125		if placedType[i] == loc("Sprite Placement Mode") then
2126				table.insert(spriteList,
2127				"	LoadSprite(" ..
2128				placedX[i] ..", " ..
2129				placedY[i] ..", " .. placedSprite[i] .. ", " ..
2130				placedFrame[i] .. -- I think this is the frame, can't remember
2131				", " ..
2132				tint2String[placedTint[i]] ..", " .. -- color
2133				"nil, nil, nil, " ..
2134				placedLandFlags[i] .. ")" --the landType
2135				)
2136		end
2137	end
2138
2139	AppendGearList(waypointList, "	------ WAYPOINT LIST ------")
2140	AppendGearList(girderList, "	------ GIRDER LIST ------")
2141	AppendGearList(rubberList, "	------ RUBBER LIST ------")
2142	AppendGearList(spriteList, "	------ SPRITE LIST ------")
2143
2144	SaveGearData()
2145
2146	WriteLnToConsole("	--END CORE DATA--")
2147
2148
2149	WriteLnToConsole("")
2150	WriteLnToConsole("	LoadHogWeapons()")
2151	WriteLnToConsole("")
2152	WriteLnToConsole("end")
2153	WriteLnToConsole("")
2154
2155	WriteLnToConsole("")
2156	WriteLnToConsole("function onGameStart()")
2157	WriteLnToConsole("")
2158	WriteLnToConsole("	LoadGearData()")
2159	WriteLnToConsole("	DetermineMissionGoal()")
2160	WriteLnToConsole("")
2161	WriteLnToConsole("end")
2162	WriteLnToConsole("")
2163
2164	WriteLnToConsole("")
2165	WriteLnToConsole("function onNewTurn()")
2166	WriteLnToConsole("	--insert code according to taste")
2167	WriteLnToConsole("end")
2168	WriteLnToConsole("")
2169
2170	WriteLnToConsole("")
2171	WriteLnToConsole("function onGameTick()")
2172	WriteLnToConsole("	runOnGears(UpdateTagCircles)")
2173	WriteLnToConsole("end")
2174	WriteLnToConsole("")
2175
2176	WriteLnToConsole("function UpdateTagCircles(gear)")
2177	WriteLnToConsole("	if getGearValue(gear,\"tag\") ~= nil then")
2178	WriteLnToConsole("		if getGearValue(gear,\"tCirc\") == nil then")
2179	WriteLnToConsole("			setGearValue(gear, \"tCirc\",AddVisualGear(0,0,vgtCircle,0,true))")
2180	WriteLnToConsole("		end")
2181	WriteLnToConsole("")
2182	WriteLnToConsole("		if getGearValue(gear,\"tag\") == \"victory\" then")
2183	WriteLnToConsole("			SetVisualGearValues(getGearValue(gear,\"tCirc\"), GetX(gear), GetY(gear), 100, 255, 1, 10, 0, 150, 3, 0xff0000ff)")
2184	WriteLnToConsole("		elseif getGearValue(gear,\"tag\") == \"failure\" then")
2185	WriteLnToConsole("			SetVisualGearValues(getGearValue(gear,\"tCirc\"), GetX(gear), GetY(gear), 100, 255, 1, 10, 0, 150, 3, 0x00ff00ff)")
2186	WriteLnToConsole("		elseif getGearValue(gear,\"tag\") == \"collection\" then")
2187	WriteLnToConsole("			SetVisualGearValues(getGearValue(gear,\"tCirc\"), GetX(gear), GetY(gear), 100, 255, 1, 10, 0, 150, 3, 0x0000ffff)")
2188	WriteLnToConsole("		end")
2189	WriteLnToConsole("	end")
2190	WriteLnToConsole("end")
2191	WriteLnToConsole("")
2192
2193	WriteLnToConsole("function CheckForConditions(gear)")
2194	WriteLnToConsole("	if getGearValue(gear,\"tag\") == \"victory\" then")
2195	WriteLnToConsole("		victoryObj = victoryObj +1")
2196	WriteLnToConsole("	elseif getGearValue(gear,\"tag\") == \"failure\" then")
2197	WriteLnToConsole("		failObj = failObj +1")
2198	WriteLnToConsole("	elseif getGearValue(gear,\"tag\") == \"collection\" then")
2199	WriteLnToConsole("		collectObj = collectObj +1")
2200	WriteLnToConsole("	end")
2201	WriteLnToConsole("end")
2202	WriteLnToConsole("")
2203
2204	WriteLnToConsole("function CheckForConclusion(gear)")
2205	WriteLnToConsole("")
2206	WriteLnToConsole("	if getGearValue(gear,\"tag\") == \"failure\" then ")
2207	WriteLnToConsole("		EndGameIn(\"failure\")")
2208	WriteLnToConsole("	else ")
2209	WriteLnToConsole("")
2210	WriteLnToConsole("		victoryObj = 0")
2211	WriteLnToConsole("		failObj = 0")
2212	WriteLnToConsole("		collectObj = 0")
2213	WriteLnToConsole("		runOnGears(CheckForConditions)")
2214	WriteLnToConsole("")
2215	WriteLnToConsole("		if GetGearType(gear) ~= gtCase then")
2216	WriteLnToConsole("")
2217	WriteLnToConsole("			victoryObj = victoryObj - 1 ")
2218	WriteLnToConsole("")
2219	WriteLnToConsole("			if (victoryObj == 0) and (collectObj == 0) then")
2220	WriteLnToConsole("				EndGameIn(\"victory\")")
2221	WriteLnToConsole("			end")
2222	WriteLnToConsole("")
2223	WriteLnToConsole("		else")
2224	WriteLnToConsole("")
2225	WriteLnToConsole("			if (GetGearMessage(gear) == 256) and (getGearValue(gear,\"tag\") == \"collection\") then ")
2226	WriteLnToConsole("				if GetHogLevel(CurrentHedgehog) ~= 0 then")
2227	WriteLnToConsole("					EndGameIn(\"failure\")")
2228	WriteLnToConsole("				else")
2229	WriteLnToConsole("					collectObj = collectObj - 1")
2230	WriteLnToConsole("					if (victoryObj == 0) and (collectObj == 0) then")
2231	WriteLnToConsole("						EndGameIn(\"victory\")")
2232	WriteLnToConsole("					end")
2233	WriteLnToConsole("				end")
2234	WriteLnToConsole("			elseif (GetGearMessage(gear) == 0) and (getGearValue(gear,\"tag\") == \"victory\") then")
2235	WriteLnToConsole("				victoryObj = victoryObj - 1")
2236	WriteLnToConsole("				if (victoryObj == 0) and (collectObj == 0) then ")
2237	WriteLnToConsole("					EndGameIn(\"victory\")")
2238	WriteLnToConsole("				end")
2239	WriteLnToConsole("			else")
2240	WriteLnToConsole("				EndGameIn(\"failure\")")
2241	WriteLnToConsole("			end")
2242	WriteLnToConsole("")
2243	WriteLnToConsole("		end")
2244	WriteLnToConsole("")
2245	WriteLnToConsole("	end")
2246	WriteLnToConsole("")
2247	WriteLnToConsole("end")
2248	WriteLnToConsole("")
2249
2250	WriteLnToConsole("function DetermineMissionGoal()")
2251	WriteLnToConsole("")
2252	WriteLnToConsole("	victoryObj = 0")
2253	WriteLnToConsole("	failObj = 0")
2254	WriteLnToConsole("	collectObj = 0")
2255	WriteLnToConsole("	vComment = \"\"")
2256	WriteLnToConsole("	fComment = \"\"")
2257	WriteLnToConsole("	collectComment = \"\"")
2258	WriteLnToConsole("")
2259	WriteLnToConsole("	runOnGears(CheckForConditions)")
2260	WriteLnToConsole("")
2261	WriteLnToConsole("	if victoryObj > 0 then ")
2262	WriteLnToConsole("		if victoryObj == 1 then ")
2263	WriteLnToConsole([[			vComment = loc("- Destroy the red target") .. "|"]])
2264	WriteLnToConsole("		else ")
2265	WriteLnToConsole([[			vComment = loc("- Destroy the red targets") .. "|"]])
2266	WriteLnToConsole("		end")
2267	WriteLnToConsole("	end")
2268	WriteLnToConsole("")
2269	WriteLnToConsole("	if collectObj > 0 then ")
2270	WriteLnToConsole("		if collectObj == 1 then ")
2271	WriteLnToConsole([[			collectComment = loc("- Collect the blue crate") .. "|"]])
2272	WriteLnToConsole("		else ")
2273	WriteLnToConsole([[			collectComment = loc("- Collect all the blue crates") .. "|"]])
2274	WriteLnToConsole("		end")
2275	WriteLnToConsole("	end")
2276	WriteLnToConsole("")
2277	WriteLnToConsole("	if (collectObj == 0) and (victoryObj == 0) then")
2278	WriteLnToConsole([[		vComment = loc("- Destroy the enemy") .. "|"]])
2279	WriteLnToConsole("	end")
2280	WriteLnToConsole("")
2281	WriteLnToConsole("	if failObj > 0 then ")
2282	WriteLnToConsole("		if failObj == 1 then ")
2283	WriteLnToConsole([[			fComment = loc("- The green target must survive") .. "|"]])
2284	WriteLnToConsole("		else ")
2285	WriteLnToConsole([[			fComment = loc("- The green targets must survive") .. "|"]])
2286	WriteLnToConsole("		end")
2287	WriteLnToConsole("	end")
2288	WriteLnToConsole("")
2289	WriteLnToConsole([[	ShowMission(loc("User Mission"), loc("Mission"), collectComment .. vComment .. fComment, 1, 0)]])
2290	WriteLnToConsole("")
2291	WriteLnToConsole("end")
2292
2293	WriteLnToConsole("")
2294	WriteLnToConsole("function isATrackedGear(gear)")
2295	WriteLnToConsole("	if 	(GetGearType(gear) == gtHedgehog) or")
2296	WriteLnToConsole("		(GetGearType(gear) == gtExplosives) or")
2297	WriteLnToConsole("		(GetGearType(gear) == gtMine) or")
2298	WriteLnToConsole("		(GetGearType(gear) == gtSMine) or")
2299	WriteLnToConsole("		(GetGearType(gear) == gtAirMine) or")
2300	WriteLnToConsole("		(GetGearType(gear) == gtTarget) or")
2301	WriteLnToConsole("		(GetGearType(gear) == gtKnife) or")
2302	WriteLnToConsole("		(GetGearType(gear) == gtPortal) or")
2303	WriteLnToConsole("		(GetGearType(gear) == gtCase)")
2304	WriteLnToConsole("	then")
2305	WriteLnToConsole("		return(true)")
2306	WriteLnToConsole("	else")
2307	WriteLnToConsole("		return(false)")
2308	WriteLnToConsole("	end")
2309	WriteLnToConsole("end")
2310	WriteLnToConsole("")
2311
2312	WriteLnToConsole("")
2313	WriteLnToConsole("function onGearAdd(gear)")
2314
2315
2316	WriteLnToConsole("	if isATrackedGear(gear) then")
2317	WriteLnToConsole("		trackGear(gear)")
2318
2319	WriteLnToConsole("	end")
2320	WriteLnToConsole("end")
2321	WriteLnToConsole("")
2322
2323	WriteLnToConsole("")
2324	WriteLnToConsole("function EndGameIn(c)")
2325	WriteLnToConsole("")
2326	WriteLnToConsole("	teamCounter = 0")
2327	WriteLnToConsole("	lastRecordedTeam = \"\" ")
2328	WriteLnToConsole("	for i = 1, #hhs do")
2329	WriteLnToConsole("")
2330	WriteLnToConsole("		if GetHogTeamName(hhs[i]) ~= lastRecordedTeam then --er, is this okay without nill checks?")
2331	WriteLnToConsole("")
2332	WriteLnToConsole("			lastRecordedTeam = GetHogTeamName(hhs[i])")
2333	WriteLnToConsole("			teamCounter = teamCounter + 1")
2334	WriteLnToConsole("			if teamCounter == 9 then")
2335	WriteLnToConsole("				teamCounter = 1")
2336	WriteLnToConsole("			end")
2337	WriteLnToConsole("")
2338	WriteLnToConsole("			if (c ==  \"victory\") and (GetHogLevel(hhs[i]) ~= 0) then")
2339	WriteLnToConsole("				DismissTeam(GetHogTeamName(hhs[i]))")
2340	WriteLnToConsole([[				AddCaption(loc("Victory!"), capcolDefault, capgrpGameState)]])
2341	WriteLnToConsole([[				ShowMission(loc("User Mission"), loc("Mission"), loc("Mission succeeded!"), 0, 0)]])
2342	WriteLnToConsole("			elseif (c ==  \"failure\") and (GetHogLevel(hhs[i]) == 0) then")
2343	WriteLnToConsole("				DismissTeam(GetHogTeamName(hhs[i]))")
2344	WriteLnToConsole([[				AddCaption(loc("Defeat!"), capcolDefault, capgrpGameState)]])
2345	WriteLnToConsole([[				ShowMission(loc("User Mission"), loc("Mission"), loc("Mission failed!"), -amSkip, 0)]])
2346	WriteLnToConsole("			elseif (c ==  \"victory\") and (GetHogLevel(hhs[i]) == 0) then")
2347	WriteLnToConsole("				PlaySound(sndVictory,hhs[i]) -- check if we actually need this")
2348	WriteLnToConsole("			end")
2349	WriteLnToConsole("")
2350	WriteLnToConsole("		end")
2351	WriteLnToConsole("")
2352	WriteLnToConsole("	end")
2353	WriteLnToConsole("")
2354	WriteLnToConsole("end")
2355	WriteLnToConsole("")
2356
2357	WriteLnToConsole("")
2358	WriteLnToConsole("function onGearDelete(gear)")
2359	WriteLnToConsole("")
2360	WriteLnToConsole("	--insert code according to taste")
2361	WriteLnToConsole("")
2362	WriteLnToConsole("	if isATrackedGear(gear) then")
2363	WriteLnToConsole("")
2364	WriteLnToConsole("		if getGearValue(gear,\"tag\") ~= nil then")
2365	WriteLnToConsole("			CheckForConclusion(gear)")
2366	WriteLnToConsole("		end")
2367
2368	WriteLnToConsole("")
2369	WriteLnToConsole("		if getGearValue(gear, \"tCirc\") ~= nil then")
2370	WriteLnToConsole("			DeleteVisualGear(getGearValue(gear, \"tCirc\"))")
2371	WriteLnToConsole("		end")
2372	WriteLnToConsole("")
2373	WriteLnToConsole("		trackDeletion(gear)")
2374	WriteLnToConsole("")
2375	WriteLnToConsole("	end")
2376	WriteLnToConsole("")
2377	WriteLnToConsole("end")
2378	WriteLnToConsole("")
2379
2380	WriteLnToConsole("")
2381	WriteLnToConsole("--enable and/or alter code according to taste")
2382	WriteLnToConsole("function onAmmoStoreInit()")
2383	WriteLnToConsole("")
2384
2385	WriteLnToConsole("	for i = 0, AmmoTypeMax do")
2386	WriteLnToConsole("		if i ~= amNothing then")
2387	WriteLnToConsole("			SetAmmo(i, 0, 0, 0, 1)")
2388	WriteLnToConsole("		end")
2389	WriteLnToConsole("	end")
2390	WriteLnToConsole("")
2391	WriteLnToConsole("	SetAmmo(amSkip, 9, 0, 0, 0)")
2392	WriteLnToConsole("")
2393	WriteLnToConsole("end")
2394	WriteLnToConsole("")
2395
2396	WriteLnToConsole("------ END GENERATED MISSION ------")
2397
2398	-- at this point, generation for the missions/training output is intended to stop
2399
2400	WriteLnToConsole("")
2401	WriteLnToConsole("function GeneratePreviewData()")
2402	WriteLnToConsole("")
2403	for i = 1, #previewDataList do
2404		WriteLnToConsole(previewDataList[i])
2405	end
2406	WriteLnToConsole("")
2407	WriteLnToConsole("end")
2408	WriteLnToConsole("")
2409
2410	ConvertGearDataToHWPText()
2411
2412	WriteLnToConsole("------ END GENERATED SCRIPT ------")
2413
2414	AddCaption(loc("Level Data Saved!"), colorInfoMessage, capgrpGameState)
2415
2416end
2417
2418----------------------------------
2419-- some special effects handling
2420----------------------------------
2421function SmokePuff(x,y,c)
2422	tempE = AddVisualGear(x, y, vgtSmoke, 0, false)
2423	SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, 1, nil, c )
2424end
2425
2426function HandleGearBasedRankingEffects(gear)
2427	if getGearValue(gear, "ranking") ~= nil then
2428		SmokePuff(GetX(gear), GetY(gear),GetRankedColour(getGearValue(gear, "ranking")))
2429	end
2430end
2431
2432function HandleRankingEffects()
2433	for i = 1, #shoppaPX do
2434		SmokePuff(shoppaPX[i], shoppaPY[i], GetRankedColour(shoppaPR[i]))
2435	end
2436	runOnHogs(HandleGearBasedRankingEffects)
2437end
2438
2439function UpdateTagCircles(gear)
2440
2441	if getGearValue(gear,"tag") ~= nil then
2442
2443		if cat[cIndex] == loc("Goal Definition Mode") then
2444
2445			-- generate circs for tagged gears that don't have a circ yet (new)
2446			if getGearValue(gear,"tCirc") == nil then
2447				setGearValue(gear, "tCirc",AddVisualGear(0,0,vgtCircle,0,true))
2448			end
2449
2450			if getGearValue(gear,"tag") == "victory" then
2451				SetVisualGearValues(getGearValue(gear,"tCirc"), GetX(gear), GetY(gear), 100, 255, 1, 10, 0, 150, 3, 0xff0000ff)
2452			elseif getGearValue(gear,"tag") == "failure" then
2453				SetVisualGearValues(getGearValue(gear,"tCirc"), GetX(gear), GetY(gear), 100, 255, 1, 10, 0, 150, 3, 0x00ff00ff)
2454			elseif getGearValue(gear,"tag") == "collection" then
2455				SetVisualGearValues(getGearValue(gear,"tCirc"), GetX(gear), GetY(gear), 100, 255, 1, 10, 0, 150, 3, 0x0000ffff)
2456			end
2457
2458		else
2459			SetVisualGearValues(getGearValue(gear,"tCirc"), GetX(gear), GetY(gear), 0, 1, 1, 10, 0, 1, 1, 0x00000000)
2460		end
2461
2462	end
2463
2464end
2465
2466-- handle short range portal gun
2467function PortalEffects(gear)
2468
2469	if GetGearType(gear) == gtPortal then
2470
2471		local tag = GetTag(gear)
2472		local col
2473		if tag == 0 then
2474			col = 0xfab02aFF -- orange ball
2475		elseif tag == 1 then
2476			col = 0x00FF00FF -- orange portal
2477		elseif tag == 2 then
2478			col = 0x364df7FF  -- blue ball
2479		elseif tag == 3 then
2480			col = 0xFFFF00FF  -- blue portal
2481		end
2482
2483		if (tag == 0) or (tag == 2) then -- i.e ball form
2484			local remLife = getGearValue(gear,"life")
2485			remLife = remLife - 1
2486			setGearValue(gear, "life", remLife)
2487
2488			-- Destroy portal ball when max. distance reached
2489			if remLife == 0 then
2490
2491				local tempE = AddVisualGear(GetX(gear)+15, GetY(gear), vgtSmoke, 0, false)
2492				SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, nil, nil, col)
2493
2494				tempE = AddVisualGear(GetX(gear)-15, GetY(gear), vgtSmoke, 0, false)
2495				SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, nil, nil, col)
2496
2497				tempE = AddVisualGear(GetX(gear), GetY(gear)+15, vgtSmoke, 0, false)
2498				SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, nil, nil, col)
2499
2500				tempE = AddVisualGear(GetX(gear), GetY(gear)-15, vgtSmoke, 0, false)
2501				SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, nil, nil, col)
2502
2503				PlaySound(sndVaporize)
2504				DeleteGear(gear)
2505
2506			end
2507
2508		end
2509
2510	end
2511
2512end
2513
2514function updateHelp(curAmmoType)
2515	if curAmmoType == nil then
2516		curAmmoType = GetCurAmmoType()
2517	end
2518
2519	if (curAmmoType ~= amGirder) and (curAmmoType ~= amRubber) and (curAmmoType ~= amCMGearPlacementTool) then
2520
2521		if not hedgeEditorMissionPanelShown then
2522			showHedgeEditorMissionPanel()
2523		end
2524
2525	elseif cat[cIndex] == loc("Girder Placement Mode") then
2526
2527		ShowMission	(
2528				loc("GIRDER PLACEMENT MODE"),
2529				loc("Place girders"),
2530				loc("Place Girder: [Left Click]") .. "|" ..
2531				loc("Change Rotation: [Left], [Right]") .. "|" ..
2532				" " .. "|" ..
2533				loc("Normal Girder: [1]") .. "|" ..
2534				loc("Indestructible Girder: [2]") .. "|" ..
2535				loc("Icy Girder: [3]") .. "|" ..
2536				loc("Bouncy Girder: [4]") .. "|" ..
2537				" " .. "|" ..
2538				loc("Deletion Mode: [5]") .. "|" ..
2539				" " .. "|" ..
2540				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2541				"", -amGirder, 60000, not helpDisabled
2542				)
2543		hedgeEditorMissionPanelShown = false
2544
2545	elseif cat[cIndex] == loc("Rubber Placement Mode") then
2546
2547		ShowMission	(
2548				loc("RUBBER PLACEMENT MODE"),
2549				loc("Place rubber"),
2550				loc("Place Object: [Left Click]") .. "|" ..
2551				loc("Change Rotation: [Left], [Right]") .. "|" ..
2552				" " .. "|" ..
2553				loc("Normal Rubber: [1]") .. "|" ..
2554				" " .. "|" ..
2555				loc("Deletion Mode: [5]") .. "|" ..
2556				" " .. "|" ..
2557				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2558				"", -amRubber, 60000, not helpDisabled
2559				)
2560		hedgeEditorMissionPanelShown = false
2561
2562	elseif cat[cIndex] == loc("Barrel Placement Mode") then
2563
2564		ShowMission	(
2565				loc("BARREL PLACEMENT MODE"),
2566				loc("Place barrels"),
2567				loc("Place Object: [Left Click]") .. "|" ..
2568				loc("Change Health: [Left], [Right]") .. "|" ..
2569				" " .. "|" ..
2570				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2571				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2572				"", 8, 60000, not helpDisabled
2573				)
2574		hedgeEditorMissionPanelShown = false
2575
2576	elseif cat[cIndex] == loc("Cleaver Placement Mode") then
2577
2578		ShowMission	(
2579				loc("CLEAVER PLACEMENT MODE"),
2580				loc("Place cleavers"),
2581				loc("Place Object: [Left Click]") .. "|" ..
2582				" " .. "|" ..
2583				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2584				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2585				"", -amKnife, 60000, not helpDisabled
2586				)
2587		hedgeEditorMissionPanelShown = false
2588
2589	elseif cat[cIndex] == loc("Target Placement Mode") then
2590
2591		ShowMission	(
2592				loc("TARGET PLACEMENT MODE"),
2593				loc("Place targets"),
2594				loc("Place Object: [Left Click]") .. "|" ..
2595				" " .. "|" ..
2596				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2597				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2598				"", 1, 60000, not helpDisabled
2599				)
2600		hedgeEditorMissionPanelShown = false
2601
2602	elseif cat[cIndex] == loc("Waypoint Editing Mode") then
2603
2604		ShowMission	(
2605				loc("WAYPOINT EDITING MODE"),
2606				loc("Place or delete waypoints"),
2607				loc("Place/Delete Waypoint: [Left Click]") .. "|" ..
2608				loc("Toggle Placement/Deletion: [Left], [Right]") .. "|" ..
2609				" " .. "|" ..
2610				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2611				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2612				"", -amCMGearPlacementTool, 60000, not helpDisabled
2613				)
2614		hedgeEditorMissionPanelShown = false
2615
2616	elseif cat[cIndex] == loc("Mine Placement Mode") then
2617
2618		ShowMission	(
2619				loc("MINE PLACEMENT MODE"),
2620				loc("Place mines"),
2621				loc("Place Object: [Left Click]") .. "|" ..
2622				loc("Change Timer: [Left], [Right]") .. "|" ..
2623				" " .. "|" ..
2624				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2625				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2626				"", -amMine, 60000, not helpDisabled
2627				)
2628		hedgeEditorMissionPanelShown = false
2629
2630	elseif cat[cIndex] == loc("Dud Mine Placement Mode") then
2631
2632		ShowMission	(
2633				loc("DUD MINE PLACEMENT MODE"),
2634				loc("Place dud mines"),
2635				loc("Place Object: [Left Click]") .. "|" ..
2636				loc("Change Health: [Left], [Right]") .. "|" ..
2637				" " .. "|" ..
2638				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2639				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2640				"", 9, 60000, not helpDisabled
2641				)
2642		hedgeEditorMissionPanelShown = false
2643
2644	elseif cat[cIndex] == loc("Sticky Mine Placement Mode") then
2645
2646		ShowMission	(
2647				loc("STICKY MINE PLACEMENT MODE"),
2648				loc("Place sticky mines"),
2649				loc("Place Object: [Left Click]") .. "|" ..
2650				loc("Change Timer: [Left], [Right]") .. "|" ..
2651				" " .. "|" ..
2652				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2653				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2654				"", -amSMine, 60000, not helpDisabled
2655				)
2656		hedgeEditorMissionPanelShown = false
2657
2658	elseif cat[cIndex] == loc("Air Mine Placement Mode") then
2659
2660		ShowMission	(
2661				loc("AIR MINE PLACEMENT MODE"),
2662				loc("Place air mines"),
2663				loc("Place Object: [Left Click]") .. "|" ..
2664				loc("Change Timer: [Left], [Right]") .. "|" ..
2665				" " .. "|" ..
2666				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2667				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2668				"", -amAirMine, 60000, not helpDisabled
2669				)
2670		hedgeEditorMissionPanelShown = false
2671
2672	elseif cat[cIndex] == loc("Weapon Crate Placement Mode") then
2673
2674		ShowMission	(
2675				loc("WEAPON CRATE PLACEMENT MODE"),
2676				loc("Place weapon crates"),
2677				loc("Place Object: [Left Click]") .. "|" ..
2678				loc("Change Content: [Left], [Right]") .. "|" ..
2679				" " .. "|" ..
2680				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2681				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2682				"", 7, 60000, not helpDisabled
2683				)
2684		hedgeEditorMissionPanelShown = false
2685
2686	elseif cat[cIndex] == loc("Utility Crate Placement Mode") then
2687
2688		ShowMission	(
2689				loc("UTILITY CRATE PLACEMENT MODE"),
2690				loc("Place utility crates"),
2691				loc("Place Object: [Left Click]") .. "|" ..
2692				loc("Change Content: [Left], [Right]") .. "|" ..
2693				" " .. "|" ..
2694				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2695				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2696				"", 5, 60000, not helpDisabled
2697				)
2698		hedgeEditorMissionPanelShown = false
2699
2700	elseif cat[cIndex] == loc("Health Crate Placement Mode") then
2701
2702		ShowMission	(
2703				loc("HEALTH CRATE PLACEMENT MODE"),
2704				loc("Place health crates"),
2705				loc("Place Object: [Left Click]") .. "|" ..
2706				loc("Change Health Boost: [Left], [Right]") .. "|" ..
2707				" " .. "|" ..
2708				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2709				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2710				"", 6, 60000, not helpDisabled
2711				)
2712		hedgeEditorMissionPanelShown = false
2713
2714	elseif cat[cIndex] == loc("Repositioning Mode") then
2715
2716		ShowMission	(
2717				loc("REPOSITIONING MODE"),
2718				loc("Select, reposition and delete gears"),
2719				loc("Select/Place/Delete Gear: [Left Click]") .. "|" ..
2720				loc("Choose Selection/Placement/Deletion: [Left], [Right]") .. "|" ..
2721				" " .. "|" ..
2722				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2723				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2724				"", -amCMGearPlacementTool, 60000, not helpDisabled
2725				)
2726		hedgeEditorMissionPanelShown = false
2727
2728	elseif cat[cIndex] == loc("Sprite Modification Mode") then
2729
2730		ShowMission	(
2731				loc("SPRITE MODIFICATION MODE"),
2732				loc("Select, modify, or delete girders, rubbers and sprites"),
2733				loc("Modify Sprite under Cursor: [Left Click]") .. "|" ..
2734				loc("Change modification mode: [Left], [Right]") .."|"..
2735				loc("While in modification mode, you can change|the LandFlag by clicking on an object.") .. "|" ..
2736				" " .. "|" ..
2737				loc("Normal Land: [1]") .. "|" ..
2738				loc("Indestructible Land: [2]") .. "|" ..
2739				loc("Icy Land: [3]") .. "|" ..
2740				loc("Bouncy Land: [4]") .. "|" ..
2741				" " .. "|" ..
2742				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2743				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2744				"", 2, 60000, not helpDisabled
2745				)
2746		hedgeEditorMissionPanelShown = false
2747
2748	elseif cat[cIndex] == loc("Sprite Placement Mode") then
2749
2750		ShowMission	(
2751				loc("SPRITE PLACEMENT MODE"),
2752				loc("Place sprites to build land"),
2753				loc("Place Sprite: [Left Click]") .. "|" ..
2754				loc("Change Sprite: [Left], [Right]") .. "|" ..
2755				loc("Change Sprite Frame: [Precise]+[Left], [Precise]+[Right]") .. "|" ..
2756				" " .. "|" ..
2757				loc("Normal Land: [1]") .. "|" ..
2758				loc("Indestructible Land: [2]") .. "|" ..
2759				loc("Icy Land: [3]") .. "|" ..
2760				loc("Bouncy Land: [4]") .. "|" ..
2761				" " .. "|" ..
2762				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2763				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2764				"", -amCMGearPlacementTool, 60000, not helpDisabled
2765				)
2766		hedgeEditorMissionPanelShown = false
2767
2768	elseif cat[cIndex] == loc("Goal Definition Mode") then
2769
2770		ShowMission	(
2771				loc("GOAL DEFINITION MODE"),
2772				loc("Mark gears for win/lose conditions"),
2773				loc("Mark/unmark gear: [Left Click]") .. "|" ..
2774				loc("Select win/lose condition: [Left], [Right]") .. "|" ..
2775				" " .. "|" ..
2776				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2777				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2778				"", 0, 60000, not helpDisabled
2779				)
2780		hedgeEditorMissionPanelShown = false
2781	elseif cat[cIndex] == loc("Hog Identity Mode") then
2782
2783		ShowMission	(
2784				loc("HOG IDENTITY MODE"),
2785				loc("Give a hog a preset identity and weapons"),
2786				loc("Set Identity: [Left Click]") .. "|" ..
2787				loc("[Left], [Right]: Change between identities.") .. "|" ..
2788				" " .. "|" ..
2789				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2790				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2791				"", 3, 60000, not helpDisabled
2792				)
2793		hedgeEditorMissionPanelShown = false
2794
2795	elseif cat[cIndex] == loc("Team Identity Mode") then
2796
2797		ShowMission	(
2798				loc("TEAM IDENTITY MODE"),
2799				loc("Give an entire team themed hats and names"),
2800				loc("Set Identity: [Left Click]") .. "|" ..
2801				loc("[Left], [Right]: Change between identities.") .. "|" ..
2802				" " .. "|" ..
2803				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2804				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2805				"", 3, 60000, not helpDisabled
2806				)
2807		hedgeEditorMissionPanelShown = false
2808
2809	elseif cat[cIndex] == loc("Health Modification Mode") then
2810
2811		ShowMission	(
2812				loc("HEALTH MODIFICATION MODE"),
2813				loc("Set the health of hogs, health crates, barrels and duds"),
2814				loc("Set Health: [Left Click]") .. "|" ..
2815				loc("[Left], [Right]: Change health value.") .. "|" ..
2816				" " .. "|" ..
2817				loc("Change Placement Mode: [Up], [Down]") .. "|" ..
2818				loc("Toggle Help: [Precise]+[1]") .. "|" ..
2819				"", 2, 60000, not helpDisabled
2820				)
2821		hedgeEditorMissionPanelShown = false
2822
2823	end
2824
2825
2826	if helpDisabled == true then
2827		HideMission()
2828		hedgeEditorMissionPanelShown = false
2829	end
2830
2831end
2832
2833function onSetWeapon(ammoType)
2834	curWep = ammoType
2835	updateHelp(ammoType)
2836end
2837
2838function onSlot()
2839	curWep = GetCurAmmoType()
2840	updateHelp(ammoType)
2841end
2842
2843function onScreenResize()
2844	updateCursorCoords()
2845end
2846
2847-- Display the X and Y coordinates of the cursor while the cursor is active
2848function updateCursorCoords()
2849	if band(GetState(CurrentHedgehog), gstChooseTarget) ~= 0 and CursorX ~= NO_CURSOR then
2850		local x1, y
2851		if INTERFACE == "touch" then
2852			x1, y = 126, 32
2853		else
2854			x1, y = 12, 24
2855		end
2856		if tagCursorX then
2857			DeleteVisualGear(tagCursorX)
2858		end
2859		tagCursorX = AddVisualGear(-div(ScreenWidth, 2)+x1, y, vgtHealthTag, CursorX, true)
2860		SetVisualGearValues(tagCursorX, nil, nil, 0, 0, nil, 1, nil, nil, 240000, 0xFFFFFFFF)
2861
2862		local x2
2863		if string.len(tostring(CursorX)) > 6 then
2864			x2 = x1 + 100
2865		else
2866			x2 = x1 + 60
2867		end
2868		if tagCursorY then
2869			DeleteVisualGear(tagCursorY)
2870		end
2871		tagCursorY = AddVisualGear(-div(ScreenWidth, 2)+x2, y, vgtHealthTag, CursorY, true)
2872		SetVisualGearValues(tagCursorY, nil, nil, 0, 0, nil, 1, nil, nil, 240000, 0xFFFFFFFF)
2873	else
2874		if tagCursorX then
2875			DeleteVisualGear(tagCursorX)
2876		end
2877		if tagCursorY then
2878			DeleteVisualGear(tagCursorY)
2879		end
2880	end
2881end
2882
2883-- called in onGameTick()
2884function HandleHedgeEditor()
2885	if CurrentHedgehog ~= nil then
2886
2887		genTimer = genTimer + 1
2888
2889		tSprCol = 0x00000000
2890		tempFrame = 0
2891		xDisplacement = 42
2892		yDisplacement = 42
2893
2894		if (curWep == amCMGearPlacementTool) then
2895
2896			SetSoundMask(sndIncoming, true)
2897
2898			--wowaweewa, holyeeeee shite this is badly hacked (please rewrite when less lazy/morefeatures)
2899			dCol = 0xFFFFFFFF
2900			dFrame = 0
2901			dAngle = 0
2902			if (cat[cIndex] == loc("Mine Placement Mode")) then
2903				dSprite = sprCustom2
2904			elseif (cat[cIndex] == loc("Dud Mine Placement Mode")) then
2905				dSprite = sprCustom4
2906			elseif (cat[cIndex] == loc("Sticky Mine Placement Mode")) then
2907				dSprite = sprCustom3
2908			elseif (cat[cIndex] == loc("Air Mine Placement Mode")) then
2909				dSprite = sprAirMine
2910			elseif (cat[cIndex] == loc("Barrel Placement Mode")) then
2911				dSprite = sprExplosives
2912			elseif (cat[cIndex] == loc("Health Crate Placement Mode")) then
2913				dSprite = sprFAid
2914			elseif (cat[cIndex] == loc("Weapon Crate Placement Mode")) then
2915				dSprite = sprCase
2916			elseif (cat[cIndex] == loc("Utility Crate Placement Mode")) then
2917				dSprite = sprUtility
2918			elseif (cat[cIndex] == loc("Target Placement Mode")) then
2919				dSprite = sprTarget
2920			elseif (cat[cIndex] == loc("Cleaver Placement Mode")) then
2921				dAngle = 270
2922				dSprite = sprKnife
2923			elseif (cat[cIndex] == loc("Sprite Placement Mode")) then
2924				dSprite = reducedSpriteIDArray[pIndex]
2925				dFrame = sFrame
2926				if ((dSprite == sprAMAmmos) or (dSprite == sprAMAmmosBW)) and (dFrame == (amCMGearPlacementTool - 1)) then
2927					-- Special case: Air attack icon of ammos sprite needs to be fixed (since this icon is overwritten)
2928					dFrame = ammoFrameAirAttack
2929				end
2930			else
2931				dCol = 0xFFFFFF00
2932				dSprite = sprArrow
2933			end
2934
2935			if CG == nil then
2936				CG = AddVisualGear(CursorX, CursorY, vgtStraightShot,0,true,3)
2937			end
2938			SetVisualGearValues(CG, CursorX, CursorY, 0, 0, dAngle, dFrame, 1000, dSprite, 1000, dCol)
2939
2940
2941
2942			if crateSprite == nil then
2943				crateSprite = AddVisualGear(CursorX, CursorY-35, vgtStraightShot,0,true,3)
2944				crateSpriteBorder = AddVisualGear(CursorX, CursorY-35, vgtStraightShot,0,true,3)
2945			end
2946
2947
2948			if (cat[cIndex] == loc("Weapon Crate Placement Mode")) or (cat[cIndex] == loc("Utility Crate Placement Mode")) then
2949				if (cat[cIndex] == loc("Weapon Crate Placement Mode")) then
2950					tArr = atkArray
2951				else
2952					tArr = utilArray
2953				end
2954
2955				tSprCol = 0xFFFFFFFF
2956				-- Get ammo icon
2957				if tArr[pIndex][3] then
2958					-- Overwritten ammo icon
2959					tempFrame = tArr[pIndex][3]
2960				else
2961					-- Use default ammo icon
2962					tempFrame = tArr[pIndex][1] - 1
2963				end
2964			end
2965
2966			-- Waypoint outline
2967			if (cat[cIndex] == loc("Waypoint Editing Mode")) and (pMode[pIndex] == loc("Place Waypoint")) then
2968				if not waypointPreviewSprite then
2969					waypointPreviewSprite = AddVisualGear(CursorX, CursorY, vgtCircle, 0, true)
2970					SetVisualGearValues(waypointPreviewSprite, CursorX, CursorY, 244, 224, 0, 0, 0, div(wpRadius, 5), 5, 0xFF0000FF)
2971				end
2972			elseif waypointPreviewSprite then
2973				DeleteVisualGear(waypointPreviewSprite)
2974				waypointPreviewSprite = nil
2975			end
2976			if waypointPreviewSprite then
2977				SetVisualGearValues(waypointPreviewSprite, CursorX, CursorY)
2978			end
2979
2980		else
2981			SetSoundMask(sndIncoming, false)
2982			if CG ~= nil then
2983				SetVisualGearValues(CG, 0, 0, 0, 0, 0, 0, 1000, sprArrow, 1000, 0xFFFFFF00)
2984			end
2985		end
2986
2987		SetVisualGearValues(crateSprite, CursorX+xDisplacement, CursorY+yDisplacement, 0, 0, dAngle, tempFrame, 1000, sprAMAmmos, 1000, tSprCol)
2988		SetVisualGearValues(crateSpriteBorder, CursorX+xDisplacement, CursorY+yDisplacement, 0, 0, 0, 0, 1000, sprCustom1, 1000, tSprCol)
2989
2990		if genTimer >= 100 then
2991
2992			genTimer = 0
2993
2994			curWep = GetCurAmmoType()
2995
2996			HandleRankingEffects()
2997			runOnGears(PortalEffects)
2998
2999			-- change to girder mode on weapon swap
3000			if (cIndex ~= 1) and (curWep == amGirder) then
3001				cIndex = 1
3002				RedefineSubset()
3003				updateHelp()
3004			elseif (cIndex ~=2) and (curWep == amRubber) then
3005				cIndex = 2
3006				RedefineSubset()
3007				updateHelp()
3008			-- change to generic mode if girder no longer selected
3009			elseif (cIndex == 1) and (curWep ~= amGirder) then
3010				cIndex = 3 -- was 2
3011				RedefineSubset()
3012			elseif (cIndex == 2) and (curWep ~= amRubber) then
3013				cIndex = 3 --new
3014				RedefineSubset()
3015			end
3016
3017			if curWep == amGirder or curWep == amRubber then
3018				SetSoundMask(sndDenied, true)
3019			else
3020				SetSoundMask(sndDenied, false)
3021			end
3022
3023			-- update display selection criteria
3024			if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMGearPlacementTool) then
3025				AddCaption(cat[cIndex], colorPlaceMode1, capgrpMessage)
3026				showSecondaryMessage()
3027				if superDelete == true then
3028					AddCaption(loc("Deletion Mode"), colorPlaceMode1, capgrpAmmoinfo)
3029				end
3030			end
3031
3032
3033			if sSprite ~= nil then
3034				SetVisualGearValues(sSprite, nil, nil, 0, 0, nil, nil, 10000, nil, 10000 )
3035			end
3036
3037			updateHelp()
3038
3039		end
3040
3041	end
3042
3043
3044	if (ufoFuel ~= 0) then
3045		if ufoFuel == 2000 then
3046			SetHealth(ufoGear, 2000)
3047		end
3048	end
3049
3050	-- kinda lazy, but at least we don't have to do elaborate tacking elsewhere
3051	SetVisualGearValues(sCirc, 0, 0, 0, 1, 1, 10, 0, 1, 1, 0x00000000)
3052	--update selected gear display
3053	if (cat[cIndex] == loc("Repositioning Mode")) and (sGear ~= nil) then
3054		SetVisualGearValues(sCirc, GetX(sGear), GetY(sGear), 100, 255, 1, 10, 0, 300, 3, 0xff00ffff)
3055	elseif (cat[cIndex] == loc("Sprite Modification Mode")) and (sSprite ~= nil) then
3056		SetVisualGearValues(sSprite, nil, nil, 0, 0, nil, nil, 10000, nil, 10000)
3057	elseif (cat[cIndex] == loc("Goal Definition Mode")) then
3058		if (sGear ~= nil) or (closestGear ~= nil) then
3059			closestGear = nil
3060			sGear = nil
3061		end
3062	end
3063
3064
3065	runOnGears(UpdateTagCircles)
3066
3067
3068	-- some kind of target detected, tell me your story
3069	if cGear ~= nil then
3070
3071		x,y = GetGearTarget(cGear)
3072
3073		if GetGearType(cGear) == gtAirAttack and GetCurAmmoType() == amCMGearPlacementTool then
3074			SetGearMessage(cGear, bor(GetGearMessage(cGear), gmDestroy))
3075			if not cGearPlacementDone then
3076				PlaceObject(x, y)
3077				cGearPlacementDone = true
3078			end
3079		elseif GetGearType(cGear) == gtGirder and not cGearPlacementDone then
3080			CGR = GetState(cGear)
3081			PlaceObject(x, y)
3082			cGearPlacementDone = true
3083		end
3084
3085	end
3086
3087	-- Show cursor coords
3088	updateCursorCoords()
3089
3090end
3091
3092--------------------------------------------------
3093-- EVENT HANDLERS
3094--------------------------------------------------
3095
3096function commandMode()
3097	if (preciseOn == true) and ((GetCurAmmoType() == amNothing) or (GetCurAmmoType() == amSkip)) then
3098		return(true)
3099	else
3100		return(false)
3101	end
3102end
3103
3104function onTimer(s)
3105
3106	superDelete = false
3107	if (commandMode() == true) and (s == 4) then
3108		SaveLevelData() -- positions of crates, etc
3109	elseif (commandMode() == true) and (s == 2) then
3110		if GetAmmoCount(CurrentHedgehog, amCMGearPlacementTool) == 100 then
3111			SetEditingWeps(0)
3112			AddCaption(loc("The editor weapons and tools have been removed!"), colorInfoMessage, capgrpGameState)
3113		else
3114			SetEditingWeps(100)
3115			AddCaption(loc("The editor weapons and tools have been added!"), colorInfoMessage, capgrpGameState)
3116		end
3117	elseif (preciseOn == true) and (s == 1) then
3118		helpDisabled = not(helpDisabled)
3119		if helpDisabled then
3120			AddCaption(loc("Help Disabled"), colorInfoMessage, capgrpVolume)
3121		else
3122			AddCaption(loc("Help Enabled"), colorInfoMessage, capgrpVolume)
3123		end
3124		updateHelp()
3125	elseif (cat[cIndex] == loc("Sprite Placement Mode")) or (cat[cIndex] == loc("Girder Placement Mode")) or (cat[cIndex] == loc("Rubber Placement Mode")) or (cat[cIndex] == loc("Sprite Modification Mode")) then
3126
3127		if (cat[cIndex] == loc("Rubber Placement Mode")) then
3128			if s == 1 then
3129				landType = lfBouncy
3130				AddCaption(loc("Bouncy Land"), colorPlaceMode1, capgrpAmmoinfo)
3131			elseif s == 5 then
3132				superDelete = true
3133			end
3134		elseif s == 1 then
3135			landType = 0
3136			AddCaption(loc("Normal Land"), colorPlaceMode1, capgrpAmmoinfo)
3137		elseif s == 2 then
3138			landType = lfIndestructible
3139			AddCaption(loc("Indestructible Land"), colorPlaceMode1, capgrpAmmoinfo)
3140		elseif s == 3 then
3141			landType = lfIce
3142			AddCaption(loc("Icy Land"), colorPlaceMode1, capgrpAmmoinfo)
3143		elseif (s == 4) then
3144			landType = lfBouncy
3145			AddCaption(loc("Bouncy Land"), colorPlaceMode1, capgrpAmmoinfo)
3146		elseif (s == 5) and (cat[cIndex] ~= loc("Sprite Modification Mode")) and (cat[cIndex] ~= loc("Sprite Placement Mode")) then
3147			superDelete = true
3148		end
3149	elseif pMode[pIndex] == loc("Selection Mode") then
3150		if sGear ~= nil and GetGearType(sGear) == gtHedgehog then
3151			setGearValue(sGear, "ranking", s)
3152		end
3153	end
3154
3155end
3156
3157function onPrecise()
3158
3159	preciseOn = true
3160
3161end
3162
3163function onPreciseUp()
3164	preciseOn = false
3165end
3166
3167function showSecondaryMessage()
3168	local caption2
3169	if curWep == amGirder then
3170		caption2 = loc("Girder")
3171	elseif curWep == amRubber then
3172		caption2 = loc("Rubber")
3173	elseif cat[cIndex] == loc("Mine Placement Mode") or cat[cIndex] == loc("Sticky Mine Placement Mode") or cat[cIndex] == loc("Air Mine Placement Mode") then
3174		caption2 = string.format(loc("%d ms"), pMode[pIndex])
3175	elseif cat[cIndex] == loc("Dud Mine Placement Mode") or cat[cIndex] == loc("Barrel Placement Mode") or cat[cIndex] == loc("Health Crate Placement Mode") then
3176		caption2 = string.format(loc("Health: %d"), pMode[pIndex])
3177	elseif cat[cIndex] == loc("Health Modification Mode") then
3178		local health = tonumber(pMode[pIndex][1])
3179		local mode = pMode[pIndex][2]
3180		if mode == "set" then
3181			caption2 = string.format(loc("Set to %d"), health)
3182		elseif mode == "mod" then
3183			if health < 0 then
3184				caption2 = string.format(loc("Subtract %d"), math.abs(health))
3185			else
3186				caption2 = string.format(loc("Add %d"), health)
3187			end
3188		else
3189			caption2 = "ERROR"
3190		end
3191	elseif type(pMode[pIndex]) == "table" then
3192		caption2 = tostring(pMode[pIndex][1])
3193	else
3194		caption2 = tostring(pMode[pIndex])
3195	end
3196	AddCaption(caption2, colorPlaceMode2, capgrpMessage2)
3197end
3198
3199---------------------------------------------------------------
3200-- Cycle through selection subsets (by changing pIndex, pMode)
3201-- i.e 	health of barrels, medikits,
3202--		timer of mines
3203--		contents of crates etc.
3204---------------------------------------------------------------
3205function onLeft()
3206
3207	if (curWep == amCMGearPlacementTool) then
3208		leftHeld = true
3209		rightHeld = false
3210
3211		if preciseOn then
3212			if cat[cIndex] == loc("Sprite Placement Mode") then
3213				sFrame = sFrame - 1
3214				if sFrame < 0 then
3215					sFrame = reducedSpriteIDArrayFrames[pIndex] - 1
3216				end
3217			end
3218		else
3219			pIndex = pIndex - 1
3220			if pIndex == 0 then
3221				pIndex = #pMode
3222			end
3223			if cat[cIndex] == loc("Sprite Placement Mode") then
3224				sFrame = math.min(sFrame, reducedSpriteIDArrayFrames[pIndex] - 1)
3225			end
3226
3227			if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMGearPlacementTool) then
3228				showSecondaryMessage()
3229			end
3230		end
3231	end
3232
3233end
3234
3235function onRight()
3236
3237	if (curWep == amCMGearPlacementTool) then
3238		leftHeld = false
3239		rightHeld = true
3240
3241		if preciseOn then
3242			if cat[cIndex] == loc("Sprite Placement Mode") then
3243				sFrame = sFrame + 1
3244				if sFrame >= reducedSpriteIDArrayFrames[pIndex] then
3245					sFrame = 0
3246				end
3247			end
3248		else
3249			pIndex = pIndex + 1
3250			if pIndex > #pMode then
3251				pIndex = 1
3252			end
3253			if cat[cIndex] == loc("Sprite Placement Mode") then
3254				sFrame = math.min(sFrame, reducedSpriteIDArrayFrames[pIndex] - 1)
3255			end
3256
3257			if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMGearPlacementTool) then
3258				showSecondaryMessage()
3259			end
3260		end
3261	end
3262
3263end
3264
3265---------------------------------------------------------
3266-- Cycle through primary categories (by changing cIndex)
3267-- i.e 	mine, sticky mine, barrels
3268--		health/weapon/utility crate, placement of gears
3269---------------------------------------------------------
3270function onUp()
3271
3272	if (curWep == amCMGearPlacementTool) then
3273		cIndex = cIndex - 1
3274		if (cIndex == 1) or (cIndex == 2) then --1	--we no longer hit girder by normal means
3275			cIndex = #cat
3276		end
3277
3278		RedefineSubset()
3279		updateHelp()
3280
3281	end
3282
3283end
3284
3285function onDown()
3286
3287	if (curWep == amCMGearPlacementTool) then
3288		cIndex = cIndex + 1
3289		if cIndex > #cat then
3290			cIndex = 3	 -- 2 ----we no longer hit girder by normal means
3291		end
3292
3293		RedefineSubset()
3294		updateHelp()
3295
3296	end
3297
3298end
3299
3300function onParameters()
3301
3302    parseParams()
3303
3304	ufoFuel = tonumber(params["ufoFuel"])
3305	if ufoFuel == nil then
3306		ufoFuel = 0
3307	end
3308
3309	mapID = tonumber(params["m"])
3310
3311	--15 is a good short range portal, for what it's worth
3312	if tonumber(params["portalDistance"]) ~= nil then
3313		portalDistance = div(tonumber(params["portalDistance"]),5)
3314	end
3315
3316	if portalDistance == nil then
3317		portalDistance = 5000
3318	end
3319
3320	if mapID == nil then
3321		mapID = 1
3322	end
3323
3324end
3325
3326function onGameInit()
3327
3328	-- perhaps we can get some of this better info in parsecommandoverride
3329
3330	if mapID == nil then
3331		mapID = 1
3332	end
3333
3334	-- read gameflags and assign their values to the gameflaglist array
3335	for i = 1, #gameFlagList do
3336		if band(GameFlags, gameFlagList[i][3]) ~= 0 then
3337			gameFlagList[i][2] = true
3338		else
3339			gameFlagList[i][2] = false
3340		end
3341	end
3342
3343	reducedSpriteIDArrayFrames = {
3344		1, 8, 4, 1, 1,
3345		AmmoTypeMax, AmmoTypeMax, 3, 4, 8, 1,
3346		1, 1, 1, 1, 1, 1,
3347		1, 1, 1, 1, 1,
3348	}
3349
3350	Explosives = 0
3351	MinesNum = 0
3352	AirMinesNum = 0
3353
3354	EnableGameFlags(gfInfAttack, gfDisableWind)
3355
3356	RedefineSubset()
3357
3358end
3359
3360function showHedgeEditorMissionPanel()
3361	ShowMission	(
3362		loc("HEDGEEDITOR"),
3363		loc("An experimental editing tool for missions and more"),
3364		loc("Manual: https://hedgewars.org/hedgeeditor") .. "|" ..
3365		" " .. "|" ..
3366		loc("Place Girder: Girder") .. "|" ..
3367		loc("Place Rubber: Rubber") .. "|" ..
3368		loc("Place Gears (and more): Gear Placement Tool") .. "|" ..
3369		loc("Toggle Help: [Precise]+[1]") .. "|" ..
3370		" " .. "|" ..
3371		loc("Editing Commands: (Use while no weapon is selected)") .. "|" ..
3372		loc("Save Level: [Precise]+[4]") .. "|" ..
3373		loc("Toggle Editing Weapons and Tools: [Precise]+[2]")
3374		, 4, 5000
3375		)
3376
3377	SetAmmoTexts(amCMGearPlacementTool,
3378		loc("Gear Placement Tool"),
3379		loc("HedgeEditor tool"),
3380		loc("Place, modify and delete gears (e.g. objects)|and waypoints, edit hedgehog settings, values,|victory conditions, and more.") .. "|" ..
3381		loc("Select a placement mode and read the infos|in the mission panel to learn how to use it.") .. "|" ..
3382		loc("Up/Down: Change placement mode") .. "|" ..
3383		loc("Cursor: Mode action"))
3384
3385	hedgeEditorMissionPanelShown = true
3386end
3387
3388function onGameStart()
3389
3390	trackTeams()
3391
3392
3393	InterpretPoints()
3394	LoadLevelData()
3395
3396	showHedgeEditorMissionPanel()
3397
3398	sCirc = AddVisualGear(0,0,vgtCircle,0,true)
3399	SetVisualGearValues(sCirc, 0, 0, 100, 255, 1, 10, 0, 40, 3, 0xffba00ff)
3400
3401	--[[ This is a small hack to disable Hedgewars' girder placement since we do it on our own;
3402	this will remove the "girder circle" and gets rid of the placement failure animation ]]
3403	SetMaxBuildDistance(1)
3404
3405	frameID = 1
3406	visualSprite = sprAmGirder
3407	sSprite = AddVisualGear(0, 0, vgtStraightShot, 0, true,1)
3408	SetVisualGearValues(sSprite, 1, 1, 0, 0, nil, frameID, 20000, visualSprite, 20000, 0 )
3409
3410	SetAmmoDelay(amCMGearPlacementTool,0)
3411	SetAmmoDelay(amGirder,0)
3412	SetAmmoDelay(amRubber,0)
3413
3414end
3415
3416function SetEditingWeps(ammoCount)
3417
3418	AddAmmo(CurrentHedgehog, amCMGearPlacementTool, ammoCount)
3419	AddAmmo(CurrentHedgehog, amGirder, ammoCount)
3420	AddAmmo(CurrentHedgehog, amRubber, ammoCount)
3421	AddAmmo(CurrentHedgehog, amTeleport, ammoCount)
3422	AddAmmo(CurrentHedgehog, amRope, ammoCount)
3423	AddAmmo(CurrentHedgehog, amSwitch, 100)
3424	AddAmmo(CurrentHedgehog, amSkip, 100)
3425
3426end
3427
3428function clearAmmo(gear)
3429	for i = 1, #atkArray do
3430		AddAmmo(gear,atkArray[i][1],0)
3431	end
3432	for i = 1, #utilArray do
3433		AddAmmo(gear,utilArray[i][1],0)
3434	end
3435end
3436
3437-- the below two functions allow you to set up a themed team.
3438-- one day, it'd be nice to be able to set their voice/flag/grave
3439-- ingame at this point, too, but for now, this is impossible
3440function SetTeamIdentity(gear)
3441	tName = pMode[pIndex]
3442	hIndex = 1
3443	hArr = {}
3444	for i = 1,#preMadeTeam[pIndex][2] do
3445		table.insert(hArr,preMadeTeam[pIndex][2][i])
3446	end
3447	nArr = {}
3448	for i = 1,#preMadeTeam[pIndex][3] do
3449		table.insert(nArr,preMadeTeam[pIndex][3][i])
3450	end
3451	SetHogTeamName(gear, tName)
3452	runOnHogs(AssignTeam)
3453end
3454
3455function AssignTeam(gear)
3456
3457	if GetHogTeamName(gear) == tName then
3458
3459		setGearValue(gear,"flag",preMadeTeam[pIndex][5])
3460		setGearValue(gear,"voice",preMadeTeam[pIndex][6])
3461		setGearValue(gear,"grave",preMadeTeam[pIndex][7])
3462		setGearValue(gear,"fort",preMadeTeam[pIndex][8])
3463		setGearValue(gear,"originalTeamName",preMadeTeamNamesOriginal[pIndex])
3464
3465		if preMadeTeam[pIndex][4] == "R" then -- random team
3466
3467			if #hArr > 0 then
3468				--if there are unchosen hats left, choose one
3469				--then remove it from the available list of hats
3470				i = 1+GetRandom(#hArr)
3471				SetHogHat(gear,hArr[i])
3472				table.remove(hArr,i)
3473			else
3474				-- choose any hat randomly
3475				SetHogHat(gear,preMadeTeam[pIndex][2][1+GetRandom(#preMadeTeam[pIndex][2])])
3476			end
3477
3478			if #nArr > 0 then
3479				i = 1+GetRandom(#nArr)
3480				SetHogNameAndTranslate(gear, nArr[i])
3481				table.remove(nArr,i)
3482			else
3483				SetHogNameAndTranslate(gear, preMadeTeam[pIndex][3][1+GetRandom(#preMadeTeam[pIndex][3])])
3484			end
3485
3486		elseif preMadeTeam[pIndex][4] == "F" then -- fixed team w/ exactly 8 guys
3487			SetHogNameAndTranslate(gear, preMadeTeam[pIndex][3][hIndex])
3488			SetHogHat(gear,preMadeTeam[pIndex][2][hIndex])
3489			hIndex = hIndex +1
3490		else -- FR fixed random team with more or less than 8 guys
3491
3492			if #hArr > 0 then
3493				i = 1+GetRandom(#hArr)
3494				SetHogHat(gear,hArr[i])
3495				SetHogNameAndTranslate(gear, nArr[i])
3496				table.remove(hArr,i)
3497				table.remove(nArr,i)
3498			else
3499				SetHogHat(gear,"NoHat")
3500				SetHogNameAndTranslate(gear,loc_noop("Hedgehog"))
3501			end
3502
3503		end
3504
3505	end
3506
3507end
3508
3509-- allows you to set a sort of identity and weapon profile for a given hog
3510-- this should only really be used when perHogAmmo is enabled
3511function SetHogProfile(gear, pro)
3512
3513	clearAmmo(gear)
3514
3515	if pro == loc("Sniper") then
3516
3517		SetHogNameAndTranslate(gear, "Sniper")
3518		SetHogHat(gear, "Sniper")
3519		SetHealth(gear, 50)
3520		AddAmmo(gear, amSniperRifle, 100)
3521		AddAmmo(gear, amDEagle, 100)
3522
3523	elseif pro == loc("Pyro") then
3524
3525		SetHogNameAndTranslate(gear, "Pyro")
3526		SetHogHat(gear, "Gasmask")
3527		SetHealth(gear, 80)
3528		AddAmmo(gear, amFlamethrower, 100)
3529		AddAmmo(gear, amMolotov, 100)
3530		AddAmmo(gear, amNapalm, 1)
3531
3532	elseif pro == loc("Soldier") then
3533
3534		SetHogNameAndTranslate(gear, "Soldier")
3535		SetHogHat(gear, "war_americanww2helmet")
3536		SetHealth(gear, 100)
3537		AddAmmo(gear, amBazooka, 100)
3538		AddAmmo(gear, amShotgun, 100)
3539		AddAmmo(gear, amMortar, 100)
3540
3541	elseif pro == loc("Grenadier") then
3542
3543		SetHogNameAndTranslate(gear, "Grenadier")
3544		SetHogHat(gear, "war_desertgrenadier1")
3545		SetHealth(gear, 100)
3546		AddAmmo(gear, amGrenade, 100)
3547		AddAmmo(gear, amClusterBomb, 100)
3548		AddAmmo(gear, amGasBomb, 100)
3549
3550	elseif pro == loc("Chef") then
3551
3552		SetHogNameAndTranslate(gear, "Chef")
3553		SetHogHat(gear, "chef")
3554		SetHealth(gear, 65)
3555		AddAmmo(gear, amGasBomb, 100)
3556		AddAmmo(gear, amKnife, 100)
3557		AddAmmo(gear, amCake, 1)
3558
3559	elseif pro == loc("Ninja") then
3560
3561		SetHogNameAndTranslate(gear, "Ninja")
3562		SetHogHat(gear, "NinjaFull")
3563		SetHealth(gear, 80)
3564		AddAmmo(gear, amRope, 100)
3565		AddAmmo(gear, amFirePunch, 100)
3566		AddAmmo(gear, amParachute, 1)
3567
3568	elseif pro == loc("Commander") then
3569
3570		SetHogNameAndTranslate(gear, "Commander")
3571		SetHogHat(gear, "sf_vega")
3572		SetHealth(gear, 120)
3573		AddAmmo(gear, amDEagle, 100)
3574		AddAmmo(gear, amAirAttack, 2)
3575		AddAmmo(gear, amNapalm, 1)
3576		AddAmmo(gear, amDrillStrike, 1)
3577		AddAmmo(gear, amMineStrike, 1)
3578
3579	elseif pro == loc("Engineer") then
3580
3581		SetHogNameAndTranslate(gear, "Engineer")
3582		SetHogHat(gear, "Glasses")
3583		SetHealth(gear, 45)
3584		AddAmmo(gear, amGirder, 4)
3585		AddAmmo(gear, amRubber, 2)
3586		AddAmmo(gear, amLandGun, 2)
3587		AddAmmo(gear, amBlowTorch, 100)
3588		AddAmmo(gear, amPickHammer, 100)
3589
3590	elseif pro == loc("Physicist") then
3591
3592		SetHogNameAndTranslate(gear, "Physicist")
3593		SetHogHat(gear, "lambda")
3594		SetHealth(gear, 80)
3595		AddAmmo(gear, amIceGun, 2)
3596		AddAmmo(gear, amSineGun, 100)
3597		AddAmmo(gear, amBee, 2)
3598		AddAmmo(gear, amLowGravity, 100)
3599
3600	elseif pro == loc("Trapper") then
3601
3602		SetHogNameAndTranslate(gear, "Trapper")
3603		SetHogHat(gear, "Skull")
3604		SetHealth(gear, 100)
3605		AddAmmo(gear, amMine, 100)
3606		AddAmmo(gear, amSMine, 4)
3607		AddAmmo(gear, amAirMine, 2)
3608		AddAmmo(gear, amMolotov, 100)
3609
3610	elseif pro == loc("Saint") then
3611
3612		SetHogNameAndTranslate(gear, "Saint")
3613		SetHogHat(gear, "angel")
3614		SetHealth(gear, 200)
3615		AddAmmo(gear, amSeduction, 100)
3616		AddAmmo(gear, amInvulnerable, 100)
3617		AddAmmo(gear, amIceGun, 2)
3618		AddAmmo(gear, amHammer, 100)
3619		AddAmmo(gear, amResurrector, 100)
3620
3621	elseif pro == loc("Clown") then
3622
3623		SetHogNameAndTranslate(gear, "Clown")
3624		SetHogHat(gear, "clown-copper")
3625		SetHealth(gear, 70)
3626		AddAmmo(gear, amBaseballBat, 100)
3627		AddAmmo(gear, amGasBomb, 100)
3628		AddAmmo(gear, amBallgun, 1)
3629		AddAmmo(gear, amKamikaze, 1)
3630
3631	-- some other ideas/roles
3632	-- relocator: portal, teleport, tardis, extra time, lasersite
3633	-- vampire: vampire, whip, birdy, extra damage, seduction
3634	-- flyboy: rc plane, deagle, whip, parachute, kamikaze
3635	-- demo: drill, dynamite, mine, smine, blowtorch
3636	-- alien: ufo, sine-gun, drill rocket
3637	-- terminator: tardis, shotgun, cake, girder
3638	-- yeti: ice-gun, firepunch, blowtorch
3639
3640	end
3641
3642	AddAmmo(gear, amSwitch, 100)
3643	AddAmmo(gear, amSkip, 100)
3644
3645end
3646
3647function onNewTurn()
3648
3649	-- regardless of our other ammo, give stuff that is useful for editing
3650	SetEditingWeps(100)
3651	if GetHogLevel(CurrentHedgehog) == 0 then
3652		SetTurnTimeLeft(MAX_TURN_TIME)
3653	else
3654		SkipTurn() -- skip the computer's turn
3655	end
3656
3657end
3658
3659function onGameTick()
3660	HandleHedgeEditor()
3661end
3662
3663function isATrackedGear(gear)
3664	if 	(GetGearType(gear) == gtHedgehog) or
3665		(GetGearType(gear) == gtGrenade) or
3666		(GetGearType(gear) == gtExplosives) or
3667		(GetGearType(gear) == gtTarget) or
3668		(GetGearType(gear) == gtKnife) or
3669		(GetGearType(gear) == gtMine) or
3670		(GetGearType(gear) == gtSMine) or
3671		(GetGearType(gear) == gtPortal) or
3672		(GetGearType(gear) == gtAirMine) or
3673		(GetGearType(gear) == gtCase)
3674	then
3675		return(true)
3676	else
3677		return(false)
3678	end
3679end
3680
3681function SetHogNameAndTranslate(gear, originalName)
3682	SetHogName(gear, loc(originalName))
3683	--[[ Store the original (usually English) hog name, since we need it for exporting.
3684	This way, we can display the translated name in the editor and export the properly
3685	loc()'ed original name afterwards ]]
3686	setGearValue(gear, "originalName", originalName)
3687end
3688
3689-- track hedgehogs and placement gears
3690function onGearAdd(gear)
3691
3692	if GetGearType(gear) == gtJetpack then
3693		ufoGear = gear
3694		if (ufoFuel ~= 0) then
3695			SetHealth(ufoGear, ufoFuel)
3696		end
3697	end
3698
3699	if (GetGearType(gear) == gtAirAttack and GetCurAmmoType() == amCMGearPlacementTool) or (GetGearType(gear) == gtGirder) then
3700		cGear = gear
3701		cGearPlacementDone = false
3702	end
3703
3704	local tagTint
3705
3706	if isATrackedGear(gear) then
3707		trackGear(gear)
3708
3709		if GetGearType(gear) == gtPortal then
3710			setGearValue(gear,"life",portalDistance)
3711		end
3712
3713	end
3714
3715end
3716
3717function onGearDelete(gear)
3718	local gt = GetGearType(gear)
3719
3720	if gt == gtJetpack then
3721		ufoGear = nil
3722	end
3723
3724	if (gt == gtAirAttack and GetGearPos(gear) == 0) or gt == gtGirder then
3725		cGear = nil
3726	end
3727
3728	if isATrackedGear(gear) then
3729
3730		if getGearValue(gear, "tCirc") ~= nil then
3731			DeleteVisualGear(getGearValue(gear, "tCirc"))
3732		end
3733
3734		trackDeletion(gear)
3735
3736	end
3737
3738end
3739
3740function onVisualGearDelete(vGear)
3741	if vGear == tagCursorX then
3742		tagCursorX = nil
3743	end
3744	if vGear == tagCursorY then
3745		tagCursorY = nil
3746	end
3747end
3748