DEADSOFTWARE

2ff21708160b0e1e063545a508f405f87453be4a
[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 {$MODE DELPHI}
17 unit g_triggers;
19 interface
21 uses
22 MAPSTRUCT, e_graphics, MAPDEF, g_basic, g_sound,
23 BinEditor;
25 type
26 TActivator = record
27 UID: Word;
28 TimeOut: Word;
29 end;
30 TTrigger = record
31 ID: DWORD;
32 ClientID: DWORD;
33 TriggerType: Byte;
34 X, Y: Integer;
35 Width, Height: Word;
36 Enabled: Boolean;
37 ActivateType: Byte;
38 Keys: Byte;
39 TexturePanel: Integer;
40 TexturePanelType: Word;
42 TimeOut: Word;
43 ActivateUID: Word;
44 Activators: array of TActivator;
45 PlayerCollide: Boolean;
46 DoorTime: Integer;
47 PressTime: Integer;
48 PressCount: Integer;
49 SoundPlayCount: Integer;
50 Sound: TPlayableSound;
51 AutoSpawn: Boolean;
52 SpawnCooldown: Integer;
53 SpawnedCount: Integer;
54 ShotPanelType: Word;
55 ShotPanelTime: Integer;
56 ShotSightTime: Integer;
57 ShotSightTimeout: Integer;
58 ShotSightTarget: Word;
59 ShotSightTargetN: Word;
60 ShotAmmoCount: Word;
61 ShotReloadTime: Integer;
63 Data: TTriggerData;
64 end;
66 function g_Triggers_Create(Trigger: TTrigger): DWORD;
67 procedure g_Triggers_Update();
68 procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte);
69 function g_Triggers_PressR(X, Y: Integer; Width, Height: Word; UID: Word;
70 ActivateType: Byte; IgnoreList: DWArray = nil): DWArray;
71 procedure g_Triggers_PressL(X1, Y1, X2, Y2: Integer; UID: DWORD; ActivateType: Byte);
72 procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte);
73 procedure g_Triggers_OpenAll();
74 procedure g_Triggers_DecreaseSpawner(ID: DWORD);
75 procedure g_Triggers_Free();
76 procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter);
77 procedure g_Triggers_LoadState(var Mem: TBinMemoryReader);
79 var
80 gTriggerClientID: Integer = 0;
81 gTriggers: array of TTrigger;
82 gSecretsCount: Integer = 0;
83 gMonstersSpawned: array of LongInt = nil;
85 implementation
87 uses
88 g_player, g_map, Math, g_gfx, g_game, g_textures,
89 g_console, g_monsters, g_items, g_phys, g_weapons,
90 wadreader, g_main, SysUtils, e_log, g_language,
91 g_options, g_net, g_netmsg, g_scripts;
93 const
94 TRIGGER_SIGNATURE = $52475254; // 'TRGR'
95 TRAP_DAMAGE = 1000;
97 function FindTrigger(): DWORD;
98 var
99 i: Integer;
100 begin
101 if gTriggers <> nil then
102 for i := 0 to High(gTriggers) do
103 if gTriggers[i].TriggerType = TRIGGER_NONE then
104 begin
105 Result := i;
106 Exit;
107 end;
109 if gTriggers = nil then
110 begin
111 SetLength(gTriggers, 8);
112 Result := 0;
113 end
114 else
115 begin
116 Result := High(gTriggers) + 1;
117 SetLength(gTriggers, Length(gTriggers) + 8);
118 end;
119 end;
121 function CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
122 var
123 a, b, c: Integer;
124 begin
125 Result := False;
127 if PanelID = -1 then Exit;
129 if not d2d then
130 begin
131 with gWalls[PanelID] do
132 begin
133 if g_CollidePlayer(X, Y, Width, Height) or
134 g_CollideMonster(X, Y, Width, Height) then Exit;
136 if not Enabled then
137 begin
138 if not NoSound then
139 begin
140 g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y);
141 if g_Game_IsServer and g_Game_IsNet then
142 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
143 end;
144 g_Map_EnableWall(PanelID);
145 Result := True;
146 end;
147 end;
148 end
149 else
150 begin
151 if gDoorMap = nil then Exit;
153 c := -1;
154 for a := 0 to High(gDoorMap) do
155 begin
156 for b := 0 to High(gDoorMap[a]) do
157 if gDoorMap[a, b] = DWORD(PanelID) then
158 begin
159 c := a;
160 Break;
161 end;
163 if c <> -1 then Break;
164 end;
165 if c = -1 then Exit;
167 for b := 0 to High(gDoorMap[c]) do
168 with gWalls[gDoorMap[c, b]] do
169 begin
170 if g_CollidePlayer(X, Y, Width, Height) or
171 g_CollideMonster(X, Y, Width, Height) then Exit;
172 end;
174 if not NoSound then
175 for b := 0 to High(gDoorMap[c]) do
176 if not gWalls[gDoorMap[c, b]].Enabled then
177 begin
178 with gWalls[PanelID] do
179 begin
180 g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y);
181 if g_Game_IsServer and g_Game_IsNet then
182 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
183 end;
184 Break;
185 end;
187 for b := 0 to High(gDoorMap[c]) do
188 if not gWalls[gDoorMap[c, b]].Enabled then
189 begin
190 g_Map_EnableWall(gDoorMap[c, b]);
191 Result := True;
192 end;
193 end;
194 end;
196 procedure CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean);
197 var
198 a, b, c: Integer;
199 begin
200 if PanelID = -1 then Exit;
202 if not d2d then
203 begin
204 with gWalls[PanelID] do
205 if (not NoSound) and (not Enabled) then
206 begin
207 g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y);
208 if g_Game_IsServer and g_Game_IsNet then
209 MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1');
210 end;
212 with gWalls[PanelID] do
213 begin
214 if gPlayers <> nil then
215 for a := 0 to High(gPlayers) do
216 if (gPlayers[a] <> nil) and gPlayers[a].Live and
217 gPlayers[a].Collide(X, Y, Width, Height) then
218 gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
220 if gMonsters <> nil then
221 for a := 0 to High(gMonsters) do
222 if (gMonsters[a] <> nil) and gMonsters[a].Live and
223 g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then
224 gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
226 if not Enabled then g_Map_EnableWall(PanelID);
227 end;
228 end
229 else
230 begin
231 if gDoorMap = nil then Exit;
233 c := -1;
234 for a := 0 to High(gDoorMap) do
235 begin
236 for b := 0 to High(gDoorMap[a]) do
237 if gDoorMap[a, b] = DWORD(PanelID) then
238 begin
239 c := a;
240 Break;
241 end;
243 if c <> -1 then Break;
244 end;
245 if c = -1 then Exit;
247 if not NoSound then
248 for b := 0 to High(gDoorMap[c]) do
249 if not gWalls[gDoorMap[c, b]].Enabled then
250 begin
251 with gWalls[PanelID] do
252 begin
253 g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y);
254 if g_Game_IsServer and g_Game_IsNet then
255 MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1');
256 end;
257 Break;
258 end;
260 for b := 0 to High(gDoorMap[c]) do
261 with gWalls[gDoorMap[c, b]] do
262 begin
263 if gPlayers <> nil then
264 for a := 0 to High(gPlayers) do
265 if (gPlayers[a] <> nil) and gPlayers[a].Live and
266 gPlayers[a].Collide(X, Y, Width, Height) then
267 gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
269 if gMonsters <> nil then
270 for a := 0 to High(gMonsters) do
271 if (gMonsters[a] <> nil) and gMonsters[a].Live and
272 g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then
273 gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
275 if not Enabled then g_Map_EnableWall(gDoorMap[c, b]);
276 end;
277 end;
278 end;
280 function OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
281 var
282 a, b, c: Integer;
283 begin
284 Result := False;
286 if PanelID = -1 then Exit;
288 if not d2d then
289 begin
290 with gWalls[PanelID] do
291 if Enabled then
292 begin
293 if not NoSound then
294 begin
295 g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y);
296 if g_Game_IsServer and g_Game_IsNet then
297 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
298 end;
299 g_Map_DisableWall(PanelID);
300 Result := True;
301 end;
302 end
303 else
304 begin
305 if gDoorMap = nil then Exit;
307 c := -1;
308 for a := 0 to High(gDoorMap) do
309 begin
310 for b := 0 to High(gDoorMap[a]) do
311 if gDoorMap[a, b] = DWORD(PanelID) then
312 begin
313 c := a;
314 Break;
315 end;
317 if c <> -1 then Break;
318 end;
319 if c = -1 then Exit;
321 if not NoSound then
322 for b := 0 to High(gDoorMap[c]) do
323 if gWalls[gDoorMap[c, b]].Enabled then
324 begin
325 with gWalls[PanelID] do
326 begin
327 g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y);
328 if g_Game_IsServer and g_Game_IsNet then
329 MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
330 end;
331 Break;
332 end;
334 for b := 0 to High(gDoorMap[c]) do
335 if gWalls[gDoorMap[c, b]].Enabled then
336 begin
337 g_Map_DisableWall(gDoorMap[c, b]);
338 Result := True;
339 end;
340 end;
341 end;
343 function SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
344 var
345 a, b, c, t: Integer;
346 begin
347 t := 0;
348 Result := False;
350 if PanelID = -1 then Exit;
352 if (gLifts[PanelID].PanelType = PANEL_LIFTUP) or
353 (gLifts[PanelID].PanelType = PANEL_LIFTDOWN) then
354 case d of
355 0: t := 0;
356 1: t := 1;
357 else t := IfThen(gLifts[PanelID].LiftType = 1, 0, 1);
358 end
359 else if (gLifts[PanelID].PanelType = PANEL_LIFTLEFT) or
360 (gLifts[PanelID].PanelType = PANEL_LIFTRIGHT) then
361 case d of
362 0: t := 2;
363 1: t := 3;
364 else t := IfThen(gLifts[PanelID].LiftType = 2, 3, 2);
365 end;
367 if not d2d then
368 begin
369 with gLifts[PanelID] do
370 if LiftType <> t then
371 begin
372 g_Map_SetLift(PanelID, t);
374 {if not NoSound then
375 g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);}
376 Result := True;
377 end;
378 end
379 else // Êàê â D2d
380 begin
381 if gLiftMap = nil then Exit;
383 c := -1;
384 for a := 0 to High(gLiftMap) do
385 begin
386 for b := 0 to High(gLiftMap[a]) do
387 if gLiftMap[a, b] = DWORD(PanelID) then
388 begin
389 c := a;
390 Break;
391 end;
393 if c <> -1 then Break;
394 end;
395 if c = -1 then Exit;
397 {if not NoSound then
398 for b := 0 to High(gLiftMap[c]) do
399 if gLifts[gLiftMap[c, b]].LiftType <> t then
400 begin
401 with gLifts[PanelID] do
402 g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);
403 Break;
404 end;}
406 for b := 0 to High(gLiftMap[c]) do
407 with gLifts[gLiftMap[c, b]] do
408 if LiftType <> t then
409 begin
410 g_Map_SetLift(gLiftMap[c, b], t);
412 Result := True;
413 end;
414 end;
415 end;
417 procedure MakeShot(var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word);
418 var
419 Projectile: Boolean;
420 snd: string;
421 TextureID: DWORD;
422 Anim: TAnimation;
423 begin
424 with Trigger do
425 if (Data.ShotAmmo = 0) or
426 ((Data.ShotAmmo > 0) and (ShotAmmoCount > 0)) then
427 begin
428 if (Data.ShotPanelID <> -1) and (ShotPanelTime = 0) then
429 begin
430 g_Map_SwitchTexture(ShotPanelType, Data.ShotPanelID);
431 ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà
432 end;
434 if Data.ShotIntSight > 0 then
435 ShotSightTimeout := 180; // ~= 5 ñåêóíä
437 if ShotAmmoCount > 0 then Dec(ShotAmmoCount);
438 Projectile := True;
439 snd := 'SOUND_WEAPON_FIREROCKET';
441 dx := dx + Random(Data.ShotAccuracy) - Random(Data.ShotAccuracy);
442 dy := dy + Random(Data.ShotAccuracy) - Random(Data.ShotAccuracy);
444 case Data.ShotType of
445 TRIGGER_SHOT_PISTOL:
446 begin
447 g_Weapon_pistol(wx, wy, dx, dy, 0, True);
448 Projectile := False;
449 snd := 'SOUND_WEAPON_FIREPISTOL';
450 if Data.ShotSound then
451 begin
452 g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
453 if g_Game_IsNet then
454 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
455 end;
456 end;
458 TRIGGER_SHOT_BULLET:
459 begin
460 g_Weapon_mgun(wx, wy, dx, dy, 0, True);
461 Projectile := False;
462 if gSoundEffectsDF then snd := 'SOUND_WEAPON_FIRECGUN'
463 else snd := 'SOUND_WEAPON_FIREPISTOL';
464 if Data.ShotSound then
465 begin
466 g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
467 if g_Game_IsNet then
468 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
469 end;
470 end;
472 TRIGGER_SHOT_SHOTGUN:
473 begin
474 g_Weapon_Shotgun(wx, wy, dx, dy, 0, True);
475 Projectile := False;
476 snd := 'SOUND_WEAPON_FIRESHOTGUN';
477 if Data.ShotSound then
478 begin
479 g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
480 if g_Game_IsNet then
481 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2);
482 end;
483 end;
485 TRIGGER_SHOT_SSG:
486 begin
487 g_Weapon_DShotgun(wx, wy, dx, dy, 0, True);
488 Projectile := False;
489 snd := 'SOUND_WEAPON_FIRESHOTGUN2';
490 if Data.ShotSound then
491 begin
492 g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
493 g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
494 if g_Game_IsNet then
495 MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3);
496 end;
497 end;
499 TRIGGER_SHOT_IMP:
500 begin
501 g_Weapon_ball1(wx, wy, dx, dy, 0, -1, True);
502 snd := 'SOUND_WEAPON_FIREBALL';
503 end;
505 TRIGGER_SHOT_PLASMA:
506 begin
507 g_Weapon_Plasma(wx, wy, dx, dy, 0, -1, True);
508 snd := 'SOUND_WEAPON_FIREPLASMA';
509 end;
511 TRIGGER_SHOT_SPIDER:
512 begin
513 g_Weapon_aplasma(wx, wy, dx, dy, 0, -1, True);
514 snd := 'SOUND_WEAPON_FIREPLASMA';
515 end;
517 TRIGGER_SHOT_CACO:
518 begin
519 g_Weapon_ball2(wx, wy, dx, dy, 0, -1, True);
520 snd := 'SOUND_WEAPON_FIREBALL';
521 end;
523 TRIGGER_SHOT_BARON:
524 begin
525 g_Weapon_ball7(wx, wy, dx, dy, 0, -1, True);
526 snd := 'SOUND_WEAPON_FIREBALL';
527 end;
529 TRIGGER_SHOT_MANCUB:
530 begin
531 g_Weapon_manfire(wx, wy, dx, dy, 0, -1, True);
532 snd := 'SOUND_WEAPON_FIREBALL';
533 end;
535 TRIGGER_SHOT_REV:
536 begin
537 g_Weapon_revf(wx, wy, dx, dy, 0, TargetUID, -1, True);
538 snd := 'SOUND_WEAPON_FIREREV';
539 end;
541 TRIGGER_SHOT_ROCKET:
542 begin
543 g_Weapon_Rocket(wx, wy, dx, dy, 0, -1, True);
544 snd := 'SOUND_WEAPON_FIREROCKET';
545 end;
547 TRIGGER_SHOT_BFG:
548 begin
549 g_Weapon_BFGShot(wx, wy, dx, dy, 0, -1, True);
550 snd := 'SOUND_WEAPON_FIREBFG';
551 end;
553 TRIGGER_SHOT_EXPL:
554 begin
555 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
556 begin
557 Anim := TAnimation.Create(TextureID, False, 6);
558 Anim.Blending := False;
559 g_GFX_OnceAnim(wx-64, wy-64, Anim);
560 Anim.Free();
561 end;
562 Projectile := False;
563 g_Weapon_Explode(wx, wy, 60, 0);
564 snd := 'SOUND_WEAPON_EXPLODEROCKET';
565 end;
567 TRIGGER_SHOT_BFGEXPL:
568 begin
569 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_BFG') then
570 begin
571 Anim := TAnimation.Create(TextureID, False, 6);
572 Anim.Blending := False;
573 g_GFX_OnceAnim(wx-64, wy-64, Anim);
574 Anim.Free();
575 end;
576 Projectile := False;
577 g_Weapon_BFG9000(wx, wy, 0);
578 snd := 'SOUND_WEAPON_EXPLODEBFG';
579 end;
580 end;
582 if g_Game_IsNet and g_Game_IsServer then
583 case Data.ShotType of
584 TRIGGER_SHOT_EXPL:
585 MH_SEND_Effect(wx, wy, Byte(Data.ShotSound), NET_GFX_EXPLODE);
586 TRIGGER_SHOT_BFGEXPL:
587 MH_SEND_Effect(wx, wy, Byte(Data.ShotSound), NET_GFX_BFGEXPL);
588 else
589 begin
590 if Projectile then
591 MH_SEND_CreateShot(LastShotID);
592 if Data.ShotSound then
593 MH_SEND_Sound(wx, wy, snd);
594 end;
595 end;
597 if Data.ShotSound then
598 g_Sound_PlayExAt(snd, wx, wy);
599 end
600 else
601 if (Data.ShotIntReload > 0) and (ShotReloadTime = 0) then
602 ShotReloadTime := Data.ShotIntReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè
603 end;
605 procedure MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
606 var
607 FramesID: DWORD;
608 Anim: TAnimation;
609 begin
610 if T = TRIGGER_EFFECT_PARTICLE then
611 case ST of
612 TRIGGER_EFFECT_SLIQUID:
613 begin
614 if (CR = 255) and (CG = 0) and (CB = 0) then
615 g_GFX_SimpleWater(X, Y, 1, VX, VY, 1, 0, 0, 0)
616 else if (CR = 0) and (CG = 255) and (CB = 0) then
617 g_GFX_SimpleWater(X, Y, 1, VX, VY, 2, 0, 0, 0)
618 else if (CR = 0) and (CG = 0) and (CB = 255) then
619 g_GFX_SimpleWater(X, Y, 1, VX, VY, 3, 0, 0, 0)
620 else
621 g_GFX_SimpleWater(X, Y, 1, VX, VY, 0, 0, 0, 0);
622 end;
623 TRIGGER_EFFECT_LLIQUID:
624 g_GFX_SimpleWater(X, Y, 1, VX, VY, 4, CR, CG, CB);
625 TRIGGER_EFFECT_DLIQUID:
626 g_GFX_SimpleWater(X, Y, 1, VX, VY, 5, CR, CG, CB);
627 TRIGGER_EFFECT_BLOOD:
628 g_GFX_Blood(X, Y, 1, VX, VY, 0, 0, CR, CG, CB);
629 TRIGGER_EFFECT_SPARK:
630 g_GFX_Spark(X, Y, 1, GetAngle2(VX, VY), 0, 0);
631 TRIGGER_EFFECT_BUBBLE:
632 g_GFX_Bubbles(X, Y, 1, 0, 0);
633 end;
634 if T = TRIGGER_EFFECT_ANIMATION then
635 case ST of
636 EFFECT_TELEPORT: begin
637 if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
638 begin
639 Anim := TAnimation.Create(FramesID, False, 3);
640 if not Silent then
641 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y);
642 g_GFX_OnceAnim(X-32, Y-32, Anim);
643 Anim.Free();
644 end;
645 if Send and g_Game_IsServer and g_Game_IsNet then
646 MH_SEND_Effect(X, Y, Byte(not Silent), NET_GFX_TELE);
647 end;
648 EFFECT_RESPAWN: begin
649 if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
650 begin
651 Anim := TAnimation.Create(FramesID, False, 4);
652 if not Silent then
653 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y);
654 g_GFX_OnceAnim(X-16, Y-16, Anim);
655 Anim.Free();
656 end;
657 if Send and g_Game_IsServer and g_Game_IsNet then
658 MH_SEND_Effect(X-16, Y-16, Byte(not Silent), NET_GFX_RESPAWN);
659 end;
660 EFFECT_FIRE: begin
661 if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
662 begin
663 Anim := TAnimation.Create(FramesID, False, 4);
664 if not Silent then
665 g_Sound_PlayExAt('SOUND_FIRE', X, Y);
666 g_GFX_OnceAnim(X-32, Y-128, Anim);
667 Anim.Free();
668 end;
669 if Send and g_Game_IsServer and g_Game_IsNet then
670 MH_SEND_Effect(X-32, Y-128, Byte(not Silent), NET_GFX_FIRE);
671 end;
672 end;
673 end;
675 function ActivateTrigger(var Trigger: TTrigger; actType: Byte): Boolean;
676 var
677 animonce: Boolean;
678 p: TPlayer;
679 m: TMonster;
680 i, k, wx, wy, xd, yd: Integer;
681 iid: LongWord;
682 coolDown: Boolean;
683 pAngle: Real;
684 FramesID: DWORD;
685 Anim: TAnimation;
686 UIDType: Byte;
687 TargetUID: Word;
688 msg: string;
689 begin
690 Result := False;
691 if g_Game_IsClient then
692 Exit;
694 if not Trigger.Enabled then
695 Exit;
696 if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then
697 Exit;
698 if gLMSRespawn = LMS_RESPAWN_WARMUP then
699 Exit;
701 animonce := False;
703 coolDown := (actType <> 0);
705 with Trigger do
706 begin
707 case TriggerType of
708 TRIGGER_EXIT:
709 begin
710 g_Sound_PlayEx('SOUND_GAME_SWITCH0');
711 if g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH0');
712 gExitByTrigger := True;
713 g_Game_ExitLevel(Data.MapName);
714 TimeOut := 18;
715 Result := True;
717 Exit;
718 end;
720 TRIGGER_TELEPORT:
721 begin
722 case g_GetUIDType(ActivateUID) of
723 UID_PLAYER:
724 begin
725 p := g_Player_Get(ActivateUID);
726 if p = nil then
727 Exit;
729 if Data.d2d_teleport then
730 begin
731 if p.TeleportTo(Data.TargetPoint.X-(p.Obj.Rect.Width div 2),
732 Data.TargetPoint.Y-p.Obj.Rect.Height,
733 Data.silent_teleport,
734 Data.TlpDir) then
735 Result := True;
736 end
737 else
738 if p.TeleportTo(Data.TargetPoint.X,
739 Data.TargetPoint.Y,
740 Data.silent_teleport,
741 Data.TlpDir) then
742 Result := True;
743 end;
745 UID_MONSTER:
746 begin
747 m := g_Monsters_Get(ActivateUID);
748 if m = nil then
749 Exit;
751 if Data.d2d_teleport then
752 begin
753 if m.TeleportTo(Data.TargetPoint.X-(m.Obj.Rect.Width div 2),
754 Data.TargetPoint.Y-m.Obj.Rect.Height,
755 Data.silent_teleport,
756 Data.TlpDir) then
757 Result := True;
758 end
759 else
760 if m.TeleportTo(Data.TargetPoint.X,
761 Data.TargetPoint.Y,
762 Data.silent_teleport,
763 Data.TlpDir) then
764 Result := True;
765 end;
766 end;
768 TimeOut := 0;
769 end;
771 TRIGGER_OPENDOOR:
772 begin
773 Result := OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
774 TimeOut := 0;
775 end;
777 TRIGGER_CLOSEDOOR:
778 begin
779 Result := CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
780 TimeOut := 0;
781 end;
783 TRIGGER_DOOR, TRIGGER_DOOR5:
784 begin
785 if Data.PanelID <> -1 then
786 begin
787 if gWalls[Data.PanelID].Enabled then
788 begin
789 Result := OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
791 if TriggerType = TRIGGER_DOOR5 then
792 DoorTime := 180;
793 end
794 else
795 Result := CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
797 if Result then
798 TimeOut := 18;
799 end;
800 end;
802 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
803 begin
804 CloseTrap(Data.PanelID, Data.NoSound, Data.d2d_doors);
806 if TriggerType = TRIGGER_TRAP then
807 begin
808 DoorTime := 40;
809 TimeOut := 76;
810 end
811 else
812 begin
813 DoorTime := -1;
814 TimeOut := 0;
815 end;
817 Result := True;
818 end;
820 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
821 begin
822 PressCount := PressCount + 1;
824 if PressTime = -1 then
825 PressTime := Data.Wait;
827 if coolDown then
828 TimeOut := 18
829 else
830 TimeOut := 0;
831 Result := True;
832 end;
834 TRIGGER_SECRET:
835 if g_GetUIDType(ActivateUID) = UID_PLAYER then
836 begin
837 Enabled := False;
838 Result := True;
839 if gLMSRespawn = LMS_RESPAWN_NONE then
840 begin
841 g_Player_Get(ActivateUID).GetSecret();
842 Inc(gCoopSecretsFound);
843 if g_Game_IsNet then MH_SEND_GameStats();
844 end;
845 end;
847 TRIGGER_LIFTUP:
848 begin
849 Result := SetLift(Data.PanelID, 0, Data.NoSound, Data.d2d_doors);
850 TimeOut := 0;
852 if (not Data.NoSound) and Result then begin
853 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
854 X + (Width div 2),
855 Y + (Height div 2));
856 if g_Game_IsServer and g_Game_IsNet then
857 MH_SEND_Sound(X + (Width div 2),
858 Y + (Height div 2),
859 'SOUND_GAME_SWITCH0');
860 end;
861 end;
863 TRIGGER_LIFTDOWN:
864 begin
865 Result := SetLift(Data.PanelID, 1, Data.NoSound, Data.d2d_doors);
866 TimeOut := 0;
868 if (not Data.NoSound) and Result then begin
869 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
870 X + (Width div 2),
871 Y + (Height div 2));
872 if g_Game_IsServer and g_Game_IsNet then
873 MH_SEND_Sound(X + (Width div 2),
874 Y + (Height div 2),
875 'SOUND_GAME_SWITCH0');
876 end;
877 end;
879 TRIGGER_LIFT:
880 begin
881 Result := SetLift(Data.PanelID, 3, Data.NoSound, Data.d2d_doors);
883 if Result then
884 begin
885 TimeOut := 18;
887 if (not Data.NoSound) and Result then begin
888 g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
889 X + (Width div 2),
890 Y + (Height div 2));
891 if g_Game_IsServer and g_Game_IsNet then
892 MH_SEND_Sound(X + (Width div 2),
893 Y + (Height div 2),
894 'SOUND_GAME_SWITCH0');
895 end;
896 end;
897 end;
899 TRIGGER_TEXTURE:
900 begin
901 if ByteBool(Data.ActivateOnce) then
902 begin
903 Enabled := False;
904 TriggerType := TRIGGER_NONE;
905 end
906 else
907 if coolDown then
908 TimeOut := 6
909 else
910 TimeOut := 0;
912 animonce := Data.AnimOnce;
913 Result := True;
914 end;
916 TRIGGER_SOUND:
917 begin
918 if Sound <> nil then
919 begin
920 if Data.SoundSwitch and Sound.IsPlaying() then
921 begin // Íóæíî âûêëþ÷èòü, åñëè èãðàë
922 Sound.Stop();
923 SoundPlayCount := 0;
924 Result := True;
925 end
926 else // (not Data.SoundSwitch) or (not Sound.IsPlaying())
927 if (Data.PlayCount > 0) or (not Sound.IsPlaying()) then
928 begin
929 if Data.PlayCount > 0 then
930 SoundPlayCount := Data.PlayCount
931 else // 0 - èãðàåì áåñêîíå÷íî
932 SoundPlayCount := 1;
933 Result := True;
934 end;
935 if g_Game_IsNet then MH_SEND_TriggerSound(Trigger);
936 end;
937 end;
939 TRIGGER_SPAWNMONSTER:
940 if (Data.MonType in [MONSTER_DEMON..MONSTER_MAN]) then
941 begin
942 Result := False;
943 if (Data.MonDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
944 begin
945 AutoSpawn := not AutoSpawn;
946 SpawnCooldown := 0;
947 // Àâòîñïàâíåð ïåðåêëþ÷åí - ìåíÿåì òåêñòóðó
948 Result := True;
949 end;
951 if ((Data.MonDelay = 0) and (actType <> ACTIVATE_CUSTOM))
952 or ((Data.MonDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
953 for k := 1 to Data.MonCount do
954 begin
955 if (actType = ACTIVATE_CUSTOM) and (Data.MonDelay > 0) then
956 SpawnCooldown := Data.MonDelay;
957 if (Data.MonMax > 0) and (SpawnedCount >= Data.MonMax) then
958 Break;
960 i := g_Monsters_Create(Data.MonType,
961 Data.MonPos.X, Data.MonPos.Y,
962 TDirection(Data.MonDir), True);
964 Result := True;
966 // Çäîðîâüå:
967 if (Data.MonHealth > 0) then
968 gMonsters[i].SetHealth(Data.MonHealth);
969 // Óñòàíàâëèâàåì ïîâåäåíèå:
970 gMonsters[i].MonsterBehaviour := Data.MonBehav;
971 // Èäåì èñêàòü öåëü, åñëè íàäî:
972 if Data.MonActive then
973 gMonsters[i].WakeUp();
974 gMonsters[i].FNoRespawn := True;
976 if Data.MonType <> MONSTER_BARREL then Inc(gTotalMonsters);
978 if g_Game_IsNet then
979 begin
980 SetLength(gMonstersSpawned, Length(gMonstersSpawned)+1);
981 gMonstersSpawned[High(gMonstersSpawned)] := gMonsters[i].UID;
982 end;
984 if Data.MonMax > 0 then
985 begin
986 gMonsters[i].SpawnTrigger := ID;
987 Inc(SpawnedCount);
988 end;
990 case Data.MonEffect of
991 EFFECT_TELEPORT: begin
992 if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
993 begin
994 Anim := TAnimation.Create(FramesID, False, 3);
995 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Data.MonPos.X, Data.MonPos.Y);
996 g_GFX_OnceAnim(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32,
997 gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-32, Anim);
998 Anim.Free();
999 end;
1000 if g_Game_IsServer and g_Game_IsNet then
1001 MH_SEND_Effect(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32,
1002 gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-32, 1,
1003 NET_GFX_TELE);
1004 end;
1005 EFFECT_RESPAWN: begin
1006 if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
1007 begin
1008 Anim := TAnimation.Create(FramesID, False, 4);
1009 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', Data.MonPos.X, Data.MonPos.Y);
1010 g_GFX_OnceAnim(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-16,
1011 gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-16, Anim);
1012 Anim.Free();
1013 end;
1014 if g_Game_IsServer and g_Game_IsNet then
1015 MH_SEND_Effect(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-16,
1016 gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-16, 1,
1017 NET_GFX_RESPAWN);
1018 end;
1019 EFFECT_FIRE: begin
1020 if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
1021 begin
1022 Anim := TAnimation.Create(FramesID, False, 4);
1023 g_Sound_PlayExAt('SOUND_FIRE', Data.MonPos.X, Data.MonPos.Y);
1024 g_GFX_OnceAnim(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32,
1025 gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+gMonsters[i].Obj.Rect.Height-128, Anim);
1026 Anim.Free();
1027 end;
1028 if g_Game_IsServer and g_Game_IsNet then
1029 MH_SEND_Effect(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32,
1030 gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+gMonsters[i].Obj.Rect.Height-128, 1,
1031 NET_GFX_FIRE);
1032 end;
1033 end;
1035 if g_Game_IsNet then
1036 MH_SEND_MonsterSpawn(gMonsters[i].UID);
1037 end;
1038 if g_Game_IsNet then
1039 begin
1040 MH_SEND_GameStats();
1041 MH_SEND_CoopStats();
1042 end;
1044 if coolDown then
1045 TimeOut := 18
1046 else
1047 TimeOut := 0;
1048 // Åñëè àêòèâèðîâàí àâòîñïàâíåðîì, íå ìåíÿåì òåêñòóðó
1049 if actType = ACTIVATE_CUSTOM then
1050 Result := False;
1051 end;
1053 TRIGGER_SPAWNITEM:
1054 if (Data.ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX]) then
1055 begin
1056 Result := False;
1057 if (Data.ItemDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
1058 begin
1059 AutoSpawn := not AutoSpawn;
1060 SpawnCooldown := 0;
1061 // Àâòîñïàâíåð ïåðåêëþ÷åí - ìåíÿåì òåêñòóðó
1062 Result := True;
1063 end;
1065 if ((Data.ItemDelay = 0) and (actType <> ACTIVATE_CUSTOM))
1066 or ((Data.ItemDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
1067 if (not Data.ItemOnlyDM) or
1068 (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) then
1069 for k := 1 to Data.ItemCount do
1070 begin
1071 if (actType = ACTIVATE_CUSTOM) and (Data.ItemDelay > 0) then
1072 SpawnCooldown := Data.ItemDelay;
1073 if (Data.ItemMax > 0) and (SpawnedCount >= Data.ItemMax) then
1074 Break;
1076 iid := g_Items_Create(Data.ItemPos.X, Data.ItemPos.Y,
1077 Data.ItemType, Data.ItemFalls, False, True);
1079 Result := True;
1081 if Data.ItemMax > 0 then
1082 begin
1083 gItems[iid].SpawnTrigger := ID;
1084 Inc(SpawnedCount);
1085 end;
1087 case Data.ItemEffect of
1088 EFFECT_TELEPORT: begin
1089 if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
1090 begin
1091 Anim := TAnimation.Create(FramesID, False, 3);
1092 g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Data.ItemPos.X, Data.ItemPos.Y);
1093 g_GFX_OnceAnim(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32,
1094 gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-32, Anim);
1095 Anim.Free();
1096 end;
1097 if g_Game_IsServer and g_Game_IsNet then
1098 MH_SEND_Effect(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32,
1099 gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-32, 1,
1100 NET_GFX_TELE);
1101 end;
1102 EFFECT_RESPAWN: begin
1103 if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
1104 begin
1105 Anim := TAnimation.Create(FramesID, False, 4);
1106 g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', Data.ItemPos.X, Data.ItemPos.Y);
1107 g_GFX_OnceAnim(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-16,
1108 gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-16, Anim);
1109 Anim.Free();
1110 end;
1111 if g_Game_IsServer and g_Game_IsNet then
1112 MH_SEND_Effect(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-16,
1113 gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-16, 1,
1114 NET_GFX_RESPAWN);
1115 end;
1116 EFFECT_FIRE: begin
1117 if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
1118 begin
1119 Anim := TAnimation.Create(FramesID, False, 4);
1120 g_Sound_PlayExAt('SOUND_FIRE', Data.ItemPos.X, Data.ItemPos.Y);
1121 g_GFX_OnceAnim(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32,
1122 gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+gItems[iid].Obj.Rect.Height-128, Anim);
1123 Anim.Free();
1124 end;
1125 if g_Game_IsServer and g_Game_IsNet then
1126 MH_SEND_Effect(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32,
1127 gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+gItems[iid].Obj.Rect.Height-128, 1,
1128 NET_GFX_FIRE);
1129 end;
1130 end;
1132 if g_Game_IsNet then
1133 MH_SEND_ItemSpawn(True, iid);
1134 end;
1136 if coolDown then
1137 TimeOut := 18
1138 else
1139 TimeOut := 0;
1140 // Åñëè àêòèâèðîâàí àâòîñïàâíåðîì, íå ìåíÿåì òåêñòóðó
1141 if actType = ACTIVATE_CUSTOM then
1142 Result := False;
1143 end;
1145 TRIGGER_MUSIC:
1146 begin
1147 // Ìåíÿåì ìóçûêó, åñëè åñòü íà ÷òî:
1148 if (Trigger.Data.MusicName <> '') then
1149 begin
1150 gMusic.SetByName(Trigger.Data.MusicName);
1151 gMusic.SpecPause := True;
1152 gMusic.Play();
1153 end;
1155 if Trigger.Data.MusicAction = 1 then
1156 begin // Âêëþ÷èòü
1157 if gMusic.SpecPause then // Áûëà íà ïàóçå => èãðàòü
1158 gMusic.SpecPause := False
1159 else // Èãðàëà => ñíà÷àëà
1160 gMusic.SetPosition(0);
1161 end
1162 else // Âûêëþ÷èòü
1163 begin
1164 // Ïàóçà:
1165 gMusic.SpecPause := True;
1166 end;
1168 if coolDown then
1169 TimeOut := 36
1170 else
1171 TimeOut := 0;
1172 Result := True;
1173 if g_Game_IsNet then MH_SEND_TriggerMusic;
1174 end;
1176 TRIGGER_PUSH:
1177 begin
1178 case g_GetUIDType(ActivateUID) of
1179 UID_PLAYER:
1180 begin
1181 p := g_Player_Get(ActivateUID);
1182 if p = nil then
1183 Exit;
1185 if Data.ResetVel then
1186 begin
1187 p.GameVelX := 0;
1188 p.GameVelY := 0;
1189 p.GameAccelX := 0;
1190 p.GameAccelY := 0;
1191 end;
1193 pAngle := -DegToRad(Data.PushAngle);
1194 p.Push(Floor(Cos(pAngle)*Data.PushForce),
1195 Floor(Sin(pAngle)*Data.PushForce));
1196 end;
1198 UID_MONSTER:
1199 begin
1200 m := g_Monsters_Get(ActivateUID);
1201 if m = nil then
1202 Exit;
1203 if Data.ResetVel then
1204 begin
1205 m.GameVelX := 0;
1206 m.GameVelY := 0;
1207 m.GameAccelX := 0;
1208 m.GameAccelY := 0;
1209 end;
1211 pAngle := -DegToRad(Data.PushAngle);
1212 m.Push(Floor(Cos(pAngle)*Data.PushForce),
1213 Floor(Sin(pAngle)*Data.PushForce));
1214 end;
1215 end;
1217 TimeOut := 0;
1218 Result := True;
1219 end;
1221 TRIGGER_SCORE:
1222 begin
1223 Result := False;
1224 // Ïðèáàâèòü èëè îòíÿòü î÷êî
1225 if (Data.ScoreAction in [0..1]) and (Data.ScoreCount > 0) then
1226 begin
1227 // Ñâîåé èëè ÷óæîé êîìàíäå
1228 if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
1229 begin
1230 p := g_Player_Get(ActivateUID);
1231 if ((Data.ScoreAction = 0) and (Data.ScoreTeam = 0) and (p.Team = TEAM_RED))
1232 or ((Data.ScoreAction = 0) and (Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1233 begin
1234 Inc(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Scores
1236 if Data.ScoreCon then
1237 if Data.ScoreTeam = 0 then
1238 begin
1239 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1240 if g_Game_IsServer and g_Game_IsNet then
1241 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+r');
1242 end else
1243 begin
1244 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1245 if g_Game_IsServer and g_Game_IsNet then
1246 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+re');
1247 end;
1249 if Data.ScoreMsg then
1250 begin
1251 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1252 if g_Game_IsServer and g_Game_IsNet then
1253 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED);
1254 end;
1255 end;
1256 if ((Data.ScoreAction = 1) and (Data.ScoreTeam = 0) and (p.Team = TEAM_RED))
1257 or ((Data.ScoreAction = 1) and (Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1258 begin
1259 Dec(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Fouls
1261 if Data.ScoreCon then
1262 if Data.ScoreTeam = 0 then
1263 begin
1264 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1265 if g_Game_IsServer and g_Game_IsNet then
1266 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-r');
1267 end else
1268 begin
1269 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1270 if g_Game_IsServer and g_Game_IsNet then
1271 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-re');
1272 end;
1274 if Data.ScoreMsg then
1275 begin
1276 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1277 if g_Game_IsServer and g_Game_IsNet then
1278 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED);
1279 end;
1280 end;
1281 if ((Data.ScoreAction = 0) and (Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE))
1282 or ((Data.ScoreAction = 0) and (Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
1283 begin
1284 Inc(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Scores
1286 if Data.ScoreCon then
1287 if Data.ScoreTeam = 0 then
1288 begin
1289 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1290 if g_Game_IsServer and g_Game_IsNet then
1291 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+b');
1292 end else
1293 begin
1294 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1295 if g_Game_IsServer and g_Game_IsNet then
1296 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+be');
1297 end;
1299 if Data.ScoreMsg then
1300 begin
1301 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1302 if g_Game_IsServer and g_Game_IsNet then
1303 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE);
1304 end;
1305 end;
1306 if ((Data.ScoreAction = 1) and (Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE))
1307 or ((Data.ScoreAction = 1) and (Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
1308 begin
1309 Dec(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Fouls
1311 if Data.ScoreCon then
1312 if Data.ScoreTeam = 0 then
1313 begin
1314 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1315 if g_Game_IsServer and g_Game_IsNet then
1316 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-b');
1317 end else
1318 begin
1319 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1320 if g_Game_IsServer and g_Game_IsNet then
1321 MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-be');
1322 end;
1324 if Data.ScoreMsg then
1325 begin
1326 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1327 if g_Game_IsServer and g_Game_IsNet then
1328 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_BLUE);
1329 end;
1330 end;
1331 Result := (p.Team = TEAM_RED) or (p.Team = TEAM_BLUE);
1332 end;
1333 // Êàêîé-òî êîíêðåòíîé êîìàíäå
1334 if Data.ScoreTeam in [2..3] then
1335 begin
1336 if (Data.ScoreAction = 0) and (Data.ScoreTeam = 2) then
1337 begin
1338 Inc(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Scores
1340 if Data.ScoreCon then
1341 begin
1342 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_RED], Data.ScoreCount]), True);
1343 if g_Game_IsServer and g_Game_IsNet then
1344 MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '+tr');
1345 end;
1347 if Data.ScoreMsg then
1348 begin
1349 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1350 if g_Game_IsServer and g_Game_IsNet then
1351 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED);
1352 end;
1353 end;
1354 if (Data.ScoreAction = 1) and (Data.ScoreTeam = 2) then
1355 begin
1356 Dec(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Fouls
1358 if Data.ScoreCon then
1359 begin
1360 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_RED], Data.ScoreCount]), True);
1361 if g_Game_IsServer and g_Game_IsNet then
1362 MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '-tr');
1363 end;
1365 if Data.ScoreMsg then
1366 begin
1367 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
1368 if g_Game_IsServer and g_Game_IsNet then
1369 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED);
1370 end;
1371 end;
1372 if (Data.ScoreAction = 0) and (Data.ScoreTeam = 3) then
1373 begin
1374 Inc(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Scores
1376 if Data.ScoreCon then
1377 begin
1378 g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_BLUE], Data.ScoreCount]), True);
1379 if g_Game_IsServer and g_Game_IsNet then
1380 MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '+tb');
1381 end;
1383 if Data.ScoreMsg then
1384 begin
1385 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1386 if g_Game_IsServer and g_Game_IsNet then
1387 MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE);
1388 end;
1389 end;
1390 if (Data.ScoreAction = 1) and (Data.ScoreTeam = 3) then
1391 begin
1392 Dec(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Fouls
1394 if Data.ScoreCon then
1395 begin
1396 g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_BLUE], Data.ScoreCount]), True);
1397 if g_Game_IsServer and g_Game_IsNet then
1398 MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '-tb');
1399 end;
1401 if Data.ScoreMsg then
1402 begin
1403 g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
1404 if g_Game_IsServer and g_Game_IsNet then
1405 MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_BLUE);
1406 end;
1407 end;
1408 Result := True;
1409 end;
1410 end;
1411 // Âûèãðûø
1412 if (Data.ScoreAction = 2) and (gGameSettings.GoalLimit > 0) then
1413 begin
1414 // Ñâîåé èëè ÷óæîé êîìàíäû
1415 if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
1416 begin
1417 p := g_Player_Get(ActivateUID);
1418 if ((Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) // Red Wins
1419 or ((Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1420 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1421 begin
1422 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1424 if Data.ScoreCon then
1425 if Data.ScoreTeam = 0 then
1426 begin
1427 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1428 if g_Game_IsServer and g_Game_IsNet then
1429 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wr');
1430 end else
1431 begin
1432 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1433 if g_Game_IsServer and g_Game_IsNet then
1434 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wre');
1435 end;
1437 Result := True;
1438 end;
1439 if ((Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Blue Wins
1440 or ((Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
1441 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1442 begin
1443 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1445 if Data.ScoreCon then
1446 if Data.ScoreTeam = 0 then
1447 begin
1448 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1449 if g_Game_IsServer and g_Game_IsNet then
1450 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wb');
1451 end else
1452 begin
1453 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1454 if g_Game_IsServer and g_Game_IsNet then
1455 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wbe');
1456 end;
1458 Result := True;
1459 end;
1460 end;
1461 // Êàêîé-òî êîíêðåòíîé êîìàíäû
1462 if Data.ScoreTeam in [2..3] then
1463 begin
1464 if Data.ScoreTeam = 2 then // Red Wins
1465 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1466 begin
1467 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1468 Result := True;
1469 end;
1470 if Data.ScoreTeam = 3 then // Blue Wins
1471 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1472 begin
1473 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1474 Result := True;
1475 end;
1476 end;
1477 end;
1478 // Ïðîèãðûø
1479 if (Data.ScoreAction = 3) and (gGameSettings.GoalLimit > 0) then
1480 begin
1481 // Ñâîåé èëè ÷óæîé êîìàíäû
1482 if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
1483 begin
1484 p := g_Player_Get(ActivateUID);
1485 if ((Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Red Wins
1486 or ((Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
1487 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1488 begin
1489 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1491 if Data.ScoreCon then
1492 if Data.ScoreTeam = 0 then
1493 begin
1494 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1495 if g_Game_IsServer and g_Game_IsNet then
1496 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wre');
1497 end else
1498 begin
1499 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
1500 if g_Game_IsServer and g_Game_IsNet then
1501 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wr');
1502 end;
1504 Result := True;
1505 end;
1506 if ((Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) // Blue Wins
1507 or ((Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
1508 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1509 begin
1510 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1512 if Data.ScoreCon then
1513 if Data.ScoreTeam = 0 then
1514 begin
1515 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1516 if g_Game_IsServer and g_Game_IsNet then
1517 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wbe');
1518 end else
1519 begin
1520 g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
1521 if g_Game_IsServer and g_Game_IsNet then
1522 MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wb');
1523 end;
1525 Result := True;
1526 end;
1527 end;
1528 // Êàêîé-òî êîíêðåòíîé êîìàíäû
1529 if Data.ScoreTeam in [2..3] then
1530 begin
1531 if Data.ScoreTeam = 3 then // Red Wins
1532 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
1533 begin
1534 gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
1535 Result := True;
1536 end;
1537 if Data.ScoreTeam = 2 then // Blue Wins
1538 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
1539 begin
1540 gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
1541 Result := True;
1542 end;
1543 end;
1544 end;
1545 if Result then begin
1546 if coolDown then
1547 TimeOut := 18
1548 else
1549 TimeOut := 0;
1550 if g_Game_IsServer and g_Game_IsNet then
1551 MH_SEND_GameStats;
1552 end;
1553 end;
1555 TRIGGER_MESSAGE:
1556 begin
1557 msg := b_Text_Format(Data.MessageText);
1558 case Data.MessageSendTo of
1559 0: // activator
1560 begin
1561 if g_GetUIDType(ActivateUID) = UID_PLAYER then
1562 begin
1563 if g_Game_IsWatchedPlayer(ActivateUID) then
1564 begin
1565 if Data.MessageKind = 0 then
1566 g_Console_Add(msg, True)
1567 else if Data.MessageKind = 1 then
1568 g_Game_Message(msg, Data.MessageTime);
1569 end
1570 else
1571 begin
1572 p := g_Player_Get(ActivateUID);
1573 if g_Game_IsNet and (p.FClientID >= 0) then
1574 if Data.MessageKind = 0 then
1575 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, p.FClientID)
1576 else if Data.MessageKind = 1 then
1577 MH_SEND_GameEvent(NET_EV_BIGTEXT, Data.MessageTime, msg, p.FClientID);
1578 end;
1579 end;
1580 end;
1582 1: // activator's team
1583 begin
1584 if g_GetUIDType(ActivateUID) = UID_PLAYER then
1585 begin
1586 p := g_Player_Get(ActivateUID);
1587 if g_Game_IsWatchedTeam(p.Team) then
1588 if Data.MessageKind = 0 then
1589 g_Console_Add(msg, True)
1590 else if Data.MessageKind = 1 then
1591 g_Game_Message(msg, Data.MessageTime);
1593 if g_Game_IsNet then
1594 begin
1595 for i := Low(gPlayers) to High(gPlayers) do
1596 if (gPlayers[i].Team = p.Team) and (gPlayers[i].FClientID >= 0) then
1597 if Data.MessageKind = 0 then
1598 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
1599 else if Data.MessageKind = 1 then
1600 MH_SEND_GameEvent(NET_EV_BIGTEXT, Data.MessageTime, msg, gPlayers[i].FClientID);
1601 end;
1602 end;
1603 end;
1605 2: // activator's enemy team
1606 begin
1607 if g_GetUIDType(ActivateUID) = UID_PLAYER then
1608 begin
1609 p := g_Player_Get(ActivateUID);
1610 if g_Game_IsWatchedTeam(p.Team) then
1611 if Data.MessageKind = 0 then
1612 g_Console_Add(msg, True)
1613 else if Data.MessageKind = 1 then
1614 g_Game_Message(msg, Data.MessageTime);
1616 if g_Game_IsNet then
1617 begin
1618 for i := Low(gPlayers) to High(gPlayers) do
1619 if (gPlayers[i].Team <> p.Team) and (gPlayers[i].FClientID >= 0) then
1620 if Data.MessageKind = 0 then
1621 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
1622 else if Data.MessageKind = 1 then
1623 MH_SEND_GameEvent(NET_EV_BIGTEXT, Data.MessageTime, msg, gPlayers[i].FClientID);
1624 end;
1625 end;
1626 end;
1628 3: // red team
1629 begin
1630 if g_Game_IsWatchedTeam(TEAM_RED) then
1631 if Data.MessageKind = 0 then
1632 g_Console_Add(msg, True)
1633 else if Data.MessageKind = 1 then
1634 g_Game_Message(msg, Data.MessageTime);
1636 if g_Game_IsNet then
1637 begin
1638 for i := Low(gPlayers) to High(gPlayers) do
1639 if (gPlayers[i].Team = TEAM_RED) and (gPlayers[i].FClientID >= 0) then
1640 if Data.MessageKind = 0 then
1641 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
1642 else if Data.MessageKind = 1 then
1643 MH_SEND_GameEvent(NET_EV_BIGTEXT, Data.MessageTime, msg, gPlayers[i].FClientID);
1644 end;
1645 end;
1647 4: // blue team
1648 begin
1649 if g_Game_IsWatchedTeam(TEAM_BLUE) then
1650 if Data.MessageKind = 0 then
1651 g_Console_Add(msg, True)
1652 else if Data.MessageKind = 1 then
1653 g_Game_Message(msg, Data.MessageTime);
1655 if g_Game_IsNet then
1656 begin
1657 for i := Low(gPlayers) to High(gPlayers) do
1658 if (gPlayers[i].Team = TEAM_BLUE) and (gPlayers[i].FClientID >= 0) then
1659 if Data.MessageKind = 0 then
1660 MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
1661 else if Data.MessageKind = 1 then
1662 MH_SEND_GameEvent(NET_EV_BIGTEXT, Data.MessageTime, msg, gPlayers[i].FClientID);
1663 end;
1664 end;
1666 5: // everyone
1667 begin
1668 if Data.MessageKind = 0 then
1669 g_Console_Add(msg, True)
1670 else if Data.MessageKind = 1 then
1671 g_Game_Message(msg, Data.MessageTime);
1673 if g_Game_IsNet then
1674 begin
1675 if Data.MessageKind = 0 then
1676 MH_SEND_Chat(msg, NET_CHAT_SYSTEM)
1677 else if Data.MessageKind = 1 then
1678 MH_SEND_GameEvent(NET_EV_BIGTEXT, Data.MessageTime, msg);
1679 end;
1680 end;
1681 end;
1682 TimeOut := 18;
1683 end;
1685 TRIGGER_DAMAGE, TRIGGER_HEALTH:
1686 begin
1687 Result := False;
1688 UIDType := g_GetUIDType(ActivateUID);
1689 if (UIDType = UID_PLAYER) or (UIDType = UID_MONSTER) then
1690 begin
1691 Result := True;
1692 k := -1;
1693 if coolDown then
1694 begin
1695 // Âñïîìèíàåì, àêòèâèðîâàë ëè îí ìåíÿ ðàíüøå
1696 for i := 0 to High(Activators) do
1697 if Activators[i].UID = ActivateUID then
1698 begin
1699 k := i;
1700 Break;
1701 end;
1702 if k = -1 then
1703 begin // Âèäèì åãî âïåðâûå
1704 // Çàïîìèíàåì åãî
1705 SetLength(Activators, Length(Activators) + 1);
1706 k := High(Activators);
1707 Activators[k].UID := ActivateUID;
1708 end else
1709 begin // Óæå âèäåëè åãî
1710 // Åñëè èíòåðâàë îòêëþ÷¸í, íî îí âñ¸ åù¸ â çîíå ïîðàæåíèÿ, äà¸ì åìó âðåìÿ
1711 if (Data.DamageInterval = 0) and (Activators[k].TimeOut > 0) then
1712 Activators[k].TimeOut := 65535;
1713 // Òàéìàóò ïðîø¸ë - ðàáîòàåì
1714 Result := Activators[k].TimeOut = 0;
1715 end;
1716 end;
1718 if Result then
1719 begin
1720 case UIDType of
1721 UID_PLAYER:
1722 begin
1723 p := g_Player_Get(ActivateUID);
1724 if p = nil then
1725 Exit;
1727 // Íàíîñèì óðîí èãðîêó
1728 if (TriggerType = TRIGGER_DAMAGE) and (Data.DamageValue > 0) then
1729 p.Damage(Data.DamageValue, 0, 0, 0, HIT_SOME);
1731 // Ëå÷èì èãðîêà
1732 if (TriggerType = TRIGGER_HEALTH) and (Data.HealValue > 0) then
1733 if p.Heal(Data.HealValue, not Data.HealMax) and (not Data.HealSilent) then
1734 begin
1735 g_Sound_PlayExAt('SOUND_ITEM_GETITEM', p.Obj.X, p.Obj.Y);
1736 if g_Game_IsServer and g_Game_IsNet then
1737 MH_SEND_Sound(p.Obj.X, p.Obj.Y, 'SOUND_ITEM_GETITEM');
1738 end;
1739 end;
1741 UID_MONSTER:
1742 begin
1743 m := g_Monsters_Get(ActivateUID);
1744 if m = nil then
1745 Exit;
1747 // Íàíîñèì óðîí ìîíñòðó
1748 if (TriggerType = TRIGGER_DAMAGE) and (Data.DamageValue > 0) then
1749 m.Damage(Data.DamageValue, 0, 0, 0, HIT_SOME);
1751 // Ëå÷èì ìîíñòðà
1752 if (TriggerType = TRIGGER_HEALTH) and (Data.HealValue > 0) then
1753 if m.Heal(Data.HealValue) and (not Data.HealSilent) then
1754 begin
1755 g_Sound_PlayExAt('SOUND_ITEM_GETITEM', m.Obj.X, m.Obj.Y);
1756 if g_Game_IsServer and g_Game_IsNet then
1757 MH_SEND_Sound(m.Obj.X, m.Obj.Y, 'SOUND_ITEM_GETITEM');
1758 end;
1759 end;
1760 end;
1761 // Íàçíà÷àåì âðåìÿ ñëåäóþùåãî âîçäåéñòâèÿ
1762 if TriggerType = TRIGGER_DAMAGE then
1763 i := Data.DamageInterval
1764 else
1765 i := Data.HealInterval;
1766 if coolDown then
1767 if i > 0 then
1768 Activators[k].TimeOut := i
1769 else
1770 Activators[k].TimeOut := 65535;
1771 end;
1772 end;
1773 TimeOut := 0;
1774 end;
1776 TRIGGER_SHOT:
1777 begin
1778 if ShotSightTime > 0 then
1779 Exit;
1781 wx := Data.ShotPos.X;
1782 wy := Data.ShotPos.Y;
1783 pAngle := -DegToRad(Data.ShotAngle);
1784 xd := wx + Round(Cos(pAngle) * 32.0);
1785 yd := wy + Round(Sin(pAngle) * 32.0);
1786 TargetUID := 0;
1788 case Data.ShotTarget of
1789 TRIGGER_SHOT_TARGET_MON: // monsters
1790 if gMonsters <> nil then
1791 for i := Low(gMonsters) to High(gMonsters) do
1792 if (gMonsters[i] <> nil) and gMonsters[i].Live and
1793 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gMonsters[i].Obj))) then
1794 begin
1795 xd := gMonsters[i].GameX + gMonsters[i].Obj.Rect.Width div 2;
1796 yd := gMonsters[i].GameY + gMonsters[i].Obj.Rect.Height div 2;
1797 TargetUID := gMonsters[i].UID;
1798 break;
1799 end;
1801 TRIGGER_SHOT_TARGET_PLR: // players
1802 if gPlayers <> nil then
1803 for i := Low(gPlayers) to High(gPlayers) do
1804 if (gPlayers[i] <> nil) and gPlayers[i].Live and
1805 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then
1806 begin
1807 xd := gPlayers[i].GameX + PLAYER_RECT_CX;
1808 yd := gPlayers[i].GameY + PLAYER_RECT_CY;
1809 TargetUID := gPlayers[i].UID;
1810 break;
1811 end;
1813 TRIGGER_SHOT_TARGET_RED: // red team
1814 if gPlayers <> nil then
1815 for i := Low(gPlayers) to High(gPlayers) do
1816 if (gPlayers[i] <> nil) and gPlayers[i].Live and
1817 (gPlayers[i].Team = TEAM_RED) and
1818 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then
1819 begin
1820 xd := gPlayers[i].GameX + PLAYER_RECT_CX;
1821 yd := gPlayers[i].GameY + PLAYER_RECT_CY;
1822 TargetUID := gPlayers[i].UID;
1823 break;
1824 end;
1826 TRIGGER_SHOT_TARGET_BLUE: // blue team
1827 if gPlayers <> nil then
1828 for i := Low(gPlayers) to High(gPlayers) do
1829 if (gPlayers[i] <> nil) and gPlayers[i].Live and
1830 (gPlayers[i].Team = TEAM_BLUE) and
1831 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then
1832 begin
1833 xd := gPlayers[i].GameX + PLAYER_RECT_CX;
1834 yd := gPlayers[i].GameY + PLAYER_RECT_CY;
1835 TargetUID := gPlayers[i].UID;
1836 break;
1837 end;
1839 TRIGGER_SHOT_TARGET_MONPLR: // monsters then players
1840 begin
1841 if gMonsters <> nil then
1842 for i := Low(gMonsters) to High(gMonsters) do
1843 if (gMonsters[i] <> nil) and gMonsters[i].Live and
1844 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gMonsters[i].Obj))) then
1845 begin
1846 xd := gMonsters[i].GameX + gMonsters[i].Obj.Rect.Width div 2;
1847 yd := gMonsters[i].GameY + gMonsters[i].Obj.Rect.Height div 2;
1848 TargetUID := gMonsters[i].UID;
1849 break;
1850 end;
1851 if (TargetUID = 0) and (gPlayers <> nil) then
1852 for i := Low(gPlayers) to High(gPlayers) do
1853 if (gPlayers[i] <> nil) and gPlayers[i].Live and
1854 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then
1855 begin
1856 xd := gPlayers[i].GameX + PLAYER_RECT_CX;
1857 yd := gPlayers[i].GameY + PLAYER_RECT_CY;
1858 TargetUID := gPlayers[i].UID;
1859 break;
1860 end;
1861 end;
1863 TRIGGER_SHOT_TARGET_PLRMON: // players then monsters
1864 begin
1865 if gPlayers <> nil then
1866 for i := Low(gPlayers) to High(gPlayers) do
1867 if (gPlayers[i] <> nil) and gPlayers[i].Live and
1868 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then
1869 begin
1870 xd := gPlayers[i].GameX + PLAYER_RECT_CX;
1871 yd := gPlayers[i].GameY + PLAYER_RECT_CY;
1872 TargetUID := gPlayers[i].UID;
1873 break;
1874 end;
1875 if (TargetUID = 0) and (gMonsters <> nil) then
1876 for i := Low(gMonsters) to High(gMonsters) do
1877 if (gMonsters[i] <> nil) and gMonsters[i].Live and
1878 (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gMonsters[i].Obj))) then
1879 begin
1880 xd := gMonsters[i].GameX + gMonsters[i].Obj.Rect.Width div 2;
1881 yd := gMonsters[i].GameY + gMonsters[i].Obj.Rect.Height div 2;
1882 TargetUID := gMonsters[i].UID;
1883 break;
1884 end;
1885 end;
1887 else TargetUID := ActivateUID;
1888 end;
1890 if (Data.ShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID > 0) then
1891 begin
1892 Result := True;
1893 if (Data.ShotIntSight = 0) or
1894 (Data.ShotTarget = TRIGGER_SHOT_TARGET_NONE) or
1895 (TargetUID = ShotSightTarget) then
1896 MakeShot(Trigger, wx, wy, xd, yd, TargetUID)
1897 else
1898 begin
1899 ShotSightTime := Data.ShotIntSight;
1900 ShotSightTargetN := TargetUID;
1901 if Data.ShotType = TRIGGER_SHOT_BFG then
1902 begin
1903 g_Sound_PlayExAt('SOUND_WEAPON_STARTFIREBFG', wx, wy);
1904 if g_Game_IsNet and g_Game_IsServer then
1905 MH_SEND_Sound(wx, wy, 'SOUND_WEAPON_STARTFIREBFG');
1906 end;
1907 end;
1908 end;
1910 TimeOut := Data.ShotWait + 1;
1911 end;
1913 TRIGGER_EFFECT:
1914 begin
1915 i := Data.FXCount;
1917 while i > 0 do
1918 begin
1919 case Data.FXPos of
1920 TRIGGER_EFFECT_POS_CENTER:
1921 begin
1922 wx := X + Width div 2;
1923 wy := Y + Height div 2;
1924 end;
1925 TRIGGER_EFFECT_POS_AREA:
1926 begin
1927 wx := X + Random(Width);
1928 wy := Y + Random(Height);
1929 end;
1930 else begin
1931 wx := X + Width div 2;
1932 wy := Y + Height div 2;
1933 end;
1934 end;
1935 xd := Data.FXVelX;
1936 yd := Data.FXVelY;
1937 if Data.FXSpreadL > 0 then xd := xd - Random(Data.FXSpreadL + 1);
1938 if Data.FXSpreadR > 0 then xd := xd + Random(Data.FXSpreadR + 1);
1939 if Data.FXSpreadU > 0 then yd := yd - Random(Data.FXSpreadU + 1);
1940 if Data.FXSpreadD > 0 then yd := yd + Random(Data.FXSpreadD + 1);
1941 MakeEffect(wx, wy, xd, yd,
1942 Data.FXType, Data.FXSubType,
1943 Data.FXColorR, Data.FXColorG, Data.FXColorB, True, False);
1944 Dec(i);
1945 end;
1946 TimeOut := Data.FXWait;
1947 end;
1949 TRIGGER_SCRIPT:
1950 begin
1951 g_Scripts_ProcExec(Data.SCRProc, [ID, ActivateUID, actType, Data.SCRArg], 'map');
1952 TimeOut := 0;
1953 Result := True;
1954 end;
1955 end;
1956 end;
1958 if Result and (Trigger.TexturePanel <> -1) then
1959 g_Map_SwitchTexture(Trigger.TexturePanelType, Trigger.TexturePanel, IfThen(animonce, 2, 1));
1960 end;
1962 function g_Triggers_Create(Trigger: TTrigger): DWORD;
1963 var
1964 find_id: DWORD;
1965 fn, mapw: String;
1966 begin
1967 // Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà:
1968 if (Trigger.TriggerType = TRIGGER_EXIT) and
1969 (not LongBool(gGameSettings.Options and GAME_OPTION_ALLOWEXIT)) then
1970 Trigger.TriggerType := TRIGGER_NONE;
1972 // Åñëè ìîíñòðû çàïðåùåíû, îòìåíÿåì òðèããåð:
1973 if (Trigger.TriggerType = TRIGGER_SPAWNMONSTER) and
1974 (not LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS)) and
1975 (gGameSettings.GameType <> GT_SINGLE) then
1976 Trigger.TriggerType := TRIGGER_NONE;
1978 // Ñ÷èòàåì êîëè÷åñòâî ñåêðåòîâ íà êàðòå:
1979 if Trigger.TriggerType = TRIGGER_SECRET then
1980 gSecretsCount := gSecretsCount + 1;
1982 find_id := FindTrigger();
1983 gTriggers[find_id] := Trigger;
1985 with gTriggers[find_id] do
1986 begin
1987 ID := find_id;
1988 // if this type of trigger exists both on the client and on the server
1989 // use an uniform numeration
1990 if Trigger.TriggerType = TRIGGER_SOUND then
1991 begin
1992 Inc(gTriggerClientID);
1993 ClientID := gTriggerClientID;
1994 end
1995 else
1996 ClientID := 0;
1997 TimeOut := 0;
1998 ActivateUID := 0;
1999 PlayerCollide := False;
2000 DoorTime := -1;
2001 PressTime := -1;
2002 PressCount := 0;
2003 SoundPlayCount := 0;
2004 Sound := nil;
2005 AutoSpawn := False;
2006 SpawnCooldown := 0;
2007 SpawnedCount := 0;
2008 end;
2010 // Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê":
2011 if (Trigger.TriggerType = TRIGGER_SOUND) and
2012 (Trigger.Data.SoundName <> '') then
2013 begin
2014 // Åùå íåò òàêîãî çâóêà:
2015 if not g_Sound_Exists(Trigger.Data.SoundName) then
2016 begin
2017 fn := g_ExtractWadName(Trigger.Data.SoundName);
2019 if fn = '' then
2020 begin // Çâóê â ôàéëå ñ êàðòîé
2021 mapw := g_ExtractWadName(gMapInfo.Map);
2022 fn := mapw+':'+g_ExtractFilePathName(Trigger.Data.SoundName);
2023 end
2024 else // Çâóê â îòäåëüíîì ôàéëå
2025 fn := GameDir + '/wads/' + Trigger.Data.SoundName;
2027 if not g_Sound_CreateWADEx(Trigger.Data.SoundName, fn) then
2028 g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.Data.SoundName]));
2029 end;
2031 // Ñîçäàåì îáúåêò çâóêà:
2032 with gTriggers[find_id] do
2033 begin
2034 Sound := TPlayableSound.Create();
2035 if not Sound.SetByName(Trigger.Data.SoundName) then
2036 begin
2037 Sound.Free();
2038 Sound := nil;
2039 end;
2040 end;
2041 end;
2043 // Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà":
2044 if (Trigger.TriggerType = TRIGGER_MUSIC) and
2045 (Trigger.Data.MusicName <> '') then
2046 begin
2047 // Åùå íåò òàêîé ìóçûêè:
2048 if not g_Sound_Exists(Trigger.Data.MusicName) then
2049 begin
2050 fn := g_ExtractWadName(Trigger.Data.MusicName);
2052 if fn = '' then
2053 begin // Ìóçûêà â ôàéëå ñ êàðòîé
2054 mapw := g_ExtractWadName(gMapInfo.Map);
2055 fn := mapw+':'+g_ExtractFilePathName(Trigger.Data.MusicName);
2056 end
2057 else // Ìóçûêà â ôàéëå ñ êàðòîé
2058 fn := GameDir+'/wads/'+Trigger.Data.MusicName;
2060 if not g_Sound_CreateWADEx(Trigger.Data.MusicName, fn, True) then
2061 g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.Data.MusicName]));
2062 end;
2063 end;
2065 // Çàãðóæàåì äàííûå òðèããåðà "Òóðåëü":
2066 if Trigger.TriggerType = TRIGGER_SHOT then
2067 with gTriggers[find_id] do
2068 begin
2069 ShotPanelTime := 0;
2070 ShotSightTime := 0;
2071 ShotSightTimeout := 0;
2072 ShotSightTarget := 0;
2073 ShotSightTargetN := 0;
2074 ShotAmmoCount := Trigger.Data.ShotAmmo;
2075 ShotReloadTime := 0;
2076 end;
2078 Result := find_id;
2079 end;
2081 procedure g_Triggers_Update();
2082 var
2083 a, b, i: Integer;
2084 Affected: array of Integer;
2085 begin
2086 if gTriggers = nil then
2087 Exit;
2088 SetLength(Affected, 0);
2090 for a := 0 to High(gTriggers) do
2091 with gTriggers[a] do
2092 // Åñòü òðèããåð:
2093 if TriggerType <> TRIGGER_NONE then
2094 begin
2095 // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè):
2096 if DoorTime > 0 then
2097 DoorTime := DoorTime - 1;
2098 // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ:
2099 if PressTime > 0 then
2100 PressTime := PressTime - 1;
2101 // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè:
2102 if (TriggerType = TRIGGER_DAMAGE) or (TriggerType = TRIGGER_HEALTH) then
2103 for b := 0 to High(Activators) do
2104 begin
2105 // Óìåíüøàåì âðåìÿ äî ïîâòîðíîãî âîçäåéñòâèÿ:
2106 if Activators[b].TimeOut > 0 then
2107 Dec(Activators[b].TimeOut)
2108 else
2109 Continue;
2110 // Ñ÷èòàåì, ÷òî îáúåêò ïîêèíóë çîíó äåéñòâèÿ òðèããåðà
2111 if (Data.DamageInterval = 0) and (Activators[b].TimeOut < 65530) then
2112 Activators[b].TimeOut := 0;
2113 end;
2115 // Îáðàáàòûâàåì ñïàâíåðû:
2116 if Enabled and AutoSpawn then
2117 if SpawnCooldown = 0 then
2118 begin
2119 // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà:
2120 if (TriggerType = TRIGGER_SPAWNMONSTER) and (Data.MonDelay > 0) then
2121 begin
2122 ActivateUID := 0;
2123 ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
2124 end;
2125 // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò:
2126 if (TriggerType = TRIGGER_SPAWNITEM) and (Data.ItemDelay > 0) then
2127 begin
2128 ActivateUID := 0;
2129 ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
2130 end;
2131 end else // Óìåíüøàåì âðåìÿ îæèäàíèÿ:
2132 Dec(SpawnCooldown);
2134 // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü":
2135 if TriggerType = TRIGGER_SHOT then
2136 begin
2137 if ShotPanelTime > 0 then
2138 begin
2139 Dec(ShotPanelTime);
2140 if ShotPanelTime = 0 then
2141 g_Map_SwitchTexture(ShotPanelType, Data.ShotPanelID);
2142 end;
2143 if ShotSightTime > 0 then
2144 begin
2145 Dec(ShotSightTime);
2146 if ShotSightTime = 0 then
2147 ShotSightTarget := ShotSightTargetN;
2148 end;
2149 if ShotSightTimeout > 0 then
2150 begin
2151 Dec(ShotSightTimeout);
2152 if ShotSightTimeout = 0 then
2153 ShotSightTarget := 0;
2154 end;
2155 if ShotReloadTime > 0 then
2156 begin
2157 Dec(ShotReloadTime);
2158 if ShotReloadTime = 0 then
2159 ShotAmmoCount := Data.ShotAmmo;
2160 end;
2161 end;
2163 // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì:
2164 if Enabled and (TriggerType = TRIGGER_SOUND) and (Sound <> nil) then
2165 if (SoundPlayCount > 0) and (not Sound.IsPlaying()) then
2166 begin
2167 if Data.PlayCount > 0 then // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
2168 SoundPlayCount := SoundPlayCount - 1;
2169 if Data.Local then
2170 Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0)
2171 else
2172 Sound.PlayPanVolume((Data.Pan-127.0)/128.0, Data.Volume/255.0);
2173 if Sound.IsPlaying() and g_Game_IsNet and g_Game_IsServer then
2174 MH_SEND_TriggerSound(gTriggers[a]);
2175 end;
2177 // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü:
2178 if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (Data.PanelID <> -1) then
2179 begin
2180 OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
2181 DoorTime := -1;
2182 end;
2184 // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü:
2185 if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (Data.PanelID <> -1) then
2186 begin
2187 // Óæå çàêðûòà:
2188 if gWalls[Data.PanelID].Enabled then
2189 DoorTime := -1
2190 else // Ïîêà îòêðûòà - çàêðûâàåì
2191 if CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors) then
2192 DoorTime := -1;
2193 end;
2195 // Òðèããåð - ðàñøèðèòåëü èëè ïåðåêëþ÷àòåëü, è ïðîøëà çàäåðæêà, è íàæàëè íóæíîå ÷èñëî ðàç:
2196 if (TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) and
2197 (PressTime = 0) and (PressCount >= Data.Count) then
2198 begin
2199 // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè:
2200 PressTime := -1;
2201 // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé:
2202 if Data.Count > 0 then
2203 PressCount := PressCount - Data.Count
2204 else
2205 PressCount := 0;
2207 // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû:
2208 for b := 0 to High(gTriggers) do
2209 if g_Collide(Data.tX, Data.tY, Data.tWidth, Data.tHeight, gTriggers[b].X, gTriggers[b].Y,
2210 gTriggers[b].Width, gTriggers[b].Height) and
2211 ((b <> a) or (Data.Wait > 0)) then
2212 begin // Can be self-activated, if there is Data.Wait
2213 if (not Data.ExtRandom) or gTriggers[b].Enabled then
2214 begin
2215 SetLength(Affected, Length(Affected) + 1);
2216 Affected[High(Affected)] := b;
2217 end;
2218 end;
2219 // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì:
2220 if (TriggerType = TRIGGER_PRESS) and Data.ExtRandom then
2221 begin
2222 if (Length(Affected) > 0) then
2223 begin
2224 b := Affected[Random(Length(Affected))];
2225 gTriggers[b].ActivateUID := gTriggers[a].ActivateUID;
2226 ActivateTrigger(gTriggers[b], 0);
2227 end;
2228 end
2229 else //  ïðîòèâíîì ñëó÷àå ðàáîòàåì êàê îáû÷íî:
2230 for i := 0 to High(Affected) do
2231 begin
2232 b := Affected[i];
2233 case TriggerType of
2234 TRIGGER_PRESS:
2235 begin
2236 gTriggers[b].ActivateUID := gTriggers[a].ActivateUID;
2237 ActivateTrigger(gTriggers[b], 0);
2238 end;
2239 TRIGGER_ON:
2240 begin
2241 gTriggers[b].Enabled := True;
2242 end;
2243 TRIGGER_OFF:
2244 begin
2245 gTriggers[b].Enabled := False;
2246 gTriggers[b].TimeOut := 0;
2247 if gTriggers[b].AutoSpawn then
2248 begin
2249 gTriggers[b].AutoSpawn := False;
2250 gTriggers[b].SpawnCooldown := 0;
2251 end;
2252 end;
2253 TRIGGER_ONOFF:
2254 begin
2255 gTriggers[b].Enabled := not gTriggers[b].Enabled;
2256 if not gTriggers[b].Enabled then
2257 begin
2258 gTriggers[b].TimeOut := 0;
2259 if gTriggers[b].AutoSpawn then
2260 begin
2261 gTriggers[b].AutoSpawn := False;
2262 gTriggers[b].SpawnCooldown := 0;
2263 end;
2264 end;
2265 end;
2266 end;
2267 end;
2268 SetLength(Affected, 0);
2269 end;
2271 // Óìåíüøàåì âðåìÿ äî âîçìîæíîñòè ïîâòîðíîé àêòèâàöèè:
2272 if TimeOut > 0 then
2273 begin
2274 TimeOut := TimeOut - 1;
2275 Continue; // ×òîáû íå ïîòåðÿòü 1 åäèíèöó çàäåðæêè
2276 end;
2278 // Íèæå èäóò òèïû àêòèâàöèè, åñëè òðèããåð îòêëþ÷¸í - èä¸ì äàëüøå
2279 if not Enabled then
2280 Continue;
2282 // "Èãðîê áëèçêî":
2283 if ByteBool(ActivateType and ACTIVATE_PLAYERCOLLIDE) and
2284 (TimeOut = 0) then
2285 if gPlayers <> nil then
2286 for b := 0 to High(gPlayers) do
2287 if gPlayers[b] <> nil then
2288 with gPlayers[b] do
2289 // Æèâ, åñòü íóæíûå êëþ÷è è îí ðÿäîì:
2290 if Live and ((gTriggers[a].Keys and GetKeys) = gTriggers[a].Keys) and
2291 Collide(X, Y, Width, Height) then
2292 begin
2293 gTriggers[a].ActivateUID := UID;
2295 if (gTriggers[a].TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) and
2296 PlayerCollide then
2297 { Don't activate sound/music again if player is here }
2298 else
2299 ActivateTrigger(gTriggers[a], ACTIVATE_PLAYERCOLLIDE);
2300 end;
2302 { TODO 5 : àêòèâàöèÿ ìîíñòðàìè òðèããåðîâ ñ êëþ÷àìè }
2304 if ByteBool(ActivateType and ACTIVATE_MONSTERCOLLIDE) and
2305 ByteBool(ActivateType and ACTIVATE_NOMONSTER) and
2306 (TimeOut = 0) and (Keys = 0) then
2307 begin
2308 // Åñëè "Ìîíñòð áëèçêî" è "Ìîíñòðîâ íåò",
2309 // çàïóñêàåì òðèããåð íà ñòàðòå êàðòû è ñíèìàåì îáà ôëàãà
2310 ActivateType := ActivateType and not (ACTIVATE_MONSTERCOLLIDE or ACTIVATE_NOMONSTER);
2311 gTriggers[a].ActivateUID := 0;
2312 ActivateTrigger(gTriggers[a], 0);
2313 end else
2314 begin
2315 // "Ìîíñòð áëèçêî":
2316 if ByteBool(ActivateType and ACTIVATE_MONSTERCOLLIDE) and
2317 (TimeOut = 0) and (Keys = 0) then // Åñëè íå íóæíû êëþ÷è
2318 if gMonsters <> nil then
2319 for b := 0 to High(gMonsters) do
2320 if (gMonsters[b] <> nil) then
2321 with gMonsters[b] do
2322 if Collide(X, Y, Width, Height) then
2323 begin
2324 gTriggers[a].ActivateUID := UID;
2325 ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE);
2326 end;
2328 // "Ìîíñòðîâ íåò":
2329 if ByteBool(ActivateType and ACTIVATE_NOMONSTER) and
2330 (TimeOut = 0) and (Keys = 0) then
2331 if not g_CollideMonster(X, Y, Width, Height) then
2332 begin
2333 gTriggers[a].ActivateUID := 0;
2334 ActivateTrigger(gTriggers[a], ACTIVATE_NOMONSTER);
2335 end;
2336 end;
2338 PlayerCollide := g_CollidePlayer(X, Y, Width, Height);
2339 end;
2340 end;
2342 procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte);
2343 begin
2344 gTriggers[ID].ActivateUID := 0;
2345 ActivateTrigger(gTriggers[ID], ActivateType);
2346 end;
2348 function g_Triggers_PressR(X, Y: Integer; Width, Height: Word; UID: Word;
2349 ActivateType: Byte; IgnoreList: DWArray = nil): DWArray;
2350 var
2351 a: Integer;
2352 k: Byte;
2353 p: TPlayer;
2354 begin
2355 Result := nil;
2357 if gTriggers = nil then Exit;
2359 case g_GetUIDType(UID) of
2360 UID_GAME: k := 255;
2361 UID_PLAYER:
2362 begin
2363 p := g_Player_Get(UID);
2364 if p <> nil then
2365 k := p.GetKeys
2366 else
2367 k := 0;
2368 end;
2369 else k := 0;
2370 end;
2372 for a := 0 to High(gTriggers) do
2373 if (gTriggers[a].TriggerType <> TRIGGER_NONE) and
2374 (gTriggers[a].TimeOut = 0) and
2375 (not InDWArray(a, IgnoreList)) and
2376 ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and
2377 ByteBool(gTriggers[a].ActivateType and ActivateType) then
2378 if g_Collide(X, Y, Width, Height,
2379 gTriggers[a].X, gTriggers[a].Y,
2380 gTriggers[a].Width, gTriggers[a].Height) then
2381 begin
2382 gTriggers[a].ActivateUID := UID;
2383 if ActivateTrigger(gTriggers[a], ActivateType) then
2384 begin
2385 SetLength(Result, Length(Result)+1);
2386 Result[High(Result)] := a;
2387 end;
2388 end;
2389 end;
2391 procedure g_Triggers_PressL(X1, Y1, X2, Y2: Integer; UID: DWORD; ActivateType: Byte);
2392 var
2393 a: Integer;
2394 k: Byte;
2395 p: TPlayer;
2396 begin
2397 if gTriggers = nil then Exit;
2399 case g_GetUIDType(UID) of
2400 UID_GAME: k := 255;
2401 UID_PLAYER:
2402 begin
2403 p := g_Player_Get(UID);
2404 if p <> nil then
2405 k := p.GetKeys
2406 else
2407 k := 0;
2408 end;
2409 else k := 0;
2410 end;
2412 for a := 0 to High(gTriggers) do
2413 if (gTriggers[a].TriggerType <> TRIGGER_NONE) and
2414 (gTriggers[a].TimeOut = 0) and
2415 ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and
2416 ByteBool(gTriggers[a].ActivateType and ActivateType) then
2417 if g_CollideLine(x1, y1, x2, y2, gTriggers[a].X, gTriggers[a].Y,
2418 gTriggers[a].Width, gTriggers[a].Height) then
2419 begin
2420 gTriggers[a].ActivateUID := UID;
2421 ActivateTrigger(gTriggers[a], ActivateType);
2422 end;
2423 end;
2425 procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte);
2426 var
2427 a: Integer;
2428 k: Byte;
2429 rsq: Word;
2430 p: TPlayer;
2431 begin
2432 if gTriggers = nil then
2433 Exit;
2435 case g_GetUIDType(UID) of
2436 UID_GAME: k := 255;
2437 UID_PLAYER:
2438 begin
2439 p := g_Player_Get(UID);
2440 if p <> nil then
2441 k := p.GetKeys
2442 else
2443 k := 0;
2444 end;
2445 else k := 0;
2446 end;
2448 rsq := Radius * Radius;
2450 for a := 0 to High(gTriggers) do
2451 if (gTriggers[a].TriggerType <> TRIGGER_NONE) and
2452 (gTriggers[a].TimeOut = 0) and
2453 ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and
2454 ByteBool(gTriggers[a].ActivateType and ActivateType) then
2455 with gTriggers[a] do
2456 if g_Collide(CX-Radius, CY-Radius, 2*Radius, 2*Radius,
2457 X, Y, Width, Height) then
2458 if ((Sqr(CX-X)+Sqr(CY-Y)) < rsq) or // Öåíòð êðóãà áëèçîê ê âåðõíåìó ëåâîìó óãëó
2459 ((Sqr(CX-X-Width)+Sqr(CY-Y)) < rsq) or // Öåíòð êðóãà áëèçîê ê âåðõíåìó ïðàâîìó óãëó
2460 ((Sqr(CX-X-Width)+Sqr(CY-Y-Height)) < rsq) or // Öåíòð êðóãà áëèçîê ê íèæíåìó ïðàâîìó óãëó
2461 ((Sqr(CX-X)+Sqr(CY-Y-Height)) < rsq) or // Öåíòð êðóãà áëèçîê ê íèæíåìó ëåâîìó óãëó
2462 ( (CX > (X-Radius)) and (CX < (X+Width+Radius)) and
2463 (CY > Y) and (CY < (Y+Height)) ) or // Öåíòð êðóãà íåäàëåêî îò âåðòèêàëüíûõ ãðàíèö ïðÿìîóãîëüíèêà
2464 ( (CY > (Y-Radius)) and (CY < (Y+Height+Radius)) and
2465 (CX > X) and (CX < (X+Width)) ) then // Öåíòð êðóãà íåäàëåêî îò ãîðèçîíòàëüíûõ ãðàíèö ïðÿìîóãîëüíèêà
2466 begin
2467 ActivateUID := UID;
2468 ActivateTrigger(gTriggers[a], ActivateType);
2469 end;
2470 end;
2472 procedure g_Triggers_OpenAll();
2473 var
2474 a: Integer;
2475 b: Boolean;
2476 begin
2477 if gTriggers = nil then Exit;
2479 b := False;
2480 for a := 0 to High(gTriggers) do
2481 with gTriggers[a] do
2482 if (TriggerType = TRIGGER_OPENDOOR) or
2483 (TriggerType = TRIGGER_DOOR5) or
2484 (TriggerType = TRIGGER_DOOR) then
2485 begin
2486 OpenDoor(Data.PanelID, True, Data.d2d_doors);
2487 if TriggerType = TRIGGER_DOOR5 then DoorTime := 180;
2488 b := True;
2489 end;
2491 if b then g_Sound_PlayEx('SOUND_GAME_DOOROPEN');
2492 end;
2494 procedure g_Triggers_DecreaseSpawner(ID: DWORD);
2495 begin
2496 if (gTriggers <> nil) then
2497 if gTriggers[ID].SpawnedCount > 0 then
2498 Dec(gTriggers[ID].SpawnedCount);
2499 end;
2501 procedure g_Triggers_Free();
2502 var
2503 a: Integer;
2504 begin
2505 if gTriggers <> nil then
2506 for a := 0 to High(gTriggers) do
2507 begin
2508 if gTriggers[a].TriggerType = TRIGGER_SOUND then
2509 begin
2510 if g_Sound_Exists(gTriggers[a].Data.SoundName) then
2511 g_Sound_Delete(gTriggers[a].Data.SoundName);
2513 gTriggers[a].Sound.Free();
2514 end;
2515 if gTriggers[a].Activators <> nil then
2516 SetLength(gTriggers[a].Activators, 0);
2517 end;
2519 gTriggers := nil;
2520 gSecretsCount := 0;
2521 SetLength(gMonstersSpawned, 0);
2522 end;
2524 procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter);
2525 var
2526 count, act_count, i, j: Integer;
2527 dw: DWORD;
2528 sg: Single;
2529 b: Boolean;
2530 p: Pointer;
2531 begin
2532 // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ:
2533 count := 0;
2534 if gTriggers <> nil then
2535 for i := 0 to High(gTriggers) do
2536 count := count + 1;
2538 Mem := TBinMemoryWriter.Create((count+1) * 200);
2540 // Êîëè÷åñòâî òðèããåðîâ:
2541 Mem.WriteInt(count);
2543 if count = 0 then
2544 Exit;
2546 for i := 0 to High(gTriggers) do
2547 begin
2548 // Ñèãíàòóðà òðèããåðà:
2549 dw := TRIGGER_SIGNATURE; // 'TRGR'
2550 Mem.WriteDWORD(dw);
2551 // Òèï òðèããåðà:
2552 Mem.WriteByte(gTriggers[i].TriggerType);
2553 // Ñïåöèàëüíûå äàííûå òðèããåðà:
2554 p := @gTriggers[i].Data;
2555 Mem.WriteMemory(p, SizeOf(TTriggerData));
2556 // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
2557 Mem.WriteInt(gTriggers[i].X);
2558 Mem.WriteInt(gTriggers[i].Y);
2559 // Ðàçìåðû:
2560 Mem.WriteWord(gTriggers[i].Width);
2561 Mem.WriteWord(gTriggers[i].Height);
2562 // Âêëþ÷åí ëè òðèããåð:
2563 Mem.WriteBoolean(gTriggers[i].Enabled);
2564 // Òèï àêòèâàöèè òðèããåðà:
2565 Mem.WriteByte(gTriggers[i].ActivateType);
2566 // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
2567 Mem.WriteByte(gTriggers[i].Keys);
2568 // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
2569 Mem.WriteInt(gTriggers[i].TexturePanel);
2570 // Òèï ýòîé ïàíåëè:
2571 Mem.WriteWord(gTriggers[i].TexturePanelType);
2572 // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
2573 Mem.WriteWord(gTriggers[i].TimeOut);
2574 // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð:
2575 Mem.WriteWord(gTriggers[i].ActivateUID);
2576 // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì:
2577 act_count := Length(gTriggers[i].Activators);
2578 Mem.WriteInt(act_count);
2579 for j := 0 to act_count-1 do
2580 begin
2581 // UID îáúåêòà
2582 Mem.WriteWord(gTriggers[i].Activators[j].UID);
2583 // Âðåìÿ îæèäàíèÿ
2584 Mem.WriteWord(gTriggers[i].Activators[j].TimeOut);
2585 end;
2586 // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà:
2587 Mem.WriteBoolean(gTriggers[i].PlayerCollide);
2588 // Âðåìÿ äî çàêðûòèÿ äâåðè:
2589 Mem.WriteInt(gTriggers[i].DoorTime);
2590 // Çàäåðæêà àêòèâàöèè:
2591 Mem.WriteInt(gTriggers[i].PressTime);
2592 // Ñ÷åò÷èê íàæàòèé:
2593 Mem.WriteInt(gTriggers[i].PressCount);
2594 // Ñïàâíåð àêòèâåí:
2595 Mem.WriteBoolean(gTriggers[i].AutoSpawn);
2596 // Çàäåðæêà ñïàâíåðà:
2597 Mem.WriteInt(gTriggers[i].SpawnCooldown);
2598 // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ:
2599 Mem.WriteInt(gTriggers[i].SpawnedCount);
2600 // Ñêîëüêî ðàç ïðîèãðàí çâóê:
2601 Mem.WriteInt(gTriggers[i].SoundPlayCount);
2602 // Ïðîèãðûâàåòñÿ ëè çâóê?
2603 if gTriggers[i].Sound <> nil then
2604 b := gTriggers[i].Sound.IsPlaying()
2605 else
2606 b := False;
2607 Mem.WriteBoolean(b);
2608 if b then
2609 begin
2610 // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà:
2611 dw := gTriggers[i].Sound.GetPosition();
2612 Mem.WriteDWORD(dw);
2613 // Ãðîìêîñòü çâóêà:
2614 sg := gTriggers[i].Sound.GetVolume();
2615 sg := sg / (gSoundLevel/255.0);
2616 Mem.WriteSingle(sg);
2617 // Ñòåðåî ñìåùåíèå çâóêà:
2618 sg := gTriggers[i].Sound.GetPan();
2619 Mem.WriteSingle(sg);
2620 end;
2621 end;
2622 end;
2624 procedure g_Triggers_LoadState(var Mem: TBinMemoryReader);
2625 var
2626 count, act_count, i, j, a: Integer;
2627 dw: DWORD;
2628 vol, pan: Single;
2629 b: Boolean;
2630 p: Pointer;
2631 Trig: TTrigger;
2632 begin
2633 if Mem = nil then
2634 Exit;
2636 g_Triggers_Free();
2638 // Êîëè÷åñòâî òðèããåðîâ:
2639 Mem.ReadInt(count);
2641 if count = 0 then
2642 Exit;
2644 for a := 0 to count-1 do
2645 begin
2646 // Ñèãíàòóðà òðèããåðà:
2647 Mem.ReadDWORD(dw);
2648 if dw <> TRIGGER_SIGNATURE then // 'TRGR'
2649 begin
2650 raise EBinSizeError.Create('g_Triggers_LoadState: Wrong Trigger Signature');
2651 end;
2652 // Òèï òðèããåðà:
2653 Mem.ReadByte(Trig.TriggerType);
2654 // Ñïåöèàëüíûå äàííûå òðèããåðà:
2655 Mem.ReadMemory(p, dw);
2656 if dw <> SizeOf(TTriggerData) then
2657 begin
2658 raise EBinSizeError.Create('g_Triggers_LoadState: Wrong TriggerData Size');
2659 end;
2660 Trig.Data := TTriggerData(p^);
2661 // Ñîçäàåì òðèããåð:
2662 i := g_Triggers_Create(Trig);
2663 // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
2664 Mem.ReadInt(gTriggers[i].X);
2665 Mem.ReadInt(gTriggers[i].Y);
2666 // Ðàçìåðû:
2667 Mem.ReadWord(gTriggers[i].Width);
2668 Mem.ReadWord(gTriggers[i].Height);
2669 // Âêëþ÷åí ëè òðèããåð:
2670 Mem.ReadBoolean(gTriggers[i].Enabled);
2671 // Òèï àêòèâàöèè òðèããåðà:
2672 Mem.ReadByte(gTriggers[i].ActivateType);
2673 // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
2674 Mem.ReadByte(gTriggers[i].Keys);
2675 // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
2676 Mem.ReadInt(gTriggers[i].TexturePanel);
2677 // Òèï ýòîé ïàíåëè:
2678 Mem.ReadWord(gTriggers[i].TexturePanelType);
2679 // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
2680 Mem.ReadWord(gTriggers[i].TimeOut);
2681 // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð:
2682 Mem.ReadWord(gTriggers[i].ActivateUID);
2683 // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì:
2684 Mem.ReadInt(act_count);
2685 if act_count > 0 then
2686 begin
2687 SetLength(gTriggers[i].Activators, act_count);
2688 for j := 0 to act_count-1 do
2689 begin
2690 // UID îáúåêòà
2691 Mem.ReadWord(gTriggers[i].Activators[j].UID);
2692 // Âðåìÿ îæèäàíèÿ
2693 Mem.ReadWord(gTriggers[i].Activators[j].TimeOut);
2694 end;
2695 end;
2696 // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà:
2697 Mem.ReadBoolean(gTriggers[i].PlayerCollide);
2698 // Âðåìÿ äî çàêðûòèÿ äâåðè:
2699 Mem.ReadInt(gTriggers[i].DoorTime);
2700 // Çàäåðæêà àêòèâàöèè:
2701 Mem.ReadInt(gTriggers[i].PressTime);
2702 // Ñ÷åò÷èê íàæàòèé:
2703 Mem.ReadInt(gTriggers[i].PressCount);
2704 // Ñïàâíåð àêòèâåí:
2705 Mem.ReadBoolean(gTriggers[i].AutoSpawn);
2706 // Çàäåðæêà ñïàâíåðà:
2707 Mem.ReadInt(gTriggers[i].SpawnCooldown);
2708 // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ:
2709 Mem.ReadInt(gTriggers[i].SpawnedCount);
2710 // Ñêîëüêî ðàç ïðîèãðàí çâóê:
2711 Mem.ReadInt(gTriggers[i].SoundPlayCount);
2712 // Ïðîèãðûâàåòñÿ ëè çâóê?
2713 Mem.ReadBoolean(b);
2714 if b then
2715 begin
2716 // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà:
2717 Mem.ReadDWORD(dw);
2718 // Ãðîìêîñòü çâóêà:
2719 Mem.ReadSingle(vol);
2720 // Ñòåðåî ñìåùåíèå çâóêà:
2721 Mem.ReadSingle(pan);
2722 // Çàïóñêàåì çâóê, åñëè åñòü:
2723 if gTriggers[i].Sound <> nil then
2724 begin
2725 gTriggers[i].Sound.PlayPanVolume(pan, vol);
2726 gTriggers[i].Sound.Pause(True);
2727 gTriggers[i].Sound.SetPosition(dw);
2728 end
2729 end;
2730 end;
2731 end;
2733 end.