DEADSOFTWARE

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