view: render map entities
[d2df-maped.git] / src / map / def.nim
blob9a323f24f3bb391beaa2b62bdd4ad590bc071bc2
1 import
2   std/typetraits, std/macros, std/tables,
3   ../serialization, ../utils, ../gfx,
4   entities
6 type
7   MapDirection* {.size: sizeof(uint8).} = enum
8     dirLeft = "DIR_LEFT"
9     dirRight = "DIR_RIGHT"
10     dirUnspecified = "DIR_SOMETHING2" # ???
12   MapKey* {.size: sizeof(uint8), bitsetNullValue: "KEY_NONE".} = enum
13     keyRed = "KEY_RED"
14     keyGreen = "KEY_GREEN"
15     keyBlue = "KEY_BLUE"
16     keyRedTeam = "KEY_REDTEAM"
17     keyBlueTeam = "KEY_BLUETEAM"
19   MapSpawnEffect* {.size: sizeof(uint8).} = enum
20     effNone = "EFFECT_NONE"
21     effTeleport = "EFFECT_TELEPORT"
22     effRespawn = "EFFECT_RESPAWN"
23     effFire = "EFFECT_FIRE"
25   MapHitType* {.size: sizeof(uint8).} = enum
26     hitSome = "HIT_SOME"
27     hitRocket = "HIT_ROCKET"
28     hitBFG = "HIT_BFG"
29     hitTrap = "HIT_TRAP"
30     hitFall = "HIT_FALL"
31     hitWater = "HIT_WATER"
32     hitAcid = "HIT_ACID"
33     hitElectro = "HIT_ELECTRO"
34     hitFlame = "HIT_FLAME"
35     hitSelf = "HIT_SELF"
36     hitDiscon = "HIT_DISCON"
38   MapObject* = ref object of Serializable
40   MapSpecialTexture* {.size: sizeof(int32).} = enum
41     texSpecialNone = (-4, "TEXTURE_SPECIAL_NONE")
42     texSpecialAcid2 = (-3, "TEXTURE_SPECIAL_ACID2")
43     texSpecialAcid1 = (-2, "TEXTURE_SPECIAL_ACID1")
44     texSpecialWater = (-1, "TEXTURE_SPECIAL_WATER")
46   MapTexture* = ref object of Serializable
47     path* {.writeDefault, resPath, maxSize: 64.}: string
48     animated* {.nonEditable.}: bool
49     # editor-specific fields
50     id* {.serializeNever, nonEditable, invisible.}: uint16
51     tex* {.serializeNever, nonEditable, invisible.}: Texture
53   # this is defined as if it was a bitfield, but it actually isn't
54   MapPanelType* {.size: sizeof(uint16).} = enum
55     panNone = (0, "PANEL_NONE")
56     panWall = (1, "PANEL_WALL")
57     panBack = (2, "PANEL_BACK")
58     panFore = (4, "PANEL_FORE")
59     panWater = (8, "PANEL_WATER")
60     panAcid1 = (16, "PANEL_ACID1")
61     panAcid2 = (32, "PANEL_ACID2")
62     panStep = (64, "PANEL_STEP")
63     panLiftUp = (128, "PANEL_LIFTUP")
64     panLiftDown = (256, "PANEL_LIFTDOWN")
65     panOpenDoor = (512, "PANEL_OPENDOOR")
66     panClosedDoor = (1024, "PANEL_CLOSEDOOR")
67     panBlockMon = (2048, "PANEL_BLOCKMON")
68     panLiftLeft = (4096, "PANEL_LIFTLEFT")
69     panLiftRight = (8192, "PANEL_LIFTRIGHT")
71   MapPanelFlags* {.size: sizeof(uint8), bitsetNullValue: "PANEL_FLAG_NONE".} = enum
72     pfBlending = "PANEL_FLAG_BLENDING"
73     pfHide = "PANEL_FLAG_HIDE"
74     pfWaterTexture = "PANEL_FLAG_WATERTEXTURES"
76   MapPanel* = ref object of MapObject
77     position* {.writeDefault.}: DFPoint
78     size* {.writeDefault.}: DFSize
79     texture* {.writeDefault.}: MapTexture
80     kind* {.writeDefault.}: MapPanelType
81     alpha*: uint8
82     flags*: set[MapPanelFlags]
83     moveSpeed* {.serializeTextOnly.}: DFPoint
84     sizeSpeed* {.serializeTextOnly.}: DFPoint
85     moveStart* {.serializeTextOnly.}: DFPoint
86     moveEnd* {.serializeTextOnly.}: DFPoint
87     sizeEnd* {.serializeTextOnly.}: DFSize
88     moveActive* {.serializeTextOnly.}: bool
89     moveOnce* {.serializeTextOnly.}: bool
90     endPosTrigger* {.serializeTextOnly.}: MapTrigger
91     endSizeTrigger*  {.serializeTextOnly.}: MapTrigger
92     # editor-specific fields
93     id* {.serializeNever, nonEditable, invisible.}: int32
95   MapItemType* {.size: sizeof(uint8).} = enum
96     itemNone = "ITEM_NONE"
97     itemMedkitSmall = "ITEM_MEDKIT_SMALL"
98     itemMedkitLarge = "ITEM_MEDKIT_LARGE"
99     itemMedkitBlack = "ITEM_MEDKIT_BLACK"
100     itemArmorGreen = "ITEM_ARMOR_GREEN"
101     itemArmorBlue = "ITEM_ARMOR_BLUE"
102     itemSphereBlue = "ITEM_SPHERE_BLUE"
103     itemSphereWhite = "ITEM_SPHERE_WHITE"
104     itemSuit = "ITEM_SUIT"
105     itemOxygen = "ITEM_OXYGEN"
106     itemInvul = "ITEM_INVUL"
107     itemWeaponSaw = "ITEM_WEAPON_SAW"
108     itemWeaponShotgun1 = "ITEM_WEAPON_SHOTGUN"
109     itemWeaponShotgun2 = "ITEM_WEAPON_SHOTGUN2"
110     itemWeaponChaingun = "ITEM_WEAPON_CHAINGUN"
111     itemWeaponRocketLauncher = "ITEM_WEAPON_ROCKETLAUNCHER"
112     itemWeaponPlasma = "ITEM_WEAPON_PLASMA"
113     itemWeaponBfg = "ITEM_WEAPON_BFG"
114     itemWeaponSuperChaingun = "ITEM_WEAPON_SUPERPULEMET"
115     itemAmmoBullets = "ITEM_AMMO_BULLETS"
116     itemAmmoBulletsBox = "ITEM_AMMO_BULLETS_BOX"
117     itemAmmoShells = "ITEM_AMMO_SHELLS"
118     itemAmmoShellsBox = "ITEM_AMMO_SHELLS_BOX"
119     itemAmmoRocket = "ITEM_AMMO_ROCKET"
120     itemAmmoRocketBox = "ITEM_AMMO_ROCKET_BOX"
121     itemAmmoCell = "ITEM_AMMO_CELL"
122     itemAmmoCellBig = "ITEM_AMMO_CELL_BIG"
123     itemAmmoBackpack = "ITEM_AMMO_BACKPACK"
124     itemKeyRed = "ITEM_KEY_RED"
125     itemKeyGreen = "ITEM_KEY_GREEN"
126     itemKeyBlue = "ITEM_KEY_BLUE"
127     itemWeaponFist = "ITEM_WEAPON_KASTET"
128     itemWeaponPistol = "ITEM_WEAPON_PISTOL"
129     itemHealthBonus = "ITEM_BOTTLE"
130     itemArmorBonus = "ITEM_HELMET"
131     itemJetpack = "ITEM_JETPACK"
132     itemInvis = "ITEM_INVIS"
133     itemWeaponFlamethrower = "ITEM_WEAPON_FLAMETHROWER"
134     itemAmmoFuelCan = "ITEM_AMMO_FUELCAN"
136   MapItemFlags* {.size: sizeof(uint8), bitsetNullValue: "ITEM_OPTION_NONE".} = enum
137     ifOnlyDM = "ITEM_OPTION_ONLYDM"
138     ifFall = "ITEM_OPTION_FALL"
140   MapItem* = ref object of MapObject
141     position* {.writeDefault.}: DFPoint
142     kind* {.writeDefault.}: MapItemType
143     options*: set[MapItemFlags]
144     # editor-specific fields
145     id* {.serializeNever, nonEditable, invisible.}: int32
146     size* {.serializeNever, nonEditable.}: DFSize
147     tex* {.serializeNever, nonEditable, invisible.}: Texture
149   MapMonsterType* {.size: sizeof(uint8).} = enum
150     monNone = "MONSTER_NONE"
151     monDemon = "MONSTER_DEMON"
152     monImp = "MONSTER_IMP"
153     monZombie = "MONSTER_ZOMBIE"
154     monSergeant = "MONSTER_SERG"
155     monCyber = "MONSTER_CYBER"
156     monChaingunner = "MONSTER_CGUN"
157     monBaron = "MONSTER_BARON"
158     monKnight = "MONSTER_KNIGHT"
159     monCaco = "MONSTER_CACO"
160     monLostSoul = "MONSTER_SOUL"
161     monPain = "MONSTER_PAIN"
162     monSpider = "MONSTER_SPIDER"
163     monBigSpider = "MONSTER_BSP"
164     monMancubus = "MONSTER_MANCUB"
165     monRevenant = "MONSTER_SKEL"
166     monArchVile = "MONSTER_VILE"
167     monFish = "MONSTER_FISH"
168     monBarrel = "MONSTER_BARREL"
169     monRobo = "MONSTER_ROBO"
170     monPrikolist = "MONSTER_MAN"
172   MapMonsterBehaviour* {.size: sizeof(uint8).} = enum
173     behNormal = "BH_NORMAL"
174     behKiller = "BH_KILLER"
175     behManiac = "BH_MANIAC"
176     behInsane = "BH_INSANE"
177     behCannibal = "BH_CANNIBAL"
178     behGood = "BH_GOOD"
180   MapMonster* = ref object of MapObject
181     position* {.writeDefault.}: DFPoint
182     kind* {.writeDefault.}: MapMonsterType
183     direction*: MapDirection
184     # editor-specific fields
185     id* {.serializeNever, nonEditable, invisible.}: int32
186     size* {.serializeNever, nonEditable.}: DFSize
187     center* {.serializeNever, nonEditable, invisible.}: DFPoint
188     delta* {.serializeNever, nonEditable, invisible.}: DFPoint
189     tex* {.serializeNever, nonEditable, invisible.}: Texture
191   MapAreaType* {.size: sizeof(uint8).} = enum
192     areaNone = "AREA_NONE"
193     areaP1Spawn = "AREA_PLAYERPOINT1"
194     areaP2Spawn = "AREA_PLAYERPOINT2"
195     areaDMSpawn = "AREA_DMPOINT"
196     areaRedFlag = "AREA_REDFLAG"
197     areaBlueFlag = "AREA_BLUEFLAG"
198     areaDomFlag = "AREA_DOMFLAG"
199     areaRedSpawn = "AREA_REDTEAMPOINT"
200     areaBlueSpawn = "AREA_BLUETEAMPOINT"
202   MapArea* = ref object of MapObject
203     position* {.writeDefault.}: DFPoint
204     kind* {.writeDefault.}: MapAreaType
205     direction*: MapDirection
206     # editor-specific fields
207     id* {.serializeNever, nonEditable, invisible.}: int32
208     size* {.serializeNever, nonEditable.}: DFSize
209     center* {.serializeNever, nonEditable, invisible.}: DFPoint
210     tex* {.serializeNever, nonEditable, invisible.}: Texture
212   MapActivationType* {.size: sizeof(uint8), bitsetNullValue: "ACTIVATE_NONE".} = enum
213     actPlayerCollide = "ACTIVATE_PLAYERCOLLIDE"
214     actMonsterCollide = "ACTIVATE_MONSTERCOLLIDE"
215     actPlayerPress = "ACTIVATE_PLAYERPRESS"
216     actMonsterPress = "ACTIVATE_MONSTERPRESS"
217     actShot = "ACTIVATE_SHOT"
218     actNoMonster = "ACTIVATE_NOMONSTER"
220   MapTriggerData* {.triggerData.} = ref object of Serializable
222   MapTriggerType* {.size: sizeof(uint8).} = enum
223     trigNone = "TRIGGER_NONE"
224     trigExit = "TRIGGER_EXIT"
225     trigTeleport = "TRIGGER_TELEPORT"
226     trigOpenDoor = "TRIGGER_OPENDOOR"
227     trigCloseDoor = "TRIGGER_CLOSEDOOR"
228     trigDoor = "TRIGGER_DOOR"
229     trigDoor5 = "TRIGGER_DOOR5"
230     trigCloseTrap = "TRIGGER_CLOSETRAP"
231     trigTrap = "TRIGGER_TRAP"
232     trigPress = "TRIGGER_PRESS"
233     trigSecret = "TRIGGER_SECRET"
234     trigLiftUp = "TRIGGER_LIFTUP"
235     trigLiftDown = "TRIGGER_LIFTDOWN"
236     trigLift = "TRIGGER_LIFT"
237     trigTexture = "TRIGGER_TEXTURE"
238     trigOn = "TRIGGER_ON"
239     trigOff = "TRIGGER_OFF"
240     trigOnOff = "TRIGGER_ONOFF"
241     trigSound = "TRIGGER_SOUND"
242     trigSpawnMonster = "TRIGGER_SPAWNMONSTER"
243     trigSpawnItem = "TRIGGER_SPAWNITEM"
244     trigMusic = "TRIGGER_MUSIC"
245     trigPush = "TRIGGER_PUSH"
246     trigScore = "TRIGGER_SCORE"
247     trigMessage = "TRIGGER_MESSAGE"
248     trigDamage = "TRIGGER_DAMAGE"
249     trigHealth = "TRIGGER_HEALTH"
250     trigShot = "TRIGGER_SHOT"
251     trigEffect = "TRIGGER_EFFECT"
252     trigScript = "TRIGGER_SCRIPT"
254   MapTrigger* = ref object of MapObject
255     position* {.writeDefault.}: DFPoint
256     size* {.writeDefault.}: DFSize
257     enabled* {.defaultValue: true.}: bool
258     texturePanel*: MapPanel
259     kind* {.writeDefault.}: MapTriggerType
260     activateType* {.writeDefault.}: set[MapActivationType]
261     keys*: set[MapKey]
262     triggerData* {.writeDefault, serializedBlockName: "triggerdata", triggerData.}: MapTriggerData # must always be last
263     # editor-specific fields
264     id* {.serializeNever, nonEditable.}: int32
266   MapHeader* = ref object of Serializable
267     mapName* {.writeDefault, serializedFieldName: "name", maxSize: 32.}: string
268     author* {.writeDefault, maxSize: 32.}: string
269     description* {.writeDefault, maxSize: 256.}: string
270     music* {.writeDefault, resPath, maxSize: 64.}: string
271     sky* {.writeDefault, resPath, maxSize: 64.}: string
272     size*  {.writeDefault.}: DFSize
274   Map* = ref object of Serializable
275     header* {.writeDefault, serializedBlockId: 7.}: MapHeader
276     textures* {.writeDefault, serializedBlockId: 1, serializedBlockName: "texture".}: ref seq[MapTexture]
277     panels* {.writeDefault, serializedBlockId: 2, serializedBlockName: "panel".}: ref seq[MapPanel]
278     items* {.writeDefault, serializedBlockId: 3, serializedBlockName: "item".}: ref seq[MapItem]
279     monsters* {.writeDefault, serializedBlockId: 5, serializedBlockName: "monster".}: ref seq[MapMonster]
280     areas* {.writeDefault, serializedBlockId: 4, serializedBlockName: "area".}: ref seq[MapArea]
281     triggers* {.writeDefault, serializedBlockId: 6, serializedBlockName: "trigger".}: ref seq[MapTrigger]
283   SomeMapObject* = MapPanel | MapItem | MapMonster | MapArea | MapTrigger
284   SomeMapRecord* = SomeMapObject | MapTexture
286   MapLayer* = enum
287     lrBackground = "Background"
288     lrWalls = "Walls"
289     lrForeground = "Foreground"
290     lrSteps = "Steps"
291     lrLiquids = "Liquids"
292     lrItems = "Items"
293     lrMonsters = "Monsters"
294     lrAreas = "Areas"
295     lrTriggers = "Triggers"
297 include helpers
299 # TRIGGER DATA TYPES START #
301 triggerDataDefs:
302   triggerDataType({ trigExit }):
303     type MapTriggerDataExit* = ref object of MapTriggerData
304       map* {.writeDefault, maxSize: 16.}: string
306   triggerDataType({ trigTeleport }):
307     type MapTriggerDataTeleport* = ref object of MapTriggerData
308       target* {.writeDefault.}: DFPoint
309       d2d*: bool
310       silent*: bool
311       direction*: MapDirection
313   triggerDataType({ trigOpenDoor..trigTrap, trigLiftUp..trigLift }):
314     type MapTriggerDataPanel* = ref object of MapTriggerData
315       panel* {.writeDefault, serializedFieldName: "panelid".}: MapPanel
316       silent*: bool
317       d2d*: bool
319   triggerDataType({ trigPress, trigOn..trigOnOff }):
320     type MapTriggerDataPress* = ref object of MapTriggerData
321       position*: DFPoint
322       size*: DFSize
323       wait*: uint16
324       count*: uint16
325       monster* {.serializedFieldName: "monsterid".}: MapMonster
326       extRandom*: bool
327       # extended fields
328       movePanel* {.serializeTextOnly, serializedFieldName: "panelid".}: MapPanel
329       silent* {.serializeTextOnly, defaultValue: true.}: bool
330       sound* {.serializeTextOnly.}: string
332   triggerDataType({ trigTexture }):
333     type MapTriggerDataTexture* = ref object of MapTriggerData
334       activateOnce* {.writeDefault.}: bool
335       animateOnce* {.writeDefault.}: bool
337   triggerDataType({ trigSound }):
338     type MapTriggerDataSound* = ref object of MapTriggerData
339       soundName* {.writeDefault, resPath, maxSize: 64.}: string
340       volume* {.writeDefault.}: uint8
341       pan*: uint8
342       local* {.defaultValue: true.}: bool
343       playCount*: uint8
344       soundSwitch*: bool
346   triggerDataType({ trigSpawnMonster }):
347     type MapTriggerDataSpawnMonster* = ref object of MapTriggerData
348       position* {.writeDefault.}: DFPoint
349       kind* {.writeDefault, overrideSize: sizeof(uint32).}: MapMonsterType
350       health* {.writeDefault.}: int32
351       direction* {.writeDefault.}: MapDirection
352       active* {.writeDefault, overrideSize: 3, defaultValue: true.}: bool
353       count* {.writeDefault, defaultValue: 1.}: int32
354       effect* {.writeDefault.}: MapSpawnEffect
355       max* {.writeDefault, defaultValue: 1.}: uint16
356       delay* {.writeDefault, defaultValue: 1000.}: uint16
357       behaviour*: MapMonsterBehaviour
359   triggerDataType({ trigSpawnItem }):
360     type MapTriggerDataSpawnItem* = ref object of MapTriggerData
361       position* {.writeDefault.}: DFPoint
362       kind* {.writeDefault.}: MapItemType
363       gravity* {.defaultValue: true.}: bool
364       dmonly* {.overrideSize: 2.}: bool
365       count* {.defaultValue: 1.}: int32
366       effect* {.overrideSize: 2.}: MapSpawnEffect
367       max* {.defaultValue: 1.}: uint16
368       delay* {.defaultValue: 1.}: uint16
370   type
371     MapTriggerMusicAction* {.size: sizeof(uint8).} = enum
372       musActionStop = "TRIGGER_MUSIC_ACTION_STOP"
373       musActionPlay = "TRIGGER_MUSIC_ACTION_PLAY"
375   triggerDataType({ trigMusic }):
376     type MapTriggerDataMusic* = ref object of MapTriggerData
377       musicName* {.writeDefault, serializedFieldName: "name", resPath, maxSize: 64.}: string
378       action* {.writeDefault.}: MapTriggerMusicAction
380   triggerDataType({ trigPush }):
381     type MapTriggerDataPush* = ref object of MapTriggerData
382       angle* {.writeDefault.}: uint16
383       force* {.writeDefault.}: uint8
384       resetVelocity* {.writeDefault.}: bool
386   type
387     MapTriggerScoreAction* {.size: sizeof(uint8).} = enum
388       scoreActionAdd = "TRIGGER_SCORE_ACTION_ADD"
389       scoreActionSub = "TRIGGER_SCORE_ACTION_SUB"
390       scoreActionWin = "TRIGGER_SCORE_ACTION_WIN"
391       scoreActionLose = "TRIGGER_SCORE_ACTION_LOOSE" # sic
393     MapTriggerScoreTeam* {.size: sizeof(uint8).} = enum
394       scoreTeamMineRed = "TRIGGER_SCORE_TEAM_MINE_RED"
395       scoreTeamMineBlue = "TRIGGER_SCORE_TEAM_MINE_BLUE"
396       scoreTeamForceRed = "TRIGGER_SCORE_TEAM_FORCE_RED"
397       scoreTeamForceBlue = "TRIGGER_SCORE_TEAM_FORCE_BLUE"
399   triggerDataType({ trigScore }):
400     type MapTriggerDataScore* = ref object of MapTriggerData
401       action* {.writeDefault.}: MapTriggerScoreAction
402       count* {.writeDefault, defaultValue: 1.}: uint8
403       team* {.writeDefault.}: MapTriggerScoreTeam
404       console* {.writeDefault.}: bool
405       message* {.writeDefault, defaultValue: true.}: bool
407   type
408     MapTriggerMessageKind* {.size: sizeof(uint8).} = enum
409       msgKindChat = "TRIGGER_MESSAGE_KIND_CHAT"
410       msgKindGame = "TRIGGER_MESSAGE_KIND_GAME"
412     MapTriggerMessageDest* {.size: sizeof(uint8).} = enum
413       msgDestMe = "TRIGGER_MESSAGE_DEST_ME"
414       msgDestMyTeam = "TRIGGER_MESSAGE_DEST_MY_TEAM"
415       msgDestEnemyTeam = "TRIGGER_MESSAGE_DEST_ENEMY_TEAM"
416       msgDestRedTeam = "TRIGGER_MESSAGE_DEST_RED_TEAM"
417       msgDestBlueTeam = "TRIGGER_MESSAGE_DEST_BLUE_TEAM"
418       msgDestEveryone = "TRIGGER_MESSAGE_DEST_EVERYONE"
420   triggerDataType({ trigMessage }):
421     type MapTriggerDataMessage* = ref object of MapTriggerData
422       kind* {.writeDefault, serializedFieldName: "kind".}: MapTriggerMessageKind
423       dest* {.writeDefault.}: MapTriggerMessageDest
424       text* {.writeDefault, maxSize: 100.}: string
425       time* {.writeDefault.}: uint16
427   triggerDataType({ trigDamage }):
428     type MapTriggerDataDamage* = ref object of MapTriggerData
429       amount* {.writeDefault.}: uint16
430       interval* {.writeDefault.}: uint16
431       kind* {.writeDefault, serializedFieldName: "kind".}: MapHitType
433   triggerDataType({ trigHealth }):
434     type MapTriggerDataHealth* = ref object of MapTriggerData
435       amount* {.writeDefault.}: uint16
436       interval* {.writeDefault.}: uint16
437       max* {.writeDefault.}: bool
438       silent* {.writeDefault.}: bool
440   type
441     MapTriggerShotKind* {.size: sizeof(uint8).} = enum
442       shotKindPistol = "TRIGGER_SHOT_PISTOL"
443       shotKindBullet = "TRIGGER_SHOT_BULLET"
444       shotKindShotgun = "TRIGGER_SHOT_SHOTGUN"
445       shotKindSSG = "TRIGGER_SHOT_SSG"
446       shotKindImp = "TRIGGER_SHOT_IMP"
447       shotKindPlasma = "TRIGGER_SHOT_PLASMA"
448       shotKindSpider = "TRIGGER_SHOT_SPIDER"
449       shotKindCaco = "TRIGGER_SHOT_CACO"
450       shotKindBaron = "TRIGGER_SHOT_BARON"
451       shotKindMancub = "TRIGGER_SHOT_MANCUB"
452       shotKindRev = "TRIGGER_SHOT_REV"
453       shotKindRocket = "TRIGGER_SHOT_ROCKET"
454       shotKindBFG = "TRIGGER_SHOT_BFG"
455       shotKindExpl = "TRIGGER_SHOT_EXPL"
456       shotKindBFGExpl = "TRIGGER_SHOT_BFGEXPL"
457       shotKindFlame = "TRIGGER_SHOT_FLAME"
458     MapTriggerShotTarget* {.size: sizeof(uint8).} = enum
459       shotTargetNone = "TRIGGER_SHOT_TARGET_NONE"
460       shotTargetMon = "TRIGGER_SHOT_TARGET_MON"
461       shotTargetPlr = "TRIGGER_SHOT_TARGET_PLR"
462       shotTargetRed = "TRIGGER_SHOT_TARGET_RED"
463       shotTargetBlue = "TRIGGER_SHOT_TARGET_BLUE"
464       shotTargetMonPlr = "TRIGGER_SHOT_TARGET_MONPLR"
465       shotTargetPlrMon = "TRIGGER_SHOT_TARGET_PLRMON"
466     MapTriggerShotAim* {.size: sizeof(uint8).} = enum
467       shotAimDefault = "TRIGGER_SHOT_AIM_DEFAULT"
468       shotAimAllMap = "TRIGGER_SHOT_AIM_ALLMAP"
469       shotAimTrace = "TRIGGER_SHOT_AIM_TRACE"
470       shotAimTraceAll = "TRIGGER_SHOT_AIM_TRACEALL"
472   triggerDataType({ trigShot }):
473     type MapTriggerDataShot* = ref object of MapTriggerData
474       position* {.writeDefault.}: DFPoint
475       kind* {.writeDefault.}: MapTriggerShotKind
476       target* {.writeDefault.}: MapTriggerShotTarget
477       sound*: bool # negbool?
478       aim*: MapTriggerShotAim
479       panel* {.writeDefault, serializedFieldName: "panelid".}: MapPanel
480       sight*: uint16
481       angle*: uint16
482       wait*: uint16
483       accuracy*: uint16
484       ammo*: uint16
485       reload*: uint16
487   type
488     MapTriggerEffectType* {.size: sizeof(uint8).} = enum
489       effectTypeParticle = "TRIGGER_EFFECT_PARTICLE"
490       effectTypeAnimation = "TRIGGER_EFFECT_ANIMATION"
491     MapTriggerEffectSubType* {.size: sizeof(uint8).} = enum
492       effectSubTypeSLiquid = "TRIGGER_EFFECT_SLIQUID"
493       effectSubTypeLLiquid = "TRIGGER_EFFECT_LLIQUID"
494       effectSubTypeDLiquid = "TRIGGER_EFFECT_DLIQUID"
495       effectSubTypeBlood = "TRIGGER_EFFECT_BLOOD"
496       effectSubTypeSpark = "TRIGGER_EFFECT_SPARK"
497       effectSubTypeBubble = "TRIGGER_EFFECT_BUBBLE"
498     MapTriggerEffectPos* {.size: sizeof(uint8).} = enum
499       effectPosCenter = "TRIGGER_EFFECT_POS_CENTER"
500       effectPosArea = "TRIGGER_EFFECT_POS_AREA"
502   triggerDataType({ trigEffect }):
503     type MapTriggerDataEffect* = ref object of MapTriggerData
504       count* {.writeDefault.}: uint8
505       kind* {.writeDefault.}: MapTriggerEffectType
506       subType* {.writeDefault.}: MapTriggerEffectSubType
507       red* {.writeDefault.}: uint8
508       green* {.writeDefault.}: uint8
509       blue* {.writeDefault.}: uint8
510       pos* {.writeDefault.}: MapTriggerEffectPos
511       wait* {.writeDefault.}: uint16
512       velX* {.writeDefault.}: int8
513       velY* {.writeDefault.}: int8
514       spreadL* {.writeDefault.}: uint8
515       spreadR* {.writeDefault.}: uint8
516       spreadU* {.writeDefault.}: uint8
517       spreadD* {.writeDefault.}: uint8
519   triggerDataType({ trigSecret }):
520     type MapTriggerDataSecret* = ref object of MapTriggerData
522 # TRIGGER DATA TYPES END #
525   currentMap*: Map = nil
527 # intiializers for map structs, executed after loading
529 proc init*(self: MapPanel) =
530   discard
532 proc init*(self: MapTrigger) =
533   discard
535 proc init*(self: MapTexture) =
536   self.tex = gfx.getTexture(self.path)
537   if self.tex == nil:
538     self.tex = gfx.getTexture("$$ERROR")
540 proc init*(self: MapItem) =
541   let typeStr = $self.kind
542   if typeStr in mapEntInfo:
543     let (_, _, size, _, _) = mapEntInfo[typeStr]
544     self.tex = gfx.getTexture("$$" & typeStr)
545     self.size = size
547 proc init*(self: MapArea) =
548   let typeStr = $self.kind
549   if typeStr in mapEntInfo:
550     let (center, _, size, _, _) = mapEntInfo[typeStr]
551     self.tex = gfx.getTexture("$$" & typeStr)
552     self.size = size
553     self.center = center
555 proc init*(self: MapMonster) =
556   let typeStr = $self.kind
557   if typeStr in mapEntInfo:
558     let (center, delta, size, _, _) = mapEntInfo[typeStr]
559     self.tex = gfx.getTexture("$$" & typeStr)
560     self.size = size
561     self.center = center
562     self.delta = delta
564 # map-wide stuff
566 iterator mapAllOfType*[T: SomeMapRecord](): var T =
567   # uh oh stinky
568   when T is MapTexture:
569     for x in currentMap.textures[].mitems(): yield x
570   elif T is MapPanel:
571     for x in currentMap.panels[].mitems(): yield x
572   elif T is MapItem:
573     for x in currentMap.items[].mitems(): yield x
574   elif T is MapMonster:
575     for x in currentMap.monsters[].mitems(): yield x
576   elif T is MapArea:
577     for x in currentMap.areas[].mitems(): yield x
578   elif T is MapTrigger:
579     for x in currentMap.triggers[].mitems(): yield x
580   else:
581     error("this shouldn't happen")
583 proc mapGetAllOfType*[T: SomeMapRecord](): seq[T] =
584   # uh oh stinky
585   when T is MapTexture:
586     return currentMap.textures
587   elif T is MapPanel:
588     return currentMap.panels
589   elif T is MapItem:
590     return currentMap.items
591   elif T is MapMonster:
592     return currentMap.monsters
593   elif T is MapArea:
594     return currentMap.areas
595   elif T is MapTrigger:
596     return currentMap.triggers
597   else:
598     error("this shouldn't happen")
600 template mapForAllRecords*(obj, blk: untyped): untyped =
601   # uh oh stinky
602   for obj in mapAllOfType[MapTexture](): blk
603   for obj in mapAllOfType[MapPanel](): blk
604   for obj in mapAllOfType[MapItem](): blk
605   for obj in mapAllOfType[MapMonster](): blk
606   for obj in mapAllOfType[MapArea](): blk
607   for obj in mapAllOfType[MapTrigger](): blk
609 template mapForAllObjects*(obj, blk: untyped): untyped =
610   # uh oh stinky
611   for obj in mapAllOfType[MapPanel](): blk
612   for obj in mapAllOfType[MapItem](): blk
613   for obj in mapAllOfType[MapMonster](): blk
614   for obj in mapAllOfType[MapArea](): blk
615   for obj in mapAllOfType[MapTrigger](): blk
617 proc mapGetByName*[T: SomeMapRecord](name: string): T =
618   if name != "":
619     for x in mapAllOfType[T]():
620       if name == x.name:
621         return x
622   result = nil
624 proc mapGetById*[T: SomeMapRecord](id: int): T =
625   if id >= 0 and id != 0xFFFF:
626     for x in mapAllOfType[T]():
627       if id == x.id.int:
628         return x
629   result = nil
631 proc newMapHeader*(name: string, w, h: int): MapHeader =
632   result = new(MapHeader)
633   result.mapName = name
634   result.size = initDFSize(w, h)
636 proc newMap*(): Map =
637   result = new(Map)
638   result.header = newMapHeader("Unnamed Map", 1600, 1600)
639   new(result.textures)
640   new(result.panels)
641   new(result.items)
642   new(result.monsters)
643   new(result.areas)
644   new(result.triggers)
646 proc newMap*(stream: SomeSerializer): Map =
647   assert(not stream.isWriting, "can't create map from writer stream")
648   result = newMap()
649   stream.serialize(result)
650   stream.finalize()
652 proc save*(self: Map, stream: SomeSerializer) =
653   assert(stream.isWriting, "can't save map to reader stream")
654   stream.serialize(self)
655   stream.finalize()
657 proc destroy*(self: Map) =
658   for mtex in self.textures[].mitems():
659     if mtex.path notin waterTextureNames:
660       mtex.tex.destroy()
661   self.textures[].setLen(0)
662   self.panels[].setLen(0)
663   self.items[].setLen(0)
664   self.monsters[].setLen(0)
665   self.areas[].setLen(0)
666   self.triggers[].setLen(0)
668 proc referenceScan[T: Serializable](self: Map, x: T) =
669   for fieldName, fieldSym in fieldPairs(x[]):
670     when fieldSym is SomeMapRecord:
671       if fieldSym != nil:
672         when T is MapPanel and fieldSym is MapTexture:
673           if pfHide in x.flags:
674             fieldSym = nil # hidden panel, no texture
675         if fieldSym != nil:
676           let searchName = fieldSym.name
677           let searchId = fieldSym.id
678           fieldSym = mapGetById[type(fieldSym)](searchId.int)
679           if fieldSym == nil:
680             fieldSym = mapGetByName[type(fieldSym)](searchName)
681     elif fieldSym is MapTriggerData:
682       fieldSym.fixupReferences(self)
684 proc fixupReferences*(self: Map) =
685   mapForAllObjects(x):
686     self.referenceScan(x)