1 (* Copyright (C) DooM 2D:Forever Developers
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, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE ../shared/a_modes.inc}
23 MAPDEF
, e_graphics
, g_basic
, g_sound
,
24 BinEditor
, xdynrec
, hashtable
, exoma
;
27 THashStrVariant
= specialize THashBase
<AnsiString, Variant>;
45 TexturePanelGUID
: Integer;
46 TexturePanelType
: Word;
50 Activators
: array of TActivator
;
51 PlayerCollide
: Boolean;
55 SoundPlayCount
: Integer;
56 Sound
: TPlayableSound
;
58 SpawnCooldown
: Integer;
59 SpawnedCount
: Integer;
61 ShotPanelTime
: Integer;
62 ShotSightTime
: Integer;
63 ShotSightTimeout
: Integer;
64 ShotSightTarget
: Word;
65 ShotSightTargetN
: Word;
67 ShotReloadTime
: Integer;
69 mapId
: AnsiString; // trigger id, from map
70 mapIndex
: Integer; // index in fields['trigger'], used in save/load
71 trigPanelGUID
: Integer;
73 trigDataRec
: TDynRecord
; // triggerdata; owned by trigger (cloned)
74 exoInit
, exoThink
, exoCheck
, exoAction
: TExprBase
;
76 userVars
: THashStrVariant
;
78 {$INCLUDE ../shared/mapdef_tgc_def.inc}
81 function trigCenter (): TDFPoint
; inline;
84 function g_Triggers_Create(Trigger
: TTrigger
; trec
: TDynRecord
; forceInternalIndex
: Integer=-1): DWORD
;
85 procedure g_Triggers_Update();
86 procedure g_Triggers_Press(ID
: DWORD
; ActivateType
: Byte; ActivateUID
: Word = 0);
87 function g_Triggers_PressR(X
, Y
: Integer; Width
, Height
: Word; UID
: Word;
88 ActivateType
: Byte; IgnoreList
: DWArray
= nil): DWArray
;
89 procedure g_Triggers_PressL(X1
, Y1
, X2
, Y2
: Integer; UID
: DWORD
; ActivateType
: Byte);
90 procedure g_Triggers_PressC(CX
, CY
: Integer; Radius
: Word; UID
: Word; ActivateType
: Byte; IgnoreTrigger
: Integer = -1);
91 procedure g_Triggers_OpenAll();
92 procedure g_Triggers_DecreaseSpawner(ID
: DWORD
);
93 procedure g_Triggers_Free();
94 procedure g_Triggers_SaveState(var Mem
: TBinMemoryWriter
);
95 procedure g_Triggers_LoadState(var Mem
: TBinMemoryReader
);
99 gTriggerClientID
: Integer = 0;
100 gTriggers
: array of TTrigger
;
101 gSecretsCount
: Integer = 0;
102 gMonstersSpawned
: array of LongInt = nil;
109 g_player
, g_map
, g_panel
, g_gfx
, g_game
, g_textures
,
110 g_console
, g_monsters
, g_items
, g_phys
, g_weapons
,
111 wadreader
, g_main
, SysUtils
, e_log
, g_language
,
112 g_options
, g_net
, g_netmsg
, utils
, xparser
;
115 TRIGGER_SIGNATURE
= $58475254; // 'TRGX'
118 {$INCLUDE ../shared/mapdef_tgc_impl.inc}
121 // ////////////////////////////////////////////////////////////////////////// //
123 TTrigScope
= class(TExprScope
)
126 monsprops
: TPropHash
;
127 platprops
: TPropHash
;
133 constructor Create ();
134 destructor Destroy (); override;
136 function getObj (const aname
: AnsiString): TObject
; override;
137 function getField (obj
: TObject
; const afldname
: AnsiString): Variant; override;
138 procedure setField (obj
: TObject
; const afldname
: AnsiString; var aval
: Variant); override;
142 // ////////////////////////////////////////////////////////////////////////// //
143 constructor TTrigScope
.Create ();
145 plrprops
:= TPropHash
.Create(TPlayer
);
146 monsprops
:= TPropHash
.Create(TMonster
);
147 platprops
:= TPropHash
.Create(TPanel
);
152 destructor TTrigScope
.Destroy ();
161 function TTrigScope
.getObj (const aname
: AnsiString): TObject
;
163 if (aname
= 'player') then result
:= gPlayers
[0] //FIXME
164 else if (aname
= 'self') or (aname
= 'this') then result
:= TObject(Pointer(PtrUInt(1)))
165 else result
:= inherited getObj(aname
);
169 function TTrigScope
.getField (obj
: TObject
; const afldname
: AnsiString): Variant;
171 if (obj
= gPlayers
[0]) then
173 if plrprops
.get(obj
, afldname
, result
) then exit
;
175 else if (obj
= TObject(Pointer(PtrUInt(1)))) then
177 if (me
<> nil) and (me
.userVars
<> nil) then
179 if me
.userVars
.get(afldname
, result
) then exit
;
182 result
:= inherited getField(obj
, afldname
);
186 procedure TTrigScope
.setField (obj
: TObject
; const afldname
: AnsiString; var aval
: Variant);
188 if (obj
= gPlayers
[0]) then
190 if plrprops
.put(obj
, afldname
, aval
) then exit
;
192 else if (obj
= TObject(Pointer(PtrUInt(1)))) then
196 if (Length(afldname
) > 4) and (afldname
[1] = 'u') and (afldname
[2] = 's') and
197 (afldname
[3] = 'e') and (afldname
[4] = 'r') then
199 if (me
.userVars
= nil) then me
.userVars
:= THashStrVariant
.Create(hsihash
, hsiequ
);
200 me
.userVars
.put(afldname
, aval
);
205 inherited setField(obj
, afldname
, aval
);
209 // ////////////////////////////////////////////////////////////////////////// //
211 tgscope
: TTrigScope
= nil;
214 // ////////////////////////////////////////////////////////////////////////// //
215 function TTrigger
.trigCenter (): TDFPoint
; inline;
217 result
:= TDFPoint
.Create(x
+width
div 2, y
+height
div 2);
221 function FindTrigger (): DWORD
;
225 olen
:= Length(gTriggers
);
227 for i
:= 0 to olen
-1 do
229 if gTriggers
[i
].TriggerType
= TRIGGER_NONE
then begin result
:= i
; exit
; end;
232 SetLength(gTriggers
, olen
+8);
235 for i
:= result
to High(gTriggers
) do
237 gTriggers
[i
].TriggerType
:= TRIGGER_NONE
;
238 gTriggers
[i
].trigDataRec
:= nil;
239 gTriggers
[i
].exoInit
:= nil;
240 gTriggers
[i
].exoThink
:= nil;
241 gTriggers
[i
].exoCheck
:= nil;
242 gTriggers
[i
].exoAction
:= nil;
243 gTriggers
[i
].userVars
:= nil;
248 function tr_CloseDoor (PanelGUID
: Integer; NoSound
: Boolean; d2d
: Boolean): Boolean;
255 pan
:= g_Map_PanelByGUID(PanelGUID
);
256 if (pan
= nil) or not pan
.isGWall
then exit
; //!FIXME!TRIGANY!
257 PanelID
:= pan
.arrIdx
;
261 with gWalls
[PanelID
] do
263 if g_CollidePlayer(X
, Y
, Width
, Height
) or g_Mons_IsAnyAliveAt(X
, Y
, Width
, Height
) then Exit
;
268 g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X
, Y
);
269 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_DOORCLOSE');
271 g_Map_EnableWallGUID(PanelGUID
);
278 if (gDoorMap
= nil) then exit
;
281 for a
:= 0 to High(gDoorMap
) do
283 for b
:= 0 to High(gDoorMap
[a
]) do
285 if gDoorMap
[a
, b
] = DWORD(PanelID
) then
291 if (c
<> -1) then break
;
293 if (c
= -1) then exit
;
295 for b
:= 0 to High(gDoorMap
[c
]) do
297 with gWalls
[gDoorMap
[c
, b
]] do
299 if g_CollidePlayer(X
, Y
, Width
, Height
) or g_Mons_IsAnyAliveAt(X
, Y
, Width
, Height
) then exit
;
305 for b
:= 0 to High(gDoorMap
[c
]) do
307 if not gWalls
[gDoorMap
[c
, b
]].Enabled
then
309 with gWalls
[PanelID
] do
311 g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X
, Y
);
312 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_DOORCLOSE');
319 for b
:= 0 to High(gDoorMap
[c
]) do
321 if not gWalls
[gDoorMap
[c
, b
]].Enabled
then
323 g_Map_EnableWall_XXX(gDoorMap
[c
, b
]);
331 procedure tr_CloseTrap (PanelGUID
: Integer; NoSound
: Boolean; d2d
: Boolean);
334 wx
, wy
, wh
, ww
: Integer;
338 function monsDamage (mon
: TMonster
): Boolean;
340 result
:= false; // don't stop
341 if g_Obj_Collide(wx
, wy
, ww
, wh
, @mon
.Obj
) then mon
.Damage(TRAP_DAMAGE
, 0, 0, 0, HIT_TRAP
);
345 pan
:= g_Map_PanelByGUID(PanelGUID
);
349 e_LogWritefln('tr_CloseTrap: pguid=%s; NO PANEL!', [PanelGUID], MSG_WARNING);
353 e_LogWritefln('tr_CloseTrap: pguid=%s; isGWall=%s; arrIdx=%s', [PanelGUID, pan.isGWall, pan.arrIdx]);
356 if (pan
= nil) or not pan
.isGWall
then exit
; //!FIXME!TRIGANY!
357 PanelID
:= pan
.arrIdx
;
361 with gWalls
[PanelID
] do
363 if (not NoSound
) and (not Enabled
) then
365 g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X
, Y
);
366 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_SWITCH1');
370 wx
:= gWalls
[PanelID
].X
;
371 wy
:= gWalls
[PanelID
].Y
;
372 ww
:= gWalls
[PanelID
].Width
;
373 wh
:= gWalls
[PanelID
].Height
;
375 with gWalls
[PanelID
] do
377 if gPlayers
<> nil then
379 for a
:= 0 to High(gPlayers
) do
381 if (gPlayers
[a
] <> nil) and gPlayers
[a
].alive
and gPlayers
[a
].Collide(X
, Y
, Width
, Height
) then
383 gPlayers
[a
].Damage(TRAP_DAMAGE
, 0, 0, 0, HIT_TRAP
);
388 //g_Mons_ForEach(monsDamage);
389 g_Mons_ForEachAliveAt(wx
, wy
, ww
, wh
, monsDamage
);
391 if not Enabled
then g_Map_EnableWallGUID(PanelGUID
);
396 if (gDoorMap
= nil) then exit
;
399 for a
:= 0 to High(gDoorMap
) do
401 for b
:= 0 to High(gDoorMap
[a
]) do
403 if gDoorMap
[a
, b
] = DWORD(PanelID
) then
409 if (c
<> -1) then break
;
411 if (c
= -1) then exit
;
415 for b
:= 0 to High(gDoorMap
[c
]) do
417 if not gWalls
[gDoorMap
[c
, b
]].Enabled
then
419 with gWalls
[PanelID
] do
421 g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X
, Y
);
422 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_SWITCH1');
429 for b
:= 0 to High(gDoorMap
[c
]) do
431 wx
:= gWalls
[gDoorMap
[c
, b
]].X
;
432 wy
:= gWalls
[gDoorMap
[c
, b
]].Y
;
433 ww
:= gWalls
[gDoorMap
[c
, b
]].Width
;
434 wh
:= gWalls
[gDoorMap
[c
, b
]].Height
;
436 with gWalls
[gDoorMap
[c
, b
]] do
438 if gPlayers
<> nil then
440 for a
:= 0 to High(gPlayers
) do
442 if (gPlayers
[a
] <> nil) and gPlayers
[a
].alive
and gPlayers
[a
].Collide(X
, Y
, Width
, Height
) then
444 gPlayers
[a
].Damage(TRAP_DAMAGE
, 0, 0, 0, HIT_TRAP
);
449 //g_Mons_ForEach(monsDamage);
450 g_Mons_ForEachAliveAt(wx
, wy
, ww
, wh
, monsDamage
);
452 if gMonsters <> nil then
453 for a := 0 to High(gMonsters) do
454 if (gMonsters[a] <> nil) and gMonsters[a].alive and
455 g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then
456 gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
459 if not Enabled
then g_Map_EnableWall_XXX(gDoorMap
[c
, b
]);
466 function tr_OpenDoor (PanelGUID
: Integer; NoSound
: Boolean; d2d
: Boolean): Boolean;
473 pan
:= g_Map_PanelByGUID(PanelGUID
);
474 if (pan
= nil) or not pan
.isGWall
then exit
; //!FIXME!TRIGANY!
475 PanelID
:= pan
.arrIdx
;
479 with gWalls
[PanelID
] do
485 g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X
, Y
);
486 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_DOOROPEN');
488 g_Map_DisableWallGUID(PanelGUID
);
495 if (gDoorMap
= nil) then exit
;
498 for a
:= 0 to High(gDoorMap
) do
500 for b
:= 0 to High(gDoorMap
[a
]) do
502 if gDoorMap
[a
, b
] = DWORD(PanelID
) then
508 if (c
<> -1) then break
;
510 if (c
= -1) then exit
;
514 for b
:= 0 to High(gDoorMap
[c
]) do
516 if gWalls
[gDoorMap
[c
, b
]].Enabled
then
518 with gWalls
[PanelID
] do
520 g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X
, Y
);
521 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_DOOROPEN');
528 for b
:= 0 to High(gDoorMap
[c
]) do
530 if gWalls
[gDoorMap
[c
, b
]].Enabled
then
532 g_Map_DisableWall_XXX(gDoorMap
[c
, b
]);
540 function tr_SetLift (PanelGUID
: Integer; d
: Integer; NoSound
: Boolean; d2d
: Boolean): Boolean;
548 pan
:= g_Map_PanelByGUID(PanelGUID
);
549 if (pan
= nil) or not pan
.isGLift
then exit
; //!FIXME!TRIGANY!
550 PanelID
:= pan
.arrIdx
;
552 if (gLifts
[PanelID
].PanelType
= PANEL_LIFTUP
) or (gLifts
[PanelID
].PanelType
= PANEL_LIFTDOWN
) then
557 else t
:= IfThen(gLifts
[PanelID
].LiftType
= 1, 0, 1);
560 else if (gLifts
[PanelID
].PanelType
= PANEL_LIFTLEFT
) or (gLifts
[PanelID
].PanelType
= PANEL_LIFTRIGHT
) then
565 else t
:= IfThen(gLifts
[PanelID
].LiftType
= 2, 3, 2);
571 with gLifts
[PanelID
] do
573 if (LiftType
<> t
) then
575 g_Map_SetLiftGUID(PanelGUID
, t
); //???
576 //if not NoSound then g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);
583 if (gLiftMap
= nil) then exit
;
586 for a
:= 0 to High(gLiftMap
) do
588 for b
:= 0 to High(gLiftMap
[a
]) do
590 if (gLiftMap
[a
, b
] = DWORD(PanelID
)) then
596 if (c
<> -1) then break
;
598 if (c
= -1) then exit
;
601 for b := 0 to High(gLiftMap[c]) do
602 if gLifts[gLiftMap[c, b]].LiftType <> t then
604 with gLifts[PanelID] do
605 g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);
609 for b
:= 0 to High(gLiftMap
[c
]) do
611 with gLifts
[gLiftMap
[c
, b
]] do
613 if (LiftType
<> t
) then
615 g_Map_SetLift_XXX(gLiftMap
[c
, b
], t
);
624 function tr_SpawnShot (ShotType
: Integer; wx
, wy
, dx
, dy
: Integer; ShotSound
: Boolean; ShotTarget
: Word): Integer;
632 TextureID
:= DWORD(-1);
633 snd
:= 'SOUND_WEAPON_FIREROCKET';
639 g_Weapon_pistol(wx
, wy
, dx
, dy
, 0, True);
640 snd
:= 'SOUND_WEAPON_FIREPISTOL';
644 g_Player_CreateShell(wx
, wy
, 0, -2, SHELL_BULLET
);
645 if g_Game_IsNet
then MH_SEND_Effect(wx
, wy
, 0, NET_GFX_SHELL1
);
651 g_Weapon_mgun(wx
, wy
, dx
, dy
, 0, True);
652 if gSoundEffectsDF
then snd
:= 'SOUND_WEAPON_FIRECGUN'
653 else snd
:= 'SOUND_WEAPON_FIREPISTOL';
657 g_Player_CreateShell(wx
, wy
, 0, -2, SHELL_BULLET
);
658 if g_Game_IsNet
then MH_SEND_Effect(wx
, wy
, 0, NET_GFX_SHELL1
);
662 TRIGGER_SHOT_SHOTGUN
:
664 g_Weapon_Shotgun(wx
, wy
, dx
, dy
, 0, True);
665 snd
:= 'SOUND_WEAPON_FIRESHOTGUN';
669 g_Player_CreateShell(wx
, wy
, 0, -2, SHELL_SHELL
);
670 if g_Game_IsNet
then MH_SEND_Effect(wx
, wy
, 0, NET_GFX_SHELL2
);
676 g_Weapon_DShotgun(wx
, wy
, dx
, dy
, 0, True);
677 snd
:= 'SOUND_WEAPON_FIRESHOTGUN2';
681 g_Player_CreateShell(wx
, wy
, 0, -2, SHELL_SHELL
);
682 g_Player_CreateShell(wx
, wy
, 0, -2, SHELL_SHELL
);
683 if g_Game_IsNet
then MH_SEND_Effect(wx
, wy
, 0, NET_GFX_SHELL3
);
689 g_Weapon_ball1(wx
, wy
, dx
, dy
, 0, -1, True);
690 snd
:= 'SOUND_WEAPON_FIREBALL';
695 g_Weapon_Plasma(wx
, wy
, dx
, dy
, 0, -1, True);
696 snd
:= 'SOUND_WEAPON_FIREPLASMA';
701 g_Weapon_aplasma(wx
, wy
, dx
, dy
, 0, -1, True);
702 snd
:= 'SOUND_WEAPON_FIREPLASMA';
707 g_Weapon_ball2(wx
, wy
, dx
, dy
, 0, -1, True);
708 snd
:= 'SOUND_WEAPON_FIREBALL';
713 g_Weapon_ball7(wx
, wy
, dx
, dy
, 0, -1, True);
714 snd
:= 'SOUND_WEAPON_FIREBALL';
719 g_Weapon_manfire(wx
, wy
, dx
, dy
, 0, -1, True);
720 snd
:= 'SOUND_WEAPON_FIREBALL';
725 g_Weapon_revf(wx
, wy
, dx
, dy
, 0, ShotTarget
, -1, True);
726 snd
:= 'SOUND_WEAPON_FIREREV';
731 g_Weapon_Rocket(wx
, wy
, dx
, dy
, 0, -1, True);
732 snd
:= 'SOUND_WEAPON_FIREROCKET';
737 g_Weapon_BFGShot(wx
, wy
, dx
, dy
, 0, -1, True);
738 snd
:= 'SOUND_WEAPON_FIREBFG';
743 if g_Frames_Get(TextureID
, 'FRAMES_EXPLODE_ROCKET') then
745 Anim
:= TAnimation
.Create(TextureID
, False, 6);
746 Anim
.Blending
:= False;
747 g_GFX_OnceAnim(wx
-64, wy
-64, Anim
);
751 g_Weapon_Explode(wx
, wy
, 60, 0);
752 snd
:= 'SOUND_WEAPON_EXPLODEROCKET';
755 TRIGGER_SHOT_BFGEXPL
:
757 if g_Frames_Get(TextureID
, 'FRAMES_EXPLODE_BFG') then
759 Anim
:= TAnimation
.Create(TextureID
, False, 6);
760 Anim
.Blending
:= False;
761 g_GFX_OnceAnim(wx
-64, wy
-64, Anim
);
765 g_Weapon_BFG9000(wx
, wy
, 0);
766 snd
:= 'SOUND_WEAPON_EXPLODEBFG';
772 if g_Game_IsNet
and g_Game_IsServer
then
775 TRIGGER_SHOT_EXPL
: MH_SEND_Effect(wx
, wy
, Byte(ShotSound
), NET_GFX_EXPLODE
);
776 TRIGGER_SHOT_BFGEXPL
: MH_SEND_Effect(wx
, wy
, Byte(ShotSound
), NET_GFX_BFGEXPL
);
779 if Projectile
then MH_SEND_CreateShot(LastShotID
);
780 if ShotSound
then MH_SEND_Sound(wx
, wy
, snd
);
785 if ShotSound
then g_Sound_PlayExAt(snd
, wx
, wy
);
787 if Projectile
then Result
:= LastShotID
;
791 procedure MakeShot (var Trigger
: TTrigger
; wx
, wy
, dx
, dy
: Integer; TargetUID
: Word);
795 if (tgcAmmo
= 0) or ((tgcAmmo
> 0) and (ShotAmmoCount
> 0)) then
797 if (trigPanelGUID
<> -1) and (ShotPanelTime
= 0) then
799 g_Map_SwitchTextureGUID(ShotPanelType
, trigPanelGUID
);
800 ShotPanelTime
:= 4; // òèêîâ íà âñïûøêó âûñòðåëà
803 if (tgcSight
> 0) then ShotSightTimeout
:= 180; // ~= 5 ñåêóíä
805 if (ShotAmmoCount
> 0) then Dec(ShotAmmoCount
);
807 dx
+= Random(tgcAccuracy
)-Random(tgcAccuracy
);
808 dy
+= Random(tgcAccuracy
)-Random(tgcAccuracy
);
810 tr_SpawnShot(tgcShotType
, wx
, wy
, dx
, dy
, not tgcQuiet
, TargetUID
);
814 if (tgcReload
> 0) and (ShotReloadTime
= 0) then
816 ShotReloadTime
:= tgcReload
; // òèêîâ íà ïåðåçàðÿäêó ïóøêè
823 procedure tr_MakeEffect (X
, Y
, VX
, VY
: Integer; T
, ST
, CR
, CG
, CB
: Byte; Silent
, Send
: Boolean);
828 if T
= TRIGGER_EFFECT_PARTICLE
then
831 TRIGGER_EFFECT_SLIQUID
:
833 if (CR
= 255) and (CG
= 0) and (CB
= 0) then g_GFX_SimpleWater(X
, Y
, 1, VX
, VY
, 1, 0, 0, 0)
834 else if (CR
= 0) and (CG
= 255) and (CB
= 0) then g_GFX_SimpleWater(X
, Y
, 1, VX
, VY
, 2, 0, 0, 0)
835 else if (CR
= 0) and (CG
= 0) and (CB
= 255) then g_GFX_SimpleWater(X
, Y
, 1, VX
, VY
, 3, 0, 0, 0)
836 else g_GFX_SimpleWater(X
, Y
, 1, VX
, VY
, 0, 0, 0, 0);
838 TRIGGER_EFFECT_LLIQUID
: g_GFX_SimpleWater(X
, Y
, 1, VX
, VY
, 4, CR
, CG
, CB
);
839 TRIGGER_EFFECT_DLIQUID
: g_GFX_SimpleWater(X
, Y
, 1, VX
, VY
, 5, CR
, CG
, CB
);
840 TRIGGER_EFFECT_BLOOD
: g_GFX_Blood(X
, Y
, 1, VX
, VY
, 0, 0, CR
, CG
, CB
);
841 TRIGGER_EFFECT_SPARK
: g_GFX_Spark(X
, Y
, 1, GetAngle2(VX
, VY
), 0, 0);
842 TRIGGER_EFFECT_BUBBLE
: g_GFX_Bubbles(X
, Y
, 1, 0, 0);
846 if T
= TRIGGER_EFFECT_ANIMATION
then
849 EFFECT_TELEPORT
: begin
850 if g_Frames_Get(FramesID
, 'FRAMES_TELEPORT') then
852 Anim
:= TAnimation
.Create(FramesID
, False, 3);
853 if not Silent
then g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X
, Y
);
854 g_GFX_OnceAnim(X
-32, Y
-32, Anim
);
857 if Send
and g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Effect(X
, Y
, Byte(not Silent
), NET_GFX_TELE
);
859 EFFECT_RESPAWN
: begin
860 if g_Frames_Get(FramesID
, 'FRAMES_ITEM_RESPAWN') then
862 Anim
:= TAnimation
.Create(FramesID
, False, 4);
863 if not Silent
then g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X
, Y
);
864 g_GFX_OnceAnim(X
-16, Y
-16, Anim
);
867 if Send
and g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Effect(X
-16, Y
-16, Byte(not Silent
), NET_GFX_RESPAWN
);
870 if g_Frames_Get(FramesID
, 'FRAMES_FIRE') then
872 Anim
:= TAnimation
.Create(FramesID
, False, 4);
873 if not Silent
then g_Sound_PlayExAt('SOUND_FIRE', X
, Y
);
874 g_GFX_OnceAnim(X
-32, Y
-128, Anim
);
877 if Send
and g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Effect(X
-32, Y
-128, Byte(not Silent
), NET_GFX_FIRE
);
884 function tr_Teleport (ActivateUID
: Integer; TX
, TY
: Integer; TDir
: Integer; Silent
: Boolean; D2D
: Boolean): Boolean;
890 if (ActivateUID
< 0) or (ActivateUID
> $FFFF) then Exit
;
891 case g_GetUIDType(ActivateUID
) of
894 p
:= g_Player_Get(ActivateUID
);
895 if p
= nil then Exit
;
898 if p
.TeleportTo(TX
-(p
.Obj
.Rect
.Width
div 2), TY
-p
.Obj
.Rect
.Height
, Silent
, TDir
) then result
:= true;
902 if p
.TeleportTo(TX
, TY
, Silent
, TDir
) then result
:= true;
907 m
:= g_Monsters_ByUID(ActivateUID
);
908 if m
= nil then Exit
;
911 if m
.TeleportTo(TX
-(m
.Obj
.Rect
.Width
div 2), TY
-m
.Obj
.Rect
.Height
, Silent
, TDir
) then result
:= true;
915 if m
.TeleportTo(TX
, TY
, Silent
, TDir
) then result
:= true;
922 function tr_Push (ActivateUID
: Integer; VX
, VY
: Integer; ResetVel
: Boolean): Boolean;
928 if (ActivateUID
< 0) or (ActivateUID
> $FFFF) then exit
;
929 case g_GetUIDType(ActivateUID
) of
932 p
:= g_Player_Get(ActivateUID
);
933 if p
= nil then Exit
;
948 m
:= g_Monsters_ByUID(ActivateUID
);
949 if m
= nil then Exit
;
965 function tr_Message (MKind
: Integer; MText
: string; MSendTo
: Integer; MTime
: Integer; ActivateUID
: Integer): Boolean;
972 if (ActivateUID
< 0) or (ActivateUID
> $FFFF) then Exit
;
973 msg
:= b_Text_Format(MText
);
975 TRIGGER_MESSAGE_DEST_ME
: // activator
977 if g_GetUIDType(ActivateUID
) = UID_PLAYER
then
979 if g_Game_IsWatchedPlayer(ActivateUID
) then
981 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then g_Console_Add(msg
, True)
982 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then g_Game_Message(msg
, MTime
);
986 p
:= g_Player_Get(ActivateUID
);
987 if g_Game_IsNet
and (p
.FClientID
>= 0) then
989 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then MH_SEND_Chat(msg
, NET_CHAT_SYSTEM
, p
.FClientID
)
990 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then MH_SEND_GameEvent(NET_EV_BIGTEXT
, MTime
, msg
, p
.FClientID
);
996 TRIGGER_MESSAGE_DEST_MY_TEAM
: // activator's team
998 if g_GetUIDType(ActivateUID
) = UID_PLAYER
then
1000 p
:= g_Player_Get(ActivateUID
);
1001 if g_Game_IsWatchedTeam(p
.Team
) then
1003 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then g_Console_Add(msg
, True)
1004 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then g_Game_Message(msg
, MTime
);
1007 if g_Game_IsNet
then
1009 for i
:= Low(gPlayers
) to High(gPlayers
) do
1011 if (gPlayers
[i
].Team
= p
.Team
) and (gPlayers
[i
].FClientID
>= 0) then
1013 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then MH_SEND_Chat(msg
, NET_CHAT_SYSTEM
, gPlayers
[i
].FClientID
)
1014 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then MH_SEND_GameEvent(NET_EV_BIGTEXT
, MTime
, msg
, gPlayers
[i
].FClientID
);
1021 TRIGGER_MESSAGE_DEST_ENEMY_TEAM
: // activator's enemy team
1023 if g_GetUIDType(ActivateUID
) = UID_PLAYER
then
1025 p
:= g_Player_Get(ActivateUID
);
1026 if g_Game_IsWatchedTeam(p
.Team
) then
1028 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then g_Console_Add(msg
, True)
1029 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then g_Game_Message(msg
, MTime
);
1032 if g_Game_IsNet
then
1034 for i
:= Low(gPlayers
) to High(gPlayers
) do
1036 if (gPlayers
[i
].Team
<> p
.Team
) and (gPlayers
[i
].FClientID
>= 0) then
1038 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then MH_SEND_Chat(msg
, NET_CHAT_SYSTEM
, gPlayers
[i
].FClientID
)
1039 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then MH_SEND_GameEvent(NET_EV_BIGTEXT
, MTime
, msg
, gPlayers
[i
].FClientID
);
1046 TRIGGER_MESSAGE_DEST_RED_TEAM
: // red team
1048 if g_Game_IsWatchedTeam(TEAM_RED
) then
1050 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then g_Console_Add(msg
, True)
1051 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then g_Game_Message(msg
, MTime
);
1054 if g_Game_IsNet
then
1056 for i
:= Low(gPlayers
) to High(gPlayers
) do
1058 if (gPlayers
[i
].Team
= TEAM_RED
) and (gPlayers
[i
].FClientID
>= 0) then
1060 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then MH_SEND_Chat(msg
, NET_CHAT_SYSTEM
, gPlayers
[i
].FClientID
)
1061 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then MH_SEND_GameEvent(NET_EV_BIGTEXT
, MTime
, msg
, gPlayers
[i
].FClientID
);
1067 TRIGGER_MESSAGE_DEST_BLUE_TEAM
: // blue team
1069 if g_Game_IsWatchedTeam(TEAM_BLUE
) then
1071 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then g_Console_Add(msg
, True)
1072 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then g_Game_Message(msg
, MTime
);
1075 if g_Game_IsNet
then
1077 for i
:= Low(gPlayers
) to High(gPlayers
) do
1079 if (gPlayers
[i
].Team
= TEAM_BLUE
) and (gPlayers
[i
].FClientID
>= 0) then
1081 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then MH_SEND_Chat(msg
, NET_CHAT_SYSTEM
, gPlayers
[i
].FClientID
)
1082 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then MH_SEND_GameEvent(NET_EV_BIGTEXT
, MTime
, msg
, gPlayers
[i
].FClientID
);
1088 TRIGGER_MESSAGE_DEST_EVERYONE
: // everyone
1090 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then g_Console_Add(msg
, True)
1091 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then g_Game_Message(msg
, MTime
);
1093 if g_Game_IsNet
then
1095 if MKind
= TRIGGER_MESSAGE_KIND_CHAT
then MH_SEND_Chat(msg
, NET_CHAT_SYSTEM
)
1096 else if MKind
= TRIGGER_MESSAGE_KIND_GAME
then MH_SEND_GameEvent(NET_EV_BIGTEXT
, MTime
, msg
);
1103 function tr_ShotAimCheck (var Trigger
: TTrigger
; Obj
: PObj
): Boolean;
1108 if TriggerType
<> TRIGGER_SHOT
then Exit
;
1109 result
:= (tgcAim
and TRIGGER_SHOT_AIM_ALLMAP
> 0)
1110 or g_Obj_Collide(X
, Y
, Width
, Height
, Obj
);
1111 if result
and (tgcAim
and TRIGGER_SHOT_AIM_TRACE
> 0) then
1113 result
:= g_TraceVector(tgcTX
, tgcTY
,
1114 Obj
^.X
+ Obj
^.Rect
.X
+ (Obj
^.Rect
.Width
div 2),
1115 Obj
^.Y
+ Obj
^.Rect
.Y
+ (Obj
^.Rect
.Height
div 2));
1121 function ActivateTrigger (var Trigger
: TTrigger
; actType
: Byte): Boolean;
1127 idx
, k
, wx
, wy
, xd
, yd
: Integer;
1138 function monsShotTarget (mon
: TMonster
): Boolean;
1140 result
:= false; // don't stop
1141 if mon
.alive
and tr_ShotAimCheck(Trigger
, @(mon
.Obj
)) then
1143 xd
:= mon
.GameX
+ mon
.Obj
.Rect
.Width
div 2;
1144 yd
:= mon
.GameY
+ mon
.Obj
.Rect
.Height
div 2;
1145 TargetUID
:= mon
.UID
;
1146 result
:= true; // stop
1150 function monsShotTargetMonPlr (mon
: TMonster
): Boolean;
1152 result
:= false; // don't stop
1153 if mon
.alive
and tr_ShotAimCheck(Trigger
, @(mon
.Obj
)) then
1155 xd
:= mon
.GameX
+ mon
.Obj
.Rect
.Width
div 2;
1156 yd
:= mon
.GameY
+ mon
.Obj
.Rect
.Height
div 2;
1157 TargetUID
:= mon
.UID
;
1158 result
:= true; // stop
1162 function monShotTargetPlrMon (mon
: TMonster
): Boolean;
1164 result
:= false; // don't stop
1165 if mon
.alive
and tr_ShotAimCheck(Trigger
, @(mon
.Obj
)) then
1167 xd
:= mon
.GameX
+ mon
.Obj
.Rect
.Width
div 2;
1168 yd
:= mon
.GameY
+ mon
.Obj
.Rect
.Height
div 2;
1169 TargetUID
:= mon
.UID
;
1170 result
:= true; // stop
1178 if g_Game_IsClient
then exit
;
1180 if not Trigger
.Enabled
then exit
;
1181 if (Trigger
.TimeOut
<> 0) and (actType
<> ACTIVATE_CUSTOM
) then exit
;
1182 if (gLMSRespawn
= LMS_RESPAWN_WARMUP
) then exit
;
1184 if (Trigger
.exoCheck
<> nil) then
1186 //conwritefln('exocheck: [%s]', [Trigger.exoCheck.toString()]);
1188 tgscope
.me
:= @Trigger
;
1189 tvval
:= Trigger
.exoCheck
.value(tgscope
);
1191 if not Boolean(tvval
) then exit
;
1194 conwritefln('trigger exocheck error: %s', [Trigger
.exoCheck
.toString()]);
1201 coolDown
:= (actType
<> 0);
1203 if (Trigger
.exoAction
<> nil) then
1205 //conwritefln('exoactivate: [%s]', [Trigger.exoAction.toString()]);
1207 tgscope
.me
:= @Trigger
;
1208 Trigger
.exoAction
.value(tgscope
);
1212 conwritefln('trigger exoactivate error: %s', [Trigger
.exoAction
.toString()]);
1222 g_Sound_PlayEx('SOUND_GAME_SWITCH0');
1223 if g_Game_IsNet
then MH_SEND_Sound(X
, Y
, 'SOUND_GAME_SWITCH0');
1224 gExitByTrigger
:= True;
1225 g_Game_ExitLevel(tgcMap
);
1234 Result
:= tr_Teleport(ActivateUID
,
1235 tgcTarget
.X
, tgcTarget
.Y
,
1236 tgcDirection
, tgcSilent
,
1243 Result
:= tr_OpenDoor(trigPanelGUID
, tgcSilent
, tgcD2d
);
1249 Result
:= tr_CloseDoor(trigPanelGUID
, tgcSilent
, tgcD2d
);
1253 TRIGGER_DOOR
, TRIGGER_DOOR5
:
1255 pan
:= g_Map_PanelByGUID(trigPanelGUID
);
1256 if (pan
<> nil) and pan
.isGWall
then
1258 if gWalls
[{trigPanelID}pan
.arrIdx
].Enabled
then
1260 result
:= tr_OpenDoor(trigPanelGUID
, tgcSilent
, tgcD2d
);
1261 if (TriggerType
= TRIGGER_DOOR5
) then DoorTime
:= 180;
1265 result
:= tr_CloseDoor(trigPanelGUID
, tgcSilent
, tgcD2d
);
1268 if result
then TimeOut
:= 18;
1272 TRIGGER_CLOSETRAP
, TRIGGER_TRAP
:
1274 tr_CloseTrap(trigPanelGUID
, tgcSilent
, tgcD2d
);
1276 if TriggerType
= TRIGGER_TRAP
then
1290 TRIGGER_PRESS
, TRIGGER_ON
, TRIGGER_OFF
, TRIGGER_ONOFF
:
1293 if PressTime
= -1 then PressTime
:= tgcWait
;
1294 if coolDown
then TimeOut
:= 18 else TimeOut
:= 0;
1299 if g_GetUIDType(ActivateUID
) = UID_PLAYER
then
1303 if gLMSRespawn
= LMS_RESPAWN_NONE
then
1305 g_Player_Get(ActivateUID
).GetSecret();
1306 Inc(gCoopSecretsFound
);
1307 if g_Game_IsNet
then MH_SEND_GameStats();
1313 Result
:= tr_SetLift(trigPanelGUID
, 0, tgcSilent
, tgcD2d
);
1316 if (not tgcSilent
) and Result
then begin
1317 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
1319 Y
+ (Height
div 2));
1320 if g_Game_IsServer
and g_Game_IsNet
then
1321 MH_SEND_Sound(X
+ (Width
div 2),
1323 'SOUND_GAME_SWITCH0');
1329 Result
:= tr_SetLift(trigPanelGUID
, 1, tgcSilent
, tgcD2d
);
1332 if (not tgcSilent
) and Result
then begin
1333 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
1335 Y
+ (Height
div 2));
1336 if g_Game_IsServer
and g_Game_IsNet
then
1337 MH_SEND_Sound(X
+ (Width
div 2),
1339 'SOUND_GAME_SWITCH0');
1345 Result
:= tr_SetLift(trigPanelGUID
, 3, tgcSilent
, tgcD2d
);
1351 if (not tgcSilent
) and Result
then begin
1352 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
1354 Y
+ (Height
div 2));
1355 if g_Game_IsServer
and g_Game_IsNet
then
1356 MH_SEND_Sound(X
+ (Width
div 2),
1358 'SOUND_GAME_SWITCH0');
1365 if tgcActivateOnce
then
1368 TriggerType
:= TRIGGER_NONE
;
1376 animonce
:= tgcAnimateOnce
;
1382 if Sound
<> nil then
1384 if tgcSoundSwitch
and Sound
.IsPlaying() then
1385 begin // Íóæíî âûêëþ÷èòü, åñëè èãðàë
1387 SoundPlayCount
:= 0;
1390 else // (not Data.SoundSwitch) or (not Sound.IsPlaying())
1391 if (tgcPlayCount
> 0) or (not Sound
.IsPlaying()) then
1393 if tgcPlayCount
> 0 then
1394 SoundPlayCount
:= tgcPlayCount
1395 else // 0 - èãðàåì áåñêîíå÷íî
1396 SoundPlayCount
:= 1;
1399 if g_Game_IsNet
then MH_SEND_TriggerSound(Trigger
);
1403 TRIGGER_SPAWNMONSTER
:
1404 if (tgcSpawnMonsType
in [MONSTER_DEMON
..MONSTER_MAN
]) then
1407 if (tgcDelay
> 0) and (actType
<> ACTIVATE_CUSTOM
) then
1409 AutoSpawn
:= not AutoSpawn
;
1411 // Àâòîñïàâíåð ïåðåêëþ÷åí - ìåíÿåì òåêñòóðó
1415 if ((tgcDelay
= 0) and (actType
<> ACTIVATE_CUSTOM
))
1416 or ((tgcDelay
> 0) and (actType
= ACTIVATE_CUSTOM
)) then
1417 for k
:= 1 to tgcMonsCount
do
1419 if (actType
= ACTIVATE_CUSTOM
) and (tgcDelay
> 0) then
1420 SpawnCooldown
:= tgcDelay
;
1421 if (tgcMax
> 0) and (SpawnedCount
>= tgcMax
) then
1424 mon
:= g_Monsters_Create(tgcSpawnMonsType
,
1426 TDirection(tgcDirection
), True);
1431 if (tgcHealth
> 0) then
1432 mon
.SetHealth(tgcHealth
);
1433 // Óñòàíàâëèâàåì ïîâåäåíèå:
1434 mon
.MonsterBehaviour
:= tgcBehaviour
;
1435 mon
.FNoRespawn
:= True;
1436 if g_Game_IsNet
then
1437 MH_SEND_MonsterSpawn(mon
.UID
);
1438 // Èäåì èñêàòü öåëü, åñëè íàäî:
1442 if tgcSpawnMonsType
<> MONSTER_BARREL
then Inc(gTotalMonsters
);
1444 if g_Game_IsNet
then
1446 SetLength(gMonstersSpawned
, Length(gMonstersSpawned
)+1);
1447 gMonstersSpawned
[High(gMonstersSpawned
)] := mon
.UID
;
1452 mon
.SpawnTrigger
:= ID
;
1457 EFFECT_TELEPORT
: begin
1458 if g_Frames_Get(FramesID
, 'FRAMES_TELEPORT') then
1460 Anim
:= TAnimation
.Create(FramesID
, False, 3);
1461 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', tgcTX
, tgcTY
);
1462 g_GFX_OnceAnim(mon
.Obj
.X
+mon
.Obj
.Rect
.X
+(mon
.Obj
.Rect
.Width
div 2)-32,
1463 mon
.Obj
.Y
+mon
.Obj
.Rect
.Y
+(mon
.Obj
.Rect
.Height
div 2)-32, Anim
);
1466 if g_Game_IsServer
and g_Game_IsNet
then
1467 MH_SEND_Effect(mon
.Obj
.X
+mon
.Obj
.Rect
.X
+(mon
.Obj
.Rect
.Width
div 2)-32,
1468 mon
.Obj
.Y
+mon
.Obj
.Rect
.Y
+(mon
.Obj
.Rect
.Height
div 2)-32, 1,
1471 EFFECT_RESPAWN
: begin
1472 if g_Frames_Get(FramesID
, 'FRAMES_ITEM_RESPAWN') then
1474 Anim
:= TAnimation
.Create(FramesID
, False, 4);
1475 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', tgcTX
, tgcTY
);
1476 g_GFX_OnceAnim(mon
.Obj
.X
+mon
.Obj
.Rect
.X
+(mon
.Obj
.Rect
.Width
div 2)-16,
1477 mon
.Obj
.Y
+mon
.Obj
.Rect
.Y
+(mon
.Obj
.Rect
.Height
div 2)-16, Anim
);
1480 if g_Game_IsServer
and g_Game_IsNet
then
1481 MH_SEND_Effect(mon
.Obj
.X
+mon
.Obj
.Rect
.X
+(mon
.Obj
.Rect
.Width
div 2)-16,
1482 mon
.Obj
.Y
+mon
.Obj
.Rect
.Y
+(mon
.Obj
.Rect
.Height
div 2)-16, 1,
1486 if g_Frames_Get(FramesID
, 'FRAMES_FIRE') then
1488 Anim
:= TAnimation
.Create(FramesID
, False, 4);
1489 g_Sound_PlayExAt('SOUND_FIRE', tgcTX
, tgcTY
);
1490 g_GFX_OnceAnim(mon
.Obj
.X
+mon
.Obj
.Rect
.X
+(mon
.Obj
.Rect
.Width
div 2)-32,
1491 mon
.Obj
.Y
+mon
.Obj
.Rect
.Y
+mon
.Obj
.Rect
.Height
-128, Anim
);
1494 if g_Game_IsServer
and g_Game_IsNet
then
1495 MH_SEND_Effect(mon
.Obj
.X
+mon
.Obj
.Rect
.X
+(mon
.Obj
.Rect
.Width
div 2)-32,
1496 mon
.Obj
.Y
+mon
.Obj
.Rect
.Y
+mon
.Obj
.Rect
.Height
-128, 1,
1501 if g_Game_IsNet
then
1503 MH_SEND_GameStats();
1504 MH_SEND_CoopStats();
1511 // Åñëè àêòèâèðîâàí àâòîñïàâíåðîì, íå ìåíÿåì òåêñòóðó
1512 if actType
= ACTIVATE_CUSTOM
then
1517 if (tgcSpawnItemType
in [ITEM_MEDKIT_SMALL
..ITEM_MAX
]) then
1520 if (tgcDelay
> 0) and (actType
<> ACTIVATE_CUSTOM
) then
1522 AutoSpawn
:= not AutoSpawn
;
1524 // Àâòîñïàâíåð ïåðåêëþ÷åí - ìåíÿåì òåêñòóðó
1528 if ((tgcDelay
= 0) and (actType
<> ACTIVATE_CUSTOM
))
1529 or ((tgcDelay
> 0) and (actType
= ACTIVATE_CUSTOM
)) then
1530 if (not tgcDmonly
) or
1531 (gGameSettings
.GameMode
in [GM_DM
, GM_TDM
, GM_CTF
]) then
1532 for k
:= 1 to tgcItemCount
do
1534 if (actType
= ACTIVATE_CUSTOM
) and (tgcDelay
> 0) then
1535 SpawnCooldown
:= tgcDelay
;
1536 if (tgcMax
> 0) and (SpawnedCount
>= tgcMax
) then
1539 iid
:= g_Items_Create(tgcTX
, tgcTY
,
1540 tgcSpawnItemType
, tgcGravity
, False, True);
1546 it
:= g_Items_ByIdx(iid
);
1547 it
.SpawnTrigger
:= ID
;
1552 EFFECT_TELEPORT
: begin
1553 it
:= g_Items_ByIdx(iid
);
1554 if g_Frames_Get(FramesID
, 'FRAMES_TELEPORT') then
1556 Anim
:= TAnimation
.Create(FramesID
, False, 3);
1557 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', tgcTX
, tgcTY
);
1558 g_GFX_OnceAnim(it
.Obj
.X
+it
.Obj
.Rect
.X
+(it
.Obj
.Rect
.Width
div 2)-32,
1559 it
.Obj
.Y
+it
.Obj
.Rect
.Y
+(it
.Obj
.Rect
.Height
div 2)-32, Anim
);
1562 if g_Game_IsServer
and g_Game_IsNet
then
1563 MH_SEND_Effect(it
.Obj
.X
+it
.Obj
.Rect
.X
+(it
.Obj
.Rect
.Width
div 2)-32,
1564 it
.Obj
.Y
+it
.Obj
.Rect
.Y
+(it
.Obj
.Rect
.Height
div 2)-32, 1,
1567 EFFECT_RESPAWN
: begin
1568 it
:= g_Items_ByIdx(iid
);
1569 if g_Frames_Get(FramesID
, 'FRAMES_ITEM_RESPAWN') then
1571 Anim
:= TAnimation
.Create(FramesID
, False, 4);
1572 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', tgcTX
, tgcTY
);
1573 g_GFX_OnceAnim(it
.Obj
.X
+it
.Obj
.Rect
.X
+(it
.Obj
.Rect
.Width
div 2)-16,
1574 it
.Obj
.Y
+it
.Obj
.Rect
.Y
+(it
.Obj
.Rect
.Height
div 2)-16, Anim
);
1577 if g_Game_IsServer
and g_Game_IsNet
then
1578 MH_SEND_Effect(it
.Obj
.X
+it
.Obj
.Rect
.X
+(it
.Obj
.Rect
.Width
div 2)-16,
1579 it
.Obj
.Y
+it
.Obj
.Rect
.Y
+(it
.Obj
.Rect
.Height
div 2)-16, 1,
1583 it
:= g_Items_ByIdx(iid
);
1584 if g_Frames_Get(FramesID
, 'FRAMES_FIRE') then
1586 Anim
:= TAnimation
.Create(FramesID
, False, 4);
1587 g_Sound_PlayExAt('SOUND_FIRE', tgcTX
, tgcTY
);
1588 g_GFX_OnceAnim(it
.Obj
.X
+it
.Obj
.Rect
.X
+(it
.Obj
.Rect
.Width
div 2)-32,
1589 it
.Obj
.Y
+it
.Obj
.Rect
.Y
+it
.Obj
.Rect
.Height
-128, Anim
);
1592 if g_Game_IsServer
and g_Game_IsNet
then
1593 MH_SEND_Effect(it
.Obj
.X
+it
.Obj
.Rect
.X
+(it
.Obj
.Rect
.Width
div 2)-32,
1594 it
.Obj
.Y
+it
.Obj
.Rect
.Y
+it
.Obj
.Rect
.Height
-128, 1,
1599 if g_Game_IsNet
then
1600 MH_SEND_ItemSpawn(True, iid
);
1607 // Åñëè àêòèâèðîâàí àâòîñïàâíåðîì, íå ìåíÿåì òåêñòóðó
1608 if actType
= ACTIVATE_CUSTOM
then
1614 // Ìåíÿåì ìóçûêó, åñëè åñòü íà ÷òî:
1615 if (Trigger
.tgcMusicName
<> '') then
1617 gMusic
.SetByName(Trigger
.tgcMusicName
);
1618 gMusic
.SpecPause
:= True;
1622 case Trigger
.tgcMusicAction
of
1623 TRIGGER_MUSIC_ACTION_STOP
: // Âûêëþ÷èòü
1624 gMusic
.SpecPause
:= True; // Ïàóçà
1625 TRIGGER_MUSIC_ACTION_PLAY
: // Âêëþ÷èòü
1626 if gMusic
.SpecPause
then // Áûëà íà ïàóçå => èãðàòü
1627 gMusic
.SpecPause
:= False
1628 else // Èãðàëà => ñíà÷àëà
1629 gMusic
.SetPosition(0);
1637 if g_Game_IsNet
then MH_SEND_TriggerMusic
;
1642 pAngle
:= -DegToRad(tgcAngle
);
1643 Result
:= tr_Push(ActivateUID
,
1644 Floor(Cos(pAngle
)*tgcForce
),
1645 Floor(Sin(pAngle
)*tgcForce
),
1653 // Ïðèáàâèòü èëè îòíÿòü î÷êî
1654 if (tgcScoreAction
in [TRIGGER_SCORE_ACTION_ADD
, TRIGGER_SCORE_ACTION_SUB
]) and (tgcScoreCount
> 0) then
1656 // Ñâîåé èëè ÷óæîé êîìàíäå
1657 if (tgcScoreTeam
in [TRIGGER_SCORE_TEAM_MINE_RED
, TRIGGER_SCORE_TEAM_MINE_BLUE
]) and (g_GetUIDType(ActivateUID
) = UID_PLAYER
) then
1659 p
:= g_Player_Get(ActivateUID
);
1660 if ((tgcScoreAction
= TRIGGER_SCORE_ACTION_ADD
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_RED
))
1661 or ((tgcScoreAction
= TRIGGER_SCORE_ACTION_ADD
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_BLUE
)) then
1663 Inc(gTeamStat
[TEAM_RED
].Goals
, tgcScoreCount
); // Red Scores
1667 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) then
1669 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_ADD_OWN
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1670 if g_Game_IsServer
and g_Game_IsNet
then
1671 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '+r');
1674 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_ADD_ENEMY
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1675 if g_Game_IsServer
and g_Game_IsNet
then
1676 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '+re');
1682 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_ADD
], [AnsiUpperCase(_lc
[I_GAME_TEAM_RED
])]), 108);
1683 if g_Game_IsServer
and g_Game_IsNet
then
1684 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, TEAM_RED
);
1687 if ((tgcScoreAction
= TRIGGER_SCORE_ACTION_SUB
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_RED
))
1688 or ((tgcScoreAction
= TRIGGER_SCORE_ACTION_SUB
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_BLUE
)) then
1690 Dec(gTeamStat
[TEAM_RED
].Goals
, tgcScoreCount
); // Red Fouls
1694 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) then
1696 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_SUB_OWN
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1697 if g_Game_IsServer
and g_Game_IsNet
then
1698 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '-r');
1701 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_SUB_ENEMY
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1702 if g_Game_IsServer
and g_Game_IsNet
then
1703 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '-re');
1709 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_SUB
], [AnsiUpperCase(_lc
[I_GAME_TEAM_RED
])]), 108);
1710 if g_Game_IsServer
and g_Game_IsNet
then
1711 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, -TEAM_RED
);
1714 if ((tgcScoreAction
= TRIGGER_SCORE_ACTION_ADD
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_BLUE
))
1715 or ((tgcScoreAction
= TRIGGER_SCORE_ACTION_ADD
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_RED
)) then
1717 Inc(gTeamStat
[TEAM_BLUE
].Goals
, tgcScoreCount
); // Blue Scores
1721 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) then
1723 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_ADD_OWN
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1724 if g_Game_IsServer
and g_Game_IsNet
then
1725 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '+b');
1728 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_ADD_ENEMY
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1729 if g_Game_IsServer
and g_Game_IsNet
then
1730 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '+be');
1736 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_ADD
], [AnsiUpperCase(_lc
[I_GAME_TEAM_BLUE
])]), 108);
1737 if g_Game_IsServer
and g_Game_IsNet
then
1738 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, TEAM_BLUE
);
1741 if ((tgcScoreAction
= TRIGGER_SCORE_ACTION_SUB
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_BLUE
))
1742 or ((tgcScoreAction
= TRIGGER_SCORE_ACTION_SUB
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_RED
)) then
1744 Dec(gTeamStat
[TEAM_BLUE
].Goals
, tgcScoreCount
); // Blue Fouls
1748 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) then
1750 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_SUB_OWN
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1751 if g_Game_IsServer
and g_Game_IsNet
then
1752 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '-b');
1755 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_SUB_ENEMY
], [p
.Name
, tgcScoreCount
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1756 if g_Game_IsServer
and g_Game_IsNet
then
1757 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
or (tgcScoreCount
shl 16), '-be');
1763 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_SUB
], [AnsiUpperCase(_lc
[I_GAME_TEAM_BLUE
])]), 108);
1764 if g_Game_IsServer
and g_Game_IsNet
then
1765 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, -TEAM_BLUE
);
1768 Result
:= (p
.Team
= TEAM_RED
) or (p
.Team
= TEAM_BLUE
);
1770 // Êàêîé-òî êîíêðåòíîé êîìàíäå
1771 if tgcScoreTeam
in [TRIGGER_SCORE_TEAM_FORCE_RED
, TRIGGER_SCORE_TEAM_FORCE_BLUE
] then
1773 if (tgcScoreAction
= TRIGGER_SCORE_ACTION_ADD
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_RED
) then
1775 Inc(gTeamStat
[TEAM_RED
].Goals
, tgcScoreCount
); // Red Scores
1779 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_ADD_TEAM
], [_lc
[I_PLAYER_SCORE_RED
], tgcScoreCount
]), True);
1780 if g_Game_IsServer
and g_Game_IsNet
then
1781 MH_SEND_GameEvent(NET_EV_SCORE
, tgcScoreCount
shl 16, '+tr');
1786 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_ADD
], [AnsiUpperCase(_lc
[I_GAME_TEAM_RED
])]), 108);
1787 if g_Game_IsServer
and g_Game_IsNet
then
1788 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, TEAM_RED
);
1791 if (tgcScoreAction
= TRIGGER_SCORE_ACTION_SUB
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_RED
) then
1793 Dec(gTeamStat
[TEAM_RED
].Goals
, tgcScoreCount
); // Red Fouls
1797 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_SUB_TEAM
], [_lc
[I_PLAYER_SCORE_RED
], tgcScoreCount
]), True);
1798 if g_Game_IsServer
and g_Game_IsNet
then
1799 MH_SEND_GameEvent(NET_EV_SCORE
, tgcScoreCount
shl 16, '-tr');
1804 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_SUB
], [AnsiUpperCase(_lc
[I_GAME_TEAM_RED
])]), 108);
1805 if g_Game_IsServer
and g_Game_IsNet
then
1806 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, -TEAM_RED
);
1809 if (tgcScoreAction
= TRIGGER_SCORE_ACTION_ADD
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_BLUE
) then
1811 Inc(gTeamStat
[TEAM_BLUE
].Goals
, tgcScoreCount
); // Blue Scores
1815 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_ADD_TEAM
], [_lc
[I_PLAYER_SCORE_BLUE
], tgcScoreCount
]), True);
1816 if g_Game_IsServer
and g_Game_IsNet
then
1817 MH_SEND_GameEvent(NET_EV_SCORE
, tgcScoreCount
shl 16, '+tb');
1822 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_ADD
], [AnsiUpperCase(_lc
[I_GAME_TEAM_BLUE
])]), 108);
1823 if g_Game_IsServer
and g_Game_IsNet
then
1824 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, TEAM_BLUE
);
1827 if (tgcScoreAction
= TRIGGER_SCORE_ACTION_SUB
) and (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_BLUE
) then
1829 Dec(gTeamStat
[TEAM_BLUE
].Goals
, tgcScoreCount
); // Blue Fouls
1833 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_SUB_TEAM
], [_lc
[I_PLAYER_SCORE_BLUE
], tgcScoreCount
]), True);
1834 if g_Game_IsServer
and g_Game_IsNet
then
1835 MH_SEND_GameEvent(NET_EV_SCORE
, tgcScoreCount
shl 16, '-tb');
1840 g_Game_Message(Format(_lc
[I_MESSAGE_SCORE_SUB
], [AnsiUpperCase(_lc
[I_GAME_TEAM_BLUE
])]), 108);
1841 if g_Game_IsServer
and g_Game_IsNet
then
1842 MH_SEND_GameEvent(NET_EV_SCORE_MSG
, -TEAM_BLUE
);
1849 if (tgcScoreAction
= TRIGGER_SCORE_ACTION_WIN
) and (gGameSettings
.GoalLimit
> 0) then
1851 // Ñâîåé èëè ÷óæîé êîìàíäû
1852 if (tgcScoreTeam
in [TRIGGER_SCORE_TEAM_MINE_RED
, TRIGGER_SCORE_TEAM_MINE_BLUE
]) and (g_GetUIDType(ActivateUID
) = UID_PLAYER
) then
1854 p
:= g_Player_Get(ActivateUID
);
1855 if ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_RED
)) // Red Wins
1856 or ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_BLUE
)) then
1858 if gTeamStat
[TEAM_RED
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1860 gTeamStat
[TEAM_RED
].Goals
:= gGameSettings
.GoalLimit
;
1864 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) then
1866 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_OWN
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1867 if g_Game_IsServer
and g_Game_IsNet
then
1868 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wr');
1871 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_ENEMY
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1872 if g_Game_IsServer
and g_Game_IsNet
then
1873 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wre');
1880 if ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_BLUE
)) // Blue Wins
1881 or ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_RED
)) then
1883 if gTeamStat
[TEAM_BLUE
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1885 gTeamStat
[TEAM_BLUE
].Goals
:= gGameSettings
.GoalLimit
;
1889 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) then
1891 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_OWN
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1892 if g_Game_IsServer
and g_Game_IsNet
then
1893 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wb');
1896 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_ENEMY
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1897 if g_Game_IsServer
and g_Game_IsNet
then
1898 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wbe');
1906 // Êàêîé-òî êîíêðåòíîé êîìàíäû
1907 if tgcScoreTeam
in [TRIGGER_SCORE_TEAM_FORCE_RED
, TRIGGER_SCORE_TEAM_FORCE_BLUE
] then
1909 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_RED
) then // Red Wins
1911 if gTeamStat
[TEAM_RED
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1913 gTeamStat
[TEAM_RED
].Goals
:= gGameSettings
.GoalLimit
;
1917 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_BLUE
) then // Blue Wins
1919 if gTeamStat
[TEAM_BLUE
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1921 gTeamStat
[TEAM_BLUE
].Goals
:= gGameSettings
.GoalLimit
;
1928 if (tgcScoreAction
= TRIGGER_SCORE_ACTION_LOOSE
) and (gGameSettings
.GoalLimit
> 0) then
1930 // Ñâîåé èëè ÷óæîé êîìàíäû
1931 if (tgcScoreTeam
in [TRIGGER_SCORE_TEAM_MINE_RED
, TRIGGER_SCORE_TEAM_MINE_BLUE
]) and (g_GetUIDType(ActivateUID
) = UID_PLAYER
) then
1933 p
:= g_Player_Get(ActivateUID
);
1934 if ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_BLUE
)) // Red Wins
1935 or ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_RED
)) then
1936 if gTeamStat
[TEAM_RED
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1938 gTeamStat
[TEAM_RED
].Goals
:= gGameSettings
.GoalLimit
;
1941 if tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
then
1943 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_ENEMY
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1944 if g_Game_IsServer
and g_Game_IsNet
then
1945 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wre');
1948 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_OWN
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_RED
]]), True);
1949 if g_Game_IsServer
and g_Game_IsNet
then
1950 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wr');
1955 if ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
) and (p
.Team
= TEAM_RED
)) // Blue Wins
1956 or ((tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_BLUE
) and (p
.Team
= TEAM_BLUE
)) then
1957 if gTeamStat
[TEAM_BLUE
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1959 gTeamStat
[TEAM_BLUE
].Goals
:= gGameSettings
.GoalLimit
;
1962 if tgcScoreTeam
= TRIGGER_SCORE_TEAM_MINE_RED
then
1964 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_ENEMY
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1965 if g_Game_IsServer
and g_Game_IsNet
then
1966 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wbe');
1969 g_Console_Add(Format(_lc
[I_PLAYER_SCORE_WIN_OWN
], [p
.Name
, _lc
[I_PLAYER_SCORE_TO_BLUE
]]), True);
1970 if g_Game_IsServer
and g_Game_IsNet
then
1971 MH_SEND_GameEvent(NET_EV_SCORE
, p
.UID
, 'wb');
1977 // Êàêîé-òî êîíêðåòíîé êîìàíäû
1978 if tgcScoreTeam
in [TRIGGER_SCORE_TEAM_FORCE_BLUE
, TRIGGER_SCORE_TEAM_FORCE_RED
] then
1980 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_BLUE
) then // Red Wins
1982 if gTeamStat
[TEAM_RED
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1984 gTeamStat
[TEAM_RED
].Goals
:= gGameSettings
.GoalLimit
;
1988 if (tgcScoreTeam
= TRIGGER_SCORE_TEAM_FORCE_RED
) then // Blue Wins
1990 if gTeamStat
[TEAM_BLUE
].Goals
< SmallInt(gGameSettings
.GoalLimit
) then
1992 gTeamStat
[TEAM_BLUE
].Goals
:= gGameSettings
.GoalLimit
;
1998 if Result
then begin
2003 if g_Game_IsServer
and g_Game_IsNet
then
2010 Result
:= tr_Message(tgcKind
, tgcText
,
2011 tgcMsgDest
, tgcMsgTime
,
2016 TRIGGER_DAMAGE
, TRIGGER_HEALTH
:
2019 UIDType
:= g_GetUIDType(ActivateUID
);
2020 if (UIDType
= UID_PLAYER
) or (UIDType
= UID_MONSTER
) then
2026 // Âñïîìèíàåì, àêòèâèðîâàë ëè îí ìåíÿ ðàíüøå
2027 for idx
:= 0 to High(Activators
) do
2028 if Activators
[idx
].UID
= ActivateUID
then
2034 begin // Âèäèì åãî âïåðâûå
2036 SetLength(Activators
, Length(Activators
) + 1);
2037 k
:= High(Activators
);
2038 Activators
[k
].UID
:= ActivateUID
;
2040 begin // Óæå âèäåëè åãî
2041 // Åñëè èíòåðâàë îòêëþ÷¸í, íî îí âñ¸ åù¸ â çîíå ïîðàæåíèÿ, äà¸ì åìó âðåìÿ
2042 if (tgcInterval
= 0) and (Activators
[k
].TimeOut
> 0) then
2043 Activators
[k
].TimeOut
:= 65535;
2044 // Òàéìàóò ïðîø¸ë - ðàáîòàåì
2045 Result
:= Activators
[k
].TimeOut
= 0;
2054 p
:= g_Player_Get(ActivateUID
);
2058 // Íàíîñèì óðîí èãðîêó
2059 if (TriggerType
= TRIGGER_DAMAGE
) and (tgcAmount
> 0) then
2060 p
.Damage(tgcAmount
, 0, 0, 0, HIT_SOME
);
2063 if (TriggerType
= TRIGGER_HEALTH
) and (tgcAmount
> 0) then
2064 if p
.Heal(tgcAmount
, not tgcHealMax
) and (not tgcSilent
) then
2066 g_Sound_PlayExAt('SOUND_ITEM_GETITEM', p
.Obj
.X
, p
.Obj
.Y
);
2067 if g_Game_IsServer
and g_Game_IsNet
then
2068 MH_SEND_Sound(p
.Obj
.X
, p
.Obj
.Y
, 'SOUND_ITEM_GETITEM');
2074 m
:= g_Monsters_ByUID(ActivateUID
);
2078 // Íàíîñèì óðîí ìîíñòðó
2079 if (TriggerType
= TRIGGER_DAMAGE
) and (tgcAmount
> 0) then
2080 m
.Damage(tgcAmount
, 0, 0, 0, HIT_SOME
);
2083 if (TriggerType
= TRIGGER_HEALTH
) and (tgcAmount
> 0) then
2084 if m
.Heal(tgcAmount
) and (not tgcSilent
) then
2086 g_Sound_PlayExAt('SOUND_ITEM_GETITEM', m
.Obj
.X
, m
.Obj
.Y
);
2087 if g_Game_IsServer
and g_Game_IsNet
then
2088 MH_SEND_Sound(m
.Obj
.X
, m
.Obj
.Y
, 'SOUND_ITEM_GETITEM');
2092 // Íàçíà÷àåì âðåìÿ ñëåäóþùåãî âîçäåéñòâèÿ
2096 Activators
[k
].TimeOut
:= idx
2098 Activators
[k
].TimeOut
:= 65535;
2106 if ShotSightTime
> 0 then
2109 // put this at the beginning so it doesn't trigger itself
2110 TimeOut
:= tgcWait
+ 1;
2114 pAngle
:= -DegToRad(tgcAngle
);
2115 xd
:= wx
+ Round(Cos(pAngle
) * 32.0);
2116 yd
:= wy
+ Round(Sin(pAngle
) * 32.0);
2119 case tgcShotTarget
of
2120 TRIGGER_SHOT_TARGET_MON
: // monsters
2121 //TODO: accelerate this!
2122 g_Mons_ForEachAlive(monsShotTarget
);
2124 TRIGGER_SHOT_TARGET_PLR
: // players
2125 if gPlayers
<> nil then
2126 for idx
:= Low(gPlayers
) to High(gPlayers
) do
2127 if (gPlayers
[idx
] <> nil) and gPlayers
[idx
].alive
and
2128 tr_ShotAimCheck(Trigger
, @(gPlayers
[idx
].Obj
)) then
2130 xd
:= gPlayers
[idx
].GameX
+ PLAYER_RECT_CX
;
2131 yd
:= gPlayers
[idx
].GameY
+ PLAYER_RECT_CY
;
2132 TargetUID
:= gPlayers
[idx
].UID
;
2136 TRIGGER_SHOT_TARGET_RED
: // red team
2137 if gPlayers
<> nil then
2138 for idx
:= Low(gPlayers
) to High(gPlayers
) do
2139 if (gPlayers
[idx
] <> nil) and gPlayers
[idx
].alive
and
2140 (gPlayers
[idx
].Team
= TEAM_RED
) and
2141 tr_ShotAimCheck(Trigger
, @(gPlayers
[idx
].Obj
)) then
2143 xd
:= gPlayers
[idx
].GameX
+ PLAYER_RECT_CX
;
2144 yd
:= gPlayers
[idx
].GameY
+ PLAYER_RECT_CY
;
2145 TargetUID
:= gPlayers
[idx
].UID
;
2149 TRIGGER_SHOT_TARGET_BLUE
: // blue team
2150 if gPlayers
<> nil then
2151 for idx
:= Low(gPlayers
) to High(gPlayers
) do
2152 if (gPlayers
[idx
] <> nil) and gPlayers
[idx
].alive
and
2153 (gPlayers
[idx
].Team
= TEAM_BLUE
) and
2154 tr_ShotAimCheck(Trigger
, @(gPlayers
[idx
].Obj
)) then
2156 xd
:= gPlayers
[idx
].GameX
+ PLAYER_RECT_CX
;
2157 yd
:= gPlayers
[idx
].GameY
+ PLAYER_RECT_CY
;
2158 TargetUID
:= gPlayers
[idx
].UID
;
2162 TRIGGER_SHOT_TARGET_MONPLR
: // monsters then players
2164 //TODO: accelerate this!
2165 g_Mons_ForEachAlive(monsShotTargetMonPlr
);
2167 if (TargetUID
= 0) and (gPlayers
<> nil) then
2168 for idx
:= Low(gPlayers
) to High(gPlayers
) do
2169 if (gPlayers
[idx
] <> nil) and gPlayers
[idx
].alive
and
2170 tr_ShotAimCheck(Trigger
, @(gPlayers
[idx
].Obj
)) then
2172 xd
:= gPlayers
[idx
].GameX
+ PLAYER_RECT_CX
;
2173 yd
:= gPlayers
[idx
].GameY
+ PLAYER_RECT_CY
;
2174 TargetUID
:= gPlayers
[idx
].UID
;
2179 TRIGGER_SHOT_TARGET_PLRMON
: // players then monsters
2181 if gPlayers
<> nil then
2182 for idx
:= Low(gPlayers
) to High(gPlayers
) do
2183 if (gPlayers
[idx
] <> nil) and gPlayers
[idx
].alive
and
2184 tr_ShotAimCheck(Trigger
, @(gPlayers
[idx
].Obj
)) then
2186 xd
:= gPlayers
[idx
].GameX
+ PLAYER_RECT_CX
;
2187 yd
:= gPlayers
[idx
].GameY
+ PLAYER_RECT_CY
;
2188 TargetUID
:= gPlayers
[idx
].UID
;
2191 if TargetUID
= 0 then
2193 //TODO: accelerate this!
2194 g_Mons_ForEachAlive(monShotTargetPlrMon
);
2199 if (tgcShotTarget
<> TRIGGER_SHOT_TARGET_NONE
) or
2200 (tgcShotType
<> TRIGGER_SHOT_REV
) then
2201 TargetUID
:= ActivateUID
;
2205 if (tgcShotTarget
= TRIGGER_SHOT_TARGET_NONE
) or (TargetUID
> 0) or
2206 ((tgcShotTarget
> TRIGGER_SHOT_TARGET_NONE
) and (TargetUID
= 0)) then
2209 if (tgcSight
= 0) or
2210 (tgcShotTarget
= TRIGGER_SHOT_TARGET_NONE
) or
2211 (TargetUID
= ShotSightTarget
) then
2212 MakeShot(Trigger
, wx
, wy
, xd
, yd
, TargetUID
)
2215 ShotSightTime
:= tgcSight
;
2216 ShotSightTargetN
:= TargetUID
;
2217 if tgcShotType
= TRIGGER_SHOT_BFG
then
2219 g_Sound_PlayExAt('SOUND_WEAPON_STARTFIREBFG', wx
, wy
);
2220 if g_Game_IsNet
and g_Game_IsServer
then
2221 MH_SEND_Sound(wx
, wy
, 'SOUND_WEAPON_STARTFIREBFG');
2234 TRIGGER_EFFECT_POS_CENTER
:
2236 wx
:= X
+ Width
div 2;
2237 wy
:= Y
+ Height
div 2;
2239 TRIGGER_EFFECT_POS_AREA
:
2241 wx
:= X
+ Random(Width
);
2242 wy
:= Y
+ Random(Height
);
2245 wx
:= X
+ Width
div 2;
2246 wy
:= Y
+ Height
div 2;
2251 if tgcSpreadL
> 0 then xd
-= Random(tgcSpreadL
+1);
2252 if tgcSpreadR
> 0 then xd
+= Random(tgcSpreadR
+1);
2253 if tgcSpreadU
> 0 then yd
-= Random(tgcSpreadU
+1);
2254 if tgcSpreadD
> 0 then yd
+= Random(tgcSpreadD
+1);
2255 tr_MakeEffect(wx
, wy
, xd
, yd
,
2256 tgcFXType
, tgcFXSubType
,
2257 tgcFXRed
, tgcFXGreen
, tgcFXBlue
, True, False);
2265 if Result
{and (Trigger.TexturePanel <> -1)} then
2267 g_Map_SwitchTextureGUID(Trigger
.TexturePanelType
, Trigger
.TexturePanelGUID
, IfThen(animonce
, 2, 1));
2272 function g_Triggers_CreateWithMapIndex (Trigger
: TTrigger
; arridx
, mapidx
: Integer): DWORD
;
2274 triggers
: TDynField
;
2276 triggers
:= gCurrentMap
['trigger'];
2277 if (triggers
= nil) then raise Exception
.Create('LOAD: map has no triggers');
2278 if (mapidx
< 0) or (mapidx
>= triggers
.count
) then raise Exception
.Create('LOAD: invalid map trigger index');
2279 //Trigger.trigDataRec := triggers.itemAt[mapidx];
2280 //if (Trigger.trigDataRec = nil) then raise Exception.Create('LOAD: internal error in trigger loader');
2281 //Trigger.mapId := Trigger.trigDataRec.id;
2282 Trigger
.mapIndex
:= mapidx
;
2284 if (Trigger.trigDataRec.trigRec <> nil) then
2286 Trigger.trigDataRec := Trigger.trigDataRec.trigRec.clone(nil);
2290 Trigger.trigDataRec := nil;
2293 result
:= g_Triggers_Create(Trigger
, triggers
.itemAt
[mapidx
], arridx
);
2297 function g_Triggers_Create(Trigger
: TTrigger
; trec
: TDynRecord
; forceInternalIndex
: Integer=-1): DWORD
;
2300 fn
, mapw
: AnsiString;
2303 if (tgscope
= nil) then tgscope
:= TTrigScope
.Create();
2305 // Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà
2306 if (Trigger
.TriggerType
= TRIGGER_EXIT
) and
2307 (not LongBool(gGameSettings
.Options
and GAME_OPTION_ALLOWEXIT
)) then
2308 Trigger
.TriggerType
:= TRIGGER_NONE
;
2310 // Åñëè ìîíñòðû çàïðåùåíû, îòìåíÿåì òðèããåð
2311 if (Trigger
.TriggerType
= TRIGGER_SPAWNMONSTER
) and
2312 (not LongBool(gGameSettings
.Options
and GAME_OPTION_MONSTERS
)) and
2313 (gGameSettings
.GameType
<> GT_SINGLE
) then
2314 Trigger
.TriggerType
:= TRIGGER_NONE
;
2316 // Ñ÷èòàåì êîëè÷åñòâî ñåêðåòîâ íà êàðòå
2317 if Trigger
.TriggerType
= TRIGGER_SECRET
then gSecretsCount
+= 1;
2319 if (forceInternalIndex
< 0) then
2321 find_id
:= FindTrigger();
2325 olen
:= Length(gTriggers
);
2326 if (forceInternalIndex
>= olen
) then
2328 SetLength(gTriggers
, forceInternalIndex
+1);
2329 for f
:= olen
to High(gTriggers
) do
2331 gTriggers
[f
].TriggerType
:= TRIGGER_NONE
;
2332 gTriggers
[f
].trigDataRec
:= nil;
2333 gTriggers
[f
].exoInit
:= nil;
2334 gTriggers
[f
].exoThink
:= nil;
2335 gTriggers
[f
].exoCheck
:= nil;
2336 gTriggers
[f
].exoAction
:= nil;
2337 gTriggers
[f
].userVars
:= nil;
2340 f
:= forceInternalIndex
;
2341 gTriggers
[f
].trigDataRec
.Free();
2342 gTriggers
[f
].exoInit
.Free();
2343 gTriggers
[f
].exoThink
.Free();
2344 gTriggers
[f
].exoCheck
.Free();
2345 gTriggers
[f
].exoAction
.Free();
2346 gTriggers
[f
].userVars
.Free();
2347 gTriggers
[f
].trigDataRec
:= nil;
2348 gTriggers
[f
].exoInit
:= nil;
2349 gTriggers
[f
].exoThink
:= nil;
2350 gTriggers
[f
].exoCheck
:= nil;
2351 gTriggers
[f
].exoAction
:= nil;
2352 gTriggers
[f
].userVars
:= nil;
2353 find_id
:= DWORD(forceInternalIndex
);
2355 gTriggers
[find_id
] := Trigger
;
2357 Trigger
.mapId
:= trec
.id
;
2358 // clone trigger data
2359 if (trec
.trigRec
= nil) then
2361 gTriggers
[find_id
].trigDataRec
:= nil;
2363 if (gTriggers
[find_id
].TriggerType
<> TRIGGER_SECRET
) then
2365 e_LogWritefln('trigger of type %s has no triggerdata; wtf?!', [gTriggers
[find_id
].TriggerType
], MSG_WARNING
);
2370 gTriggers
[find_id
].trigDataRec
:= trec
.trigRec
.clone(nil);
2373 with gTriggers
[find_id
] do
2376 // if this type of trigger exists both on the client and on the server
2377 // use an uniform numeration
2378 if Trigger
.TriggerType
= TRIGGER_SOUND
then
2380 Inc(gTriggerClientID
);
2381 ClientID
:= gTriggerClientID
;
2389 PlayerCollide
:= False;
2393 SoundPlayCount
:= 0;
2400 // update cached trigger variables
2401 trigUpdateCacheData(gTriggers
[find_id
], gTriggers
[find_id
].trigDataRec
);
2403 gTriggers
[find_id
].userVars
:= nil; //THashStrVariant.Create(hsihash, hsiequ);
2406 gTriggers
[find_id
].exoThink
:= TExprBase
.parseStatList(VarToStr(trec
.user
['exoma_think']));
2408 conwritefln('*** ERROR parsing exoma_think: [%s]', [VarToStr(trec
.user
['exoma_think'])]);
2409 gTriggers
[find_id
].exoThink
:= nil;
2412 gTriggers
[find_id
].exoCheck
:= TExprBase
.parse(VarToStr(trec
.user
['exoma_check']));
2414 conwritefln('*** ERROR parsing exoma_check: [%s]', [VarToStr(trec
.user
['exoma_check'])]);
2415 gTriggers
[find_id
].exoCheck
:= nil;
2418 gTriggers
[find_id
].exoAction
:= TExprBase
.parseStatList(VarToStr(trec
.user
['exoma_action']));
2420 conwritefln('*** ERROR parsing exoma_action: [%s]', [VarToStr(trec
.user
['exoma_action'])]);
2421 gTriggers
[find_id
].exoAction
:= nil;
2424 gTriggers
[find_id
].exoInit
:= TExprBase
.parseStatList(VarToStr(trec
.user
['exoma_init']));
2426 conwritefln('*** ERROR parsing exoma_init: [%s]', [VarToStr(trec
.user
['exoma_init'])]);
2427 gTriggers
[find_id
].exoInit
:= nil;
2430 if (forceInternalIndex
< 0) and (gTriggers
[find_id
].exoInit
<> nil) then
2432 //conwritefln('executing trigger init: [%s]', [gTriggers[find_id].exoInit.toString()]);
2434 tgscope
.me
:= @gTriggers
[find_id
];
2435 gTriggers
[find_id
].exoInit
.value(tgscope
);
2439 conwritefln('*** trigger exoactivate error: %s', [gTriggers
[find_id
].exoInit
.toString()]);
2444 // Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê"
2445 if (Trigger
.TriggerType
= TRIGGER_SOUND
) and (Trigger
.tgcSoundName
<> '') then
2447 // Åùå íåò òàêîãî çâóêà
2448 if not g_Sound_Exists(Trigger
.tgcSoundName
) then
2450 fn
:= g_ExtractWadName(Trigger
.tgcSoundName
);
2452 begin // Çâóê â ôàéëå ñ êàðòîé
2453 mapw
:= g_ExtractWadName(gMapInfo
.Map
);
2454 fn
:= mapw
+':'+g_ExtractFilePathName(Trigger
.tgcSoundName
);
2456 else // Çâóê â îòäåëüíîì ôàéëå
2458 fn
:= GameDir
+ '/wads/' + Trigger
.tgcSoundName
;
2461 if not g_Sound_CreateWADEx(Trigger
.tgcSoundName
, fn
) then
2463 g_FatalError(Format(_lc
[I_GAME_ERROR_TR_SOUND
], [fn
, Trigger
.tgcSoundName
]));
2467 // Ñîçäàåì îáúåêò çâóêà
2468 with gTriggers
[find_id
] do
2470 Sound
:= TPlayableSound
.Create();
2471 if not Sound
.SetByName(Trigger
.tgcSoundName
) then
2479 // Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà"
2480 if (Trigger
.TriggerType
= TRIGGER_MUSIC
) and (Trigger
.tgcMusicName
<> '') then
2482 // Åùå íåò òàêîé ìóçûêè
2483 if not g_Sound_Exists(Trigger
.tgcMusicName
) then
2485 fn
:= g_ExtractWadName(Trigger
.tgcMusicName
);
2488 begin // Ìóçûêà â ôàéëå ñ êàðòîé
2489 mapw
:= g_ExtractWadName(gMapInfo
.Map
);
2490 fn
:= mapw
+':'+g_ExtractFilePathName(Trigger
.tgcMusicName
);
2492 else // Ìóçûêà â ôàéëå ñ êàðòîé
2494 fn
:= GameDir
+'/wads/'+Trigger
.tgcMusicName
;
2497 if not g_Sound_CreateWADEx(Trigger
.tgcMusicName
, fn
, True) then
2499 g_FatalError(Format(_lc
[I_GAME_ERROR_TR_SOUND
], [fn
, Trigger
.tgcMusicName
]));
2504 // Çàãðóæàåì äàííûå òðèããåðà "Òóðåëü"
2505 if Trigger
.TriggerType
= TRIGGER_SHOT
then
2507 with gTriggers
[find_id
] do
2511 ShotSightTimeout
:= 0;
2512 ShotSightTarget
:= 0;
2513 ShotSightTargetN
:= 0;
2514 ShotAmmoCount
:= Trigger
.tgcAmmo
;
2515 ShotReloadTime
:= 0;
2523 // sorry; grid doesn't support recursive queries, so we have to do this
2525 TSimpleMonsterList
= specialize TSimpleList
<TMonster
>;
2528 tgMonsList
: TSimpleMonsterList
= nil;
2530 procedure g_Triggers_Update();
2533 Affected
: array of Integer;
2535 function monsNear (mon
: TMonster
): Boolean;
2537 result
:= false; // don't stop
2539 gTriggers[a].ActivateUID := mon.UID;
2540 ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE);
2542 tgMonsList
.append(mon
);
2549 if (tgMonsList
= nil) then tgMonsList
:= TSimpleMonsterList
.Create();
2551 if gTriggers
= nil then
2553 SetLength(Affected
, 0);
2555 for a
:= 0 to High(gTriggers
) do
2556 with gTriggers
[a
] do
2558 if TriggerType
<> TRIGGER_NONE
then
2560 // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè)
2561 if DoorTime
> 0 then DoorTime
:= DoorTime
- 1;
2562 // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ
2563 if PressTime
> 0 then PressTime
:= PressTime
- 1;
2564 // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè:
2565 if (TriggerType
= TRIGGER_DAMAGE
) or (TriggerType
= TRIGGER_HEALTH
) then
2567 for b
:= 0 to High(Activators
) do
2569 // Óìåíüøàåì âðåìÿ äî ïîâòîðíîãî âîçäåéñòâèÿ:
2570 if Activators
[b
].TimeOut
> 0 then
2572 Dec(Activators
[b
].TimeOut
);
2578 // Ñ÷èòàåì, ÷òî îáúåêò ïîêèíóë çîíó äåéñòâèÿ òðèããåðà
2579 if (tgcInterval
= 0) and (Activators
[b
].TimeOut
< 65530) then Activators
[b
].TimeOut
:= 0;
2583 // Îáðàáàòûâàåì ñïàâíåðû
2584 if Enabled
and AutoSpawn
then
2586 if SpawnCooldown
= 0 then
2588 // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà
2589 if (TriggerType
= TRIGGER_SPAWNMONSTER
) and (tgcDelay
> 0) then
2592 ActivateTrigger(gTriggers
[a
], ACTIVATE_CUSTOM
);
2594 // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò
2595 if (TriggerType
= TRIGGER_SPAWNITEM
) and (tgcDelay
> 0) then
2598 ActivateTrigger(gTriggers
[a
], ACTIVATE_CUSTOM
);
2603 // Óìåíüøàåì âðåìÿ îæèäàíèÿ
2608 // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü"
2609 if TriggerType
= TRIGGER_SHOT
then
2611 if ShotPanelTime
> 0 then
2614 if ShotPanelTime
= 0 then g_Map_SwitchTextureGUID(ShotPanelType
, trigPanelGUID
);
2616 if ShotSightTime
> 0 then
2619 if ShotSightTime
= 0 then ShotSightTarget
:= ShotSightTargetN
;
2621 if ShotSightTimeout
> 0 then
2623 Dec(ShotSightTimeout
);
2624 if ShotSightTimeout
= 0 then ShotSightTarget
:= 0;
2626 if ShotReloadTime
> 0 then
2628 Dec(ShotReloadTime
);
2629 if ShotReloadTime
= 0 then ShotAmmoCount
:= tgcAmmo
;
2633 // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì
2634 if Enabled
and (TriggerType
= TRIGGER_SOUND
) and (Sound
<> nil) then
2636 if (SoundPlayCount
> 0) and (not Sound
.IsPlaying()) then
2638 if tgcPlayCount
> 0 then SoundPlayCount
-= 1; // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
2641 Sound
.PlayVolumeAt(X
+(Width
div 2), Y
+(Height
div 2), tgcVolume
/255.0);
2645 Sound
.PlayPanVolume((tgcPan
-127.0)/128.0, tgcVolume
/255.0);
2647 if Sound
.IsPlaying() and g_Game_IsNet
and g_Game_IsServer
then MH_SEND_TriggerSound(gTriggers
[a
]);
2651 // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü
2652 if (TriggerType
= TRIGGER_TRAP
) and (DoorTime
= 0) and (g_Map_PanelByGUID(trigPanelGUID
) <> nil) then
2654 tr_OpenDoor(trigPanelGUID
, tgcSilent
, tgcD2d
);
2658 // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü
2659 if (TriggerType
= TRIGGER_DOOR5
) and (DoorTime
= 0) and (g_Map_PanelByGUID(trigPanelGUID
) <> nil) then
2661 pan
:= g_Map_PanelByGUID(trigPanelGUID
);
2662 if (pan
<> nil) and pan
.isGWall
then
2665 if {gWalls[trigPanelID].Enabled} pan
.Enabled
then
2671 // Ïîêà îòêðûòà - çàêðûâàåì
2672 if tr_CloseDoor(trigPanelGUID
, tgcSilent
, tgcD2d
) then DoorTime
:= -1;
2677 // Òðèããåð - ðàñøèðèòåëü èëè ïåðåêëþ÷àòåëü, è ïðîøëà çàäåðæêà, è íàæàëè íóæíîå ÷èñëî ðàç:
2678 if (TriggerType
in [TRIGGER_PRESS
, TRIGGER_ON
, TRIGGER_OFF
, TRIGGER_ONOFF
]) and
2679 (PressTime
= 0) and (PressCount
>= tgcPressCount
) then
2681 // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè:
2683 // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé:
2684 if tgcPressCount
> 0 then PressCount
-= tgcPressCount
else PressCount
:= 0;
2686 // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû:
2687 for b
:= 0 to High(gTriggers
) do
2689 if g_Collide(tgcTX
, tgcTY
, tgcTWidth
, tgcTHeight
, gTriggers
[b
].X
, gTriggers
[b
].Y
,
2690 gTriggers
[b
].Width
, gTriggers
[b
].Height
) and
2691 ((b
<> a
) or (tgcWait
> 0)) then
2692 begin // Can be self-activated, if there is Data.Wait
2693 if (not tgcExtRandom
) or gTriggers
[b
].Enabled
then
2695 SetLength(Affected
, Length(Affected
) + 1);
2696 Affected
[High(Affected
)] := b
;
2702 // if we have panelid, assume that it will switch the moving platform
2703 pan
:= g_Map_PanelByGUID(trigPanelGUID
);
2704 if (pan
<> nil) then
2707 TRIGGER_PRESS
: pan
.movingActive
:= true; // what to do here?
2708 TRIGGER_ON
: pan
.movingActive
:= true;
2709 TRIGGER_OFF
: pan
.movingActive
:= false;
2710 TRIGGER_ONOFF
: pan
.movingActive
:= not pan
.movingActive
;
2712 if not tgcSilent
and (Length(tgcSound
) > 0) then
2714 g_Sound_PlayExAt(tgcSound
, X
, Y
);
2715 if g_Game_IsServer
and g_Game_IsNet
then MH_SEND_Sound(X
, Y
, tgcSound
);
2719 // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì:
2720 if (TriggerType
= TRIGGER_PRESS
) and tgcExtRandom
then
2722 if (Length(Affected
) > 0) then
2724 b
:= Affected
[Random(Length(Affected
))];
2725 gTriggers
[b
].ActivateUID
:= gTriggers
[a
].ActivateUID
;
2726 ActivateTrigger(gTriggers
[b
], 0);
2729 else //  ïðîòèâíîì ñëó÷àå ðàáîòàåì êàê îáû÷íî:
2731 for i
:= 0 to High(Affected
) do
2737 gTriggers
[b
].ActivateUID
:= gTriggers
[a
].ActivateUID
;
2738 ActivateTrigger(gTriggers
[b
], 0);
2742 gTriggers
[b
].Enabled
:= True;
2746 gTriggers
[b
].Enabled
:= False;
2747 gTriggers
[b
].TimeOut
:= 0;
2748 if gTriggers
[b
].AutoSpawn
then
2750 gTriggers
[b
].AutoSpawn
:= False;
2751 gTriggers
[b
].SpawnCooldown
:= 0;
2756 gTriggers
[b
].Enabled
:= not gTriggers
[b
].Enabled
;
2757 if not gTriggers
[b
].Enabled
then
2759 gTriggers
[b
].TimeOut
:= 0;
2760 if gTriggers
[b
].AutoSpawn
then
2762 gTriggers
[b
].AutoSpawn
:= False;
2763 gTriggers
[b
].SpawnCooldown
:= 0;
2770 SetLength(Affected
, 0);
2773 // Óìåíüøàåì âðåìÿ äî âîçìîæíîñòè ïîâòîðíîé àêòèâàöèè:
2776 TimeOut
:= TimeOut
- 1;
2777 Continue
; // ×òîáû íå ïîòåðÿòü 1 åäèíèöó çàäåðæêè
2780 // Íèæå èäóò òèïû àêòèâàöèè, åñëè òðèããåð îòêëþ÷¸í - èä¸ì äàëüøå
2785 if ByteBool(ActivateType
and ACTIVATE_PLAYERCOLLIDE
) and
2787 if gPlayers
<> nil then
2788 for b
:= 0 to High(gPlayers
) do
2789 if gPlayers
[b
] <> nil then
2791 // Æèâ, åñòü íóæíûå êëþ÷è è îí ðÿäîì:
2792 if alive
and ((gTriggers
[a
].Keys
and GetKeys
) = gTriggers
[a
].Keys
) and
2793 Collide(X
, Y
, Width
, Height
) then
2795 gTriggers
[a
].ActivateUID
:= UID
;
2797 if (gTriggers
[a
].TriggerType
in [TRIGGER_SOUND
, TRIGGER_MUSIC
]) and
2799 { Don't activate sound/music again if player is here }
2801 ActivateTrigger(gTriggers
[a
], ACTIVATE_PLAYERCOLLIDE
);
2804 { TODO 5 : àêòèâàöèÿ ìîíñòðàìè òðèããåðîâ ñ êëþ÷àìè }
2806 if ByteBool(ActivateType
and ACTIVATE_MONSTERCOLLIDE
) and
2807 ByteBool(ActivateType
and ACTIVATE_NOMONSTER
) and
2808 (TimeOut
= 0) and (Keys
= 0) then
2810 // Åñëè "Ìîíñòð áëèçêî" è "Ìîíñòðîâ íåò",
2811 // çàïóñêàåì òðèããåð íà ñòàðòå êàðòû è ñíèìàåì îáà ôëàãà
2812 ActivateType
:= ActivateType
and not (ACTIVATE_MONSTERCOLLIDE
or ACTIVATE_NOMONSTER
);
2813 gTriggers
[a
].ActivateUID
:= 0;
2814 ActivateTrigger(gTriggers
[a
], 0);
2818 if ByteBool(ActivateType
and ACTIVATE_MONSTERCOLLIDE
) and
2819 (TimeOut
= 0) and (Keys
= 0) then // Åñëè íå íóæíû êëþ÷è
2821 //g_Mons_ForEach(monsNear);
2824 g_Mons_ForEachAt(gTriggers
[a
].X
, gTriggers
[a
].Y
, gTriggers
[a
].Width
, gTriggers
[a
].Height
, monsNear
);
2825 for mon
in tgMonsList
do
2827 gTriggers
[a
].ActivateUID
:= mon
.UID
;
2828 ActivateTrigger(gTriggers
[a
], ACTIVATE_MONSTERCOLLIDE
);
2830 tgMonsList
.reset(); // just in case
2834 if ByteBool(ActivateType
and ACTIVATE_NOMONSTER
) and
2835 (TimeOut
= 0) and (Keys
= 0) then
2836 if not g_Mons_IsAnyAliveAt(X
, Y
, Width
, Height
) then
2838 gTriggers
[a
].ActivateUID
:= 0;
2839 ActivateTrigger(gTriggers
[a
], ACTIVATE_NOMONSTER
);
2843 PlayerCollide
:= g_CollidePlayer(X
, Y
, Width
, Height
);
2847 procedure g_Triggers_Press(ID
: DWORD
; ActivateType
: Byte; ActivateUID
: Word = 0);
2849 if (ID
>= Length(gTriggers
)) then exit
;
2850 gTriggers
[ID
].ActivateUID
:= ActivateUID
;
2851 ActivateTrigger(gTriggers
[ID
], ActivateType
);
2854 function g_Triggers_PressR(X
, Y
: Integer; Width
, Height
: Word; UID
: Word;
2855 ActivateType
: Byte; IgnoreList
: DWArray
= nil): DWArray
;
2863 if gTriggers
= nil then Exit
;
2865 case g_GetUIDType(UID
) of
2869 p
:= g_Player_Get(UID
);
2878 for a
:= 0 to High(gTriggers
) do
2879 if (gTriggers
[a
].TriggerType
<> TRIGGER_NONE
) and
2880 (gTriggers
[a
].TimeOut
= 0) and
2881 (not InDWArray(a
, IgnoreList
)) and
2882 ((gTriggers
[a
].Keys
and k
) = gTriggers
[a
].Keys
) and
2883 ByteBool(gTriggers
[a
].ActivateType
and ActivateType
) then
2884 if g_Collide(X
, Y
, Width
, Height
,
2885 gTriggers
[a
].X
, gTriggers
[a
].Y
,
2886 gTriggers
[a
].Width
, gTriggers
[a
].Height
) then
2888 gTriggers
[a
].ActivateUID
:= UID
;
2889 if ActivateTrigger(gTriggers
[a
], ActivateType
) then
2891 SetLength(Result
, Length(Result
)+1);
2892 Result
[High(Result
)] := a
;
2897 procedure g_Triggers_PressL(X1
, Y1
, X2
, Y2
: Integer; UID
: DWORD
; ActivateType
: Byte);
2903 if gTriggers
= nil then Exit
;
2905 case g_GetUIDType(UID
) of
2909 p
:= g_Player_Get(UID
);
2918 for a
:= 0 to High(gTriggers
) do
2919 if (gTriggers
[a
].TriggerType
<> TRIGGER_NONE
) and
2920 (gTriggers
[a
].TimeOut
= 0) and
2921 ((gTriggers
[a
].Keys
and k
) = gTriggers
[a
].Keys
) and
2922 ByteBool(gTriggers
[a
].ActivateType
and ActivateType
) then
2923 if g_CollideLine(x1
, y1
, x2
, y2
, gTriggers
[a
].X
, gTriggers
[a
].Y
,
2924 gTriggers
[a
].Width
, gTriggers
[a
].Height
) then
2926 gTriggers
[a
].ActivateUID
:= UID
;
2927 ActivateTrigger(gTriggers
[a
], ActivateType
);
2931 procedure g_Triggers_PressC(CX
, CY
: Integer; Radius
: Word; UID
: Word; ActivateType
: Byte; IgnoreTrigger
: Integer = -1);
2938 if gTriggers
= nil then
2941 case g_GetUIDType(UID
) of
2945 p
:= g_Player_Get(UID
);
2954 rsq
:= Radius
* Radius
;
2956 for a
:= 0 to High(gTriggers
) do
2957 if (gTriggers
[a
].ID
<> DWORD(IgnoreTrigger
)) and
2958 (gTriggers
[a
].TriggerType
<> TRIGGER_NONE
) and
2959 (gTriggers
[a
].TimeOut
= 0) and
2960 ((gTriggers
[a
].Keys
and k
) = gTriggers
[a
].Keys
) and
2961 ByteBool(gTriggers
[a
].ActivateType
and ActivateType
) then
2962 with gTriggers
[a
] do
2963 if g_Collide(CX
-Radius
, CY
-Radius
, 2*Radius
, 2*Radius
,
2964 X
, Y
, Width
, Height
) then
2965 if ((Sqr(CX
-X
)+Sqr(CY
-Y
)) < rsq
) or // Öåíòð êðóãà áëèçîê ê âåðõíåìó ëåâîìó óãëó
2966 ((Sqr(CX
-X
-Width
)+Sqr(CY
-Y
)) < rsq
) or // Öåíòð êðóãà áëèçîê ê âåðõíåìó ïðàâîìó óãëó
2967 ((Sqr(CX
-X
-Width
)+Sqr(CY
-Y
-Height
)) < rsq
) or // Öåíòð êðóãà áëèçîê ê íèæíåìó ïðàâîìó óãëó
2968 ((Sqr(CX
-X
)+Sqr(CY
-Y
-Height
)) < rsq
) or // Öåíòð êðóãà áëèçîê ê íèæíåìó ëåâîìó óãëó
2969 ( (CX
> (X
-Radius
)) and (CX
< (X
+Width
+Radius
)) and
2970 (CY
> Y
) and (CY
< (Y
+Height
)) ) or // Öåíòð êðóãà íåäàëåêî îò âåðòèêàëüíûõ ãðàíèö ïðÿìîóãîëüíèêà
2971 ( (CY
> (Y
-Radius
)) and (CY
< (Y
+Height
+Radius
)) and
2972 (CX
> X
) and (CX
< (X
+Width
)) ) then // Öåíòð êðóãà íåäàëåêî îò ãîðèçîíòàëüíûõ ãðàíèö ïðÿìîóãîëüíèêà
2975 ActivateTrigger(gTriggers
[a
], ActivateType
);
2979 procedure g_Triggers_OpenAll();
2984 if gTriggers
= nil then Exit
;
2987 for a
:= 0 to High(gTriggers
) do
2989 with gTriggers
[a
] do
2991 if (TriggerType
= TRIGGER_OPENDOOR
) or
2992 (TriggerType
= TRIGGER_DOOR5
) or
2993 (TriggerType
= TRIGGER_DOOR
) then
2995 tr_OpenDoor(trigPanelGUID
, True, tgcD2d
);
2996 if TriggerType
= TRIGGER_DOOR5
then DoorTime
:= 180;
3002 if b
then g_Sound_PlayEx('SOUND_GAME_DOOROPEN');
3005 procedure g_Triggers_DecreaseSpawner(ID
: DWORD
);
3007 if (gTriggers
<> nil) then
3008 if gTriggers
[ID
].SpawnedCount
> 0 then
3009 Dec(gTriggers
[ID
].SpawnedCount
);
3013 procedure g_Triggers_Free ();
3017 for a
:= 0 to High(gTriggers
) do
3019 if (gTriggers
[a
].TriggerType
= TRIGGER_SOUND
) then
3021 if g_Sound_Exists(gTriggers
[a
].tgcSoundName
) then
3023 g_Sound_Delete(gTriggers
[a
].tgcSoundName
);
3025 gTriggers
[a
].Sound
.Free();
3027 if (gTriggers
[a
].Activators
<> nil) then
3029 SetLength(gTriggers
[a
].Activators
, 0);
3031 gTriggers
[a
].trigDataRec
.Free();
3033 gTriggers
[a
].exoThink
.Free();
3034 gTriggers
[a
].exoCheck
.Free();
3035 gTriggers
[a
].exoAction
.Free();
3036 gTriggers
[a
].userVars
.Free();
3041 SetLength(gMonstersSpawned
, 0);
3045 procedure g_Triggers_SaveState(var Mem
: TBinMemoryWriter
);
3047 count
, actCount
, i
, j
: Integer;
3051 kv
: THashStrVariant
.PEntry
;
3052 //it: THashStrVariant.TKeyValEnumerator;
3053 //uname: AnsiString;
3056 // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ
3057 count
:= Length(gTriggers
);
3058 Mem
:= TBinMemoryWriter
.Create((count
+1)*200);
3060 // Êîëè÷åñòâî òðèããåðîâ
3061 Mem
.WriteInt(count
);
3062 if (count
= 0) then exit
;
3064 for i
:= 0 to High(gTriggers
) do
3066 // Ñèãíàòóðà òðèããåðà
3067 dw
:= TRIGGER_SIGNATURE
; // 'TRGX'
3070 Mem
.WriteByte(gTriggers
[i
].TriggerType
);
3071 if (gTriggers
[i
].TriggerType
= TRIGGER_NONE
) then continue
; // empty one
3072 // Ñïåöèàëüíûå äàííûå òðèããåðà: ïîòîì èç êàðòû îïÿòü âûòàùèì; ñîõðàíèì òîëüêî èíäåêñ
3073 Mem
.WriteInt(gTriggers
[i
].mapIndex
);
3074 // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà
3075 Mem
.WriteInt(gTriggers
[i
].X
);
3076 Mem
.WriteInt(gTriggers
[i
].Y
);
3078 Mem
.WriteWord(gTriggers
[i
].Width
);
3079 Mem
.WriteWord(gTriggers
[i
].Height
);
3080 // Âêëþ÷åí ëè òðèããåð
3081 Mem
.WriteBoolean(gTriggers
[i
].Enabled
);
3082 // Òèï àêòèâàöèè òðèããåðà
3083 Mem
.WriteByte(gTriggers
[i
].ActivateType
);
3084 // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè
3085 Mem
.WriteByte(gTriggers
[i
].Keys
);
3086 // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ
3087 Mem
.WriteInt(gTriggers
[i
].TexturePanelGUID
);
3089 Mem
.WriteWord(gTriggers
[i
].TexturePanelType
);
3090 // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû)
3091 Mem
.WriteInt(gTriggers
[i
].trigPanelGUID
);
3092 // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè
3093 Mem
.WriteWord(gTriggers
[i
].TimeOut
);
3094 // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð
3095 Mem
.WriteWord(gTriggers
[i
].ActivateUID
);
3096 // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì
3097 actCount
:= Length(gTriggers
[i
].Activators
);
3098 Mem
.WriteInt(actCount
);
3099 for j
:= 0 to actCount
-1 do
3102 Mem
.WriteWord(gTriggers
[i
].Activators
[j
].UID
);
3104 Mem
.WriteWord(gTriggers
[i
].Activators
[j
].TimeOut
);
3106 // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà
3107 Mem
.WriteBoolean(gTriggers
[i
].PlayerCollide
);
3108 // Âðåìÿ äî çàêðûòèÿ äâåðè
3109 Mem
.WriteInt(gTriggers
[i
].DoorTime
);
3110 // Çàäåðæêà àêòèâàöèè
3111 Mem
.WriteInt(gTriggers
[i
].PressTime
);
3113 Mem
.WriteInt(gTriggers
[i
].PressCount
);
3115 Mem
.WriteBoolean(gTriggers
[i
].AutoSpawn
);
3116 // Çàäåðæêà ñïàâíåðà
3117 Mem
.WriteInt(gTriggers
[i
].SpawnCooldown
);
3118 // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ
3119 Mem
.WriteInt(gTriggers
[i
].SpawnedCount
);
3120 // Ñêîëüêî ðàç ïðîèãðàí çâóê
3121 Mem
.WriteInt(gTriggers
[i
].SoundPlayCount
);
3122 // Ïðîèãðûâàåòñÿ ëè çâóê?
3123 if (gTriggers
[i
].Sound
<> nil) then b
:= gTriggers
[i
].Sound
.IsPlaying() else b
:= false;
3124 Mem
.WriteBoolean(b
);
3127 // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà
3128 dw
:= gTriggers
[i
].Sound
.GetPosition();
3131 sg
:= gTriggers
[i
].Sound
.GetVolume();
3132 sg
:= sg
/ (gSoundLevel
/255.0);
3133 Mem
.WriteSingle(sg
);
3134 // Ñòåðåî ñìåùåíèå çâóêà
3135 sg
:= gTriggers
[i
].Sound
.GetPan();
3136 Mem
.WriteSingle(sg
);
3139 if (gTriggers
[i
].userVars
= nil) then
3145 Mem
.WriteInt(gTriggers
[i
].userVars
.count
);
3146 for kv
in gTriggers
[i
].userVars
.byKeyValue
do
3148 //writeln('<', kv.key, '>:<', VarToStr(kv.value), '>');
3149 Mem
.WriteString(kv
.key
);
3150 t
:= LongInt(varType(kv
.value
));
3153 varString
: Mem
.WriteString(AnsiString(kv
.value
));
3154 varBoolean
: Mem
.WriteBoolean(Boolean(kv
.value
));
3155 varShortInt
: Mem
.WriteInt(Integer(kv
.value
));
3156 varSmallint
: Mem
.WriteInt(Integer(kv
.value
));
3157 varInteger
: Mem
.WriteInt(Integer(kv
.value
));
3158 //varInt64: Mem.WriteInt(Integer(kv.value));
3159 varByte
: Mem
.WriteInt(Integer(kv
.value
));
3160 varWord
: Mem
.WriteInt(Integer(kv
.value
));
3161 varLongWord
: Mem
.WriteInt(Integer(kv
.value
));
3163 else raise Exception
.CreateFmt('cannot save uservar ''%s''', [kv
.key
]);
3171 procedure g_Triggers_LoadState (var Mem
: TBinMemoryReader
);
3173 count
, actCount
, i
, j
, a
: Integer;
3187 if (Mem
= nil) then exit
;
3191 // Êîëè÷åñòâî òðèããåðîâ
3193 if (count
= 0) then exit
;
3195 for a
:= 0 to count
-1 do
3197 // Ñèãíàòóðà òðèããåðà
3198 Mem
.ReadDWORD(dw
); // 'TRGX'
3199 if (dw
<> TRIGGER_SIGNATURE
) then raise EBinSizeError
.Create('g_Triggers_LoadState: Wrong Trigger Signature');
3201 Mem
.ReadByte(Trig
.TriggerType
);
3202 // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers']
3203 if (Trig
.TriggerType
= TRIGGER_NONE
) then continue
; // empty one
3204 Mem
.ReadInt(mapIndex
);
3205 i
:= g_Triggers_CreateWithMapIndex(Trig
, a
, mapIndex
);
3206 // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
3207 Mem
.ReadInt(gTriggers
[i
].X
);
3208 Mem
.ReadInt(gTriggers
[i
].Y
);
3210 Mem
.ReadWord(gTriggers
[i
].Width
);
3211 Mem
.ReadWord(gTriggers
[i
].Height
);
3212 // Âêëþ÷åí ëè òðèããåð:
3213 Mem
.ReadBoolean(gTriggers
[i
].Enabled
);
3214 // Òèï àêòèâàöèè òðèããåðà:
3215 Mem
.ReadByte(gTriggers
[i
].ActivateType
);
3216 // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
3217 Mem
.ReadByte(gTriggers
[i
].Keys
);
3218 // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
3219 Mem
.ReadInt(gTriggers
[i
].TexturePanelGUID
);
3221 Mem
.ReadWord(gTriggers
[i
].TexturePanelType
);
3222 // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû)
3223 Mem
.ReadInt(gTriggers
[i
].trigPanelGUID
);
3224 // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
3225 Mem
.ReadWord(gTriggers
[i
].TimeOut
);
3226 // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð:
3227 Mem
.ReadWord(gTriggers
[i
].ActivateUID
);
3228 // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì:
3229 Mem
.ReadInt(actCount
);
3230 if actCount
> 0 then
3232 SetLength(gTriggers
[i
].Activators
, actCount
);
3233 for j
:= 0 to actCount
-1 do
3236 Mem
.ReadWord(gTriggers
[i
].Activators
[j
].UID
);
3238 Mem
.ReadWord(gTriggers
[i
].Activators
[j
].TimeOut
);
3241 // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà:
3242 Mem
.ReadBoolean(gTriggers
[i
].PlayerCollide
);
3243 // Âðåìÿ äî çàêðûòèÿ äâåðè:
3244 Mem
.ReadInt(gTriggers
[i
].DoorTime
);
3245 // Çàäåðæêà àêòèâàöèè:
3246 Mem
.ReadInt(gTriggers
[i
].PressTime
);
3248 Mem
.ReadInt(gTriggers
[i
].PressCount
);
3250 Mem
.ReadBoolean(gTriggers
[i
].AutoSpawn
);
3251 // Çàäåðæêà ñïàâíåðà:
3252 Mem
.ReadInt(gTriggers
[i
].SpawnCooldown
);
3253 // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ:
3254 Mem
.ReadInt(gTriggers
[i
].SpawnedCount
);
3255 // Ñêîëüêî ðàç ïðîèãðàí çâóê:
3256 Mem
.ReadInt(gTriggers
[i
].SoundPlayCount
);
3257 // Ïðîèãðûâàåòñÿ ëè çâóê?
3261 // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà:
3264 Mem
.ReadSingle(vol
);
3265 // Ñòåðåî ñìåùåíèå çâóêà:
3266 Mem
.ReadSingle(pan
);
3267 // Çàïóñêàåì çâóê, åñëè åñòü:
3268 if gTriggers
[i
].Sound
<> nil then
3270 gTriggers
[i
].Sound
.PlayPanVolume(pan
, vol
);
3271 gTriggers
[i
].Sound
.Pause(True);
3272 gTriggers
[i
].Sound
.SetPosition(dw
);
3276 gTriggers
[i
].userVars
.Free();
3277 gTriggers
[i
].userVars
:= nil;
3278 Mem
.ReadInt(uvcount
);
3279 if (uvcount
> 0) then
3281 gTriggers
[i
].userVars
:= THashStrVariant
.Create(hsihash
, hsiequ
);
3283 while (uvcount
> 0) do
3287 Mem
.ReadString(uvname
);
3290 varString
: begin ustr
:= ''; Mem
.ReadString(ustr
); vv
:= ustr
; end;
3291 varBoolean
: begin Mem
.ReadBoolean(ubool
); vv
:= ubool
; end;
3292 varShortInt
: begin Mem
.ReadInt(uint
); vv
:= ShortInt(uint
); end;
3293 varSmallint
: begin Mem
.ReadInt(uint
); vv
:= SmallInt(uint
); end;
3294 varInteger
: begin Mem
.ReadInt(uint
); vv
:= LongInt(uint
); end;
3295 varByte
: begin Mem
.ReadInt(uint
); vv
:= Byte(uint
); end;
3296 varWord
: begin Mem
.ReadInt(uint
); vv
:= Word(uint
); end;
3297 varLongWord
: begin Mem
.ReadInt(uint
); vv
:= LongWord(uint
); end;
3298 else raise Exception
.CreateFmt('cannot load uservar ''%s''', [uvname
]);
3300 gTriggers
[i
].userVars
.put(uvname
, vv
);