DEADSOFTWARE

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