DEADSOFTWARE

trigger loading now works; map loading code cleanup
[d2df-sdl.git] / src / game / g_triggers.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
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.
7 *
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.
12 *
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/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit g_triggers;
19 interface
21 uses
22 MAPDEF, e_graphics, g_basic, g_sound,
23 BinEditor, xdynrec;
25 type
26 TActivator = record
27 UID: Word;
28 TimeOut: Word;
29 end;
30 PTrigger = ^TTrigger;
31 TTrigger = record
32 public
33 ID: DWORD;
34 ClientID: DWORD;
35 TriggerType: Byte;
36 X, Y: Integer;
37 Width, Height: Word;
38 Enabled: Boolean;
39 ActivateType: Byte;
40 Keys: Byte;
41 TexturePanel: Integer;
42 TexturePanelType: Word;
44 TimeOut: Word;
45 ActivateUID: Word;
46 Activators: array of TActivator;
47 PlayerCollide: Boolean;
48 DoorTime: Integer;
49 PressTime: Integer;
50 PressCount: Integer;
51 SoundPlayCount: Integer;
52 Sound: TPlayableSound;
53 AutoSpawn: Boolean;
54 SpawnCooldown: Integer;
55 SpawnedCount: Integer;
56 ShotPanelType: Word;
57 ShotPanelTime: Integer;
58 ShotSightTime: Integer;
59 ShotSightTimeout: Integer;
60 ShotSightTarget: Word;
61 ShotSightTargetN: Word;
62 ShotAmmoCount: Word;
63 ShotReloadTime: Integer;
65 mapId: AnsiString; // trigger id, from map
66 //trigShotPanelId: Integer;
67 trigPanelId: Integer;
69 //TrigData: TTriggerData;
70 trigData: TDynRecord; // triggerdata; owned by trigger
72 public
73 function trigCenter (): TDFPoint; inline;
75 public
76 property trigShotPanelId: Integer read trigPanelId write trigPanelId;
77 end;
79 function g_Triggers_Create(Trigger: TTrigger): DWORD;
80 procedure g_Triggers_Update();
81 procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0);
82 function g_Triggers_PressR(X, Y: Integer; Width, Height: Word; UID: Word;
83 ActivateType: Byte; IgnoreList: DWArray = nil): DWArray;
84 procedure g_Triggers_PressL(X1, Y1, X2, Y2: Integer; UID: DWORD; ActivateType: Byte);
85 procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte; IgnoreTrigger: Integer = -1);
86 procedure g_Triggers_OpenAll();
87 procedure g_Triggers_DecreaseSpawner(ID: DWORD);
88 procedure g_Triggers_Free();
89 procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter);
90 procedure g_Triggers_LoadState(var Mem: TBinMemoryReader);
92 function tr_Message(MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean;
94 function tr_CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
95 function tr_OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
96 procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean);
97 function tr_SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
99 function tr_Teleport(ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean;
100 function tr_Push(ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean;
102 procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
103 function tr_SpawnShot(ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer;
105 var
106 gTriggerClientID: Integer = 0;
107 gTriggers: array of TTrigger;
108 gSecretsCount: Integer = 0;
109 gMonstersSpawned: array of LongInt = nil;
111 implementation
113 uses
114 g_player, g_map, Math, g_gfx, g_game, g_textures,
115 g_console, g_monsters, g_items, g_phys, g_weapons,
116 wadreader, g_main, SysUtils, e_log, g_language,
117 g_options, g_net, g_netmsg, utils;
119 const
120 TRIGGER_SIGNATURE = $52475254; // 'TRGR'
121 TRAP_DAMAGE = 1000;
124 function TTrigger.trigCenter (): TDFPoint; inline;
125 begin
126 result := TDFPoint.Create(x+width div 2, y+height div 2);
127 end;
130 function FindTrigger(): DWORD;
131 var
132 i: Integer;
133 begin
134 if gTriggers <> nil then
135 for i := 0 to High(gTriggers) do
136 if gTriggers[i].TriggerType = TRIGGER_NONE then
137 begin
138 Result := i;
139 Exit;
140 end;
142 if gTriggers = nil then
143 begin
144 SetLength(gTriggers, 8);
145 Result := 0;
146 end
147 else
148 begin
149 Result := High(gTriggers) + 1;
150 SetLength(gTriggers, Length(gTriggers) + 8);
151 end;
152 end;
154 function tr_CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
155 var
156 a, b, c: Integer;
157 begin
158 Result := False;
160 if PanelID = -1 then Exit;
162 if not d2d then
163 begin
164 with gWalls[PanelID] do
165 begin
166 if g_CollidePlayer(X, Y, Width, Height) or
167 g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
169 if not Enabled then
170 begin
171 if not NoSound then
172 begin
173 g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y);
174 if g_Game_IsServer and g_Game_IsNet then
175 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
176 end;
177 g_Map_EnableWall(PanelID);
178 Result := True;
179 end;
180 end;
181 end
182 else
183 begin
184 if gDoorMap = nil then Exit;
186 c := -1;
187 for a := 0 to High(gDoorMap) do
188 begin
189 for b := 0 to High(gDoorMap[a]) do
190 if gDoorMap[a, b] = DWORD(PanelID) then
191 begin
192 c := a;
193 Break;
194 end;
196 if c <> -1 then Break;
197 end;
198 if c = -1 then Exit;
200 for b := 0 to High(gDoorMap[c]) do
201 with gWalls[gDoorMap[c, b]] do
202 begin
203 if g_CollidePlayer(X, Y, Width, Height) or
204 g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
205 end;
207 if not NoSound then
208 for b := 0 to High(gDoorMap[c]) do
209 if not gWalls[gDoorMap[c, b]].Enabled then
210 begin
211 with gWalls[PanelID] do
212 begin
213 g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y);
214 if g_Game_IsServer and g_Game_IsNet then
215 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
216 end;
217 Break;
218 end;
220 for b := 0 to High(gDoorMap[c]) do
221 if not gWalls[gDoorMap[c, b]].Enabled then
222 begin
223 g_Map_EnableWall(gDoorMap[c, b]);
224 Result := True;
225 end;
226 end;
227 end;
229 procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean);
230 var
231 a, b, c: Integer;
232 wx, wy, wh, ww: Integer;
234 function monsDamage (mon: TMonster): Boolean;
235 begin
236 result := false; // don't stop
237 if g_Obj_Collide(wx, wy, ww, wh, @mon.Obj) then mon.Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
238 end;
240 begin
241 if PanelID = -1 then Exit;
243 if not d2d then
244 begin
245 with gWalls[PanelID] do
246 begin
247 if (not NoSound) and (not Enabled) then
248 begin
249 g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y);
250 if g_Game_IsServer and g_Game_IsNet then
251 MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1');
252 end;
253 end;
255 wx := gWalls[PanelID].X;
256 wy := gWalls[PanelID].Y;
257 ww := gWalls[PanelID].Width;
258 wh := gWalls[PanelID].Height;
260 with gWalls[PanelID] do
261 begin
262 if gPlayers <> nil then
263 for a := 0 to High(gPlayers) do
264 if (gPlayers[a] <> nil) and gPlayers[a].Live and
265 gPlayers[a].Collide(X, Y, Width, Height) then
266 gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
268 //g_Mons_ForEach(monsDamage);
269 g_Mons_ForEachAliveAt(wx, wy, ww, wh, monsDamage);
271 if not Enabled then g_Map_EnableWall(PanelID);
272 end;
273 end
274 else
275 begin
276 if gDoorMap = nil then Exit;
278 c := -1;
279 for a := 0 to High(gDoorMap) do
280 begin
281 for b := 0 to High(gDoorMap[a]) do
282 begin
283 if gDoorMap[a, b] = DWORD(PanelID) then
284 begin
285 c := a;
286 Break;
287 end;
288 end;
290 if c <> -1 then Break;
291 end;
292 if c = -1 then Exit;
294 if not NoSound then
295 begin
296 for b := 0 to High(gDoorMap[c]) do
297 begin
298 if not gWalls[gDoorMap[c, b]].Enabled then
299 begin
300 with gWalls[PanelID] do
301 begin
302 g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y);
303 if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1');
304 end;
305 Break;
306 end;
307 end;
308 end;
310 for b := 0 to High(gDoorMap[c]) do
311 begin
312 wx := gWalls[gDoorMap[c, b]].X;
313 wy := gWalls[gDoorMap[c, b]].Y;
314 ww := gWalls[gDoorMap[c, b]].Width;
315 wh := gWalls[gDoorMap[c, b]].Height;
317 with gWalls[gDoorMap[c, b]] do
318 begin
319 if gPlayers <> nil then
320 for a := 0 to High(gPlayers) do
321 if (gPlayers[a] <> nil) and gPlayers[a].Live and
322 gPlayers[a].Collide(X, Y, Width, Height) then
323 gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
325 //g_Mons_ForEach(monsDamage);
326 g_Mons_ForEachAliveAt(wx, wy, ww, wh, monsDamage);
327 (*
328 if gMonsters <> nil then
329 for a := 0 to High(gMonsters) do
330 if (gMonsters[a] <> nil) and gMonsters[a].Live and
331 g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then
332 gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
333 *)
335 if not Enabled then g_Map_EnableWall(gDoorMap[c, b]);
336 end;
337 end;
338 end;
339 end;
341 function tr_OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
342 var
343 a, b, c: Integer;
344 begin
345 Result := False;
347 if PanelID = -1 then Exit;
349 if not d2d then
350 begin
351 with gWalls[PanelID] do
352 if Enabled then
353 begin
354 if not NoSound then
355 begin
356 g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y);
357 if g_Game_IsServer and g_Game_IsNet then
358 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
359 end;
360 g_Map_DisableWall(PanelID);
361 Result := True;
362 end;
363 end
364 else
365 begin
366 if gDoorMap = nil then Exit;
368 c := -1;
369 for a := 0 to High(gDoorMap) do
370 begin
371 for b := 0 to High(gDoorMap[a]) do
372 if gDoorMap[a, b] = DWORD(PanelID) then
373 begin
374 c := a;
375 Break;
376 end;
378 if c <> -1 then Break;
379 end;
380 if c = -1 then Exit;
382 if not NoSound then
383 for b := 0 to High(gDoorMap[c]) do
384 if gWalls[gDoorMap[c, b]].Enabled then
385 begin
386 with gWalls[PanelID] do
387 begin
388 g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y);
389 if g_Game_IsServer and g_Game_IsNet then
390 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
391 end;
392 Break;
393 end;
395 for b := 0 to High(gDoorMap[c]) do
396 if gWalls[gDoorMap[c, b]].Enabled then
397 begin
398 g_Map_DisableWall(gDoorMap[c, b]);
399 Result := True;
400 end;
401 end;
402 end;
404 function tr_SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
405 var
406 a, b, c, t: Integer;
407 begin
408 t := 0;
409 Result := False;
411 if PanelID = -1 then Exit;
413 if (gLifts[PanelID].PanelType = PANEL_LIFTUP) or
414 (gLifts[PanelID].PanelType = PANEL_LIFTDOWN) then
415 case d of
416 0: t := 0;
417 1: t := 1;
418 else t := IfThen(gLifts[PanelID].LiftType = 1, 0, 1);
419 end
420 else if (gLifts[PanelID].PanelType = PANEL_LIFTLEFT) or
421 (gLifts[PanelID].PanelType = PANEL_LIFTRIGHT) then
422 case d of
423 0: t := 2;
424 1: t := 3;
425 else t := IfThen(gLifts[PanelID].LiftType = 2, 3, 2);
426 end;
428 if not d2d then
429 begin
430 with gLifts[PanelID] do
431 if LiftType <> t then
432 begin
433 g_Map_SetLift(PanelID, t);
435 {if not NoSound then
436 g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);}
437 Result := True;
438 end;
439 end
440 else // Êàê â D2d
441 begin
442 if gLiftMap = nil then Exit;
444 c := -1;
445 for a := 0 to High(gLiftMap) do
446 begin
447 for b := 0 to High(gLiftMap[a]) do
448 if gLiftMap[a, b] = DWORD(PanelID) then
449 begin
450 c := a;
451 Break;
452 end;
454 if c <> -1 then Break;
455 end;
456 if c = -1 then Exit;
458 {if not NoSound then
459 for b := 0 to High(gLiftMap[c]) do
460 if gLifts[gLiftMap[c, b]].LiftType <> t then
461 begin
462 with gLifts[PanelID] do
463 g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);
464 Break;
465 end;}
467 for b := 0 to High(gLiftMap[c]) do
468 with gLifts[gLiftMap[c, b]] do
469 if LiftType <> t then
470 begin
471 g_Map_SetLift(gLiftMap[c, b], t);
473 Result := True;
474 end;
475 end;
476 end;
478 function tr_SpawnShot(ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer;
479 var
480 snd: string;
481 Projectile: Boolean;
482 TextureID: DWORD;
483 Anim: TAnimation;
484 begin
485 Result := -1;
486 TextureID := DWORD(-1);
487 snd := 'SOUND_WEAPON_FIREROCKET';
488 Projectile := True;
489 case ShotType of
490 TRIGGER_SHOT_PISTOL:
491 begin
492 g_Weapon_pistol(wx, wy, dx, dy, 0, True);
493 snd := 'SOUND_WEAPON_FIREPISTOL';
494 Projectile := False;
495 if ShotSound then
496 begin
497 g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
498 if g_Game_IsNet then
499 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
500 end;
501 end;
503 TRIGGER_SHOT_BULLET:
504 begin
505 g_Weapon_mgun(wx, wy, dx, dy, 0, True);
506 if gSoundEffectsDF then snd := 'SOUND_WEAPON_FIRECGUN'
507 else snd := 'SOUND_WEAPON_FIREPISTOL';
508 Projectile := False;
509 if ShotSound then
510 begin
511 g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
512 if g_Game_IsNet then
513 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
514 end;
515 end;
517 TRIGGER_SHOT_SHOTGUN:
518 begin
519 g_Weapon_Shotgun(wx, wy, dx, dy, 0, True);
520 snd := 'SOUND_WEAPON_FIRESHOTGUN';
521 Projectile := False;
522 if ShotSound then
523 begin
524 g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
525 if g_Game_IsNet then
526 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2);
527 end;
528 end;
530 TRIGGER_SHOT_SSG:
531 begin
532 g_Weapon_DShotgun(wx, wy, dx, dy, 0, True);
533 snd := 'SOUND_WEAPON_FIRESHOTGUN2';
534 Projectile := False;
535 if ShotSound then
536 begin
537 g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
538 g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
539 if g_Game_IsNet then
540 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3);
541 end;
542 end;
544 TRIGGER_SHOT_IMP:
545 begin
546 g_Weapon_ball1(wx, wy, dx, dy, 0, -1, True);
547 snd := 'SOUND_WEAPON_FIREBALL';
548 end;
550 TRIGGER_SHOT_PLASMA:
551 begin
552 g_Weapon_Plasma(wx, wy, dx, dy, 0, -1, True);
553 snd := 'SOUND_WEAPON_FIREPLASMA';
554 end;
556 TRIGGER_SHOT_SPIDER:
557 begin
558 g_Weapon_aplasma(wx, wy, dx, dy, 0, -1, True);
559 snd := 'SOUND_WEAPON_FIREPLASMA';
560 end;
562 TRIGGER_SHOT_CACO:
563 begin
564 g_Weapon_ball2(wx, wy, dx, dy, 0, -1, True);
565 snd := 'SOUND_WEAPON_FIREBALL';
566 end;
568 TRIGGER_SHOT_BARON:
569 begin
570 g_Weapon_ball7(wx, wy, dx, dy, 0, -1, True);
571 snd := 'SOUND_WEAPON_FIREBALL';
572 end;
574 TRIGGER_SHOT_MANCUB:
575 begin
576 g_Weapon_manfire(wx, wy, dx, dy, 0, -1, True);
577 snd := 'SOUND_WEAPON_FIREBALL';
578 end;
580 TRIGGER_SHOT_REV:
581 begin
582 g_Weapon_revf(wx, wy, dx, dy, 0, ShotTarget, -1, True);
583 snd := 'SOUND_WEAPON_FIREREV';
584 end;
586 TRIGGER_SHOT_ROCKET:
587 begin
588 g_Weapon_Rocket(wx, wy, dx, dy, 0, -1, True);
589 snd := 'SOUND_WEAPON_FIREROCKET';
590 end;
592 TRIGGER_SHOT_BFG:
593 begin
594 g_Weapon_BFGShot(wx, wy, dx, dy, 0, -1, True);
595 snd := 'SOUND_WEAPON_FIREBFG';
596 end;
598 TRIGGER_SHOT_EXPL:
599 begin
600 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
601 begin
602 Anim := TAnimation.Create(TextureID, False, 6);
603 Anim.Blending := False;
604 g_GFX_OnceAnim(wx-64, wy-64, Anim);
605 Anim.Free();
606 end;
607 Projectile := False;
608 g_Weapon_Explode(wx, wy, 60, 0);
609 snd := 'SOUND_WEAPON_EXPLODEROCKET';
610 end;
612 TRIGGER_SHOT_BFGEXPL:
613 begin
614 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_BFG') then
615 begin
616 Anim := TAnimation.Create(TextureID, False, 6);
617 Anim.Blending := False;
618 g_GFX_OnceAnim(wx-64, wy-64, Anim);
619 Anim.Free();
620 end;
621 Projectile := False;
622 g_Weapon_BFG9000(wx, wy, 0);
623 snd := 'SOUND_WEAPON_EXPLODEBFG';
624 end;
626 else exit;
627 end;
629 if g_Game_IsNet and g_Game_IsServer then
630 case ShotType of
631 TRIGGER_SHOT_EXPL:
632 MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_EXPLODE);
633 TRIGGER_SHOT_BFGEXPL:
634 MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_BFGEXPL);
635 else
636 begin
637 if Projectile then
638 MH_SEND_CreateShot(LastShotID);
639 if ShotSound then
640 MH_SEND_Sound(wx, wy, snd);
641 end;
642 end;
644 if ShotSound then
645 g_Sound_PlayExAt(snd, wx, wy);
647 if Projectile then
648 Result := LastShotID;
649 end;
651 procedure MakeShot(var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word);
652 begin
653 with Trigger do
654 if (trigData.trigShotAmmo = 0) or
655 ((trigData.trigShotAmmo > 0) and (ShotAmmoCount > 0)) then
656 begin
657 if (trigShotPanelID <> -1) and (ShotPanelTime = 0) then
658 begin
659 g_Map_SwitchTexture(ShotPanelType, trigShotPanelID);
660 ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà
661 end;
663 if trigData.trigShotIntSight > 0 then
664 ShotSightTimeout := 180; // ~= 5 ñåêóíä
666 if ShotAmmoCount > 0 then Dec(ShotAmmoCount);
668 dx := dx + Random(trigData.trigShotAccuracy) - Random(trigData.trigShotAccuracy);
669 dy := dy + Random(trigData.trigShotAccuracy) - Random(trigData.trigShotAccuracy);
671 tr_SpawnShot(trigData.trigShotType, wx, wy, dx, dy, trigData.trigShotSound, TargetUID);
672 end
673 else
674 if (trigData.trigShotIntReload > 0) and (ShotReloadTime = 0) then
675 ShotReloadTime := trigData.trigShotIntReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè
676 end;
678 procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
679 var
680 FramesID: DWORD;
681 Anim: TAnimation;
682 begin
683 if T = TRIGGER_EFFECT_PARTICLE then
684 case ST of
685 TRIGGER_EFFECT_SLIQUID:
686 begin
687 if (CR = 255) and (CG = 0) and (CB = 0) then
688 g_GFX_SimpleWater(X, Y, 1, VX, VY, 1, 0, 0, 0)
689 else if (CR = 0) and (CG = 255) and (CB = 0) then
690 g_GFX_SimpleWater(X, Y, 1, VX, VY, 2, 0, 0, 0)
691 else if (CR = 0) and (CG = 0) and (CB = 255) then
692 g_GFX_SimpleWater(X, Y, 1, VX, VY, 3, 0, 0, 0)
693 else
694 g_GFX_SimpleWater(X, Y, 1, VX, VY, 0, 0, 0, 0);
695 end;
696 TRIGGER_EFFECT_LLIQUID:
697 g_GFX_SimpleWater(X, Y, 1, VX, VY, 4, CR, CG, CB);
698 TRIGGER_EFFECT_DLIQUID:
699 g_GFX_SimpleWater(X, Y, 1, VX, VY, 5, CR, CG, CB);
700 TRIGGER_EFFECT_BLOOD:
701 g_GFX_Blood(X, Y, 1, VX, VY, 0, 0, CR, CG, CB);
702 TRIGGER_EFFECT_SPARK:
703 g_GFX_Spark(X, Y, 1, GetAngle2(VX, VY), 0, 0);
704 TRIGGER_EFFECT_BUBBLE:
705 g_GFX_Bubbles(X, Y, 1, 0, 0);
706 end;
707 if T = TRIGGER_EFFECT_ANIMATION then
708 case ST of
709 EFFECT_TELEPORT: begin
710 if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
711 begin
712 Anim := TAnimation.Create(FramesID, False, 3);
713 if not Silent then
714 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y);
715 g_GFX_OnceAnim(X-32, Y-32, Anim);
716 Anim.Free();
717 end;
718 if Send and g_Game_IsServer and g_Game_IsNet then
719 MH_SEND_Effect(X, Y, Byte(not Silent), NET_GFX_TELE);
720 end;
721 EFFECT_RESPAWN: begin
722 if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
723 begin
724 Anim := TAnimation.Create(FramesID, False, 4);
725 if not Silent then
726 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y);
727 g_GFX_OnceAnim(X-16, Y-16, Anim);
728 Anim.Free();
729 end;
730 if Send and g_Game_IsServer and g_Game_IsNet then
731 MH_SEND_Effect(X-16, Y-16, Byte(not Silent), NET_GFX_RESPAWN);
732 end;
733 EFFECT_FIRE: begin
734 if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
735 begin
736 Anim := TAnimation.Create(FramesID, False, 4);
737 if not Silent then
738 g_Sound_PlayExAt('SOUND_FIRE', X, Y);
739 g_GFX_OnceAnim(X-32, Y-128, Anim);
740 Anim.Free();
741 end;
742 if Send and g_Game_IsServer and g_Game_IsNet then
743 MH_SEND_Effect(X-32, Y-128, Byte(not Silent), NET_GFX_FIRE);
744 end;
745 end;
746 end;
748 function tr_Teleport(ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean;
749 var
750 p: TPlayer;
751 m: TMonster;
752 begin
753 Result := False;
754 if (ActivateUID < 0) or (ActivateUID > $FFFF) then Exit;
755 case g_GetUIDType(ActivateUID) of
756 UID_PLAYER:
757 begin
758 p := g_Player_Get(ActivateUID);
759 if p = nil then
760 Exit;
762 if D2D then
763 begin
764 if p.TeleportTo(TX-(p.Obj.Rect.Width div 2),
765 TY-p.Obj.Rect.Height,
766 Silent,
767 TDir) then
768 Result := True;
769 end
770 else
771 if p.TeleportTo(TX, TY, Silent, TDir) then
772 Result := True;
773 end;
775 UID_MONSTER:
776 begin
777 m := g_Monsters_ByUID(ActivateUID);
778 if m = nil then
779 Exit;
781 if D2D then
782 begin
783 if m.TeleportTo(TX-(m.Obj.Rect.Width div 2),
784 TY-m.Obj.Rect.Height,
785 Silent,
786 TDir) then
787 Result := True;
788 end
789 else
790 if m.TeleportTo(TX, TY, Silent, TDir) then
791 Result := True;
792 end;
793 end;
794 end;
796 function tr_Push(ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean;
797 var
798 p: TPlayer;
799 m: TMonster;
800 begin
801 Result := True;
802 if (ActivateUID < 0) or (ActivateUID > $FFFF) then Exit;
803 case g_GetUIDType(ActivateUID) of
804 UID_PLAYER:
805 begin
806 p := g_Player_Get(ActivateUID);
807 if p = nil then
808 Exit;
810 if ResetVel then
811 begin
812 p.GameVelX := 0;
813 p.GameVelY := 0;
814 p.GameAccelX := 0;
815 p.GameAccelY := 0;
816 end;
818 p.Push(VX, VY);
819 end;
821 UID_MONSTER:
822 begin
823 m := g_Monsters_ByUID(ActivateUID);
824 if m = nil then
825 Exit;
827 if ResetVel then
828 begin
829 m.GameVelX := 0;
830 m.GameVelY := 0;
831 m.GameAccelX := 0;
832 m.GameAccelY := 0;
833 end;
835 m.Push(VX, VY);
836 end;
837 end;
838 end;
840 function tr_Message(MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean;
841 var
842 msg: string;
843 p: TPlayer;
844 i: Integer;
845 begin
846 Result := True;
847 if (ActivateUID < 0) or (ActivateUID > $FFFF) then Exit;
848 msg := b_Text_Format(MText);
849 case MSendTo of
850 0: // activator
851 begin
852 if g_GetUIDType(ActivateUID) = UID_PLAYER then
853 begin
854 if g_Game_IsWatchedPlayer(ActivateUID) then
855 begin
856 if MKind = 0 then
857 g_Console_Add(msg, True)
858 else if MKind = 1 then
859 g_Game_Message(msg, MTime);
860 end
861 else
862 begin
863 p := g_Player_Get(ActivateUID);
864 if g_Game_IsNet and (p.FClientID >= 0) then
865 if MKind = 0 then
866 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, p.FClientID)
867 else if MKind = 1 then
868 MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, p.FClientID);
869 end;
870 end;
871 end;
873 1: // activator's team
874 begin
875 if g_GetUIDType(ActivateUID) = UID_PLAYER then
876 begin
877 p := g_Player_Get(ActivateUID);
878 if g_Game_IsWatchedTeam(p.Team) then
879 if MKind = 0 then
880 g_Console_Add(msg, True)
881 else if MKind = 1 then
882 g_Game_Message(msg, MTime);
884 if g_Game_IsNet then
885 begin
886 for i := Low(gPlayers) to High(gPlayers) do
887 if (gPlayers[i].Team = p.Team) and (gPlayers[i].FClientID >= 0) then
888 if MKind = 0 then
889 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
890 else if MKind = 1 then
891 MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
892 end;
893 end;
894 end;
896 2: // activator's enemy team
897 begin
898 if g_GetUIDType(ActivateUID) = UID_PLAYER then
899 begin
900 p := g_Player_Get(ActivateUID);
901 if g_Game_IsWatchedTeam(p.Team) then
902 if MKind = 0 then
903 g_Console_Add(msg, True)
904 else if MKind = 1 then
905 g_Game_Message(msg, MTime);
907 if g_Game_IsNet then
908 begin
909 for i := Low(gPlayers) to High(gPlayers) do
910 if (gPlayers[i].Team <> p.Team) and (gPlayers[i].FClientID >= 0) then
911 if MKind = 0 then
912 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
913 else if MKind = 1 then
914 MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
915 end;
916 end;
917 end;
919 3: // red team
920 begin
921 if g_Game_IsWatchedTeam(TEAM_RED) then
922 if MKind = 0 then
923 g_Console_Add(msg, True)
924 else if MKind = 1 then
925 g_Game_Message(msg, MTime);
927 if g_Game_IsNet then
928 begin
929 for i := Low(gPlayers) to High(gPlayers) do
930 if (gPlayers[i].Team = TEAM_RED) and (gPlayers[i].FClientID >= 0) then
931 if MKind = 0 then
932 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
933 else if MKind = 1 then
934 MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
935 end;
936 end;
938 4: // blue team
939 begin
940 if g_Game_IsWatchedTeam(TEAM_BLUE) then
941 if MKind = 0 then
942 g_Console_Add(msg, True)
943 else if MKind = 1 then
944 g_Game_Message(msg, MTime);
946 if g_Game_IsNet then
947 begin
948 for i := Low(gPlayers) to High(gPlayers) do
949 if (gPlayers[i].Team = TEAM_BLUE) and (gPlayers[i].FClientID >= 0) then
950 if MKind = 0 then
951 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
952 else if MKind = 1 then
953 MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
954 end;
955 end;
957 5: // everyone
958 begin
959 if MKind = 0 then
960 g_Console_Add(msg, True)
961 else if MKind = 1 then
962 g_Game_Message(msg, MTime);
964 if g_Game_IsNet then
965 begin
966 if MKind = 0 then
967 MH_SEND_Chat(msg, NET_CHAT_SYSTEM)
968 else if MKind = 1 then
969 MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg);
970 end;
971 end;
972 end;
973 end;
975 function tr_ShotAimCheck(var Trigger: TTrigger; Obj: PObj): Boolean;
976 begin
977 result := false;
978 with Trigger do
979 begin
980 if TriggerType <> TRIGGER_SHOT then
981 Exit;
982 Result := (trigData.trigShotAim and TRIGGER_SHOT_AIM_ALLMAP > 0)
983 or g_Obj_Collide(X, Y, Width, Height, Obj);
984 if Result and (trigData.trigShotAim and TRIGGER_SHOT_AIM_TRACE > 0) then
985 Result := g_TraceVector(trigData.trigShotPos.X,
986 trigData.trigShotPos.Y,
987 Obj^.X + Obj^.Rect.X + (Obj^.Rect.Width div 2),
988 Obj^.Y + Obj^.Rect.Y + (Obj^.Rect.Height div 2));
989 end;
990 end;
992 function ActivateTrigger(var Trigger: TTrigger; actType: Byte): Boolean;
993 var
994 animonce: Boolean;
995 p: TPlayer;
996 m: TMonster;
997 idx, k, wx, wy, xd, yd: Integer;
998 iid: LongWord;
999 coolDown: Boolean;
1000 pAngle: Real;
1001 FramesID: DWORD;
1002 Anim: TAnimation;
1003 UIDType: Byte;
1004 TargetUID: Word;
1005 it: PItem;
1006 mon: TMonster;
1008 function monsShotTarget (mon: TMonster): Boolean;
1009 begin
1010 result := false; // don't stop
1011 if mon.Live and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
1012 begin
1013 xd := mon.GameX + mon.Obj.Rect.Width div 2;
1014 yd := mon.GameY + mon.Obj.Rect.Height div 2;
1015 TargetUID := mon.UID;
1016 result := true; // stop
1017 end;
1018 end;
1020 function monsShotTargetMonPlr (mon: TMonster): Boolean;
1021 begin
1022 result := false; // don't stop
1023 if mon.Live and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
1024 begin
1025 xd := mon.GameX + mon.Obj.Rect.Width div 2;
1026 yd := mon.GameY + mon.Obj.Rect.Height div 2;
1027 TargetUID := mon.UID;
1028 result := true; // stop
1029 end;
1030 end;
1032 function monShotTargetPlrMon (mon: TMonster): Boolean;
1033 begin
1034 result := false; // don't stop
1035 if mon.Live and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
1036 begin
1037 xd := mon.GameX + mon.Obj.Rect.Width div 2;
1038 yd := mon.GameY + mon.Obj.Rect.Height div 2;
1039 TargetUID := mon.UID;
1040 result := true; // stop
1041 end;
1042 end;
1044 begin
1045 Result := False;
1046 if g_Game_IsClient then
1047 Exit;
1049 if not Trigger.Enabled then
1050 Exit;
1051 if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then
1052 Exit;
1053 if gLMSRespawn = LMS_RESPAWN_WARMUP then
1054 Exit;
1056 animonce := False;
1058 coolDown := (actType <> 0);
1060 with Trigger do
1061 begin
1062 case TriggerType of
1063 TRIGGER_EXIT:
1064 begin
1065 g_Sound_PlayEx('SOUND_GAME_SWITCH0');
1066 if g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH0');
1067 gExitByTrigger := True;
1068 g_Game_ExitLevel(trigData.trigMapName);
1069 TimeOut := 18;
1070 Result := True;
1072 Exit;
1073 end;
1075 TRIGGER_TELEPORT:
1076 begin
1077 Result := tr_Teleport(ActivateUID,
1078 trigData.trigTargetPoint.X, trigData.trigTargetPoint.Y,
1079 trigData.trigTlpDir, trigData.trigsilent_teleport,
1080 trigData.trigd2d_teleport);
1081 TimeOut := 0;
1082 end;
1084 TRIGGER_OPENDOOR:
1085 begin
1086 Result := tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
1087 TimeOut := 0;
1088 end;
1090 TRIGGER_CLOSEDOOR:
1091 begin
1092 Result := tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
1093 TimeOut := 0;
1094 end;
1096 TRIGGER_DOOR, TRIGGER_DOOR5:
1097 begin
1098 if trigPanelID <> -1 then
1099 begin
1100 if gWalls[trigPanelID].Enabled then
1101 begin
1102 Result := tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
1104 if TriggerType = TRIGGER_DOOR5 then
1105 DoorTime := 180;
1106 end
1107 else
1108 Result := tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
1110 if Result then
1111 TimeOut := 18;
1112 end;
1113 end;
1115 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1116 begin
1117 tr_CloseTrap(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
1119 if TriggerType = TRIGGER_TRAP then
1120 begin
1121 DoorTime := 40;
1122 TimeOut := 76;
1123 end
1124 else
1125 begin
1126 DoorTime := -1;
1127 TimeOut := 0;
1128 end;
1130 Result := True;
1131 end;
1133 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
1134 begin
1135 PressCount := PressCount + 1;
1137 if PressTime = -1 then
1138 PressTime := trigData.trigWait;
1140 if coolDown then
1141 TimeOut := 18
1142 else
1143 TimeOut := 0;
1144 Result := True;
1145 end;
1147 TRIGGER_SECRET:
1148 if g_GetUIDType(ActivateUID) = UID_PLAYER then
1149 begin
1150 Enabled := False;
1151 Result := True;
1152 if gLMSRespawn = LMS_RESPAWN_NONE then
1153 begin
1154 g_Player_Get(ActivateUID).GetSecret();
1155 Inc(gCoopSecretsFound);
1156 if g_Game_IsNet then MH_SEND_GameStats();
1157 end;
1158 end;
1160 TRIGGER_LIFTUP:
1161 begin
1162 Result := tr_SetLift(trigPanelID, 0, trigData.trigNoSound, trigData.trigd2d_doors);
1163 TimeOut := 0;
1165 if (not trigData.trigNoSound) and Result then begin
1166 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
1167 X + (Width div 2),
1168 Y + (Height div 2));
1169 if g_Game_IsServer and g_Game_IsNet then
1170 MH_SEND_Sound(X + (Width div 2),
1171 Y + (Height div 2),
1172 'SOUND_GAME_SWITCH0');
1173 end;
1174 end;
1176 TRIGGER_LIFTDOWN:
1177 begin
1178 Result := tr_SetLift(trigPanelID, 1, trigData.trigNoSound, trigData.trigd2d_doors);
1179 TimeOut := 0;
1181 if (not trigData.trigNoSound) and Result then begin
1182 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
1183 X + (Width div 2),
1184 Y + (Height div 2));
1185 if g_Game_IsServer and g_Game_IsNet then
1186 MH_SEND_Sound(X + (Width div 2),
1187 Y + (Height div 2),
1188 'SOUND_GAME_SWITCH0');
1189 end;
1190 end;
1192 TRIGGER_LIFT:
1193 begin
1194 Result := tr_SetLift(trigPanelID, 3, trigData.trigNoSound, trigData.trigd2d_doors);
1196 if Result then
1197 begin
1198 TimeOut := 18;
1200 if (not trigData.trigNoSound) and Result then begin
1201 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
1202 X + (Width div 2),
1203 Y + (Height div 2));
1204 if g_Game_IsServer and g_Game_IsNet then
1205 MH_SEND_Sound(X + (Width div 2),
1206 Y + (Height div 2),
1207 'SOUND_GAME_SWITCH0');
1208 end;
1209 end;
1210 end;
1212 TRIGGER_TEXTURE:
1213 begin
1214 if trigData.trigActivateOnce then
1215 begin
1216 Enabled := False;
1217 TriggerType := TRIGGER_NONE;
1218 end
1219 else
1220 if coolDown then
1221 TimeOut := 6
1222 else
1223 TimeOut := 0;
1225 animonce := trigData.trigAnimOnce;
1226 Result := True;
1227 end;
1229 TRIGGER_SOUND:
1230 begin
1231 if Sound <> nil then
1232 begin
1233 if trigData.trigSoundSwitch and Sound.IsPlaying() then
1234 begin // Íóæíî âûêëþ÷èòü, åñëè èãðàë
1235 Sound.Stop();
1236 SoundPlayCount := 0;
1237 Result := True;
1238 end
1239 else // (not Data.SoundSwitch) or (not Sound.IsPlaying())
1240 if (trigData.trigPlayCount > 0) or (not Sound.IsPlaying()) then
1241 begin
1242 if trigData.trigPlayCount > 0 then
1243 SoundPlayCount := trigData.trigPlayCount
1244 else // 0 - èãðàåì áåñêîíå÷íî
1245 SoundPlayCount := 1;
1246 Result := True;
1247 end;
1248 if g_Game_IsNet then MH_SEND_TriggerSound(Trigger);
1249 end;
1250 end;
1252 TRIGGER_SPAWNMONSTER:
1253 if (trigData.trigMonType in [MONSTER_DEMON..MONSTER_MAN]) then
1254 begin
1255 Result := False;
1256 if (trigData.trigMonDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
1257 begin
1258 AutoSpawn := not AutoSpawn;
1259 SpawnCooldown := 0;
1260 // Àâòîñïàâíåð ïåðåêëþ÷åí - ìåíÿåì òåêñòóðó
1261 Result := True;
1262 end;
1264 if ((trigData.trigMonDelay = 0) and (actType <> ACTIVATE_CUSTOM))
1265 or ((trigData.trigMonDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
1266 for k := 1 to trigData.trigMonCount do
1267 begin
1268 if (actType = ACTIVATE_CUSTOM) and (trigData.trigMonDelay > 0) then
1269 SpawnCooldown := trigData.trigMonDelay;
1270 if (trigData.trigMonMax > 0) and (SpawnedCount >= trigData.trigMonMax) then
1271 Break;
1273 mon := g_Monsters_Create(trigData.trigMonType,
1274 trigData.trigMonPos.X, trigData.trigMonPos.Y,
1275 TDirection(trigData.trigMonDir), True);
1277 Result := True;
1279 // Çäîðîâüå:
1280 if (trigData.trigMonHealth > 0) then
1281 mon.SetHealth(trigData.trigMonHealth);
1282 // Óñòàíàâëèâàåì ïîâåäåíèå:
1283 mon.MonsterBehaviour := trigData.trigMonBehav;
1284 mon.FNoRespawn := True;
1285 if g_Game_IsNet then
1286 MH_SEND_MonsterSpawn(mon.UID);
1287 // Èäåì èñêàòü öåëü, åñëè íàäî:
1288 if trigData.trigMonActive then
1289 mon.WakeUp();
1291 if trigData.trigMonType <> MONSTER_BARREL then Inc(gTotalMonsters);
1293 if g_Game_IsNet then
1294 begin
1295 SetLength(gMonstersSpawned, Length(gMonstersSpawned)+1);
1296 gMonstersSpawned[High(gMonstersSpawned)] := mon.UID;
1297 end;
1299 if trigData.trigMonMax > 0 then
1300 begin
1301 mon.SpawnTrigger := ID;
1302 Inc(SpawnedCount);
1303 end;
1305 case trigData.trigMonEffect of
1306 EFFECT_TELEPORT: begin
1307 if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
1308 begin
1309 Anim := TAnimation.Create(FramesID, False, 3);
1310 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', trigData.trigMonPos.X, trigData.trigMonPos.Y);
1311 g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32,
1312 mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-32, Anim);
1313 Anim.Free();
1314 end;
1315 if g_Game_IsServer and g_Game_IsNet then
1316 MH_SEND_Effect(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32,
1317 mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-32, 1,
1318 NET_GFX_TELE);
1319 end;
1320 EFFECT_RESPAWN: begin
1321 if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
1322 begin
1323 Anim := TAnimation.Create(FramesID, False, 4);
1324 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', trigData.trigMonPos.X, trigData.trigMonPos.Y);
1325 g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-16,
1326 mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-16, Anim);
1327 Anim.Free();
1328 end;
1329 if g_Game_IsServer and g_Game_IsNet then
1330 MH_SEND_Effect(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-16,
1331 mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-16, 1,
1332 NET_GFX_RESPAWN);
1333 end;
1334 EFFECT_FIRE: begin
1335 if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
1336 begin
1337 Anim := TAnimation.Create(FramesID, False, 4);
1338 g_Sound_PlayExAt('SOUND_FIRE', trigData.trigMonPos.X, trigData.trigMonPos.Y);
1339 g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32,
1340 mon.Obj.Y+mon.Obj.Rect.Y+mon.Obj.Rect.Height-128, Anim);
1341 Anim.Free();
1342 end;
1343 if g_Game_IsServer and g_Game_IsNet then
1344 MH_SEND_Effect(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32,
1345 mon.Obj.Y+mon.Obj.Rect.Y+mon.Obj.Rect.Height-128, 1,
1346 NET_GFX_FIRE);
1347 end;
1348 end;
1349 end;
1350 if g_Game_IsNet then
1351 begin
1352 MH_SEND_GameStats();
1353 MH_SEND_CoopStats();
1354 end;
1356 if coolDown then
1357 TimeOut := 18
1358 else
1359 TimeOut := 0;
1360 // Åñëè àêòèâèðîâàí àâòîñïàâíåðîì, íå ìåíÿåì òåêñòóðó
1361 if actType = ACTIVATE_CUSTOM then
1362 Result := False;
1363 end;
1365 TRIGGER_SPAWNITEM:
1366 if (trigData.trigItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX]) then
1367 begin
1368 Result := False;
1369 if (trigData.trigItemDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
1370 begin
1371 AutoSpawn := not AutoSpawn;
1372 SpawnCooldown := 0;
1373 // Àâòîñïàâíåð ïåðåêëþ÷åí - ìåíÿåì òåêñòóðó
1374 Result := True;
1375 end;
1377 if ((trigData.trigItemDelay = 0) and (actType <> ACTIVATE_CUSTOM))
1378 or ((trigData.trigItemDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
1379 if (not trigData.trigItemOnlyDM) or
1380 (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) then
1381 for k := 1 to trigData.trigItemCount do
1382 begin
1383 if (actType = ACTIVATE_CUSTOM) and (trigData.trigItemDelay > 0) then
1384 SpawnCooldown := trigData.trigItemDelay;
1385 if (trigData.trigItemMax > 0) and (SpawnedCount >= trigData.trigItemMax) then
1386 Break;
1388 iid := g_Items_Create(trigData.trigItemPos.X, trigData.trigItemPos.Y,
1389 trigData.trigItemType, trigData.trigItemFalls, False, True);
1391 Result := True;
1393 if trigData.trigItemMax > 0 then
1394 begin
1395 it := g_Items_ByIdx(iid);
1396 it.SpawnTrigger := ID;
1397 Inc(SpawnedCount);
1398 end;
1400 case trigData.trigItemEffect of
1401 EFFECT_TELEPORT: begin
1402 it := g_Items_ByIdx(iid);
1403 if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
1404 begin
1405 Anim := TAnimation.Create(FramesID, False, 3);
1406 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', trigData.trigItemPos.X, trigData.trigItemPos.Y);
1407 g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32,
1408 it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-32, Anim);
1409 Anim.Free();
1410 end;
1411 if g_Game_IsServer and g_Game_IsNet then
1412 MH_SEND_Effect(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32,
1413 it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-32, 1,
1414 NET_GFX_TELE);
1415 end;
1416 EFFECT_RESPAWN: begin
1417 it := g_Items_ByIdx(iid);
1418 if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
1419 begin
1420 Anim := TAnimation.Create(FramesID, False, 4);
1421 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', trigData.trigItemPos.X, trigData.trigItemPos.Y);
1422 g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-16,
1423 it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-16, Anim);
1424 Anim.Free();
1425 end;
1426 if g_Game_IsServer and g_Game_IsNet then
1427 MH_SEND_Effect(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-16,
1428 it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-16, 1,
1429 NET_GFX_RESPAWN);
1430 end;
1431 EFFECT_FIRE: begin
1432 it := g_Items_ByIdx(iid);
1433 if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
1434 begin
1435 Anim := TAnimation.Create(FramesID, False, 4);
1436 g_Sound_PlayExAt('SOUND_FIRE', trigData.trigItemPos.X, trigData.trigItemPos.Y);
1437 g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32,
1438 it.Obj.Y+it.Obj.Rect.Y+it.Obj.Rect.Height-128, Anim);
1439 Anim.Free();
1440 end;
1441 if g_Game_IsServer and g_Game_IsNet then
1442 MH_SEND_Effect(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32,
1443 it.Obj.Y+it.Obj.Rect.Y+it.Obj.Rect.Height-128, 1,
1444 NET_GFX_FIRE);
1445 end;
1446 end;
1448 if g_Game_IsNet then
1449 MH_SEND_ItemSpawn(True, iid);
1450 end;
1452 if coolDown then
1453 TimeOut := 18
1454 else
1455 TimeOut := 0;
1456 // Åñëè àêòèâèðîâàí àâòîñïàâíåðîì, íå ìåíÿåì òåêñòóðó
1457 if actType = ACTIVATE_CUSTOM then
1458 Result := False;
1459 end;
1461 TRIGGER_MUSIC:
1462 begin
1463 // Ìåíÿåì ìóçûêó, åñëè åñòü íà ÷òî:
1464 if (Trigger.trigData.trigMusicName <> '') then
1465 begin
1466 gMusic.SetByName(Trigger.trigData.trigMusicName);
1467 gMusic.SpecPause := True;
1468 gMusic.Play();
1469 end;
1471 if Trigger.trigData.trigMusicAction = 1 then
1472 begin // Âêëþ÷èòü
1473 if gMusic.SpecPause then // Áûëà íà ïàóçå => èãðàòü
1474 gMusic.SpecPause := False
1475 else // Èãðàëà => ñíà÷àëà
1476 gMusic.SetPosition(0);
1477 end
1478 else // Âûêëþ÷èòü
1479 begin
1480 // Ïàóçà:
1481 gMusic.SpecPause := True;
1482 end;
1484 if coolDown then
1485 TimeOut := 36
1486 else
1487 TimeOut := 0;
1488 Result := True;
1489 if g_Game_IsNet then MH_SEND_TriggerMusic;
1490 end;
1492 TRIGGER_PUSH:
1493 begin
1494 pAngle := -DegToRad(trigData.trigPushAngle);
1495 Result := tr_Push(ActivateUID,
1496 Floor(Cos(pAngle)*trigData.trigPushForce),
1497 Floor(Sin(pAngle)*trigData.trigPushForce),
1498 trigData.trigResetVel);
1499 TimeOut := 0;
1500 end;
1502 TRIGGER_SCORE:
1503 begin
1504 Result := False;
1505 // Ïðèáàâèòü èëè îòíÿòü î÷êî
1506 if (trigData.trigScoreAction in [0..1]) and (trigData.trigScoreCount > 0) then
1507 begin
1508 // Ñâîåé èëè ÷óæîé êîìàíäå
1509 if (trigData.trigScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
1510 begin
1511 p := g_Player_Get(ActivateUID);
1512 if ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED))
1513 or ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1514 begin
1515 Inc(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Scores
1517 if trigData.trigScoreCon then
1518 if trigData.trigScoreTeam = 0 then
1519 begin
1520 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1521 if g_Game_IsServer and g_Game_IsNet then
1522 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+r');
1523 end else
1524 begin
1525 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1526 if g_Game_IsServer and g_Game_IsNet then
1527 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+re');
1528 end;
1530 if trigData.trigScoreMsg then
1531 begin
1532 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1533 if g_Game_IsServer and g_Game_IsNet then
1534 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED);
1535 end;
1536 end;
1537 if ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED))
1538 or ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1539 begin
1540 Dec(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Fouls
1542 if trigData.trigScoreCon then
1543 if trigData.trigScoreTeam = 0 then
1544 begin
1545 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1546 if g_Game_IsServer and g_Game_IsNet then
1547 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-r');
1548 end else
1549 begin
1550 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1551 if g_Game_IsServer and g_Game_IsNet then
1552 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-re');
1553 end;
1555 if trigData.trigScoreMsg then
1556 begin
1557 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1558 if g_Game_IsServer and g_Game_IsNet then
1559 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED);
1560 end;
1561 end;
1562 if ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE))
1563 or ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
1564 begin
1565 Inc(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Scores
1567 if trigData.trigScoreCon then
1568 if trigData.trigScoreTeam = 0 then
1569 begin
1570 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1571 if g_Game_IsServer and g_Game_IsNet then
1572 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+b');
1573 end else
1574 begin
1575 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1576 if g_Game_IsServer and g_Game_IsNet then
1577 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+be');
1578 end;
1580 if trigData.trigScoreMsg then
1581 begin
1582 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1583 if g_Game_IsServer and g_Game_IsNet then
1584 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE);
1585 end;
1586 end;
1587 if ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE))
1588 or ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
1589 begin
1590 Dec(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Fouls
1592 if trigData.trigScoreCon then
1593 if trigData.trigScoreTeam = 0 then
1594 begin
1595 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1596 if g_Game_IsServer and g_Game_IsNet then
1597 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-b');
1598 end else
1599 begin
1600 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1601 if g_Game_IsServer and g_Game_IsNet then
1602 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-be');
1603 end;
1605 if trigData.trigScoreMsg then
1606 begin
1607 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1608 if g_Game_IsServer and g_Game_IsNet then
1609 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_BLUE);
1610 end;
1611 end;
1612 Result := (p.Team = TEAM_RED) or (p.Team = TEAM_BLUE);
1613 end;
1614 // Êàêîé-òî êîíêðåòíîé êîìàíäå
1615 if trigData.trigScoreTeam in [2..3] then
1616 begin
1617 if (trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 2) then
1618 begin
1619 Inc(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Scores
1621 if trigData.trigScoreCon then
1622 begin
1623 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_RED], trigData.trigScoreCount]), True);
1624 if g_Game_IsServer and g_Game_IsNet then
1625 MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '+tr');
1626 end;
1628 if trigData.trigScoreMsg then
1629 begin
1630 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1631 if g_Game_IsServer and g_Game_IsNet then
1632 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED);
1633 end;
1634 end;
1635 if (trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 2) then
1636 begin
1637 Dec(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Fouls
1639 if trigData.trigScoreCon then
1640 begin
1641 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_RED], trigData.trigScoreCount]), True);
1642 if g_Game_IsServer and g_Game_IsNet then
1643 MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '-tr');
1644 end;
1646 if trigData.trigScoreMsg then
1647 begin
1648 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1649 if g_Game_IsServer and g_Game_IsNet then
1650 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED);
1651 end;
1652 end;
1653 if (trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 3) then
1654 begin
1655 Inc(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Scores
1657 if trigData.trigScoreCon then
1658 begin
1659 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_BLUE], trigData.trigScoreCount]), True);
1660 if g_Game_IsServer and g_Game_IsNet then
1661 MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '+tb');
1662 end;
1664 if trigData.trigScoreMsg then
1665 begin
1666 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1667 if g_Game_IsServer and g_Game_IsNet then
1668 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE);
1669 end;
1670 end;
1671 if (trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 3) then
1672 begin
1673 Dec(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Fouls
1675 if trigData.trigScoreCon then
1676 begin
1677 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_BLUE], trigData.trigScoreCount]), True);
1678 if g_Game_IsServer and g_Game_IsNet then
1679 MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '-tb');
1680 end;
1682 if trigData.trigScoreMsg then
1683 begin
1684 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1685 if g_Game_IsServer and g_Game_IsNet then
1686 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_BLUE);
1687 end;
1688 end;
1689 Result := True;
1690 end;
1691 end;
1692 // Âûèãðûø
1693 if (trigData.trigScoreAction = 2) and (gGameSettings.GoalLimit > 0) then
1694 begin
1695 // Ñâîåé èëè ÷óæîé êîìàíäû
1696 if (trigData.trigScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
1697 begin
1698 p := g_Player_Get(ActivateUID);
1699 if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED)) // Red Wins
1700 or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1701 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1702 begin
1703 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1705 if trigData.trigScoreCon then
1706 if trigData.trigScoreTeam = 0 then
1707 begin
1708 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1709 if g_Game_IsServer and g_Game_IsNet then
1710 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wr');
1711 end else
1712 begin
1713 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1714 if g_Game_IsServer and g_Game_IsNet then
1715 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wre');
1716 end;
1718 Result := True;
1719 end;
1720 if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Blue Wins
1721 or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
1722 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1723 begin
1724 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1726 if trigData.trigScoreCon then
1727 if trigData.trigScoreTeam = 0 then
1728 begin
1729 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1730 if g_Game_IsServer and g_Game_IsNet then
1731 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wb');
1732 end else
1733 begin
1734 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1735 if g_Game_IsServer and g_Game_IsNet then
1736 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wbe');
1737 end;
1739 Result := True;
1740 end;
1741 end;
1742 // Êàêîé-òî êîíêðåòíîé êîìàíäû
1743 if trigData.trigScoreTeam in [2..3] then
1744 begin
1745 if trigData.trigScoreTeam = 2 then // Red Wins
1746 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1747 begin
1748 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1749 Result := True;
1750 end;
1751 if trigData.trigScoreTeam = 3 then // Blue Wins
1752 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1753 begin
1754 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1755 Result := True;
1756 end;
1757 end;
1758 end;
1759 // Ïðîèãðûø
1760 if (trigData.trigScoreAction = 3) and (gGameSettings.GoalLimit > 0) then
1761 begin
1762 // Ñâîåé èëè ÷óæîé êîìàíäû
1763 if (trigData.trigScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
1764 begin
1765 p := g_Player_Get(ActivateUID);
1766 if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Red Wins
1767 or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
1768 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1769 begin
1770 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1772 if trigData.trigScoreCon then
1773 if trigData.trigScoreTeam = 0 then
1774 begin
1775 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1776 if g_Game_IsServer and g_Game_IsNet then
1777 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wre');
1778 end else
1779 begin
1780 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1781 if g_Game_IsServer and g_Game_IsNet then
1782 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wr');
1783 end;
1785 Result := True;
1786 end;
1787 if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED)) // Blue Wins
1788 or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1789 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1790 begin
1791 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1793 if trigData.trigScoreCon then
1794 if trigData.trigScoreTeam = 0 then
1795 begin
1796 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1797 if g_Game_IsServer and g_Game_IsNet then
1798 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wbe');
1799 end else
1800 begin
1801 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1802 if g_Game_IsServer and g_Game_IsNet then
1803 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wb');
1804 end;
1806 Result := True;
1807 end;
1808 end;
1809 // Êàêîé-òî êîíêðåòíîé êîìàíäû
1810 if trigData.trigScoreTeam in [2..3] then
1811 begin
1812 if trigData.trigScoreTeam = 3 then // Red Wins
1813 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1814 begin
1815 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1816 Result := True;
1817 end;
1818 if trigData.trigScoreTeam = 2 then // Blue Wins
1819 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1820 begin
1821 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1822 Result := True;
1823 end;
1824 end;
1825 end;
1826 if Result then begin
1827 if coolDown then
1828 TimeOut := 18
1829 else
1830 TimeOut := 0;
1831 if g_Game_IsServer and g_Game_IsNet then
1832 MH_SEND_GameStats;
1833 end;
1834 end;
1836 TRIGGER_MESSAGE:
1837 begin
1838 Result := tr_Message(trigData.trigMessageKind, trigData.trigMessageText,
1839 trigData.trigMessageSendTo, trigData.trigMessageTime,
1840 ActivateUID);
1841 TimeOut := 18;
1842 end;
1844 TRIGGER_DAMAGE, TRIGGER_HEALTH:
1845 begin
1846 Result := False;
1847 UIDType := g_GetUIDType(ActivateUID);
1848 if (UIDType = UID_PLAYER) or (UIDType = UID_MONSTER) then
1849 begin
1850 Result := True;
1851 k := -1;
1852 if coolDown then
1853 begin
1854 // Âñïîìèíàåì, àêòèâèðîâàë ëè îí ìåíÿ ðàíüøå
1855 for idx := 0 to High(Activators) do
1856 if Activators[idx].UID = ActivateUID then
1857 begin
1858 k := idx;
1859 Break;
1860 end;
1861 if k = -1 then
1862 begin // Âèäèì åãî âïåðâûå
1863 // Çàïîìèíàåì åãî
1864 SetLength(Activators, Length(Activators) + 1);
1865 k := High(Activators);
1866 Activators[k].UID := ActivateUID;
1867 end else
1868 begin // Óæå âèäåëè åãî
1869 // Åñëè èíòåðâàë îòêëþ÷¸í, íî îí âñ¸ åù¸ â çîíå ïîðàæåíèÿ, äà¸ì åìó âðåìÿ
1870 if (trigData.trigDamageInterval = 0) and (Activators[k].TimeOut > 0) then
1871 Activators[k].TimeOut := 65535;
1872 // Òàéìàóò ïðîø¸ë - ðàáîòàåì
1873 Result := Activators[k].TimeOut = 0;
1874 end;
1875 end;
1877 if Result then
1878 begin
1879 case UIDType of
1880 UID_PLAYER:
1881 begin
1882 p := g_Player_Get(ActivateUID);
1883 if p = nil then
1884 Exit;
1886 // Íàíîñèì óðîí èãðîêó
1887 if (TriggerType = TRIGGER_DAMAGE) and (trigData.trigDamageValue > 0) then
1888 p.Damage(trigData.trigDamageValue, 0, 0, 0, HIT_SOME);
1890 // Ëå÷èì èãðîêà
1891 if (TriggerType = TRIGGER_HEALTH) and (trigData.trigHealValue > 0) then
1892 if p.Heal(trigData.trigHealValue, not trigData.trigHealMax) and (not trigData.trigHealSilent) then
1893 begin
1894 g_Sound_PlayExAt('SOUND_ITEM_GETITEM', p.Obj.X, p.Obj.Y);
1895 if g_Game_IsServer and g_Game_IsNet then
1896 MH_SEND_Sound(p.Obj.X, p.Obj.Y, 'SOUND_ITEM_GETITEM');
1897 end;
1898 end;
1900 UID_MONSTER:
1901 begin
1902 m := g_Monsters_ByUID(ActivateUID);
1903 if m = nil then
1904 Exit;
1906 // Íàíîñèì óðîí ìîíñòðó
1907 if (TriggerType = TRIGGER_DAMAGE) and (trigData.trigDamageValue > 0) then
1908 m.Damage(trigData.trigDamageValue, 0, 0, 0, HIT_SOME);
1910 // Ëå÷èì ìîíñòðà
1911 if (TriggerType = TRIGGER_HEALTH) and (trigData.trigHealValue > 0) then
1912 if m.Heal(trigData.trigHealValue) and (not trigData.trigHealSilent) then
1913 begin
1914 g_Sound_PlayExAt('SOUND_ITEM_GETITEM', m.Obj.X, m.Obj.Y);
1915 if g_Game_IsServer and g_Game_IsNet then
1916 MH_SEND_Sound(m.Obj.X, m.Obj.Y, 'SOUND_ITEM_GETITEM');
1917 end;
1918 end;
1919 end;
1920 // Íàçíà÷àåì âðåìÿ ñëåäóþùåãî âîçäåéñòâèÿ
1921 if TriggerType = TRIGGER_DAMAGE then
1922 idx := trigData.trigDamageInterval
1923 else
1924 idx := trigData.trigHealInterval;
1925 if coolDown then
1926 if idx > 0 then
1927 Activators[k].TimeOut := idx
1928 else
1929 Activators[k].TimeOut := 65535;
1930 end;
1931 end;
1932 TimeOut := 0;
1933 end;
1935 TRIGGER_SHOT:
1936 begin
1937 if ShotSightTime > 0 then
1938 Exit;
1940 // put this at the beginning so it doesn't trigger itself
1941 TimeOut := trigData.trigShotWait + 1;
1943 wx := trigData.trigShotPos.X;
1944 wy := trigData.trigShotPos.Y;
1945 pAngle := -DegToRad(trigData.trigShotAngle);
1946 xd := wx + Round(Cos(pAngle) * 32.0);
1947 yd := wy + Round(Sin(pAngle) * 32.0);
1948 TargetUID := 0;
1950 case trigData.trigShotTarget of
1951 TRIGGER_SHOT_TARGET_MON: // monsters
1952 //TODO: accelerate this!
1953 g_Mons_ForEachAlive(monsShotTarget);
1955 TRIGGER_SHOT_TARGET_PLR: // players
1956 if gPlayers <> nil then
1957 for idx := Low(gPlayers) to High(gPlayers) do
1958 if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
1959 tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
1960 begin
1961 xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
1962 yd := gPlayers[idx].GameY + PLAYER_RECT_CY;
1963 TargetUID := gPlayers[idx].UID;
1964 break;
1965 end;
1967 TRIGGER_SHOT_TARGET_RED: // red team
1968 if gPlayers <> nil then
1969 for idx := Low(gPlayers) to High(gPlayers) do
1970 if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
1971 (gPlayers[idx].Team = TEAM_RED) and
1972 tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
1973 begin
1974 xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
1975 yd := gPlayers[idx].GameY + PLAYER_RECT_CY;
1976 TargetUID := gPlayers[idx].UID;
1977 break;
1978 end;
1980 TRIGGER_SHOT_TARGET_BLUE: // blue team
1981 if gPlayers <> nil then
1982 for idx := Low(gPlayers) to High(gPlayers) do
1983 if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
1984 (gPlayers[idx].Team = TEAM_BLUE) and
1985 tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
1986 begin
1987 xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
1988 yd := gPlayers[idx].GameY + PLAYER_RECT_CY;
1989 TargetUID := gPlayers[idx].UID;
1990 break;
1991 end;
1993 TRIGGER_SHOT_TARGET_MONPLR: // monsters then players
1994 begin
1995 //TODO: accelerate this!
1996 g_Mons_ForEachAlive(monsShotTargetMonPlr);
1998 if (TargetUID = 0) and (gPlayers <> nil) then
1999 for idx := Low(gPlayers) to High(gPlayers) do
2000 if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
2001 tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
2002 begin
2003 xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
2004 yd := gPlayers[idx].GameY + PLAYER_RECT_CY;
2005 TargetUID := gPlayers[idx].UID;
2006 break;
2007 end;
2008 end;
2010 TRIGGER_SHOT_TARGET_PLRMON: // players then monsters
2011 begin
2012 if gPlayers <> nil then
2013 for idx := Low(gPlayers) to High(gPlayers) do
2014 if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
2015 tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
2016 begin
2017 xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
2018 yd := gPlayers[idx].GameY + PLAYER_RECT_CY;
2019 TargetUID := gPlayers[idx].UID;
2020 break;
2021 end;
2022 if TargetUID = 0 then
2023 begin
2024 //TODO: accelerate this!
2025 g_Mons_ForEachAlive(monShotTargetPlrMon);
2026 end;
2027 end;
2029 else begin
2030 if (trigData.trigShotTarget <> TRIGGER_SHOT_TARGET_NONE) or
2031 (trigData.trigShotType <> TRIGGER_SHOT_REV) then
2032 TargetUID := ActivateUID;
2033 end;
2034 end;
2036 if (trigData.trigShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID > 0) or
2037 ((trigData.trigShotTarget > TRIGGER_SHOT_TARGET_NONE) and (TargetUID = 0)) then
2038 begin
2039 Result := True;
2040 if (trigData.trigShotIntSight = 0) or
2041 (trigData.trigShotTarget = TRIGGER_SHOT_TARGET_NONE) or
2042 (TargetUID = ShotSightTarget) then
2043 MakeShot(Trigger, wx, wy, xd, yd, TargetUID)
2044 else
2045 begin
2046 ShotSightTime := trigData.trigShotIntSight;
2047 ShotSightTargetN := TargetUID;
2048 if trigData.trigShotType = TRIGGER_SHOT_BFG then
2049 begin
2050 g_Sound_PlayExAt('SOUND_WEAPON_STARTFIREBFG', wx, wy);
2051 if g_Game_IsNet and g_Game_IsServer then
2052 MH_SEND_Sound(wx, wy, 'SOUND_WEAPON_STARTFIREBFG');
2053 end;
2054 end;
2055 end;
2056 end;
2058 TRIGGER_EFFECT:
2059 begin
2060 idx := trigData.trigFXCount;
2062 while idx > 0 do
2063 begin
2064 case trigData.trigFXPos of
2065 TRIGGER_EFFECT_POS_CENTER:
2066 begin
2067 wx := X + Width div 2;
2068 wy := Y + Height div 2;
2069 end;
2070 TRIGGER_EFFECT_POS_AREA:
2071 begin
2072 wx := X + Random(Width);
2073 wy := Y + Random(Height);
2074 end;
2075 else begin
2076 wx := X + Width div 2;
2077 wy := Y + Height div 2;
2078 end;
2079 end;
2080 xd := trigData.trigFXVelX;
2081 yd := trigData.trigFXVelY;
2082 if trigData.trigFXSpreadL > 0 then xd := xd - Random(trigData.trigFXSpreadL + 1);
2083 if trigData.trigFXSpreadR > 0 then xd := xd + Random(trigData.trigFXSpreadR + 1);
2084 if trigData.trigFXSpreadU > 0 then yd := yd - Random(trigData.trigFXSpreadU + 1);
2085 if trigData.trigFXSpreadD > 0 then yd := yd + Random(trigData.trigFXSpreadD + 1);
2086 tr_MakeEffect(wx, wy, xd, yd,
2087 trigData.trigFXType, trigData.trigFXSubType,
2088 trigData.trigFXColorR, trigData.trigFXColorG, trigData.trigFXColorB, True, False);
2089 Dec(idx);
2090 end;
2091 TimeOut := trigData.trigFXWait;
2092 end;
2093 end;
2094 end;
2096 if Result and (Trigger.TexturePanel <> -1) then
2097 g_Map_SwitchTexture(Trigger.TexturePanelType, Trigger.TexturePanel, IfThen(animonce, 2, 1));
2098 end;
2100 function g_Triggers_Create(Trigger: TTrigger): DWORD;
2101 var
2102 find_id: DWORD;
2103 fn, mapw: String;
2104 begin
2105 // Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà:
2106 if (Trigger.TriggerType = TRIGGER_EXIT) and
2107 (not LongBool(gGameSettings.Options and GAME_OPTION_ALLOWEXIT)) then
2108 Trigger.TriggerType := TRIGGER_NONE;
2110 // Åñëè ìîíñòðû çàïðåùåíû, îòìåíÿåì òðèããåð:
2111 if (Trigger.TriggerType = TRIGGER_SPAWNMONSTER) and
2112 (not LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS)) and
2113 (gGameSettings.GameType <> GT_SINGLE) then
2114 Trigger.TriggerType := TRIGGER_NONE;
2116 // Ñ÷èòàåì êîëè÷åñòâî ñåêðåòîâ íà êàðòå:
2117 if Trigger.TriggerType = TRIGGER_SECRET then
2118 gSecretsCount := gSecretsCount + 1;
2120 find_id := FindTrigger();
2121 gTriggers[find_id] := Trigger;
2124 writeln('trigger #', find_id, ': pos=(', Trigger.x, ',', Trigger.y, ')-(', Trigger.width, 'x', Trigger.height, ')',
2125 '; TexturePanel=', Trigger.TexturePanel,
2126 '; TexturePanelType=', Trigger.TexturePanelType,
2127 '; ShotPanelType=', Trigger.ShotPanelType,
2128 '; TriggerType=', Trigger.TriggerType,
2129 '; ActivateType=', Trigger.ActivateType,
2130 '; Keys=', Trigger.Keys,
2131 '; trigPanelId=', Trigger.trigPanelId,
2132 '; trigShotPanelId=', Trigger.trigShotPanelId
2133 );
2136 with gTriggers[find_id] do
2137 begin
2138 ID := find_id;
2139 // if this type of trigger exists both on the client and on the server
2140 // use an uniform numeration
2141 if Trigger.TriggerType = TRIGGER_SOUND then
2142 begin
2143 Inc(gTriggerClientID);
2144 ClientID := gTriggerClientID;
2145 end
2146 else
2147 ClientID := 0;
2148 TimeOut := 0;
2149 ActivateUID := 0;
2150 PlayerCollide := False;
2151 DoorTime := -1;
2152 PressTime := -1;
2153 PressCount := 0;
2154 SoundPlayCount := 0;
2155 Sound := nil;
2156 AutoSpawn := False;
2157 SpawnCooldown := 0;
2158 SpawnedCount := 0;
2159 end;
2161 // Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê":
2162 if (Trigger.TriggerType = TRIGGER_SOUND) and
2163 (Trigger.trigData.trigSoundName <> '') then
2164 begin
2165 // Åùå íåò òàêîãî çâóêà:
2166 if not g_Sound_Exists(Trigger.trigData.trigSoundName) then
2167 begin
2168 fn := g_ExtractWadName(Trigger.trigData.trigSoundName);
2170 if fn = '' then
2171 begin // Çâóê â ôàéëå ñ êàðòîé
2172 mapw := g_ExtractWadName(gMapInfo.Map);
2173 fn := mapw+':'+g_ExtractFilePathName(Trigger.trigData.trigSoundName);
2174 end
2175 else // Çâóê â îòäåëüíîì ôàéëå
2176 fn := GameDir + '/wads/' + Trigger.trigData.trigSoundName;
2178 if not g_Sound_CreateWADEx(Trigger.trigData.trigSoundName, fn) then
2179 g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.trigData.trigSoundName]));
2180 end;
2182 // Ñîçäàåì îáúåêò çâóêà:
2183 with gTriggers[find_id] do
2184 begin
2185 Sound := TPlayableSound.Create();
2186 if not Sound.SetByName(Trigger.trigData.trigSoundName) then
2187 begin
2188 Sound.Free();
2189 Sound := nil;
2190 end;
2191 end;
2192 end;
2194 // Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà":
2195 if (Trigger.TriggerType = TRIGGER_MUSIC) and
2196 (Trigger.trigData.trigMusicName <> '') then
2197 begin
2198 // Åùå íåò òàêîé ìóçûêè:
2199 if not g_Sound_Exists(Trigger.trigData.trigMusicName) then
2200 begin
2201 fn := g_ExtractWadName(Trigger.trigData.trigMusicName);
2203 if fn = '' then
2204 begin // Ìóçûêà â ôàéëå ñ êàðòîé
2205 mapw := g_ExtractWadName(gMapInfo.Map);
2206 fn := mapw+':'+g_ExtractFilePathName(Trigger.trigData.trigMusicName);
2207 end
2208 else // Ìóçûêà â ôàéëå ñ êàðòîé
2209 fn := GameDir+'/wads/'+Trigger.trigData.trigMusicName;
2211 if not g_Sound_CreateWADEx(Trigger.trigData.trigMusicName, fn, True) then
2212 g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.trigData.trigMusicName]));
2213 end;
2214 end;
2216 // Çàãðóæàåì äàííûå òðèããåðà "Òóðåëü":
2217 if Trigger.TriggerType = TRIGGER_SHOT then
2218 with gTriggers[find_id] do
2219 begin
2220 ShotPanelTime := 0;
2221 ShotSightTime := 0;
2222 ShotSightTimeout := 0;
2223 ShotSightTarget := 0;
2224 ShotSightTargetN := 0;
2225 ShotAmmoCount := Trigger.trigData.trigShotAmmo;
2226 ShotReloadTime := 0;
2227 end;
2229 Result := find_id;
2230 end;
2233 // sorry; grid doesn't support recursive queries, so we have to do this
2234 type
2235 TSimpleMonsterList = specialize TSimpleList<TMonster>;
2237 var
2238 tgMonsList: TSimpleMonsterList = nil;
2240 procedure g_Triggers_Update();
2241 var
2242 a, b, i: Integer;
2243 Affected: array of Integer;
2245 function monsNear (mon: TMonster): Boolean;
2246 begin
2247 result := false; // don't stop
2249 gTriggers[a].ActivateUID := mon.UID;
2250 ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE);
2252 tgMonsList.append(mon);
2253 end;
2255 var
2256 mon: TMonster;
2257 begin
2258 if (tgMonsList = nil) then tgMonsList := TSimpleMonsterList.Create();
2260 if gTriggers = nil then
2261 Exit;
2262 SetLength(Affected, 0);
2264 for a := 0 to High(gTriggers) do
2265 with gTriggers[a] do
2266 // Åñòü òðèããåð:
2267 if TriggerType <> TRIGGER_NONE then
2268 begin
2269 // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè):
2270 if DoorTime > 0 then
2271 DoorTime := DoorTime - 1;
2272 // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ:
2273 if PressTime > 0 then
2274 PressTime := PressTime - 1;
2275 // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè:
2276 if (TriggerType = TRIGGER_DAMAGE) or (TriggerType = TRIGGER_HEALTH) then
2277 for b := 0 to High(Activators) do
2278 begin
2279 // Óìåíüøàåì âðåìÿ äî ïîâòîðíîãî âîçäåéñòâèÿ:
2280 if Activators[b].TimeOut > 0 then
2281 Dec(Activators[b].TimeOut)
2282 else
2283 Continue;
2284 // Ñ÷èòàåì, ÷òî îáúåêò ïîêèíóë çîíó äåéñòâèÿ òðèããåðà
2285 if (trigData.trigDamageInterval = 0) and (Activators[b].TimeOut < 65530) then
2286 Activators[b].TimeOut := 0;
2287 end;
2289 // Îáðàáàòûâàåì ñïàâíåðû:
2290 if Enabled and AutoSpawn then
2291 if SpawnCooldown = 0 then
2292 begin
2293 // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà:
2294 if (TriggerType = TRIGGER_SPAWNMONSTER) and (trigData.trigMonDelay > 0) then
2295 begin
2296 ActivateUID := 0;
2297 ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
2298 end;
2299 // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò:
2300 if (TriggerType = TRIGGER_SPAWNITEM) and (trigData.trigItemDelay > 0) then
2301 begin
2302 ActivateUID := 0;
2303 ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
2304 end;
2305 end else // Óìåíüøàåì âðåìÿ îæèäàíèÿ:
2306 Dec(SpawnCooldown);
2308 // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü":
2309 if TriggerType = TRIGGER_SHOT then
2310 begin
2311 if ShotPanelTime > 0 then
2312 begin
2313 Dec(ShotPanelTime);
2314 if ShotPanelTime = 0 then
2315 g_Map_SwitchTexture(ShotPanelType, trigShotPanelID);
2316 end;
2317 if ShotSightTime > 0 then
2318 begin
2319 Dec(ShotSightTime);
2320 if ShotSightTime = 0 then
2321 ShotSightTarget := ShotSightTargetN;
2322 end;
2323 if ShotSightTimeout > 0 then
2324 begin
2325 Dec(ShotSightTimeout);
2326 if ShotSightTimeout = 0 then
2327 ShotSightTarget := 0;
2328 end;
2329 if ShotReloadTime > 0 then
2330 begin
2331 Dec(ShotReloadTime);
2332 if ShotReloadTime = 0 then
2333 ShotAmmoCount := trigData.trigShotAmmo;
2334 end;
2335 end;
2337 // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì:
2338 if Enabled and (TriggerType = TRIGGER_SOUND) and (Sound <> nil) then
2339 if (SoundPlayCount > 0) and (not Sound.IsPlaying()) then
2340 begin
2341 if trigData.trigPlayCount > 0 then // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
2342 SoundPlayCount := SoundPlayCount - 1;
2343 if trigData.trigLocal then
2344 Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0)
2345 else
2346 Sound.PlayPanVolume((trigData.trigPan-127.0)/128.0, trigData.trigVolume/255.0);
2347 if Sound.IsPlaying() and g_Game_IsNet and g_Game_IsServer then
2348 MH_SEND_TriggerSound(gTriggers[a]);
2349 end;
2351 // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü:
2352 if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (trigPanelID <> -1) then
2353 begin
2354 tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
2355 DoorTime := -1;
2356 end;
2358 // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü:
2359 if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (trigPanelID <> -1) then
2360 begin
2361 // Óæå çàêðûòà:
2362 if gWalls[trigPanelID].Enabled then
2363 DoorTime := -1
2364 else // Ïîêà îòêðûòà - çàêðûâàåì
2365 if tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors) then
2366 DoorTime := -1;
2367 end;
2369 // Òðèããåð - ðàñøèðèòåëü èëè ïåðåêëþ÷àòåëü, è ïðîøëà çàäåðæêà, è íàæàëè íóæíîå ÷èñëî ðàç:
2370 if (TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) and
2371 (PressTime = 0) and (PressCount >= trigData.trigCount) then
2372 begin
2373 // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè:
2374 PressTime := -1;
2375 // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé:
2376 if trigData.trigCount > 0 then
2377 PressCount := PressCount - trigData.trigCount
2378 else
2379 PressCount := 0;
2381 // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû:
2382 for b := 0 to High(gTriggers) do
2383 if g_Collide(trigData.trigtX, trigData.trigtY, trigData.trigtWidth, trigData.trigtHeight, gTriggers[b].X, gTriggers[b].Y,
2384 gTriggers[b].Width, gTriggers[b].Height) and
2385 ((b <> a) or (trigData.trigWait > 0)) then
2386 begin // Can be self-activated, if there is Data.Wait
2387 if (not trigData.trigExtRandom) or gTriggers[b].Enabled then
2388 begin
2389 SetLength(Affected, Length(Affected) + 1);
2390 Affected[High(Affected)] := b;
2391 end;
2392 end;
2393 // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì:
2394 if (TriggerType = TRIGGER_PRESS) and trigData.trigExtRandom then
2395 begin
2396 if (Length(Affected) > 0) then
2397 begin
2398 b := Affected[Random(Length(Affected))];
2399 gTriggers[b].ActivateUID := gTriggers[a].ActivateUID;
2400 ActivateTrigger(gTriggers[b], 0);
2401 end;
2402 end
2403 else //  ïðîòèâíîì ñëó÷àå ðàáîòàåì êàê îáû÷íî:
2404 for i := 0 to High(Affected) do
2405 begin
2406 b := Affected[i];
2407 case TriggerType of
2408 TRIGGER_PRESS:
2409 begin
2410 gTriggers[b].ActivateUID := gTriggers[a].ActivateUID;
2411 ActivateTrigger(gTriggers[b], 0);
2412 end;
2413 TRIGGER_ON:
2414 begin
2415 gTriggers[b].Enabled := True;
2416 end;
2417 TRIGGER_OFF:
2418 begin
2419 gTriggers[b].Enabled := False;
2420 gTriggers[b].TimeOut := 0;
2421 if gTriggers[b].AutoSpawn then
2422 begin
2423 gTriggers[b].AutoSpawn := False;
2424 gTriggers[b].SpawnCooldown := 0;
2425 end;
2426 end;
2427 TRIGGER_ONOFF:
2428 begin
2429 gTriggers[b].Enabled := not gTriggers[b].Enabled;
2430 if not gTriggers[b].Enabled then
2431 begin
2432 gTriggers[b].TimeOut := 0;
2433 if gTriggers[b].AutoSpawn then
2434 begin
2435 gTriggers[b].AutoSpawn := False;
2436 gTriggers[b].SpawnCooldown := 0;
2437 end;
2438 end;
2439 end;
2440 end;
2441 end;
2442 SetLength(Affected, 0);
2443 end;
2445 // Óìåíüøàåì âðåìÿ äî âîçìîæíîñòè ïîâòîðíîé àêòèâàöèè:
2446 if TimeOut > 0 then
2447 begin
2448 TimeOut := TimeOut - 1;
2449 Continue; // ×òîáû íå ïîòåðÿòü 1 åäèíèöó çàäåðæêè
2450 end;
2452 // Íèæå èäóò òèïû àêòèâàöèè, åñëè òðèããåð îòêëþ÷¸í - èä¸ì äàëüøå
2453 if not Enabled then
2454 Continue;
2456 // "Èãðîê áëèçêî":
2457 if ByteBool(ActivateType and ACTIVATE_PLAYERCOLLIDE) and
2458 (TimeOut = 0) then
2459 if gPlayers <> nil then
2460 for b := 0 to High(gPlayers) do
2461 if gPlayers[b] <> nil then
2462 with gPlayers[b] do
2463 // Æèâ, åñòü íóæíûå êëþ÷è è îí ðÿäîì:
2464 if Live and ((gTriggers[a].Keys and GetKeys) = gTriggers[a].Keys) and
2465 Collide(X, Y, Width, Height) then
2466 begin
2467 gTriggers[a].ActivateUID := UID;
2469 if (gTriggers[a].TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) and
2470 PlayerCollide then
2471 { Don't activate sound/music again if player is here }
2472 else
2473 ActivateTrigger(gTriggers[a], ACTIVATE_PLAYERCOLLIDE);
2474 end;
2476 { TODO 5 : àêòèâàöèÿ ìîíñòðàìè òðèããåðîâ ñ êëþ÷àìè }
2478 if ByteBool(ActivateType and ACTIVATE_MONSTERCOLLIDE) and
2479 ByteBool(ActivateType and ACTIVATE_NOMONSTER) and
2480 (TimeOut = 0) and (Keys = 0) then
2481 begin
2482 // Åñëè "Ìîíñòð áëèçêî" è "Ìîíñòðîâ íåò",
2483 // çàïóñêàåì òðèããåð íà ñòàðòå êàðòû è ñíèìàåì îáà ôëàãà
2484 ActivateType := ActivateType and not (ACTIVATE_MONSTERCOLLIDE or ACTIVATE_NOMONSTER);
2485 gTriggers[a].ActivateUID := 0;
2486 ActivateTrigger(gTriggers[a], 0);
2487 end else
2488 begin
2489 // "Ìîíñòð áëèçêî"
2490 if ByteBool(ActivateType and ACTIVATE_MONSTERCOLLIDE) and
2491 (TimeOut = 0) and (Keys = 0) then // Åñëè íå íóæíû êëþ÷è
2492 begin
2493 //g_Mons_ForEach(monsNear);
2494 //Alive?!
2495 tgMonsList.reset();
2496 g_Mons_ForEachAt(gTriggers[a].X, gTriggers[a].Y, gTriggers[a].Width, gTriggers[a].Height, monsNear);
2497 for mon in tgMonsList do
2498 begin
2499 gTriggers[a].ActivateUID := mon.UID;
2500 ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE);
2501 end;
2502 tgMonsList.reset(); // just in case
2503 end;
2505 // "Ìîíñòðîâ íåò"
2506 if ByteBool(ActivateType and ACTIVATE_NOMONSTER) and
2507 (TimeOut = 0) and (Keys = 0) then
2508 if not g_Mons_IsAnyAliveAt(X, Y, Width, Height) then
2509 begin
2510 gTriggers[a].ActivateUID := 0;
2511 ActivateTrigger(gTriggers[a], ACTIVATE_NOMONSTER);
2512 end;
2513 end;
2515 PlayerCollide := g_CollidePlayer(X, Y, Width, Height);
2516 end;
2517 end;
2519 procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0);
2520 begin
2521 gTriggers[ID].ActivateUID := ActivateUID;
2522 ActivateTrigger(gTriggers[ID], ActivateType);
2523 end;
2525 function g_Triggers_PressR(X, Y: Integer; Width, Height: Word; UID: Word;
2526 ActivateType: Byte; IgnoreList: DWArray = nil): DWArray;
2527 var
2528 a: Integer;
2529 k: Byte;
2530 p: TPlayer;
2531 begin
2532 Result := nil;
2534 if gTriggers = nil then Exit;
2536 case g_GetUIDType(UID) of
2537 UID_GAME: k := 255;
2538 UID_PLAYER:
2539 begin
2540 p := g_Player_Get(UID);
2541 if p <> nil then
2542 k := p.GetKeys
2543 else
2544 k := 0;
2545 end;
2546 else k := 0;
2547 end;
2549 for a := 0 to High(gTriggers) do
2550 if (gTriggers[a].TriggerType <> TRIGGER_NONE) and
2551 (gTriggers[a].TimeOut = 0) and
2552 (not InDWArray(a, IgnoreList)) and
2553 ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and
2554 ByteBool(gTriggers[a].ActivateType and ActivateType) then
2555 if g_Collide(X, Y, Width, Height,
2556 gTriggers[a].X, gTriggers[a].Y,
2557 gTriggers[a].Width, gTriggers[a].Height) then
2558 begin
2559 gTriggers[a].ActivateUID := UID;
2560 if ActivateTrigger(gTriggers[a], ActivateType) then
2561 begin
2562 SetLength(Result, Length(Result)+1);
2563 Result[High(Result)] := a;
2564 end;
2565 end;
2566 end;
2568 procedure g_Triggers_PressL(X1, Y1, X2, Y2: Integer; UID: DWORD; ActivateType: Byte);
2569 var
2570 a: Integer;
2571 k: Byte;
2572 p: TPlayer;
2573 begin
2574 if gTriggers = nil then Exit;
2576 case g_GetUIDType(UID) of
2577 UID_GAME: k := 255;
2578 UID_PLAYER:
2579 begin
2580 p := g_Player_Get(UID);
2581 if p <> nil then
2582 k := p.GetKeys
2583 else
2584 k := 0;
2585 end;
2586 else k := 0;
2587 end;
2589 for a := 0 to High(gTriggers) do
2590 if (gTriggers[a].TriggerType <> TRIGGER_NONE) and
2591 (gTriggers[a].TimeOut = 0) and
2592 ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and
2593 ByteBool(gTriggers[a].ActivateType and ActivateType) then
2594 if g_CollideLine(x1, y1, x2, y2, gTriggers[a].X, gTriggers[a].Y,
2595 gTriggers[a].Width, gTriggers[a].Height) then
2596 begin
2597 gTriggers[a].ActivateUID := UID;
2598 ActivateTrigger(gTriggers[a], ActivateType);
2599 end;
2600 end;
2602 procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte; IgnoreTrigger: Integer = -1);
2603 var
2604 a: Integer;
2605 k: Byte;
2606 rsq: Word;
2607 p: TPlayer;
2608 begin
2609 if gTriggers = nil then
2610 Exit;
2612 case g_GetUIDType(UID) of
2613 UID_GAME: k := 255;
2614 UID_PLAYER:
2615 begin
2616 p := g_Player_Get(UID);
2617 if p <> nil then
2618 k := p.GetKeys
2619 else
2620 k := 0;
2621 end;
2622 else k := 0;
2623 end;
2625 rsq := Radius * Radius;
2627 for a := 0 to High(gTriggers) do
2628 if (gTriggers[a].ID <> DWORD(IgnoreTrigger)) and
2629 (gTriggers[a].TriggerType <> TRIGGER_NONE) and
2630 (gTriggers[a].TimeOut = 0) and
2631 ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and
2632 ByteBool(gTriggers[a].ActivateType and ActivateType) then
2633 with gTriggers[a] do
2634 if g_Collide(CX-Radius, CY-Radius, 2*Radius, 2*Radius,
2635 X, Y, Width, Height) then
2636 if ((Sqr(CX-X)+Sqr(CY-Y)) < rsq) or // Öåíòð êðóãà áëèçîê ê âåðõíåìó ëåâîìó óãëó
2637 ((Sqr(CX-X-Width)+Sqr(CY-Y)) < rsq) or // Öåíòð êðóãà áëèçîê ê âåðõíåìó ïðàâîìó óãëó
2638 ((Sqr(CX-X-Width)+Sqr(CY-Y-Height)) < rsq) or // Öåíòð êðóãà áëèçîê ê íèæíåìó ïðàâîìó óãëó
2639 ((Sqr(CX-X)+Sqr(CY-Y-Height)) < rsq) or // Öåíòð êðóãà áëèçîê ê íèæíåìó ëåâîìó óãëó
2640 ( (CX > (X-Radius)) and (CX < (X+Width+Radius)) and
2641 (CY > Y) and (CY < (Y+Height)) ) or // Öåíòð êðóãà íåäàëåêî îò âåðòèêàëüíûõ ãðàíèö ïðÿìîóãîëüíèêà
2642 ( (CY > (Y-Radius)) and (CY < (Y+Height+Radius)) and
2643 (CX > X) and (CX < (X+Width)) ) then // Öåíòð êðóãà íåäàëåêî îò ãîðèçîíòàëüíûõ ãðàíèö ïðÿìîóãîëüíèêà
2644 begin
2645 ActivateUID := UID;
2646 ActivateTrigger(gTriggers[a], ActivateType);
2647 end;
2648 end;
2650 procedure g_Triggers_OpenAll();
2651 var
2652 a: Integer;
2653 b: Boolean;
2654 begin
2655 if gTriggers = nil then Exit;
2657 b := False;
2658 for a := 0 to High(gTriggers) do
2659 with gTriggers[a] do
2660 if (TriggerType = TRIGGER_OPENDOOR) or
2661 (TriggerType = TRIGGER_DOOR5) or
2662 (TriggerType = TRIGGER_DOOR) then
2663 begin
2664 tr_OpenDoor(trigPanelID, True, trigData.trigd2d_doors);
2665 if TriggerType = TRIGGER_DOOR5 then DoorTime := 180;
2666 b := True;
2667 end;
2669 if b then g_Sound_PlayEx('SOUND_GAME_DOOROPEN');
2670 end;
2672 procedure g_Triggers_DecreaseSpawner(ID: DWORD);
2673 begin
2674 if (gTriggers <> nil) then
2675 if gTriggers[ID].SpawnedCount > 0 then
2676 Dec(gTriggers[ID].SpawnedCount);
2677 end;
2679 procedure g_Triggers_Free();
2680 var
2681 a: Integer;
2682 begin
2683 for a := 0 to High(gTriggers) do
2684 begin
2685 if (gTriggers[a].TriggerType = TRIGGER_SOUND) then
2686 begin
2687 if g_Sound_Exists(gTriggers[a].trigData.trigSoundName) then
2688 begin
2689 g_Sound_Delete(gTriggers[a].trigData.trigSoundName);
2690 end;
2691 gTriggers[a].Sound.Free();
2692 end;
2693 if (gTriggers[a].Activators <> nil) then
2694 begin
2695 SetLength(gTriggers[a].Activators, 0);
2696 end;
2697 gTriggers[a].trigData.Free();
2698 end;
2700 gTriggers := nil;
2701 gSecretsCount := 0;
2702 SetLength(gMonstersSpawned, 0);
2703 end;
2705 procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter);
2706 var
2707 count, act_count, i, j: Integer;
2708 dw: DWORD;
2709 sg: Single;
2710 b: Boolean;
2711 //p: Pointer;
2712 begin
2713 // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ:
2714 count := 0;
2715 if gTriggers <> nil then
2716 for i := 0 to High(gTriggers) do
2717 count := count + 1;
2719 Mem := TBinMemoryWriter.Create((count+1) * 200);
2721 // Êîëè÷åñòâî òðèããåðîâ:
2722 Mem.WriteInt(count);
2724 if count = 0 then
2725 Exit;
2727 for i := 0 to High(gTriggers) do
2728 begin
2729 // Ñèãíàòóðà òðèããåðà:
2730 dw := TRIGGER_SIGNATURE; // 'TRGR'
2731 Mem.WriteDWORD(dw);
2732 // Òèï òðèããåðà:
2733 Mem.WriteByte(gTriggers[i].TriggerType);
2734 // Ñïåöèàëüíûå äàííûå òðèããåðà:
2735 //!!!FIXME!!!
2736 //p := @gTriggers[i].Data;
2737 //Mem.WriteMemory(p, SizeOf(TTriggerData));
2738 // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
2739 Mem.WriteInt(gTriggers[i].X);
2740 Mem.WriteInt(gTriggers[i].Y);
2741 // Ðàçìåðû:
2742 Mem.WriteWord(gTriggers[i].Width);
2743 Mem.WriteWord(gTriggers[i].Height);
2744 // Âêëþ÷åí ëè òðèããåð:
2745 Mem.WriteBoolean(gTriggers[i].Enabled);
2746 // Òèï àêòèâàöèè òðèããåðà:
2747 Mem.WriteByte(gTriggers[i].ActivateType);
2748 // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
2749 Mem.WriteByte(gTriggers[i].Keys);
2750 // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
2751 Mem.WriteInt(gTriggers[i].TexturePanel);
2752 // Òèï ýòîé ïàíåëè:
2753 Mem.WriteWord(gTriggers[i].TexturePanelType);
2754 // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
2755 Mem.WriteWord(gTriggers[i].TimeOut);
2756 // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð:
2757 Mem.WriteWord(gTriggers[i].ActivateUID);
2758 // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì:
2759 act_count := Length(gTriggers[i].Activators);
2760 Mem.WriteInt(act_count);
2761 for j := 0 to act_count-1 do
2762 begin
2763 // UID îáúåêòà
2764 Mem.WriteWord(gTriggers[i].Activators[j].UID);
2765 // Âðåìÿ îæèäàíèÿ
2766 Mem.WriteWord(gTriggers[i].Activators[j].TimeOut);
2767 end;
2768 // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà:
2769 Mem.WriteBoolean(gTriggers[i].PlayerCollide);
2770 // Âðåìÿ äî çàêðûòèÿ äâåðè:
2771 Mem.WriteInt(gTriggers[i].DoorTime);
2772 // Çàäåðæêà àêòèâàöèè:
2773 Mem.WriteInt(gTriggers[i].PressTime);
2774 // Ñ÷åò÷èê íàæàòèé:
2775 Mem.WriteInt(gTriggers[i].PressCount);
2776 // Ñïàâíåð àêòèâåí:
2777 Mem.WriteBoolean(gTriggers[i].AutoSpawn);
2778 // Çàäåðæêà ñïàâíåðà:
2779 Mem.WriteInt(gTriggers[i].SpawnCooldown);
2780 // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ:
2781 Mem.WriteInt(gTriggers[i].SpawnedCount);
2782 // Ñêîëüêî ðàç ïðîèãðàí çâóê:
2783 Mem.WriteInt(gTriggers[i].SoundPlayCount);
2784 // Ïðîèãðûâàåòñÿ ëè çâóê?
2785 if gTriggers[i].Sound <> nil then
2786 b := gTriggers[i].Sound.IsPlaying()
2787 else
2788 b := False;
2789 Mem.WriteBoolean(b);
2790 if b then
2791 begin
2792 // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà:
2793 dw := gTriggers[i].Sound.GetPosition();
2794 Mem.WriteDWORD(dw);
2795 // Ãðîìêîñòü çâóêà:
2796 sg := gTriggers[i].Sound.GetVolume();
2797 sg := sg / (gSoundLevel/255.0);
2798 Mem.WriteSingle(sg);
2799 // Ñòåðåî ñìåùåíèå çâóêà:
2800 sg := gTriggers[i].Sound.GetPan();
2801 Mem.WriteSingle(sg);
2802 end;
2803 end;
2804 end;
2806 procedure g_Triggers_LoadState(var Mem: TBinMemoryReader);
2807 var
2808 count, act_count, i, j, a: Integer;
2809 dw: DWORD;
2810 vol, pan: Single;
2811 b: Boolean;
2812 //p: Pointer;
2813 Trig: TTrigger;
2814 begin
2815 if Mem = nil then
2816 Exit;
2818 g_Triggers_Free();
2820 // Êîëè÷åñòâî òðèããåðîâ:
2821 Mem.ReadInt(count);
2823 if count = 0 then
2824 Exit;
2826 for a := 0 to count-1 do
2827 begin
2828 // Ñèãíàòóðà òðèããåðà:
2829 Mem.ReadDWORD(dw);
2830 if dw <> TRIGGER_SIGNATURE then // 'TRGR'
2831 begin
2832 raise EBinSizeError.Create('g_Triggers_LoadState: Wrong Trigger Signature');
2833 end;
2834 // Òèï òðèããåðà:
2835 Mem.ReadByte(Trig.TriggerType);
2836 // Ñïåöèàëüíûå äàííûå òðèããåðà:
2837 //!!!FIXME!!!
2839 Mem.ReadMemory(p, dw);
2840 if dw <> SizeOf(TTriggerData) then
2841 begin
2842 raise EBinSizeError.Create('g_Triggers_LoadState: Wrong TriggerData Size');
2843 end;
2844 Trig.Data := TTriggerData(p^);
2846 // Ñîçäàåì òðèããåð:
2847 i := g_Triggers_Create(Trig);
2848 // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
2849 Mem.ReadInt(gTriggers[i].X);
2850 Mem.ReadInt(gTriggers[i].Y);
2851 // Ðàçìåðû:
2852 Mem.ReadWord(gTriggers[i].Width);
2853 Mem.ReadWord(gTriggers[i].Height);
2854 // Âêëþ÷åí ëè òðèããåð:
2855 Mem.ReadBoolean(gTriggers[i].Enabled);
2856 // Òèï àêòèâàöèè òðèããåðà:
2857 Mem.ReadByte(gTriggers[i].ActivateType);
2858 // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
2859 Mem.ReadByte(gTriggers[i].Keys);
2860 // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
2861 Mem.ReadInt(gTriggers[i].TexturePanel);
2862 // Òèï ýòîé ïàíåëè:
2863 Mem.ReadWord(gTriggers[i].TexturePanelType);
2864 // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
2865 Mem.ReadWord(gTriggers[i].TimeOut);
2866 // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð:
2867 Mem.ReadWord(gTriggers[i].ActivateUID);
2868 // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì:
2869 Mem.ReadInt(act_count);
2870 if act_count > 0 then
2871 begin
2872 SetLength(gTriggers[i].Activators, act_count);
2873 for j := 0 to act_count-1 do
2874 begin
2875 // UID îáúåêòà
2876 Mem.ReadWord(gTriggers[i].Activators[j].UID);
2877 // Âðåìÿ îæèäàíèÿ
2878 Mem.ReadWord(gTriggers[i].Activators[j].TimeOut);
2879 end;
2880 end;
2881 // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà:
2882 Mem.ReadBoolean(gTriggers[i].PlayerCollide);
2883 // Âðåìÿ äî çàêðûòèÿ äâåðè:
2884 Mem.ReadInt(gTriggers[i].DoorTime);
2885 // Çàäåðæêà àêòèâàöèè:
2886 Mem.ReadInt(gTriggers[i].PressTime);
2887 // Ñ÷åò÷èê íàæàòèé:
2888 Mem.ReadInt(gTriggers[i].PressCount);
2889 // Ñïàâíåð àêòèâåí:
2890 Mem.ReadBoolean(gTriggers[i].AutoSpawn);
2891 // Çàäåðæêà ñïàâíåðà:
2892 Mem.ReadInt(gTriggers[i].SpawnCooldown);
2893 // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ:
2894 Mem.ReadInt(gTriggers[i].SpawnedCount);
2895 // Ñêîëüêî ðàç ïðîèãðàí çâóê:
2896 Mem.ReadInt(gTriggers[i].SoundPlayCount);
2897 // Ïðîèãðûâàåòñÿ ëè çâóê?
2898 Mem.ReadBoolean(b);
2899 if b then
2900 begin
2901 // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà:
2902 Mem.ReadDWORD(dw);
2903 // Ãðîìêîñòü çâóêà:
2904 Mem.ReadSingle(vol);
2905 // Ñòåðåî ñìåùåíèå çâóêà:
2906 Mem.ReadSingle(pan);
2907 // Çàïóñêàåì çâóê, åñëè åñòü:
2908 if gTriggers[i].Sound <> nil then
2909 begin
2910 gTriggers[i].Sound.PlayPanVolume(pan, vol);
2911 gTriggers[i].Sound.Pause(True);
2912 gTriggers[i].Sound.SetPosition(dw);
2913 end
2914 end;
2915 end;
2916 end;
2918 end.