1 (* Copyright (C) SovietPony
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 {$MODESWITCH ANSISTRINGS+}
18 {$MODESWITCH AUTODEREF+}
19 {$MODESWITCH CLASSICPROCVARS+}
20 {$MODESWITCH DEFAULTPARAMETERS+}
21 {$MODESWITCH DUPLICATELOCALS-}
22 {$MODESWITCH EXCEPTIONS+}
23 {$MODESWITCH HINTDIRECTIVE+}
24 {$MODESWITCH NESTEDCOMMENTS+}
25 {$MODESWITCH NESTEDPROCVARS+}
28 {$MODESWITCH PCHARTOSTRING+}
29 {$MODESWITCH POINTERTOPROCVAR+}
30 {$MODESWITCH REPEATFORWARD+}
32 {$MODESWITCH UNICODESTRINGS-}
40 uses Classes
, SysUtils
, Math
, SDL
, SDL_image
;
66 MP_AMMO_BACKPACK
= 20;
68 MP_AMMO_BULLETS_BOX
= 22;
70 MP_AMMO_SHELLS_BOX
= 24;
74 MP_AMMO_ROCKET_BOX
= 28;
76 MP_AMMO_CELL_BIG
= 30;
77 MP_WEAPON_SHOTGUN1
= 31;
78 MP_WEAPON_SHOTGUN2
= 32;
79 MP_WEAPON_CHAINGUN
= 33;
81 MP_WEAPON_ROCKETLAUNCHER
= 35;
82 MP_WEAPON_PLASMA
= 36;
84 MP_WEAPON_SUPERPULEMET
= 38;
85 // areas and triggers here!
92 MP_BLUETEAMPOINT
= 41;
96 (* MP Trigger activation *)
124 PANEL_LIFTDOWN
= 256;
125 PANEL_OPENDOOR
= 512;
126 PANEL_CLOSEDOOR
= 1024;
127 PANEL_BLOCKMON
= 2048;
128 PANEL_LIFTLEFT
= 4096;
129 PANEL_LIFTRIGHT
= 8192;
131 PANEL_FLAG_BLENDING
= 1;
133 PANEL_FLAG_WATERTEXTURES
= 4;
136 ITEM_MEDKIT_SMALL
= 1;
137 ITEM_MEDKIT_LARGE
= 2;
138 ITEM_MEDKIT_BLACK
= 3;
139 ITEM_ARMOR_GREEN
= 4;
141 ITEM_SPHERE_BLUE
= 6;
142 ITEM_SPHERE_WHITE
= 7;
146 ITEM_WEAPON_SAW
= 11;
147 ITEM_WEAPON_SHOTGUN1
= 12;
148 ITEM_WEAPON_SHOTGUN2
= 13;
149 ITEM_WEAPON_CHAINGUN
= 14;
150 ITEM_WEAPON_ROCKETLAUNCHER
= 15;
151 ITEM_WEAPON_PLASMA
= 16;
152 ITEM_WEAPON_BFG
= 17;
153 ITEM_WEAPON_SUPERPULEMET
= 18;
154 ITEM_AMMO_BULLETS
= 19;
155 ITEM_AMMO_BULLETS_BOX
= 20;
156 ITEM_AMMO_SHELLS
= 21;
157 ITEM_AMMO_SHELLS_BOX
= 22;
158 ITEM_AMMO_ROCKET
= 23;
159 ITEM_AMMO_ROCKET_BOX
= 24;
161 ITEM_AMMO_CELL_BIG
= 26;
162 ITEM_AMMO_BACKPACK
= 27;
166 ITEM_WEAPON_KASTET
= 31;
167 ITEM_WEAPON_PISTOL
= 32;
172 ITEM_WEAPON_FLAMETHROWER
= 37;
173 ITEM_AMMO_FUELCAN
= 38;
175 ITEM_OPTION_ONLYDM
= 1;
176 ITEM_OPTION_FALL
= 2;
179 AREA_PLAYERPOINT1
= 1;
180 AREA_PLAYERPOINT2
= 2;
185 AREA_REDTEAMPOINT
= 7;
186 AREA_BLUETEAMPOINT
= 8;
190 TRIGGER_TELEPORT
= 2;
191 TRIGGER_OPENDOOR
= 3;
192 TRIGGER_CLOSEDOOR
= 4;
195 TRIGGER_CLOSETRAP
= 7;
200 TRIGGER_LIFTDOWN
= 12;
202 TRIGGER_TEXTURE
= 14;
207 TRIGGER_SPAWNMONSTER
= 19;
208 TRIGGER_SPAWNITEM
= 20;
212 TRIGGER_MESSAGE
= 24;
219 TRIGGER_SHOT_PISTOL
= 0;
220 TRIGGER_SHOT_BULLET
= 1;
221 TRIGGER_SHOT_SHOTGUN
= 2;
222 TRIGGER_SHOT_SSG
= 3;
223 TRIGGER_SHOT_IMP
= 4;
224 TRIGGER_SHOT_PLASMA
= 5;
225 TRIGGER_SHOT_SPIDER
= 6;
226 TRIGGER_SHOT_CACO
= 7;
227 TRIGGER_SHOT_BARON
= 8;
228 TRIGGER_SHOT_MANCUB
= 9;
229 TRIGGER_SHOT_REV
= 10;
230 TRIGGER_SHOT_ROCKET
= 11;
231 TRIGGER_SHOT_BFG
= 12;
232 TRIGGER_SHOT_EXPL
= 13;
233 TRIGGER_SHOT_BFGEXPL
= 14;
234 TRIGGER_SHOT_FLAME
= 15;
235 TRIGGER_SHOT_MAX
= 15;
237 TRIGGER_SHOT_TARGET_NONE
= 0;
238 TRIGGER_SHOT_TARGET_MON
= 1;
239 TRIGGER_SHOT_TARGET_PLR
= 2;
240 TRIGGER_SHOT_TARGET_RED
= 3;
241 TRIGGER_SHOT_TARGET_BLUE
= 4;
242 TRIGGER_SHOT_TARGET_MONPLR
= 5;
243 TRIGGER_SHOT_TARGET_PLRMON
= 6;
245 TRIGGER_SHOT_AIM_DEFAULT
= 0;
246 TRIGGER_SHOT_AIM_ALLMAP
= 1;
247 TRIGGER_SHOT_AIM_TRACE
= 2;
248 TRIGGER_SHOT_AIM_TRACEALL
= 3;
250 TRIGGER_EFFECT_PARTICLE
= 0;
251 TRIGGER_EFFECT_ANIMATION
= 1;
253 TRIGGER_EFFECT_SLIQUID
= 0;
254 TRIGGER_EFFECT_LLIQUID
= 1;
255 TRIGGER_EFFECT_DLIQUID
= 2;
256 TRIGGER_EFFECT_BLOOD
= 3;
257 TRIGGER_EFFECT_SPARK
= 4;
258 TRIGGER_EFFECT_BUBBLE
= 5;
259 TRIGGER_EFFECT_MAX
= 5;
261 TRIGGER_EFFECT_POS_CENTER
= 0;
262 TRIGGER_EFFECT_POS_AREA
= 1;
264 ACTIVATE_PLAYERCOLLIDE
= 1;
265 ACTIVATE_MONSTERCOLLIDE
= 2;
266 ACTIVATE_PLAYERPRESS
= 4;
267 ACTIVATE_MONSTERPRESS
= 8;
269 ACTIVATE_NOMONSTER
= 32;
270 ACTIVATE_CUSTOM
= 255;
278 TEXTURE_SPECIAL_WATER
= DWORD(-1);
279 TEXTURE_SPECIAL_ACID1
= DWORD(-2);
280 TEXTURE_SPECIAL_ACID2
= DWORD(-3);
281 TEXTURE_NONE
= DWORD(-4);
283 mp2df_wall
: array [MP_WALL
..MP_LIFTRIGHT
] of Integer = (
284 PANEL_WALL
, PANEL_STEP
, PANEL_BACK
, PANEL_FORE
, PANEL_WATER
,
285 PANEL_ACID1
, PANEL_ACID2
, PANEL_LIFTUP
, PANEL_LIFTDOWN
,
286 PANEL_LIFTLEFT
, PANEL_LIFTRIGHT
289 mp2df_item
: array [MP_MEDKIT_SMALL
..MP_SUIT
] of Byte = (
290 ITEM_MEDKIT_SMALL
, ITEM_MEDKIT_LARGE
, ITEM_ARMOR_GREEN
, ITEM_ARMOR_BLUE
,
291 ITEM_SPHERE_BLUE
, ITEM_SPHERE_WHITE
, ITEM_INVUL
, ITEM_JETPACK
,
292 ITEM_MEDKIT_BLACK
, ITEM_AMMO_BACKPACK
, ITEM_AMMO_BULLETS
, ITEM_AMMO_BULLETS_BOX
,
293 ITEM_AMMO_SHELLS
, ITEM_AMMO_SHELLS_BOX
, ITEM_BOTTLE
, ITEM_HELMET
,
294 ITEM_AMMO_ROCKET
, ITEM_AMMO_ROCKET_BOX
, ITEM_AMMO_CELL
, ITEM_AMMO_CELL_BIG
,
295 ITEM_WEAPON_SHOTGUN1
, ITEM_WEAPON_SHOTGUN2
, ITEM_WEAPON_CHAINGUN
, ITEM_WEAPON_SAW
,
296 ITEM_WEAPON_ROCKETLAUNCHER
, ITEM_WEAPON_PLASMA
, ITEM_WEAPON_BFG
, ITEM_WEAPON_SUPERPULEMET
,
297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // unused here
298 ITEM_INVIS
, ITEM_SUIT
301 mp2df_area
: array [MP_DMPOINT
..MP_BLUEFLAG
] of Byte = (
302 AREA_DMPOINT
, AREA_REDTEAMPOINT
, AREA_BLUETEAMPOINT
,
303 AREA_REDFLAG
, AREA_BLUEFLAG
306 mp2df_act
: array [MP_COLLIDE
..MP_NOACT
] of Byte = (
307 ACTIVATE_PLAYERCOLLIDE
, ACTIVATE_PLAYERPRESS
, ACTIVATE_SHOT
,
308 ACTIVATE_NOMONSTER
or ACTIVATE_MONSTERCOLLIDE
, 0
311 mp2df_trig
: array [MP_CLOSEDOOR
..MP_EXIT
] of Byte = (
312 TRIGGER_CLOSETRAP
, TRIGGER_OPENDOOR
, TRIGGER_DOOR
,
313 TRIGGER_PRESS
, TRIGGER_PRESS
, // random, extender
314 TRIGGER_ONOFF
, TRIGGER_DAMAGE
, TRIGGER_TELEPORT
, TRIGGER_EXIT
321 x0
, y0
, x1
, y1
: Integer;
323 door
: Boolean; // door
324 switch
: Boolean; // switchable door
325 id
: Integer; // door panel id
326 did
: Integer; // switchable door id
337 name
, desc
, music
, sky
: AnsiString;
338 width
, height
: Integer;
339 textures
: array of Texture
;
340 tiles
: array of Tile
;
342 (* --------- Reader --------- *)
344 procedure ReadMap (fname
: AnsiString);
345 var f
: TextFile
; i
, n
: Integer;
347 procedure ReadInt (var i
: Integer);
354 procedure ReadFloat (var i
: Single);
371 SetLength(textures
, n
);
372 for i
:= 1 to n
- 1 do
374 ReadLn(f
, textures
[i
].name
);
377 while eof(f
) = false do
380 SetLength(tiles
, i
+ 1);
387 if (t
>= 44) and (t
<= 48) then
407 (* --------- Analyse --------- *)
409 function isCollide (x0
, y0
, w0
, h0
, x1
, y1
, w1
, h1
: Integer): Boolean;
410 var xx0
, yy0
, xx1
, yy1
: Integer;
416 result
:= (xx0
>= x1
) and (x0
<= xx1
) and (yy0
>= y1
) and (y0
<= yy1
)
420 var i
, j
, t
, x
, y
, w
, h
, xx
, yy
, ww
, hh
: Integer; n
: AnsiString; s
: PSDL_Surface
;
422 if sky
= '*NO_BACKGROUND' then sky
:= '';
423 if music
= '*NO_MUSIC' then music
:= '';
427 textures
[0].flags
:= PANEL_FLAG_HIDE
;
428 for i
:= 1 to High(textures
) do
430 n
:= StringReplace(textures
[i
].name
, '\', '/', [rfReplaceAll
]);
431 s
:= IMG_Load(PChar(n
));
434 textures
[i
].w
:= s
.w
;
435 textures
[i
].h
:= s
.h
;
442 WriteLn('warning: texture ', n
, ' not loaded: ', IMG_GetError())
444 textures
[i
].id
:= i
- 1;
445 textures
[i
].flags
:= 0;
447 for i
:= 0 to High(tiles
) do
450 if tiles
[i
].t
in [MP_COLLIDE
..MP_NOACT
] then
453 if (t
in [MP_CLOSEDOOR
..MP_DOOR
]) or (t
>= 101) and (t
<= 400) or (t
>= 501) and (t
<= 800) then
457 w
:= tiles
[i
].x1
- tiles
[i
].x0
;
458 h
:= tiles
[i
].y1
- tiles
[i
].y0
;
459 for j
:= 0 to High(tiles
) do
461 if tiles
[j
].t
= MP_WALL
then
465 ww
:= textures
[tiles
[j
].s
].w
;
466 hh
:= textures
[tiles
[j
].s
].h
;
467 if isCollide(x
, y
, w
, h
, xx
, yy
, ww
, hh
) then
469 tiles
[j
].door
:= tiles
[j
].t
= MP_WALL
;
470 if tiles
[j
].door
and ((t
= MP_DOOR
) or ((t
>= 101) and (t
<= 400))) then
471 tiles
[j
].switch
:= true;
479 for i
:= 0 to High(tiles
) do
482 if tiles
[i
].switch
then
488 // TODO merge tiles to panels, but this can be done by df editor so...
491 (* --------- Writer --------- *)
501 procedure WriteBytes (f
: TFileStream
; x
: array of Byte);
503 f
.Write(x
, Length(x
));
504 Inc(wrCount
, Length(x
))
507 procedure WriteChars(f
: TFileStream
; x
: array of Char);
510 for i
:= 0 to High(x
) do
512 WriteBytes(f
, [Ord(x
[i
])])
516 procedure WriteAnsiString (f
: TFileStream
; s
: AnsiString; maxlen
: Integer);
521 len
:= min(Length(s
), maxlen
);
525 WriteChars(f
, [s
[i
]]);
535 procedure WriteInt (f
: TFileStream
; x
: Integer);
536 var a
, b
, c
, d
: Integer;
540 c
:= x
>> 16 and $FF;
541 d
:= x
>> 24 and $FF;
542 WriteBytes(f
, [a
, b
, c
, d
])
545 procedure WriteInt16 (f
: TFileStream
; x
: Integer);
550 WriteBytes(f
, [a
, b
])
553 procedure BeginBlock (f
: TFileStream
; t
: Byte);
558 wrFixup
:= f
.Position
;
563 procedure EndBlock(f
: TFileStream
);
567 f
.Position
:= wrFixup
;
568 WriteInt(f
, wrCount
);
574 procedure WriteHeader (f
: TFileStream
; name
, author
, desc
, mus
, sky
: AnsiString; w
, h
: Integer);
577 WriteAnsiString(f
, name
, 32);
578 WriteAnsiString(f
, author
, 32);
579 WriteAnsiString(f
, desc
, 256);
580 WriteAnsiString(f
, mus
, 64);
581 WriteAnsiString(f
, sky
, 64);
587 procedure WriteTexture (f
: TFileStream
; name
: AnsiString; anim
: Byte);
589 WriteAnsiString(f
, name
, 64);
590 WriteBytes(f
, [anim
]);
593 procedure WritePanel (f
: TFileStream
; x
, y
, w
, h
, tex
, typ
, alpha
, flags
: Integer);
595 if (tex
< 0) or (tex
> High(textures
)) then
597 WriteLn('warning: panel ', wrPanels
, ' [', x
, 'x', y
, ':', w
, 'x', h
, ':typ=', typ
, '] have invalid texture id ', tex
);
606 WriteBytes(f
, [alpha
, flags
]);
610 procedure WriteItem (f
: TFileStream
; x
, y
: Integer; typ
, flags
: Byte);
614 WriteBytes(f
, [typ
, flags
]);
617 procedure WriteArea (f
: TFileStream
; x
, y
: Integer; typ
, dir
: Byte);
621 WriteBytes(f
, [typ
, dir
]);
624 procedure WriteEnd (f
: TFileStream
);
630 function BoolToInt (x
: Boolean): Integer;
632 if x
then result
:= 1 else result
:= 0
635 procedure BeginTrigger (f
: TFileStream
; x
, y
, w
, h
, enabled
, texpan
, typ
, act
, keys
: Integer);
638 assert(typ
in [TRIGGER_EXIT
..TRIGGER_MAX
]);
644 WriteBytes(f
, [enabled
]);
646 WriteBytes(f
, [typ
, act
, keys
]);
650 procedure EndTrigger (f
: TFileStream
);
654 for i
:= wrCount
mod 148 to 148 - 1 do
658 assert(wrCount
mod 148 = 0);
663 procedure ExitTrigger (f
: TFileStream
; map
: AnsiString);
666 assert(wrTag
= TRIGGER_EXIT
);
667 WriteAnsiString(f
, map
, 16);
671 procedure TeleportTrigger (f
: TFileStream
; x
, y
: Integer; d2d
, silent
: Boolean; dir
: Integer);
674 assert(wrTag
= TRIGGER_TELEPORT
);
677 WriteBytes(f
, [BoolToInt(d2d
), BoolToInt(silent
), dir
]);
681 procedure DoorTrigger (f
: TFileStream
; panelid
: Integer; nosound
, d2d
: Boolean);
684 assert(wrTag
in [TRIGGER_OPENDOOR
..TRIGGER_TRAP
, TRIGGER_LIFTUP
..TRIGGER_LIFT
]);
685 WriteInt(f
, panelid
);
686 WriteBytes(f
, [BoolToInt(nosound
), BoolToInt(d2d
)]);
690 procedure SwitchTrigger (f
: TFileStream
; x
, y
, w
, h
, wait
, count
, monsterid
: Integer; random
: Boolean);
693 assert(wrTag
in [TRIGGER_PRESS
, TRIGGER_ON
..TRIGGER_ONOFF
]);
699 WriteInt16(f
, count
);
700 WriteInt(f
, monsterid
);
701 WriteBytes(f
, [BoolToInt(random
)]);
705 procedure DamageTrigger (f
: TFileStream
; damage
, interval
, typ
: Integer);
708 assert(wrTag
= TRIGGER_DAMAGE
);
709 WriteInt16(f
, damage
);
710 WriteInt16(f
, interval
);
711 WriteBytes(f
, [typ
]);
715 function SecToTick (sec
: Integer): Integer;
717 result
:= sec
* 1000 div 28;
720 procedure WriteMap (fname
: AnsiString);
721 var f
: TFileStream
; i
, j
, typ
, wait
: Integer; t
: Tile
;
723 f
:= TFileStream
.Create(fname
, fmCreate
);
725 WriteBytes(f
, [Ord('M'), Ord('A'), Ord('P'), 1]);
726 WriteLn('header...');
727 WriteHeader(f
, name
, '', desc
, music
, sky
, width
, height
);
728 WriteLn('textures...');
730 for i
:= 1 to High(textures
) do
732 WriteTexture(f
, ':' + textures
[i
].name
, 0)
735 WriteLn('panels...');
737 for i
:= 0 to High(tiles
) do
740 if t
.t
in [MP_WALL
..MP_LIFTRIGHT
] then
742 tiles
[i
].id
:= wrPanels
;
744 WritePanel(f
, t
.x
, t
.y
, textures
[t
.s
].w
, textures
[t
.s
].h
, textures
[t
.s
].id
, PANEL_CLOSEDOOR
, 0, textures
[t
.s
].flags
)
745 else if t
.t
in [MP_LIFTUP
..MP_LIFTRIGHT
] then
746 WritePanel(f
, t
.x
, t
.y
, 16, 16, 0, mp2df_wall
[t
.t
], 0, PANEL_FLAG_HIDE
)
747 else if t
.t
in [MP_WATER
..MP_ACID2
] then
748 WritePanel(f
, t
.x
, t
.y
, textures
[t
.s
].w
, textures
[t
.s
].h
, textures
[t
.s
].id
, mp2df_wall
[t
.t
], 0, textures
[t
.s
].flags
or PANEL_FLAG_WATERTEXTURES
)
750 WritePanel(f
, t
.x
, t
.y
, textures
[t
.s
].w
, textures
[t
.s
].h
, textures
[t
.s
].id
, mp2df_wall
[t
.t
], 0, textures
[t
.s
].flags
)
756 for i
:= 0 to High(tiles
) do
759 if t
.t
in [MP_MEDKIT_SMALL
..MP_WEAPON_SUPERPULEMET
, MP_INVIS
, MP_SUIT
] then
760 WriteItem(f
, t
.x
, t
.y
, mp2df_item
[t
.t
], 0)
765 for i
:= 0 to High(tiles
) do
769 MP_DMPOINT
..MP_BLUETEAMPOINT
: WriteArea(f
, t
.x
, t
.y
+ 12, mp2df_area
[t
.t
], 0);
770 MP_REDFLAG
, MP_BLUEFLAG
: WriteArea(f
, t
.x
+ 8, t
.y
- 4, mp2df_area
[t
.t
], 1);
774 WriteLn('triggers...');
776 for i
:= 0 to High(tiles
) do
779 if t
.t
in [MP_COLLIDE
..MP_NOACT
] then
784 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, TRIGGER_EXIT
, mp2df_act
[t
.t
], 0);
790 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, TRIGGER_TELEPORT
, mp2df_act
[t
.t
], 0);
791 TeleportTrigger(f
, t
.x0
, t
.y0
+ 32, true, false, 0);
794 MP_CLOSEDOOR
, MP_OPENDOOR
:
796 for j
:= 0 to High(tiles
) do
798 if tiles
[j
].door
and isCollide(t
.x0
, t
.y0
, t
.x1
- t
.x0
, t
.y1
- t
.y0
, tiles
[j
].x
, tiles
[j
].y
, textures
[tiles
[j
].s
].w
, textures
[tiles
[j
].s
].h
) then
800 if tiles
[j
].switch
then
803 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, TRIGGER_PRESS
, mp2df_act
[t
.t
], 0);
804 SwitchTrigger(f
, tiles
[j
].did
* 32, IfThen(t
.s
= MP_CLOSEDOOR
, -16, -32), 32, 16, 0, 1, 0, false);
809 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, mp2df_trig
[t
.s
], mp2df_act
[t
.t
], 0);
810 DoorTrigger(f
, tiles
[j
].id
, false, false);
818 wait
:= IfThen(t
.s
= MP_DOOR
, 0, t
.s
- 100);
819 // button: activate sequence in not locked
820 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, TRIGGER_PRESS
, mp2df_act
[t
.t
], 0);
821 SwitchTrigger(f
, wrX
, -80, 32, 16, 0, 1, 0, false);
823 // start: activate group + timer
824 BeginTrigger(f
, wrX
, -80, 16, 16, 1, -1, TRIGGER_PRESS
, 0, 0);
825 SwitchTrigger(f
, wrX
, -64, 32, 32, 0, 1, 0, false);
828 BeginTrigger(f
, wrX
+ 16, -80, 16, 16, 1, -1, TRIGGER_OFF
, 0, 0);
829 SwitchTrigger(f
, wrX
, -80, 16, 16, 0, 1, 0, false);
831 for j
:= 0 to High(tiles
) do
833 if tiles
[j
].switch
and isCollide(t
.x0
, t
.y0
, t
.x1
- t
.x0
, t
.y1
- t
.y0
, tiles
[j
].x
, tiles
[j
].y
, textures
[tiles
[j
].s
].w
, textures
[tiles
[j
].s
].h
) then
835 // group: activate both branches
836 BeginTrigger(f
, wrX
, -64, 16, 16, 1, -1, TRIGGER_PRESS
, 0, 0);
837 SwitchTrigger(f
, tiles
[j
].did
* 32, -32, 32, 32, 0, 1, 0, false);
841 // timer: wait & activate group
842 BeginTrigger(f
, wrX
, -48, 16, 16, 1, -1, TRIGGER_PRESS
, 0, 0);
843 SwitchTrigger(f
, wrX
, -64, 32, 16, SecToTick(wait
), 1, 0, false);
845 // timer: wait & unlock start
846 BeginTrigger(f
, wrX
+ 16, -48, 16, 16, 1, -1, TRIGGER_ON
, 0, 0);
847 SwitchTrigger(f
, wrX
, -80, 16, 16, SecToTick(wait
), 1, 0, false);
851 MP_EXTENDER
, MP_RANDOM
, MP_SWITCH
, 501..800:
853 wait
:= IfThen(t
.s
in [MP_EXTENDER
, MP_RANDOM
, MP_SWITCH
], 0, t
.s
- 500);
854 typ
:= IfThen(t
.s
in [MP_EXTENDER
, MP_RANDOM
, MP_SWITCH
], mp2df_trig
[t
.s
], TRIGGER_PRESS
);
855 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, typ
, mp2df_act
[t
.t
], 0);
856 SwitchTrigger(f
, t
.x0
, t
.y0
, t
.x1
- t
.x0
, t
.y1
- t
.y0
, SecToTick(wait
), 1, 0, t
.s
= MP_RANDOM
);
861 if (t
.x
= t
.x0
) and (t
.y
= t
.y0
) and (16 * t
.sx
= t
.x1
- t
.x0
) and (16 * t
.sy
= t
.y1
- t
.y0
) then
863 BeginTrigger(f
, t
.x
, t
.y
, t
.x1
- t
.x0
, t
.y1
- t
.y0
, 1, -1, TRIGGER_DAMAGE
, mp2df_act
[t
.t
], 0);
864 DamageTrigger(f
, 666, 0, 0);
869 // TODO find non intersectable location for activation
870 BeginTrigger(f
, t
.x
, t
.y
, Round(16 * t
.sx
), Round(16 * t
.sy
), 1, -1, TRIGGER_PRESS
, mp2df_act
[t
.t
], 0);
871 SwitchTrigger(f
, t
.x0
, t
.y0
, 16, 16, 0, 1, 0, false);
873 BeginTrigger(f
, t
.x0
, t
.y0
, t
.x1
- t
.x0
, t
.y1
- t
.y0
, 1, -1, TRIGGER_DAMAGE
, 0, 0);
874 DamageTrigger(f
, 999, 0, 0);
876 for j
:= 0 to High(tiles
) do
878 if (j
<> i
) and isCollide(t
.x0
, t
.y0
, 16, 16, tiles
[j
].x0
, tiles
[j
].y0
, tiles
[j
].x1
- tiles
[j
].x0
, tiles
[j
].x1
- tiles
[j
].y0
) then
880 WriteLn('waring: trigger damage may activate triggers at ', t
.x0
, 'x', t
.y0
);
885 else WriteLn('warning: unknown MP trigger ', t
.s
)
889 // MP_DOOR intermediate triggers
890 for i
:= 0 to High(tiles
) do
892 if tiles
[i
].switch
then
895 BeginTrigger(f
, tiles
[i
].did
* 32 + 16, -32, 16, 32, 1, -1, TRIGGER_ONOFF
, 0, 0);
896 SwitchTrigger(f
, tiles
[i
].did
* 32, -32, 16, 32, 0, 1, 0, false);
899 BeginTrigger(f
, tiles
[i
].did
* 32, -32, 16, 16, 1, -1, TRIGGER_OPENDOOR
, 0, 0);
900 DoorTrigger(f
, tiles
[i
].id
, false, false);
903 BeginTrigger(f
, tiles
[i
].did
* 32, -16, 16, 16, 0, -1, TRIGGER_CLOSETRAP
, 0, 0);
904 DoorTrigger(f
, tiles
[i
].id
, false, false);
913 (* --------- Init --------- *)
916 inputFile
: AnsiString;
917 outputFile
: AnsiString = 'MAP01';
918 listTextures
: Boolean = false;
920 procedure PrintTextureList
;
921 var i
: Integer; n
: AnsiString;
923 for i
:= 1 to High(textures
) do
925 n
:= StringReplace(textures
[i
].name
, '\', '/', [rfReplaceAll
]);
932 WriteLn('Usage: mp2df [OPTION] FILE.dlv [OUTPUT]');
934 WriteLn(' -l list textures used on map and exit');
935 WriteLn(' -h show this help');
940 var i
, n
: Integer; done
: Boolean; str
: AnsiString;
942 i
:= 1; done
:= false;
943 while (i
<= ParamCount
) and (not done
) do
946 done
:= (Length(str
) = 0) or (str
[1] <> '-');
950 '-l': listTextures
:= true;
953 WriteLn('mp2df: unknown argument ', str
);
959 n
:= ParamCount
- i
+ 1;
962 inputFile
:= ParamStr(i
);
964 else if (n
= 2) and (not listTextures
) then
966 inputFile
:= ParamStr(i
);
967 outputFile
:= ParamStr(i
+ 1);
971 WriteLn('mp2df: you may specify input file and output file only, use -h to know more');
974 if inputFile
= '' then
976 WriteLn('mp2df: empty input file path');
979 if outputFile
= '' then
981 WriteLn('mp2df: empty output file path');