DEADSOFTWARE

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