X-Git-Url: https://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=blobdiff_plain;f=src%2Fgame%2Fg_triggers.pas;h=3a1bec2ccbf37a95c84c49de76b6da6bc45c10c0;hp=b8e39d6873b6601f479dd8f2593e2f97fcddef41;hb=HEAD;hpb=cde2fe32ea377e5a5b2582ab689ce666e19f41b0 diff --git a/src/game/g_triggers.pas b/src/game/g_triggers.pas index b8e39d6..3a1bec2 100644 --- a/src/game/g_triggers.pas +++ b/src/game/g_triggers.pas @@ -1,9 +1,8 @@ -(* Copyright (C) DooM 2D:Forever Developers +(* Copyright (C) Doom 2D: Forever Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,21 +12,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) -{$MODE DELPHI} +{$INCLUDE ../shared/a_modes.inc} unit g_triggers; interface uses - MAPSTRUCT, e_graphics, MAPDEF, g_basic, g_sound, - BinEditor; + SysUtils, Variants, Classes, + MAPDEF, e_graphics, g_basic, g_sound, + xdynrec, hashtable, exoma; type TActivator = record UID: Word; TimeOut: Word; end; + + PTrigger = ^TTrigger; TTrigger = record + public ID: DWORD; ClientID: DWORD; TriggerType: Byte; @@ -36,8 +39,8 @@ type Enabled: Boolean; ActivateType: Byte; Keys: Byte; - TexturePanel: Integer; - TexturePanelType: Word; + TexturePanelGUID: Integer; + //TexturePanelType: Word; TimeOut: Word; ActivateUID: Word; @@ -51,7 +54,7 @@ type AutoSpawn: Boolean; SpawnCooldown: Integer; SpawnedCount: Integer; - ShotPanelType: Word; + //ShotPanelType: Word; ShotPanelTime: Integer; ShotSightTime: Integer; ShotSightTimeout: Integer; @@ -60,34 +63,34 @@ type ShotAmmoCount: Word; ShotReloadTime: Integer; - Data: TTriggerData; + mapId: AnsiString; // trigger id, from map + mapIndex: Integer; // index in fields['trigger'], used in save/load + trigPanelGUID: Integer; + + trigDataRec: TDynRecord; // triggerdata; owned by trigger (cloned) + exoInit, exoThink, exoCheck, exoAction: TExprBase; + + userVars: THashStrVariant; + + {$INCLUDE ../shared/mapdef_tgc_def.inc} + + public + function trigCenter (): TDFPoint; inline; end; -function g_Triggers_Create(Trigger: TTrigger): DWORD; +function g_Triggers_Create (aTrigger: TTrigger; trec: TDynRecord; forceInternalIndex: Integer=-1): DWORD; procedure g_Triggers_Update(); procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0); function g_Triggers_PressR(X, Y: Integer; Width, Height: Word; UID: Word; ActivateType: Byte; IgnoreList: DWArray = nil): DWArray; procedure g_Triggers_PressL(X1, Y1, X2, Y2: Integer; UID: DWORD; ActivateType: Byte); -procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte); +procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte; IgnoreTrigger: Integer = -1); procedure g_Triggers_OpenAll(); procedure g_Triggers_DecreaseSpawner(ID: DWORD); procedure g_Triggers_Free(); -procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter); -procedure g_Triggers_LoadState(var Mem: TBinMemoryReader); +procedure g_Triggers_SaveState (st: TStream); +procedure g_Triggers_LoadState (st: TStream); -function tr_Message(MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean; - -function tr_CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean; -function tr_OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean; -procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean); -function tr_SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean; - -function tr_Teleport(ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean; -function tr_Push(ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean; - -procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean); -function tr_SpawnShot(ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer; var gTriggerClientID: Integer = 0; @@ -95,317 +98,543 @@ var gSecretsCount: Integer = 0; gMonstersSpawned: array of LongInt = nil; + implementation uses - g_player, g_map, Math, g_gfx, g_game, g_textures, + Math, + g_player, g_map, g_panel, g_gfx, g_game, g_textures, g_console, g_monsters, g_items, g_phys, g_weapons, - wadreader, g_main, SysUtils, e_log, g_language, - g_options, g_net, g_netmsg, g_scripts; + wadreader, g_main, e_log, g_language, e_res, + g_options, g_net, g_netmsg, utils, xparser, xstreams; const - TRIGGER_SIGNATURE = $52475254; // 'TRGR' + TRIGGER_SIGNATURE = $58475254; // 'TRGX' TRAP_DAMAGE = 1000; -function FindTrigger(): DWORD; +{$INCLUDE ../shared/mapdef_tgc_impl.inc} + + +// ////////////////////////////////////////////////////////////////////////// // +type + TTrigScope = class(TExprScope) + private + plrprops: TPropHash; + monsprops: TPropHash; + platprops: TPropHash; + + public + me: PTrigger; + + public + constructor Create (); + destructor Destroy (); override; + + function getObj (const aname: AnsiString): TObject; override; + function getField (obj: TObject; const afldname: AnsiString): Variant; override; + procedure setField (obj: TObject; const afldname: AnsiString; var aval: Variant); override; + end; + + +// ////////////////////////////////////////////////////////////////////////// // +type + TMyConstList = class(TExprConstList) + public + function valid (const cname: AnsiString): Boolean; override; + function get (const cname: AnsiString; out v: Variant): Boolean; override; + end; + + +// ////////////////////////////////////////////////////////////////////////// // +function TMyConstList.valid (const cname: AnsiString): Boolean; +begin + //writeln('CHECK: ''', cname, ''''); + result := + (cname = 'player') or + (cname = 'self') or + false; +end; + +function TMyConstList.get (const cname: AnsiString; out v: Variant): Boolean; var - i: Integer; + eidx: Integer; + ebs: TDynEBS; +begin + //if (cname = 'answer') then begin v := LongInt(42); result := true; exit; end; + result := false; + if (gCurrentMap = nil) then exit; + for eidx := 0 to gCurrentMap.mapdef.ebsTypeCount-1 do + begin + ebs := gCurrentMap.mapdef.ebsTypeAt[eidx]; + if ebs.has[cname] then + begin + //writeln('FOUND: ''', cname, ''''); + v := ebs[cname]; + result := true; + exit; + end; + end; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +constructor TTrigScope.Create (); +begin + plrprops := TPropHash.Create(TPlayer, 'e'); + monsprops := TPropHash.Create(TMonster, 'e'); + platprops := TPropHash.Create(TPanel, 'e'); + me := nil; +end; + + +destructor TTrigScope.Destroy (); +begin + platprops.Free(); + monsprops.Free(); + plrprops.Free(); + inherited; +end; + + +function TTrigScope.getObj (const aname: AnsiString): TObject; +begin + if (aname = 'player') then result := gPlayers[0] //FIXME + else if (aname = 'self') or (aname = 'this') then result := TObject(Pointer(PtrUInt(1))) + else result := inherited getObj(aname); +end; + + +function TTrigScope.getField (obj: TObject; const afldname: AnsiString): Variant; +begin + if (obj = gPlayers[0]) then + begin + if plrprops.get(obj, afldname, result) then exit; + end + else if (obj = TObject(Pointer(PtrUInt(1)))) then + begin + if (me <> nil) and (me.userVars <> nil) then + begin + if me.userVars.get(afldname, result) then exit; + end; + end; + result := inherited getField(obj, afldname); +end; + + +procedure TTrigScope.setField (obj: TObject; const afldname: AnsiString; var aval: Variant); begin - if gTriggers <> nil then - for i := 0 to High(gTriggers) do - if gTriggers[i].TriggerType = TRIGGER_NONE then + if (obj = gPlayers[0]) then + begin + if plrprops.put(obj, afldname, aval) then exit; + end + else if (obj = TObject(Pointer(PtrUInt(1)))) then + begin + if (me <> nil) then + begin + if (Length(afldname) > 4) and (afldname[1] = 'u') and (afldname[2] = 's') and + (afldname[3] = 'e') and (afldname[4] = 'r') then begin - Result := i; - Exit; + if (me.userVars = nil) then me.userVars := THashStrVariant.Create(); + me.userVars.put(afldname, aval); + exit; end; + end; + end; + inherited setField(obj, afldname, aval); +end; - if gTriggers = nil then + +// ////////////////////////////////////////////////////////////////////////// // +var + tgscope: TTrigScope = nil; + tgclist: TMyConstList = nil; + + +// ////////////////////////////////////////////////////////////////////////// // +function TTrigger.trigCenter (): TDFPoint; inline; +begin + result := TDFPoint.Create(x+width div 2, y+height div 2); +end; + + +function FindTrigger (): DWORD; +var + i, olen: Integer; +begin + olen := Length(gTriggers); + + for i := 0 to olen-1 do begin - SetLength(gTriggers, 8); - Result := 0; - end - else + if gTriggers[i].TriggerType = TRIGGER_NONE then begin result := i; exit; end; + end; + + SetLength(gTriggers, olen+8); + result := olen; + + for i := result to High(gTriggers) do begin - Result := High(gTriggers) + 1; - SetLength(gTriggers, Length(gTriggers) + 8); + gTriggers[i].TriggerType := TRIGGER_NONE; + gTriggers[i].trigDataRec := nil; + gTriggers[i].exoInit := nil; + gTriggers[i].exoThink := nil; + gTriggers[i].exoCheck := nil; + gTriggers[i].exoAction := nil; + gTriggers[i].userVars := nil; end; end; -function tr_CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean; + +function tr_CloseDoor (PanelGUID: Integer; NoSound: Boolean; d2d: Boolean): Boolean; var a, b, c: Integer; + pan: TPanel; + PanelID: Integer; begin - Result := False; - - if PanelID = -1 then Exit; + result := false; + pan := g_Map_PanelByGUID(PanelGUID); + if (pan = nil) or not pan.isGWall then exit; //!FIXME!TRIGANY! + PanelID := pan.arrIdx; if not d2d then begin with gWalls[PanelID] do begin - if g_CollidePlayer(X, Y, Width, Height) or - g_CollideMonster(X, Y, Width, Height) then Exit; - + if g_CollidePlayer(X, Y, Width, Height) or g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit; if not Enabled then begin if not NoSound then begin g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE'); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE'); end; - g_Map_EnableWall(PanelID); - Result := True; + g_Map_EnableWallGUID(PanelGUID); + result := true; end; end; end else begin - if gDoorMap = nil then Exit; + if (gDoorMap = nil) then exit; c := -1; for a := 0 to High(gDoorMap) do begin for b := 0 to High(gDoorMap[a]) do + begin if gDoorMap[a, b] = DWORD(PanelID) then begin c := a; - Break; + break; end; - - if c <> -1 then Break; + end; + if (c <> -1) then break; end; - if c = -1 then Exit; + if (c = -1) then exit; for b := 0 to High(gDoorMap[c]) do + begin with gWalls[gDoorMap[c, b]] do begin - if g_CollidePlayer(X, Y, Width, Height) or - g_CollideMonster(X, Y, Width, Height) then Exit; + if g_CollidePlayer(X, Y, Width, Height) or g_Mons_IsAnyAliveAt(X, Y, Width, Height) then exit; end; + end; if not NoSound then + begin for b := 0 to High(gDoorMap[c]) do + begin if not gWalls[gDoorMap[c, b]].Enabled then begin with gWalls[PanelID] do begin g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE'); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE'); end; - Break; + break; end; + end; + end; for b := 0 to High(gDoorMap[c]) do + begin if not gWalls[gDoorMap[c, b]].Enabled then begin - g_Map_EnableWall(gDoorMap[c, b]); - Result := True; + g_Map_EnableWall_XXX(gDoorMap[c, b]); + result := true; end; + end; end; end; -procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean); + +procedure tr_CloseTrap (PanelGUID: Integer; NoSound: Boolean; d2d: Boolean); var a, b, c: Integer; + wx, wy, wh, ww: Integer; + pan: TPanel; + PanelID: Integer; + + function monsDamage (mon: TMonster): Boolean; + begin + result := false; // don't stop + if g_Obj_Collide(wx, wy, ww, wh, @mon.Obj) then mon.Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + end; + begin - if PanelID = -1 then Exit; + pan := g_Map_PanelByGUID(PanelGUID); + { + if (pan = nil) then + begin + e_LogWritefln('tr_CloseTrap: pguid=%s; NO PANEL!', [PanelGUID], MSG_WARNING); + end + else + begin + e_LogWritefln('tr_CloseTrap: pguid=%s; isGWall=%s; arrIdx=%s', [PanelGUID, pan.isGWall, pan.arrIdx]); + end; + } + if (pan = nil) or not pan.isGWall then exit; //!FIXME!TRIGANY! + PanelID := pan.arrIdx; if not d2d then begin with gWalls[PanelID] do + begin if (not NoSound) and (not Enabled) then begin g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1'); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1'); end; + end; + + wx := gWalls[PanelID].X; + wy := gWalls[PanelID].Y; + ww := gWalls[PanelID].Width; + wh := gWalls[PanelID].Height; with gWalls[PanelID] do begin if gPlayers <> nil then + begin for a := 0 to High(gPlayers) do - if (gPlayers[a] <> nil) and gPlayers[a].Live and - gPlayers[a].Collide(X, Y, Width, Height) then + begin + if (gPlayers[a] <> nil) and gPlayers[a].alive and gPlayers[a].Collide(X, Y, Width, Height) then + begin gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + end; + end; + end; - if gMonsters <> nil then - for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) and gMonsters[a].Live and - g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then - gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + //g_Mons_ForEach(monsDamage); + g_Mons_ForEachAliveAt(wx, wy, ww, wh, monsDamage); - if not Enabled then g_Map_EnableWall(PanelID); + if not Enabled then g_Map_EnableWallGUID(PanelGUID); end; end else begin - if gDoorMap = nil then Exit; + if (gDoorMap = nil) then exit; c := -1; for a := 0 to High(gDoorMap) do begin for b := 0 to High(gDoorMap[a]) do + begin if gDoorMap[a, b] = DWORD(PanelID) then begin c := a; - Break; + break; end; - - if c <> -1 then Break; + end; + if (c <> -1) then break; end; - if c = -1 then Exit; + if (c = -1) then exit; if not NoSound then + begin for b := 0 to High(gDoorMap[c]) do + begin if not gWalls[gDoorMap[c, b]].Enabled then begin with gWalls[PanelID] do begin g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1'); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1'); end; Break; end; + end; + end; for b := 0 to High(gDoorMap[c]) do + begin + wx := gWalls[gDoorMap[c, b]].X; + wy := gWalls[gDoorMap[c, b]].Y; + ww := gWalls[gDoorMap[c, b]].Width; + wh := gWalls[gDoorMap[c, b]].Height; + with gWalls[gDoorMap[c, b]] do begin if gPlayers <> nil then + begin for a := 0 to High(gPlayers) do - if (gPlayers[a] <> nil) and gPlayers[a].Live and - gPlayers[a].Collide(X, Y, Width, Height) then + begin + if (gPlayers[a] <> nil) and gPlayers[a].alive and gPlayers[a].Collide(X, Y, Width, Height) then + begin gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + end; + end; + end; + //g_Mons_ForEach(monsDamage); + g_Mons_ForEachAliveAt(wx, wy, ww, wh, monsDamage); + (* if gMonsters <> nil then for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) and gMonsters[a].Live and + if (gMonsters[a] <> nil) and gMonsters[a].alive and g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + *) - if not Enabled then g_Map_EnableWall(gDoorMap[c, b]); + if not Enabled then g_Map_EnableWall_XXX(gDoorMap[c, b]); end; + end; end; end; -function tr_OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean; + +function tr_OpenDoor (PanelGUID: Integer; NoSound: Boolean; d2d: Boolean): Boolean; var a, b, c: Integer; + pan: TPanel; + PanelID: Integer; begin - Result := False; - - if PanelID = -1 then Exit; + result := false; + pan := g_Map_PanelByGUID(PanelGUID); + if (pan = nil) or not pan.isGWall then exit; //!FIXME!TRIGANY! + PanelID := pan.arrIdx; if not d2d then begin with gWalls[PanelID] do + begin if Enabled then begin if not NoSound then begin g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN'); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN'); end; - g_Map_DisableWall(PanelID); - Result := True; + g_Map_DisableWallGUID(PanelGUID); + result := true; end; + end end else begin - if gDoorMap = nil then Exit; + if (gDoorMap = nil) then exit; c := -1; for a := 0 to High(gDoorMap) do begin for b := 0 to High(gDoorMap[a]) do + begin if gDoorMap[a, b] = DWORD(PanelID) then begin c := a; - Break; + break; end; - - if c <> -1 then Break; + end; + if (c <> -1) then break; end; - if c = -1 then Exit; + if (c = -1) then exit; if not NoSound then + begin for b := 0 to High(gDoorMap[c]) do + begin if gWalls[gDoorMap[c, b]].Enabled then begin with gWalls[PanelID] do begin g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y); - if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN'); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN'); end; - Break; + break; end; + end; + end; for b := 0 to High(gDoorMap[c]) do + begin if gWalls[gDoorMap[c, b]].Enabled then begin - g_Map_DisableWall(gDoorMap[c, b]); - Result := True; + g_Map_DisableWall_XXX(gDoorMap[c, b]); + result := true; end; + end; end; end; -function tr_SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean; + +function tr_SetLift (PanelGUID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean; var - a, b, c, t: Integer; + a, b, c: Integer; + t: Integer = 0; + pan: TPanel; + PanelID: Integer; begin - t := 0; - Result := False; + result := false; + pan := g_Map_PanelByGUID(PanelGUID); + if (pan = nil) or not pan.isGLift then exit; //!FIXME!TRIGANY! + PanelID := pan.arrIdx; - if PanelID = -1 then Exit; - - if (gLifts[PanelID].PanelType = PANEL_LIFTUP) or - (gLifts[PanelID].PanelType = PANEL_LIFTDOWN) then + if (gLifts[PanelID].PanelType = PANEL_LIFTUP) or (gLifts[PanelID].PanelType = PANEL_LIFTDOWN) then + begin case d of - 0: t := 0; - 1: t := 1; - else t := IfThen(gLifts[PanelID].LiftType = 1, 0, 1); + 0: t := LIFTTYPE_UP; + 1: t := LIFTTYPE_DOWN; + else t := IfThen(gLifts[PanelID].LiftType = LIFTTYPE_DOWN, LIFTTYPE_UP, LIFTTYPE_DOWN); end - else if (gLifts[PanelID].PanelType = PANEL_LIFTLEFT) or - (gLifts[PanelID].PanelType = PANEL_LIFTRIGHT) then + end + else if (gLifts[PanelID].PanelType = PANEL_LIFTLEFT) or (gLifts[PanelID].PanelType = PANEL_LIFTRIGHT) then + begin case d of - 0: t := 2; - 1: t := 3; - else t := IfThen(gLifts[PanelID].LiftType = 2, 3, 2); + 0: t := LIFTTYPE_LEFT; + 1: t := LIFTTYPE_RIGHT; + else t := IfThen(gLifts[PanelID].LiftType = LIFTTYPE_LEFT, LIFTTYPE_RIGHT, LIFTTYPE_LEFT); end; + end; if not d2d then begin with gLifts[PanelID] do - if LiftType <> t then + begin + if (LiftType <> t) then begin - g_Map_SetLift(PanelID, t); - - {if not NoSound then - g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);} - Result := True; + g_Map_SetLiftGUID(PanelGUID, t); //??? + //if not NoSound then g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y); + result := true; end; + end; end else // Êàê â D2d begin - if gLiftMap = nil then Exit; + if (gLiftMap = nil) then exit; c := -1; for a := 0 to High(gLiftMap) do begin for b := 0 to High(gLiftMap[a]) do - if gLiftMap[a, b] = DWORD(PanelID) then + begin + if (gLiftMap[a, b] = DWORD(PanelID)) then begin c := a; - Break; + break; end; - - if c <> -1 then Break; + end; + if (c <> -1) then break; end; - if c = -1 then Exit; + if (c = -1) then exit; {if not NoSound then for b := 0 to High(gLiftMap[c]) do @@ -417,26 +646,32 @@ begin end;} for b := 0 to High(gLiftMap[c]) do + begin with gLifts[gLiftMap[c, b]] do - if LiftType <> t then + begin + if (LiftType <> t) then begin - g_Map_SetLift(gLiftMap[c, b], t); - - Result := True; + g_Map_SetLift_XXX(gLiftMap[c, b], t); + result := true; end; + end; + end; end; end; -function tr_SpawnShot(ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer; + +function tr_SpawnShot (ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer; var snd: string; Projectile: Boolean; TextureID: DWORD; Anim: TAnimation; begin - Result := -1; + result := -1; + TextureID := DWORD(-1); snd := 'SOUND_WEAPON_FIREROCKET'; - Projectile := True; + Projectile := true; + case ShotType of TRIGGER_SHOT_PISTOL: begin @@ -446,8 +681,7 @@ begin if ShotSound then begin g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET); - if g_Game_IsNet then - MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1); + if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1); end; end; @@ -460,8 +694,7 @@ begin if ShotSound then begin g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET); - if g_Game_IsNet then - MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1); + if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1); end; end; @@ -473,8 +706,7 @@ begin if ShotSound then begin g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL); - if g_Game_IsNet then - MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2); + if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2); end; end; @@ -487,44 +719,43 @@ begin begin g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL); g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL); - if g_Game_IsNet then - MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3); + if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3); end; end; TRIGGER_SHOT_IMP: begin - g_Weapon_ball1(wx, wy, dx, dy, 0, -1, True); + g_Weapon_ball1(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREBALL'; end; TRIGGER_SHOT_PLASMA: begin - g_Weapon_Plasma(wx, wy, dx, dy, 0, -1, True); + g_Weapon_Plasma(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREPLASMA'; end; TRIGGER_SHOT_SPIDER: begin - g_Weapon_aplasma(wx, wy, dx, dy, 0, -1, True); + g_Weapon_aplasma(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREPLASMA'; end; TRIGGER_SHOT_CACO: begin - g_Weapon_ball2(wx, wy, dx, dy, 0, -1, True); + g_Weapon_ball2(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREBALL'; end; TRIGGER_SHOT_BARON: begin - g_Weapon_ball7(wx, wy, dx, dy, 0, -1, True); + g_Weapon_ball7(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREBALL'; end; TRIGGER_SHOT_MANCUB: begin - g_Weapon_manfire(wx, wy, dx, dy, 0, -1, True); + g_Weapon_manfire(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREBALL'; end; @@ -536,13 +767,13 @@ begin TRIGGER_SHOT_ROCKET: begin - g_Weapon_Rocket(wx, wy, dx, dy, 0, -1, True); + g_Weapon_Rocket(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREROCKET'; end; TRIGGER_SHOT_BFG: begin - g_Weapon_BFGShot(wx, wy, dx, dy, 0, -1, True); + g_Weapon_BFGShot(wx, wy, dx, dy, 0, -1, True, False); snd := 'SOUND_WEAPON_FIREBFG'; end; @@ -574,129 +805,128 @@ begin snd := 'SOUND_WEAPON_EXPLODEBFG'; end; + TRIGGER_SHOT_FLAME: + begin + g_Weapon_flame(wx, wy, dx, dy, 0, -1, True, False); + snd := 'SOUND_GAME_BURNING'; + end; + else exit; end; if g_Game_IsNet and g_Game_IsServer then + begin case ShotType of - TRIGGER_SHOT_EXPL: - MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_EXPLODE); - TRIGGER_SHOT_BFGEXPL: - MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_BFGEXPL); + TRIGGER_SHOT_EXPL: MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_EXPLODE); + TRIGGER_SHOT_BFGEXPL: MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_BFGEXPL); else begin - if Projectile then - MH_SEND_CreateShot(LastShotID); - if ShotSound then - MH_SEND_Sound(wx, wy, snd); + if Projectile then MH_SEND_CreateShot(LastShotID); + if ShotSound then MH_SEND_Sound(wx, wy, snd); end; end; + end; - if ShotSound then - g_Sound_PlayExAt(snd, wx, wy); + if ShotSound then g_Sound_PlayExAt(snd, wx, wy); - if Projectile then - Result := LastShotID; + if Projectile then Result := LastShotID; end; -procedure MakeShot(var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word); + +procedure MakeShot (var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word); begin with Trigger do - if (Data.ShotAmmo = 0) or - ((Data.ShotAmmo > 0) and (ShotAmmoCount > 0)) then + begin + if (tgcAmmo = 0) or ((tgcAmmo > 0) and (ShotAmmoCount > 0)) then begin - if (Data.ShotPanelID <> -1) and (ShotPanelTime = 0) then + if (trigPanelGUID <> -1) and (ShotPanelTime = 0) then begin - g_Map_SwitchTexture(ShotPanelType, Data.ShotPanelID); + g_Map_SwitchTextureGUID({ShotPanelType,} trigPanelGUID); ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà end; - if Data.ShotIntSight > 0 then - ShotSightTimeout := 180; // ~= 5 ñåêóíä + if (tgcSight > 0) then ShotSightTimeout := 180; // ~= 5 ñåêóíä - if ShotAmmoCount > 0 then Dec(ShotAmmoCount); + if (ShotAmmoCount > 0) then Dec(ShotAmmoCount); - dx := dx + Random(Data.ShotAccuracy) - Random(Data.ShotAccuracy); - dy := dy + Random(Data.ShotAccuracy) - Random(Data.ShotAccuracy); - - tr_SpawnShot(Data.ShotType, wx, wy, dx, dy, Data.ShotSound, TargetUID); + dx += Random(tgcAccuracy)-Random(tgcAccuracy); + dy += Random(tgcAccuracy)-Random(tgcAccuracy); + + tr_SpawnShot(tgcShotType, wx, wy, dx, dy, tgcShotSound, TargetUID); end else - if (Data.ShotIntReload > 0) and (ShotReloadTime = 0) then - ShotReloadTime := Data.ShotIntReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè + begin + if (tgcReload > 0) and (ShotReloadTime = 0) then + begin + ShotReloadTime := tgcReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè + end; + end; + end; end; -procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean); + +procedure tr_MakeEffect (X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean); var FramesID: DWORD; Anim: TAnimation; begin if T = TRIGGER_EFFECT_PARTICLE then + begin case ST of TRIGGER_EFFECT_SLIQUID: begin - if (CR = 255) and (CG = 0) and (CB = 0) then - g_GFX_SimpleWater(X, Y, 1, VX, VY, 1, 0, 0, 0) - else if (CR = 0) and (CG = 255) and (CB = 0) then - g_GFX_SimpleWater(X, Y, 1, VX, VY, 2, 0, 0, 0) - else if (CR = 0) and (CG = 0) and (CB = 255) then - g_GFX_SimpleWater(X, Y, 1, VX, VY, 3, 0, 0, 0) - else - g_GFX_SimpleWater(X, Y, 1, VX, VY, 0, 0, 0, 0); - end; - TRIGGER_EFFECT_LLIQUID: - g_GFX_SimpleWater(X, Y, 1, VX, VY, 4, CR, CG, CB); - TRIGGER_EFFECT_DLIQUID: - g_GFX_SimpleWater(X, Y, 1, VX, VY, 5, CR, CG, CB); - TRIGGER_EFFECT_BLOOD: - g_GFX_Blood(X, Y, 1, VX, VY, 0, 0, CR, CG, CB); - TRIGGER_EFFECT_SPARK: - g_GFX_Spark(X, Y, 1, GetAngle2(VX, VY), 0, 0); - TRIGGER_EFFECT_BUBBLE: - g_GFX_Bubbles(X, Y, 1, 0, 0); + if (CR = 255) and (CG = 0) and (CB = 0) then g_GFX_SimpleWater(X, Y, 1, VX, VY, 1, 0, 0, 0) + else if (CR = 0) and (CG = 255) and (CB = 0) then g_GFX_SimpleWater(X, Y, 1, VX, VY, 2, 0, 0, 0) + else if (CR = 0) and (CG = 0) and (CB = 255) then g_GFX_SimpleWater(X, Y, 1, VX, VY, 3, 0, 0, 0) + else g_GFX_SimpleWater(X, Y, 1, VX, VY, 0, 0, 0, 0); + end; + TRIGGER_EFFECT_LLIQUID: g_GFX_SimpleWater(X, Y, 1, VX, VY, 4, CR, CG, CB); + TRIGGER_EFFECT_DLIQUID: g_GFX_SimpleWater(X, Y, 1, VX, VY, 5, CR, CG, CB); + TRIGGER_EFFECT_BLOOD: g_GFX_Blood(X, Y, 1, VX, VY, 0, 0, CR, CG, CB); + TRIGGER_EFFECT_SPARK: g_GFX_Spark(X, Y, 1, GetAngle2(VX, VY), 0, 0); + TRIGGER_EFFECT_BUBBLE: g_Game_Effect_Bubbles(X, Y, 1, 0, 0, Silent); end; + end; + if T = TRIGGER_EFFECT_ANIMATION then + begin case ST of EFFECT_TELEPORT: begin if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then begin Anim := TAnimation.Create(FramesID, False, 3); - if not Silent then - g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y); + if not Silent then g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y); g_GFX_OnceAnim(X-32, Y-32, Anim); Anim.Free(); end; - if Send and g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(X, Y, Byte(not Silent), NET_GFX_TELE); + if Send and g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(X, Y, Byte(not Silent), NET_GFX_TELE); end; EFFECT_RESPAWN: begin if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then begin Anim := TAnimation.Create(FramesID, False, 4); - if not Silent then - g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y); + if not Silent then g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y); g_GFX_OnceAnim(X-16, Y-16, Anim); Anim.Free(); end; - if Send and g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(X-16, Y-16, Byte(not Silent), NET_GFX_RESPAWN); + if Send and g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(X-16, Y-16, Byte(not Silent), NET_GFX_RESPAWN); end; EFFECT_FIRE: begin if g_Frames_Get(FramesID, 'FRAMES_FIRE') then begin Anim := TAnimation.Create(FramesID, False, 4); - if not Silent then - g_Sound_PlayExAt('SOUND_FIRE', X, Y); + if not Silent then g_Sound_PlayExAt('SOUND_FIRE', X, Y); g_GFX_OnceAnim(X-32, Y-128, Anim); Anim.Free(); end; - if Send and g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(X-32, Y-128, Byte(not Silent), NET_GFX_FIRE); + if Send and g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(X-32, Y-128, Byte(not Silent), NET_GFX_FIRE); end; end; + end; end; -function tr_Teleport(ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean; + +function tr_Teleport (ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean; var p: TPlayer; m: TMonster; @@ -707,56 +937,45 @@ begin UID_PLAYER: begin p := g_Player_Get(ActivateUID); - if p = nil then - Exit; - + if p = nil then Exit; if D2D then - begin - if p.TeleportTo(TX-(p.Obj.Rect.Width div 2), - TY-p.Obj.Rect.Height, - Silent, - TDir) then - Result := True; - end + begin + if p.TeleportTo(TX-(p.Obj.Rect.Width div 2), TY-p.Obj.Rect.Height, Silent, TDir) then result := true; + end else - if p.TeleportTo(TX, TY, Silent, TDir) then - Result := True; + begin + if p.TeleportTo(TX, TY, Silent, TDir) then result := true; + end; end; - UID_MONSTER: begin - m := g_Monsters_Get(ActivateUID); - if m = nil then - Exit; - + m := g_Monsters_ByUID(ActivateUID); + if m = nil then Exit; if D2D then - begin - if m.TeleportTo(TX-(m.Obj.Rect.Width div 2), - TY-m.Obj.Rect.Height, - Silent, - TDir) then - Result := True; - end + begin + if m.TeleportTo(TX-(m.Obj.Rect.Width div 2), TY-m.Obj.Rect.Height, Silent, TDir) then result := true; + end else - if m.TeleportTo(TX, TY, Silent, TDir) then - Result := True; + begin + if m.TeleportTo(TX, TY, Silent, TDir) then result := true; + end; end; end; end; -function tr_Push(ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean; + +function tr_Push (ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean; var p: TPlayer; m: TMonster; begin - Result := True; - if (ActivateUID < 0) or (ActivateUID > $FFFF) then Exit; + result := true; + if (ActivateUID < 0) or (ActivateUID > $FFFF) then exit; case g_GetUIDType(ActivateUID) of UID_PLAYER: begin p := g_Player_Get(ActivateUID); - if p = nil then - Exit; + if p = nil then Exit; if ResetVel then begin @@ -771,9 +990,8 @@ begin UID_MONSTER: begin - m := g_Monsters_Get(ActivateUID); - if m = nil then - Exit; + m := g_Monsters_ByUID(ActivateUID); + if m = nil then Exit; if ResetVel then begin @@ -788,7 +1006,8 @@ begin end; end; -function tr_Message(MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean; + +function tr_Message (MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean; var msg: string; p: TPlayer; @@ -798,137 +1017,159 @@ begin if (ActivateUID < 0) or (ActivateUID > $FFFF) then Exit; msg := b_Text_Format(MText); case MSendTo of - 0: // activator + TRIGGER_MESSAGE_DEST_ME: // activator begin if g_GetUIDType(ActivateUID) = UID_PLAYER then begin if g_Game_IsWatchedPlayer(ActivateUID) then begin - if MKind = 0 then - g_Console_Add(msg, True) - else if MKind = 1 then - g_Game_Message(msg, MTime); + if MKind = TRIGGER_MESSAGE_KIND_CHAT then g_Console_Add(msg, True) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then g_Game_Message(msg, MTime); end else begin p := g_Player_Get(ActivateUID); if g_Game_IsNet and (p.FClientID >= 0) then - if MKind = 0 then - MH_SEND_Chat(msg, NET_CHAT_SYSTEM, p.FClientID) - else if MKind = 1 then - MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, p.FClientID); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, p.FClientID) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, p.FClientID); + end; end; end; end; - 1: // activator's team + TRIGGER_MESSAGE_DEST_MY_TEAM: // activator's team begin if g_GetUIDType(ActivateUID) = UID_PLAYER then begin p := g_Player_Get(ActivateUID); if g_Game_IsWatchedTeam(p.Team) then - if MKind = 0 then - g_Console_Add(msg, True) - else if MKind = 1 then - g_Game_Message(msg, MTime); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then g_Console_Add(msg, True) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then g_Game_Message(msg, MTime); + end; if g_Game_IsNet then begin for i := Low(gPlayers) to High(gPlayers) do + begin if (gPlayers[i].Team = p.Team) and (gPlayers[i].FClientID >= 0) then - if MKind = 0 then - MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) - else if MKind = 1 then - MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + end; + end; end; end; end; - 2: // activator's enemy team + TRIGGER_MESSAGE_DEST_ENEMY_TEAM: // activator's enemy team begin if g_GetUIDType(ActivateUID) = UID_PLAYER then begin p := g_Player_Get(ActivateUID); if g_Game_IsWatchedTeam(p.Team) then - if MKind = 0 then - g_Console_Add(msg, True) - else if MKind = 1 then - g_Game_Message(msg, MTime); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then g_Console_Add(msg, True) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then g_Game_Message(msg, MTime); + end; if g_Game_IsNet then begin for i := Low(gPlayers) to High(gPlayers) do + begin if (gPlayers[i].Team <> p.Team) and (gPlayers[i].FClientID >= 0) then - if MKind = 0 then - MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) - else if MKind = 1 then - MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + end; + end; end; end; end; - 3: // red team + TRIGGER_MESSAGE_DEST_RED_TEAM: // red team begin if g_Game_IsWatchedTeam(TEAM_RED) then - if MKind = 0 then - g_Console_Add(msg, True) - else if MKind = 1 then - g_Game_Message(msg, MTime); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then g_Console_Add(msg, True) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then g_Game_Message(msg, MTime); + end; if g_Game_IsNet then begin for i := Low(gPlayers) to High(gPlayers) do + begin if (gPlayers[i].Team = TEAM_RED) and (gPlayers[i].FClientID >= 0) then - if MKind = 0 then - MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) - else if MKind = 1 then - MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + end; + end; end; end; - 4: // blue team + TRIGGER_MESSAGE_DEST_BLUE_TEAM: // blue team begin if g_Game_IsWatchedTeam(TEAM_BLUE) then - if MKind = 0 then - g_Console_Add(msg, True) - else if MKind = 1 then - g_Game_Message(msg, MTime); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then g_Console_Add(msg, True) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then g_Game_Message(msg, MTime); + end; if g_Game_IsNet then begin for i := Low(gPlayers) to High(gPlayers) do + begin if (gPlayers[i].Team = TEAM_BLUE) and (gPlayers[i].FClientID >= 0) then - if MKind = 0 then - MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) - else if MKind = 1 then - MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + begin + if MKind = TRIGGER_MESSAGE_KIND_CHAT then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID); + end; + end; end; end; - 5: // everyone + TRIGGER_MESSAGE_DEST_EVERYONE: // everyone begin - if MKind = 0 then - g_Console_Add(msg, True) - else if MKind = 1 then - g_Game_Message(msg, MTime); + if MKind = TRIGGER_MESSAGE_KIND_CHAT then g_Console_Add(msg, True) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then g_Game_Message(msg, MTime); if g_Game_IsNet then begin - if MKind = 0 then - MH_SEND_Chat(msg, NET_CHAT_SYSTEM) - else if MKind = 1 then - MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg); + if MKind = TRIGGER_MESSAGE_KIND_CHAT then MH_SEND_Chat(msg, NET_CHAT_SYSTEM) + else if MKind = TRIGGER_MESSAGE_KIND_GAME then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg); end; end; end; end; -function ActivateTrigger(var Trigger: TTrigger; actType: Byte): Boolean; + +function tr_ShotAimCheck (var Trigger: TTrigger; Obj: PObj): Boolean; +begin + result := false; + with Trigger do + begin + if TriggerType <> TRIGGER_SHOT then Exit; + result := (tgcAim and TRIGGER_SHOT_AIM_ALLMAP > 0) + or g_Obj_Collide(X, Y, Width, Height, Obj); + if result and (tgcAim and TRIGGER_SHOT_AIM_TRACE > 0) then + begin + result := g_TraceVector(tgcTX, tgcTY, + Obj^.X + Obj^.Rect.X + (Obj^.Rect.Width div 2), + Obj^.Y + Obj^.Rect.Y + (Obj^.Rect.Height div 2)); + end; + end; +end; + + +function ActivateTrigger (var Trigger: TTrigger; actType: Byte): Boolean; var animonce: Boolean; p: TPlayer; m: TMonster; - i, k, wx, wy, xd, yd: Integer; + pan: TPanel; + idx, k, wx, wy, xd, yd: Integer; iid: LongWord; coolDown: Boolean; pAngle: Real; @@ -936,22 +1177,92 @@ var Anim: TAnimation; UIDType: Byte; TargetUID: Word; + it: PItem; + mon: TMonster; + + function monsShotTarget (mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.alive and tr_ShotAimCheck(Trigger, @(mon.Obj)) then + begin + xd := mon.GameX + mon.Obj.Rect.Width div 2; + yd := mon.GameY + mon.Obj.Rect.Height div 2; + TargetUID := mon.UID; + result := true; // stop + end; + end; + + function monsShotTargetMonPlr (mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.alive and tr_ShotAimCheck(Trigger, @(mon.Obj)) then + begin + xd := mon.GameX + mon.Obj.Rect.Width div 2; + yd := mon.GameY + mon.Obj.Rect.Height div 2; + TargetUID := mon.UID; + result := true; // stop + end; + end; + + function monShotTargetPlrMon (mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.alive and tr_ShotAimCheck(Trigger, @(mon.Obj)) then + begin + xd := mon.GameX + mon.Obj.Rect.Width div 2; + yd := mon.GameY + mon.Obj.Rect.Height div 2; + TargetUID := mon.UID; + result := true; // stop + end; + end; + +var + tvval: Variant; begin - Result := False; - if g_Game_IsClient then - Exit; + result := false; + if g_Game_IsClient then exit; - if not Trigger.Enabled then - Exit; - if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then - Exit; - if gLMSRespawn = LMS_RESPAWN_WARMUP then - Exit; + if not Trigger.Enabled then exit; + if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then exit; + if (gLMSRespawn > LMS_RESPAWN_NONE) then exit; + + if (Trigger.exoCheck <> nil) then + begin + //conwritefln('exocheck: [%s]', [Trigger.exoCheck.toString()]); + try + tgscope.me := @Trigger; + tvval := Trigger.exoCheck.value(tgscope); + tgscope.me := nil; + if not Boolean(tvval) then exit; + except on e: Exception do + begin + tgscope.me := nil; + conwritefln('trigger exocheck error: %s [%s]', [e.message, Trigger.exoCheck.toString()]); + exit; + end; + end; + end; animonce := False; coolDown := (actType <> 0); + if (Trigger.exoAction <> nil) then + begin + //conwritefln('exoactivate: [%s]', [Trigger.exoAction.toString()]); + try + tgscope.me := @Trigger; + Trigger.exoAction.value(tgscope); + tgscope.me := nil; + except on e: Exception do + begin + tgscope.me := nil; + conwritefln('trigger exoactivate error: %s [%s]', [e.message, Trigger.exoAction.toString()]); + exit; + end; + end; + end; + with Trigger do begin case TriggerType of @@ -960,7 +1271,7 @@ begin g_Sound_PlayEx('SOUND_GAME_SWITCH0'); if g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH0'); gExitByTrigger := True; - g_Game_ExitLevel(Data.MapName); + g_Game_ExitLevel(tgcMap); TimeOut := 18; Result := True; @@ -970,46 +1281,46 @@ begin TRIGGER_TELEPORT: begin Result := tr_Teleport(ActivateUID, - Data.TargetPoint.X, Data.TargetPoint.Y, - Data.TlpDir, Data.silent_teleport, - Data.d2d_teleport); + tgcTarget.X, tgcTarget.Y, + tgcDirection, tgcSilent, + tgcD2d); TimeOut := 0; end; TRIGGER_OPENDOOR: begin - Result := tr_OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors); + Result := tr_OpenDoor(trigPanelGUID, tgcSilent, tgcD2d); TimeOut := 0; end; TRIGGER_CLOSEDOOR: begin - Result := tr_CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors); + Result := tr_CloseDoor(trigPanelGUID, tgcSilent, tgcD2d); TimeOut := 0; end; TRIGGER_DOOR, TRIGGER_DOOR5: begin - if Data.PanelID <> -1 then + pan := g_Map_PanelByGUID(trigPanelGUID); + if (pan <> nil) and pan.isGWall then begin - if gWalls[Data.PanelID].Enabled then - begin - Result := tr_OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors); - - if TriggerType = TRIGGER_DOOR5 then - DoorTime := 180; - end + if gWalls[{trigPanelID}pan.arrIdx].Enabled then + begin + result := tr_OpenDoor(trigPanelGUID, tgcSilent, tgcD2d); + if (TriggerType = TRIGGER_DOOR5) then DoorTime := 180; + end else - Result := tr_CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors); + begin + result := tr_CloseDoor(trigPanelGUID, tgcSilent, tgcD2d); + end; - if Result then - TimeOut := 18; + if result then TimeOut := 18; end; end; TRIGGER_CLOSETRAP, TRIGGER_TRAP: begin - tr_CloseTrap(Data.PanelID, Data.NoSound, Data.d2d_doors); + tr_CloseTrap(trigPanelGUID, tgcSilent, tgcD2d); if TriggerType = TRIGGER_TRAP then begin @@ -1027,15 +1338,9 @@ begin TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF: begin - PressCount := PressCount + 1; - - if PressTime = -1 then - PressTime := Data.Wait; - - if coolDown then - TimeOut := 18 - else - TimeOut := 0; + PressCount += 1; + if PressTime = -1 then PressTime := tgcWait; + if coolDown then TimeOut := 18 else TimeOut := 0; Result := True; end; @@ -1044,20 +1349,22 @@ begin begin Enabled := False; Result := True; - if gLMSRespawn = LMS_RESPAWN_NONE then + p := g_Player_Get(ActivateUID); + p.GetSecret(); + Inc(gCoopSecretsFound); + if g_Game_IsNet then begin - g_Player_Get(ActivateUID).GetSecret(); - Inc(gCoopSecretsFound); - if g_Game_IsNet then MH_SEND_GameStats(); + MH_SEND_GameStats(); + MH_SEND_GameEvent(NET_EV_SECRET, p.UID, ''); end; end; TRIGGER_LIFTUP: begin - Result := tr_SetLift(Data.PanelID, 0, Data.NoSound, Data.d2d_doors); + Result := tr_SetLift(trigPanelGUID, 0, tgcSilent, tgcD2d); TimeOut := 0; - if (not Data.NoSound) and Result then begin + if (not tgcSilent) and Result then begin g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X + (Width div 2), Y + (Height div 2)); @@ -1070,10 +1377,10 @@ begin TRIGGER_LIFTDOWN: begin - Result := tr_SetLift(Data.PanelID, 1, Data.NoSound, Data.d2d_doors); + Result := tr_SetLift(trigPanelGUID, 1, tgcSilent, tgcD2d); TimeOut := 0; - if (not Data.NoSound) and Result then begin + if (not tgcSilent) and Result then begin g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X + (Width div 2), Y + (Height div 2)); @@ -1086,13 +1393,13 @@ begin TRIGGER_LIFT: begin - Result := tr_SetLift(Data.PanelID, 3, Data.NoSound, Data.d2d_doors); + Result := tr_SetLift(trigPanelGUID, 3, tgcSilent, tgcD2d); if Result then begin TimeOut := 18; - if (not Data.NoSound) and Result then begin + if (not tgcSilent) and Result then begin g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X + (Width div 2), Y + (Height div 2)); @@ -1106,7 +1413,7 @@ begin TRIGGER_TEXTURE: begin - if ByteBool(Data.ActivateOnce) then + if tgcActivateOnce then begin Enabled := False; TriggerType := TRIGGER_NONE; @@ -1117,7 +1424,7 @@ begin else TimeOut := 0; - animonce := Data.AnimOnce; + animonce := tgcAnimateOnce; Result := True; end; @@ -1125,17 +1432,17 @@ begin begin if Sound <> nil then begin - if Data.SoundSwitch and Sound.IsPlaying() then + if tgcSoundSwitch and Sound.IsPlaying() then begin // Íóæíî âûêëþ÷èòü, åñëè èãðàë Sound.Stop(); SoundPlayCount := 0; Result := True; end else // (not Data.SoundSwitch) or (not Sound.IsPlaying()) - if (Data.PlayCount > 0) or (not Sound.IsPlaying()) then + if (tgcPlayCount > 0) or (not Sound.IsPlaying()) then begin - if Data.PlayCount > 0 then - SoundPlayCount := Data.PlayCount + if tgcPlayCount > 0 then + SoundPlayCount := tgcPlayCount else // 0 - èãðàåì áåñêîíå÷íî SoundPlayCount := 1; Result := True; @@ -1145,10 +1452,10 @@ begin end; TRIGGER_SPAWNMONSTER: - if (Data.MonType in [MONSTER_DEMON..MONSTER_MAN]) then + if (tgcSpawnMonsType in [MONSTER_DEMON..MONSTER_MAN]) then begin Result := False; - if (Data.MonDelay > 0) and (actType <> ACTIVATE_CUSTOM) then + if (tgcDelay > 0) and (actType <> ACTIVATE_CUSTOM) then begin AutoSpawn := not AutoSpawn; SpawnCooldown := 0; @@ -1156,88 +1463,85 @@ begin Result := True; end; - if ((Data.MonDelay = 0) and (actType <> ACTIVATE_CUSTOM)) - or ((Data.MonDelay > 0) and (actType = ACTIVATE_CUSTOM)) then - for k := 1 to Data.MonCount do + if ((tgcDelay = 0) and (actType <> ACTIVATE_CUSTOM)) + or ((tgcDelay > 0) and (actType = ACTIVATE_CUSTOM)) then + for k := 1 to tgcMonsCount do begin - if (actType = ACTIVATE_CUSTOM) and (Data.MonDelay > 0) then - SpawnCooldown := Data.MonDelay; - if (Data.MonMax > 0) and (SpawnedCount >= Data.MonMax) then + if (actType = ACTIVATE_CUSTOM) and (tgcDelay > 0) then + SpawnCooldown := -1; // Çàäåðæêà âûñòàâèòñÿ ìîíñòðîì ïðè óíè÷òîæåíèè + if (tgcMax > 0) and (SpawnedCount >= tgcMax) then Break; - i := g_Monsters_Create(Data.MonType, - Data.MonPos.X, Data.MonPos.Y, - TDirection(Data.MonDir), True); + mon := g_Monsters_Create(tgcSpawnMonsType, + tgcTX, tgcTY, + TDirection(tgcDirection), True); Result := True; // Çäîðîâüå: - if (Data.MonHealth > 0) then - gMonsters[i].SetHealth(Data.MonHealth); + if (tgcHealth > 0) then + mon.SetHealth(tgcHealth); // Óñòàíàâëèâàåì ïîâåäåíèå: - gMonsters[i].MonsterBehaviour := Data.MonBehav; - gMonsters[i].FNoRespawn := True; + mon.MonsterBehaviour := tgcBehaviour; + mon.FNoRespawn := True; if g_Game_IsNet then - MH_SEND_MonsterSpawn(gMonsters[i].UID); + MH_SEND_MonsterSpawn(mon.UID); // Èäåì èñêàòü öåëü, åñëè íàäî: - if Data.MonActive then - gMonsters[i].WakeUp(); + if tgcActive then + mon.WakeUp(); - if Data.MonType <> MONSTER_BARREL then Inc(gTotalMonsters); + if tgcSpawnMonsType <> MONSTER_BARREL then Inc(gTotalMonsters); if g_Game_IsNet then begin SetLength(gMonstersSpawned, Length(gMonstersSpawned)+1); - gMonstersSpawned[High(gMonstersSpawned)] := gMonsters[i].UID; + gMonstersSpawned[High(gMonstersSpawned)] := mon.UID; end; - if Data.MonMax > 0 then - begin - gMonsters[i].SpawnTrigger := ID; - Inc(SpawnedCount); - end; + mon.SpawnTrigger := ID; + if tgcMax > 0 then Inc(SpawnedCount); - case Data.MonEffect of + case tgcEffect of EFFECT_TELEPORT: begin if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then begin Anim := TAnimation.Create(FramesID, False, 3); - g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Data.MonPos.X, Data.MonPos.Y); - g_GFX_OnceAnim(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32, - gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-32, Anim); + g_Sound_PlayExAt('SOUND_GAME_TELEPORT', tgcTX, tgcTY); + g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32, + mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-32, Anim); Anim.Free(); end; if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32, - gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-32, 1, + MH_SEND_Effect(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32, + mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-32, 1, NET_GFX_TELE); end; EFFECT_RESPAWN: begin if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then begin Anim := TAnimation.Create(FramesID, False, 4); - g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', Data.MonPos.X, Data.MonPos.Y); - g_GFX_OnceAnim(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-16, - gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-16, Anim); + g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', tgcTX, tgcTY); + g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-16, + mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-16, Anim); Anim.Free(); end; if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-16, - gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+(gMonsters[i].Obj.Rect.Height div 2)-16, 1, + MH_SEND_Effect(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-16, + mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-16, 1, NET_GFX_RESPAWN); end; EFFECT_FIRE: begin if g_Frames_Get(FramesID, 'FRAMES_FIRE') then begin Anim := TAnimation.Create(FramesID, False, 4); - g_Sound_PlayExAt('SOUND_FIRE', Data.MonPos.X, Data.MonPos.Y); - g_GFX_OnceAnim(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32, - gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+gMonsters[i].Obj.Rect.Height-128, Anim); + g_Sound_PlayExAt('SOUND_FIRE', tgcTX, tgcTY); + g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32, + mon.Obj.Y+mon.Obj.Rect.Y+mon.Obj.Rect.Height-128, Anim); Anim.Free(); end; if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(gMonsters[i].Obj.X+gMonsters[i].Obj.Rect.X+(gMonsters[i].Obj.Rect.Width div 2)-32, - gMonsters[i].Obj.Y+gMonsters[i].Obj.Rect.Y+gMonsters[i].Obj.Rect.Height-128, 1, + MH_SEND_Effect(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32, + mon.Obj.Y+mon.Obj.Rect.Y+mon.Obj.Rect.Height-128, 1, NET_GFX_FIRE); end; end; @@ -1258,10 +1562,10 @@ begin end; TRIGGER_SPAWNITEM: - if (Data.ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX]) then + if (tgcSpawnItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX]) then begin Result := False; - if (Data.ItemDelay > 0) and (actType <> ACTIVATE_CUSTOM) then + if (tgcDelay > 0) and (actType <> ACTIVATE_CUSTOM) then begin AutoSpawn := not AutoSpawn; SpawnCooldown := 0; @@ -1269,69 +1573,70 @@ begin Result := True; end; - if ((Data.ItemDelay = 0) and (actType <> ACTIVATE_CUSTOM)) - or ((Data.ItemDelay > 0) and (actType = ACTIVATE_CUSTOM)) then - if (not Data.ItemOnlyDM) or + if ((tgcDelay = 0) and (actType <> ACTIVATE_CUSTOM)) + or ((tgcDelay > 0) and (actType = ACTIVATE_CUSTOM)) then + if (not tgcDmonly) or (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) then - for k := 1 to Data.ItemCount do + for k := 1 to tgcItemCount do begin - if (actType = ACTIVATE_CUSTOM) and (Data.ItemDelay > 0) then - SpawnCooldown := Data.ItemDelay; - if (Data.ItemMax > 0) and (SpawnedCount >= Data.ItemMax) then + if (actType = ACTIVATE_CUSTOM) and (tgcDelay > 0) then + SpawnCooldown := -1; // Çàäåðæêà âûñòàâèòñÿ èòåìîì ïðè óíè÷òîæåíèè + if (tgcMax > 0) and (SpawnedCount >= tgcMax) then Break; - iid := g_Items_Create(Data.ItemPos.X, Data.ItemPos.Y, - Data.ItemType, Data.ItemFalls, False, True); + iid := g_Items_Create(tgcTX, tgcTY, + tgcSpawnItemType, tgcGravity, False, True); Result := True; - if Data.ItemMax > 0 then - begin - gItems[iid].SpawnTrigger := ID; - Inc(SpawnedCount); - end; + it := g_Items_ByIdx(iid); + it.SpawnTrigger := ID; + if tgcMax > 0 then Inc(SpawnedCount); - case Data.ItemEffect of + case tgcEffect of EFFECT_TELEPORT: begin + it := g_Items_ByIdx(iid); if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then begin Anim := TAnimation.Create(FramesID, False, 3); - g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Data.ItemPos.X, Data.ItemPos.Y); - g_GFX_OnceAnim(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32, - gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-32, Anim); + g_Sound_PlayExAt('SOUND_GAME_TELEPORT', tgcTX, tgcTY); + g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32, + it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-32, Anim); Anim.Free(); end; if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32, - gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-32, 1, + MH_SEND_Effect(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32, + it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-32, 1, NET_GFX_TELE); end; EFFECT_RESPAWN: begin + it := g_Items_ByIdx(iid); if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then begin Anim := TAnimation.Create(FramesID, False, 4); - g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', Data.ItemPos.X, Data.ItemPos.Y); - g_GFX_OnceAnim(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-16, - gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-16, Anim); + g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', tgcTX, tgcTY); + g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-16, + it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-16, Anim); Anim.Free(); end; if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-16, - gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+(gItems[iid].Obj.Rect.Height div 2)-16, 1, + MH_SEND_Effect(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-16, + it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-16, 1, NET_GFX_RESPAWN); end; EFFECT_FIRE: begin + it := g_Items_ByIdx(iid); if g_Frames_Get(FramesID, 'FRAMES_FIRE') then begin Anim := TAnimation.Create(FramesID, False, 4); - g_Sound_PlayExAt('SOUND_FIRE', Data.ItemPos.X, Data.ItemPos.Y); - g_GFX_OnceAnim(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32, - gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+gItems[iid].Obj.Rect.Height-128, Anim); + g_Sound_PlayExAt('SOUND_FIRE', tgcTX, tgcTY); + g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32, + it.Obj.Y+it.Obj.Rect.Y+it.Obj.Rect.Height-128, Anim); Anim.Free(); end; if g_Game_IsServer and g_Game_IsNet then - MH_SEND_Effect(gItems[iid].Obj.X+gItems[iid].Obj.Rect.X+(gItems[iid].Obj.Rect.Width div 2)-32, - gItems[iid].Obj.Y+gItems[iid].Obj.Rect.Y+gItems[iid].Obj.Rect.Height-128, 1, + MH_SEND_Effect(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32, + it.Obj.Y+it.Obj.Rect.Y+it.Obj.Rect.Height-128, 1, NET_GFX_FIRE); end; end; @@ -1352,25 +1657,22 @@ begin TRIGGER_MUSIC: begin // Ìåíÿåì ìóçûêó, åñëè åñòü íà ÷òî: - if (Trigger.Data.MusicName <> '') then + if (Trigger.tgcMusicName <> '') then begin - gMusic.SetByName(Trigger.Data.MusicName); + gMusic.SetByName(Trigger.tgcMusicName); gMusic.SpecPause := True; gMusic.Play(); end; - if Trigger.Data.MusicAction = 1 then - begin // Âêëþ÷èòü + case Trigger.tgcMusicAction of + TRIGGER_MUSIC_ACTION_STOP: // Âûêëþ÷èòü + gMusic.SpecPause := True; // Ïàóçà + TRIGGER_MUSIC_ACTION_PLAY: // Âêëþ÷èòü if gMusic.SpecPause then // Áûëà íà ïàóçå => èãðàòü gMusic.SpecPause := False else // Èãðàëà => ñíà÷àëà gMusic.SetPosition(0); - end - else // Âûêëþ÷èòü - begin - // Ïàóçà: - gMusic.SpecPause := True; - end; + end; if coolDown then TimeOut := 36 @@ -1382,11 +1684,11 @@ begin TRIGGER_PUSH: begin - pAngle := -DegToRad(Data.PushAngle); + pAngle := -DegToRad(tgcAngle); Result := tr_Push(ActivateUID, - Floor(Cos(pAngle)*Data.PushForce), - Floor(Sin(pAngle)*Data.PushForce), - Data.ResetVel); + Floor(Cos(pAngle)*tgcForce), + Floor(Sin(pAngle)*tgcForce), + tgcResetVelocity); TimeOut := 0; end; @@ -1394,106 +1696,114 @@ begin begin Result := False; // Ïðèáàâèòü èëè îòíÿòü î÷êî - if (Data.ScoreAction in [0..1]) and (Data.ScoreCount > 0) then + if (tgcScoreAction in [TRIGGER_SCORE_ACTION_ADD, TRIGGER_SCORE_ACTION_SUB]) and (tgcScoreCount > 0) then begin // Ñâîåé èëè ÷óæîé êîìàíäå - if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then + if (tgcScoreTeam in [TRIGGER_SCORE_TEAM_MINE_RED, TRIGGER_SCORE_TEAM_MINE_BLUE]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then begin p := g_Player_Get(ActivateUID); - if ((Data.ScoreAction = 0) and (Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) - or ((Data.ScoreAction = 0) and (Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then + if ((tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_RED)) + or ((tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_BLUE)) then begin - Inc(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Scores + Inc(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Scores - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + begin + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+r'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '+r'); end else begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+re'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '+re'); end; + end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108); if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED); end; end; - if ((Data.ScoreAction = 1) and (Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) - or ((Data.ScoreAction = 1) and (Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then + if ((tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_RED)) + or ((tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_BLUE)) then begin - Dec(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Fouls + Dec(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Fouls - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + begin + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-r'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '-r'); end else begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-re'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '-re'); end; + end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108); if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED); end; end; - if ((Data.ScoreAction = 0) and (Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) - or ((Data.ScoreAction = 0) and (Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then + if ((tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_BLUE)) + or ((tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_RED)) then begin - Inc(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Scores + Inc(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Scores - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + begin + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+b'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '+b'); end else begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+be'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '+be'); end; + end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108); if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE); end; end; - if ((Data.ScoreAction = 1) and (Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) - or ((Data.ScoreAction = 1) and (Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then + if ((tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_BLUE)) + or ((tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_RED)) then begin - Dec(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Fouls + Dec(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Fouls - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + begin + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-b'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '-b'); end else begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, tgcScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-be'); + MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (tgcScoreCount shl 16), '-be'); end; + end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108); if g_Game_IsServer and g_Game_IsNet then @@ -1503,74 +1813,74 @@ begin Result := (p.Team = TEAM_RED) or (p.Team = TEAM_BLUE); end; // Êàêîé-òî êîíêðåòíîé êîìàíäå - if Data.ScoreTeam in [2..3] then + if tgcScoreTeam in [TRIGGER_SCORE_TEAM_FORCE_RED, TRIGGER_SCORE_TEAM_FORCE_BLUE] then begin - if (Data.ScoreAction = 0) and (Data.ScoreTeam = 2) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then begin - Inc(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Scores + Inc(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Scores - if Data.ScoreCon then + if tgcScoreCon then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_RED], Data.ScoreCount]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_RED], tgcScoreCount]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '+tr'); + MH_SEND_GameEvent(NET_EV_SCORE, tgcScoreCount shl 16, '+tr'); end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108); if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED); end; end; - if (Data.ScoreAction = 1) and (Data.ScoreTeam = 2) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then begin - Dec(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Fouls + Dec(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Fouls - if Data.ScoreCon then + if tgcScoreCon then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_RED], Data.ScoreCount]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_RED], tgcScoreCount]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '-tr'); + MH_SEND_GameEvent(NET_EV_SCORE, tgcScoreCount shl 16, '-tr'); end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108); if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED); end; end; - if (Data.ScoreAction = 0) and (Data.ScoreTeam = 3) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then begin - Inc(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Scores + Inc(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Scores - if Data.ScoreCon then + if tgcScoreCon then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_BLUE], Data.ScoreCount]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_BLUE], tgcScoreCount]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '+tb'); + MH_SEND_GameEvent(NET_EV_SCORE, tgcScoreCount shl 16, '+tb'); end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108); if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE); end; end; - if (Data.ScoreAction = 1) and (Data.ScoreTeam = 3) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then begin - Dec(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Fouls + Dec(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Fouls - if Data.ScoreCon then + if tgcScoreCon then begin - g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_BLUE], Data.ScoreCount]), True); + g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_BLUE], tgcScoreCount]), True); if g_Game_IsServer and g_Game_IsNet then - MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '-tb'); + MH_SEND_GameEvent(NET_EV_SCORE, tgcScoreCount shl 16, '-tb'); end; - if Data.ScoreMsg then + if tgcScoreMsg then begin g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108); if g_Game_IsServer and g_Game_IsNet then @@ -1581,20 +1891,22 @@ begin end; end; // Âûèãðûø - if (Data.ScoreAction = 2) and (gGameSettings.GoalLimit > 0) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_WIN) and (gGameSettings.ScoreLimit > 0) then begin // Ñâîåé èëè ÷óæîé êîìàíäû - if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then + if (tgcScoreTeam in [TRIGGER_SCORE_TEAM_MINE_RED, TRIGGER_SCORE_TEAM_MINE_BLUE]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then begin p := g_Player_Get(ActivateUID); - if ((Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) // Red Wins - or ((Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then - if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then + if ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_RED)) // Red Wins + or ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_BLUE)) then + begin + if gTeamStat[TEAM_RED].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_RED].Score := gGameSettings.ScoreLimit; - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + begin + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) then begin g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True); if g_Game_IsServer and g_Game_IsNet then @@ -1605,17 +1917,21 @@ begin if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wre'); end; + end; Result := True; end; - if ((Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Blue Wins - or ((Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then - if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then + end; + if ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_BLUE)) // Blue Wins + or ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_RED)) then + begin + if gTeamStat[TEAM_BLUE].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_BLUE].Score := gGameSettings.ScoreLimit; - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + begin + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) then begin g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); if g_Game_IsServer and g_Game_IsNet then @@ -1626,42 +1942,48 @@ begin if g_Game_IsServer and g_Game_IsNet then MH_SEND_GameEvent(NET_EV_SCORE, p.UID, 'wbe'); end; + end; Result := True; end; + end; end; // Êàêîé-òî êîíêðåòíîé êîìàíäû - if Data.ScoreTeam in [2..3] then + if tgcScoreTeam in [TRIGGER_SCORE_TEAM_FORCE_RED, TRIGGER_SCORE_TEAM_FORCE_BLUE] then begin - if Data.ScoreTeam = 2 then // Red Wins - if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then // Red Wins + begin + if gTeamStat[TEAM_RED].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_RED].Score := gGameSettings.ScoreLimit; Result := True; end; - if Data.ScoreTeam = 3 then // Blue Wins - if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then + end; + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then // Blue Wins + begin + if gTeamStat[TEAM_BLUE].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_BLUE].Score := gGameSettings.ScoreLimit; Result := True; end; + end; end; end; // Ïðîèãðûø - if (Data.ScoreAction = 3) and (gGameSettings.GoalLimit > 0) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_LOOSE) and (gGameSettings.ScoreLimit > 0) then begin // Ñâîåé èëè ÷óæîé êîìàíäû - if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then + if (tgcScoreTeam in [TRIGGER_SCORE_TEAM_MINE_RED, TRIGGER_SCORE_TEAM_MINE_BLUE]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then begin p := g_Player_Get(ActivateUID); - if ((Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Red Wins - or ((Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then - if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then + if ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_BLUE)) // Red Wins + or ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_RED)) then + if gTeamStat[TEAM_RED].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_RED].Score := gGameSettings.ScoreLimit; - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + if tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED then begin g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True); if g_Game_IsServer and g_Game_IsNet then @@ -1675,14 +1997,14 @@ begin Result := True; end; - if ((Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) // Blue Wins - or ((Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then - if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then + if ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED) and (p.Team = TEAM_RED)) // Blue Wins + or ((tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_BLUE) and (p.Team = TEAM_BLUE)) then + if gTeamStat[TEAM_BLUE].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_BLUE].Score := gGameSettings.ScoreLimit; - if Data.ScoreCon then - if Data.ScoreTeam = 0 then + if tgcScoreCon then + if tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED then begin g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True); if g_Game_IsServer and g_Game_IsNet then @@ -1698,20 +2020,24 @@ begin end; end; // Êàêîé-òî êîíêðåòíîé êîìàíäû - if Data.ScoreTeam in [2..3] then + if tgcScoreTeam in [TRIGGER_SCORE_TEAM_FORCE_BLUE, TRIGGER_SCORE_TEAM_FORCE_RED] then begin - if Data.ScoreTeam = 3 then // Red Wins - if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then // Red Wins + begin + if gTeamStat[TEAM_RED].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_RED].Score := gGameSettings.ScoreLimit; Result := True; end; - if Data.ScoreTeam = 2 then // Blue Wins - if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then + end; + if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then // Blue Wins + begin + if gTeamStat[TEAM_BLUE].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_BLUE].Score := gGameSettings.ScoreLimit; Result := True; end; + end; end; end; if Result then begin @@ -1726,8 +2052,8 @@ begin TRIGGER_MESSAGE: begin - Result := tr_Message(Data.MessageKind, Data.MessageText, - Data.MessageSendTo, Data.MessageTime, + Result := tr_Message(tgcKind, tgcText, + tgcMsgDest, tgcMsgTime, ActivateUID); TimeOut := 18; end; @@ -1743,10 +2069,10 @@ begin if coolDown then begin // Âñïîìèíàåì, àêòèâèðîâàë ëè îí ìåíÿ ðàíüøå - for i := 0 to High(Activators) do - if Activators[i].UID = ActivateUID then + for idx := 0 to High(Activators) do + if Activators[idx].UID = ActivateUID then begin - k := i; + k := idx; Break; end; if k = -1 then @@ -1758,7 +2084,7 @@ begin end else begin // Óæå âèäåëè åãî // Åñëè èíòåðâàë îòêëþ÷¸í, íî îí âñ¸ åù¸ â çîíå ïîðàæåíèÿ, äà¸ì åìó âðåìÿ - if (Data.DamageInterval = 0) and (Activators[k].TimeOut > 0) then + if (tgcInterval = 0) and (Activators[k].TimeOut > 0) then Activators[k].TimeOut := 65535; // Òàéìàóò ïðîø¸ë - ðàáîòàåì Result := Activators[k].TimeOut = 0; @@ -1775,12 +2101,19 @@ begin Exit; // Íàíîñèì óðîí èãðîêó - if (TriggerType = TRIGGER_DAMAGE) and (Data.DamageValue > 0) then - p.Damage(Data.DamageValue, 0, 0, 0, HIT_SOME); + if (TriggerType = TRIGGER_DAMAGE) and (tgcAmount > 0) then + begin + // Êèñëîòíûé óðîí íå íàíîñèòñÿ êîãäà åñòü êîñòþì + // "Âîäÿíîé" óðîí íå íàíîñèòñÿ êîãäà åñòü êèñëîðîä + if not (((tgcKind = HIT_ACID) and (p.FPowerups[MR_SUIT] > gTime)) or + ((tgcKind = HIT_WATER) and (p.Air > 0))) then + p.Damage(tgcAmount, 0, 0, 0, tgcKind); + if (tgcKind = HIT_FLAME) then p.CatchFire(0); + end; // Ëå÷èì èãðîêà - if (TriggerType = TRIGGER_HEALTH) and (Data.HealValue > 0) then - if p.Heal(Data.HealValue, not Data.HealMax) and (not Data.HealSilent) then + if (TriggerType = TRIGGER_HEALTH) and (tgcAmount > 0) then + if p.Heal(tgcAmount, not tgcHealMax) and (not tgcSilent) then begin g_Sound_PlayExAt('SOUND_ITEM_GETITEM', p.Obj.X, p.Obj.Y); if g_Game_IsServer and g_Game_IsNet then @@ -1790,17 +2123,20 @@ begin UID_MONSTER: begin - m := g_Monsters_Get(ActivateUID); + m := g_Monsters_ByUID(ActivateUID); if m = nil then Exit; // Íàíîñèì óðîí ìîíñòðó - if (TriggerType = TRIGGER_DAMAGE) and (Data.DamageValue > 0) then - m.Damage(Data.DamageValue, 0, 0, 0, HIT_SOME); + if (TriggerType = TRIGGER_DAMAGE) and (tgcAmount > 0) then + begin + m.Damage(tgcAmount, 0, 0, 0, tgcKind); + if (tgcKind = HIT_FLAME) then m.CatchFire(0); + end; // Ëå÷èì ìîíñòðà - if (TriggerType = TRIGGER_HEALTH) and (Data.HealValue > 0) then - if m.Heal(Data.HealValue) and (not Data.HealSilent) then + if (TriggerType = TRIGGER_HEALTH) and (tgcAmount > 0) then + if m.Heal(tgcAmount) and (not tgcSilent) then begin g_Sound_PlayExAt('SOUND_ITEM_GETITEM', m.Obj.X, m.Obj.Y); if g_Game_IsServer and g_Game_IsNet then @@ -1809,13 +2145,10 @@ begin end; end; // Íàçíà÷àåì âðåìÿ ñëåäóþùåãî âîçäåéñòâèÿ - if TriggerType = TRIGGER_DAMAGE then - i := Data.DamageInterval - else - i := Data.HealInterval; + idx := tgcInterval; if coolDown then - if i > 0 then - Activators[k].TimeOut := i + if idx > 0 then + Activators[k].TimeOut := idx else Activators[k].TimeOut := 65535; end; @@ -1828,84 +2161,72 @@ begin if ShotSightTime > 0 then Exit; - wx := Data.ShotPos.X; - wy := Data.ShotPos.Y; - pAngle := -DegToRad(Data.ShotAngle); + // put this at the beginning so it doesn't trigger itself + TimeOut := tgcWait + 1; + + wx := tgcTX; + wy := tgcTY; + pAngle := -DegToRad(tgcAngle); xd := wx + Round(Cos(pAngle) * 32.0); yd := wy + Round(Sin(pAngle) * 32.0); TargetUID := 0; - case Data.ShotTarget of + case tgcShotTarget of TRIGGER_SHOT_TARGET_MON: // monsters - if gMonsters <> nil then - for i := Low(gMonsters) to High(gMonsters) do - if (gMonsters[i] <> nil) and gMonsters[i].Live and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gMonsters[i].Obj))) then - begin - xd := gMonsters[i].GameX + gMonsters[i].Obj.Rect.Width div 2; - yd := gMonsters[i].GameY + gMonsters[i].Obj.Rect.Height div 2; - TargetUID := gMonsters[i].UID; - break; - end; + //TODO: accelerate this! + g_Mons_ForEachAlive(monsShotTarget); TRIGGER_SHOT_TARGET_PLR: // players if gPlayers <> nil then - for i := Low(gPlayers) to High(gPlayers) do - if (gPlayers[i] <> nil) and gPlayers[i].Live and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].alive and + tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then begin - xd := gPlayers[i].GameX + PLAYER_RECT_CX; - yd := gPlayers[i].GameY + PLAYER_RECT_CY; - TargetUID := gPlayers[i].UID; + xd := gPlayers[idx].GameX + PLAYER_RECT_CX; + yd := gPlayers[idx].GameY + PLAYER_RECT_CY; + TargetUID := gPlayers[idx].UID; break; end; TRIGGER_SHOT_TARGET_RED: // red team if gPlayers <> nil then - for i := Low(gPlayers) to High(gPlayers) do - if (gPlayers[i] <> nil) and gPlayers[i].Live and - (gPlayers[i].Team = TEAM_RED) and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].alive and + (gPlayers[idx].Team = TEAM_RED) and + tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then begin - xd := gPlayers[i].GameX + PLAYER_RECT_CX; - yd := gPlayers[i].GameY + PLAYER_RECT_CY; - TargetUID := gPlayers[i].UID; + xd := gPlayers[idx].GameX + PLAYER_RECT_CX; + yd := gPlayers[idx].GameY + PLAYER_RECT_CY; + TargetUID := gPlayers[idx].UID; break; end; TRIGGER_SHOT_TARGET_BLUE: // blue team if gPlayers <> nil then - for i := Low(gPlayers) to High(gPlayers) do - if (gPlayers[i] <> nil) and gPlayers[i].Live and - (gPlayers[i].Team = TEAM_BLUE) and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].alive and + (gPlayers[idx].Team = TEAM_BLUE) and + tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then begin - xd := gPlayers[i].GameX + PLAYER_RECT_CX; - yd := gPlayers[i].GameY + PLAYER_RECT_CY; - TargetUID := gPlayers[i].UID; + xd := gPlayers[idx].GameX + PLAYER_RECT_CX; + yd := gPlayers[idx].GameY + PLAYER_RECT_CY; + TargetUID := gPlayers[idx].UID; break; end; TRIGGER_SHOT_TARGET_MONPLR: // monsters then players begin - if gMonsters <> nil then - for i := Low(gMonsters) to High(gMonsters) do - if (gMonsters[i] <> nil) and gMonsters[i].Live and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gMonsters[i].Obj))) then - begin - xd := gMonsters[i].GameX + gMonsters[i].Obj.Rect.Width div 2; - yd := gMonsters[i].GameY + gMonsters[i].Obj.Rect.Height div 2; - TargetUID := gMonsters[i].UID; - break; - end; + //TODO: accelerate this! + g_Mons_ForEachAlive(monsShotTargetMonPlr); + if (TargetUID = 0) and (gPlayers <> nil) then - for i := Low(gPlayers) to High(gPlayers) do - if (gPlayers[i] <> nil) and gPlayers[i].Live and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].alive and + tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then begin - xd := gPlayers[i].GameX + PLAYER_RECT_CX; - yd := gPlayers[i].GameY + PLAYER_RECT_CY; - TargetUID := gPlayers[i].UID; + xd := gPlayers[idx].GameX + PLAYER_RECT_CX; + yd := gPlayers[idx].GameY + PLAYER_RECT_CY; + TargetUID := gPlayers[idx].UID; break; end; end; @@ -1913,42 +2234,42 @@ begin TRIGGER_SHOT_TARGET_PLRMON: // players then monsters begin if gPlayers <> nil then - for i := Low(gPlayers) to High(gPlayers) do - if (gPlayers[i] <> nil) and gPlayers[i].Live and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gPlayers[i].Obj))) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].alive and + tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then begin - xd := gPlayers[i].GameX + PLAYER_RECT_CX; - yd := gPlayers[i].GameY + PLAYER_RECT_CY; - TargetUID := gPlayers[i].UID; - break; - end; - if (TargetUID = 0) and (gMonsters <> nil) then - for i := Low(gMonsters) to High(gMonsters) do - if (gMonsters[i] <> nil) and gMonsters[i].Live and - (Data.ShotAllMap or g_Obj_Collide(X, Y, Width, Height, @(gMonsters[i].Obj))) then - begin - xd := gMonsters[i].GameX + gMonsters[i].Obj.Rect.Width div 2; - yd := gMonsters[i].GameY + gMonsters[i].Obj.Rect.Height div 2; - TargetUID := gMonsters[i].UID; + xd := gPlayers[idx].GameX + PLAYER_RECT_CX; + yd := gPlayers[idx].GameY + PLAYER_RECT_CY; + TargetUID := gPlayers[idx].UID; break; end; + if TargetUID = 0 then + begin + //TODO: accelerate this! + g_Mons_ForEachAlive(monShotTargetPlrMon); + end; end; - else TargetUID := ActivateUID; + else begin + if (tgcShotTarget <> TRIGGER_SHOT_TARGET_NONE) or + (tgcShotType <> TRIGGER_SHOT_REV) then + TargetUID := ActivateUID; + end; end; - if (Data.ShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID > 0) then + if (tgcShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID > 0) or + ((tgcShotTarget > TRIGGER_SHOT_TARGET_NONE) and (TargetUID = 0)) then begin Result := True; - if (Data.ShotIntSight = 0) or - (Data.ShotTarget = TRIGGER_SHOT_TARGET_NONE) or + if (tgcSight = 0) or + (tgcShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID = ShotSightTarget) then MakeShot(Trigger, wx, wy, xd, yd, TargetUID) else begin - ShotSightTime := Data.ShotIntSight; + ShotSightTime := tgcSight; ShotSightTargetN := TargetUID; - if Data.ShotType = TRIGGER_SHOT_BFG then + if tgcShotType = TRIGGER_SHOT_BFG then begin g_Sound_PlayExAt('SOUND_WEAPON_STARTFIREBFG', wx, wy); if g_Game_IsNet and g_Game_IsServer then @@ -1956,17 +2277,15 @@ begin end; end; end; - - TimeOut := Data.ShotWait + 1; end; TRIGGER_EFFECT: begin - i := Data.FXCount; + idx := tgcFXCount; - while i > 0 do + while idx > 0 do begin - case Data.FXPos of + case tgcFXPos of TRIGGER_EFFECT_POS_CENTER: begin wx := X + Width div 2; @@ -1982,68 +2301,136 @@ begin wy := Y + Height div 2; end; end; - xd := Data.FXVelX; - yd := Data.FXVelY; - if Data.FXSpreadL > 0 then xd := xd - Random(Data.FXSpreadL + 1); - if Data.FXSpreadR > 0 then xd := xd + Random(Data.FXSpreadR + 1); - if Data.FXSpreadU > 0 then yd := yd - Random(Data.FXSpreadU + 1); - if Data.FXSpreadD > 0 then yd := yd + Random(Data.FXSpreadD + 1); + xd := tgcVelX; + yd := tgcVelY; + if tgcSpreadL > 0 then xd -= Random(tgcSpreadL+1); + if tgcSpreadR > 0 then xd += Random(tgcSpreadR+1); + if tgcSpreadU > 0 then yd -= Random(tgcSpreadU+1); + if tgcSpreadD > 0 then yd += Random(tgcSpreadD+1); tr_MakeEffect(wx, wy, xd, yd, - Data.FXType, Data.FXSubType, - Data.FXColorR, Data.FXColorG, Data.FXColorB, True, False); - Dec(i); + tgcFXType, tgcFXSubType, + tgcFXRed, tgcFXGreen, tgcFXBlue, True, False); + Dec(idx); end; - TimeOut := Data.FXWait; - end; - - TRIGGER_SCRIPT: - begin - g_Scripts_ProcExec(Data.SCRProc, [ID, ActivateUID, actType, Data.SCRArg], 'map'); - TimeOut := 0; - Result := True; + TimeOut := tgcWait; + result := true; end; end; end; - if Result and (Trigger.TexturePanel <> -1) then - g_Map_SwitchTexture(Trigger.TexturePanelType, Trigger.TexturePanel, IfThen(animonce, 2, 1)); + if Result {and (Trigger.TexturePanel <> -1)} then + begin + g_Map_SwitchTextureGUID({Trigger.TexturePanelType,} Trigger.TexturePanelGUID, IfThen(animonce, 2, 1)); + end; +end; + + +function g_Triggers_CreateWithMapIndex (aTrigger: TTrigger; arridx, mapidx: Integer): DWORD; +var + triggers: TDynField; +begin + triggers := gCurrentMap['trigger']; + if (triggers = nil) then raise Exception.Create('LOAD: map has no triggers'); + if (mapidx < 0) or (mapidx >= triggers.count) then raise Exception.Create('LOAD: invalid map trigger index'); + aTrigger.mapIndex := mapidx; + result := g_Triggers_Create(aTrigger, triggers.itemAt[mapidx], arridx); end; -function g_Triggers_Create(Trigger: TTrigger): DWORD; + +function g_Triggers_Create (aTrigger: TTrigger; trec: TDynRecord; forceInternalIndex: Integer=-1): DWORD; var find_id: DWORD; - fn, mapw: String; + fn: AnsiString; + f, olen: Integer; + ptg: PTrigger; begin -// Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà: - if (Trigger.TriggerType = TRIGGER_EXIT) and - (not LongBool(gGameSettings.Options and GAME_OPTION_ALLOWEXIT)) then - Trigger.TriggerType := TRIGGER_NONE; - -// Åñëè ìîíñòðû çàïðåùåíû, îòìåíÿåì òðèããåð: - if (Trigger.TriggerType = TRIGGER_SPAWNMONSTER) and - (not LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS)) and + if (tgscope = nil) then tgscope := TTrigScope.Create(); + if (tgclist = nil) then tgclist := TMyConstList.Create(); + + // Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà + if (aTrigger.TriggerType = TRIGGER_EXIT) and + (not (TGameOption.ALLOW_EXIT in gGameSettings.Options)) then + begin + aTrigger.TriggerType := TRIGGER_NONE; + end; + + // Åñëè ìîíñòðû çàïðåùåíû, îòìåíÿåì òðèããåð + if (aTrigger.TriggerType = TRIGGER_SPAWNMONSTER) and + (not (TGameOption.MONSTERS in gGameSettings.Options)) and (gGameSettings.GameType <> GT_SINGLE) then - Trigger.TriggerType := TRIGGER_NONE; + begin + aTrigger.TriggerType := TRIGGER_NONE; + end; -// Ñ÷èòàåì êîëè÷åñòâî ñåêðåòîâ íà êàðòå: - if Trigger.TriggerType = TRIGGER_SECRET then - gSecretsCount := gSecretsCount + 1; + // Ñ÷èòàåì êîëè÷åñòâî ñåêðåòîâ íà êàðòå + if (aTrigger.TriggerType = TRIGGER_SECRET) then gSecretsCount += 1; + + if (forceInternalIndex < 0) then + begin + find_id := FindTrigger(); + end + else + begin + olen := Length(gTriggers); + if (forceInternalIndex >= olen) then + begin + SetLength(gTriggers, forceInternalIndex+1); + for f := olen to High(gTriggers) do + begin + gTriggers[f].TriggerType := TRIGGER_NONE; + gTriggers[f].trigDataRec := nil; + gTriggers[f].exoInit := nil; + gTriggers[f].exoThink := nil; + gTriggers[f].exoCheck := nil; + gTriggers[f].exoAction := nil; + gTriggers[f].userVars := nil; + end; + end; + f := forceInternalIndex; + gTriggers[f].trigDataRec.Free(); + gTriggers[f].exoInit.Free(); + gTriggers[f].exoThink.Free(); + gTriggers[f].exoCheck.Free(); + gTriggers[f].exoAction.Free(); + gTriggers[f].userVars.Free(); + gTriggers[f].trigDataRec := nil; + gTriggers[f].exoInit := nil; + gTriggers[f].exoThink := nil; + gTriggers[f].exoCheck := nil; + gTriggers[f].exoAction := nil; + gTriggers[f].userVars := nil; + find_id := DWORD(forceInternalIndex); + end; + gTriggers[find_id] := aTrigger; + ptg := @gTriggers[find_id]; - find_id := FindTrigger(); - gTriggers[find_id] := Trigger; + ptg.mapId := trec.id; + // clone trigger data + if (trec.trigRec = nil) then + begin + ptg.trigDataRec := nil; + //HACK! + if (ptg.TriggerType <> TRIGGER_SECRET) then + begin + e_LogWritefln('trigger of type %s has no triggerdata; wtf?!', [ptg.TriggerType], TMsgType.Warning); + end; + end + else + begin + ptg.trigDataRec := trec.trigRec.clone(nil); + end; - with gTriggers[find_id] do + with ptg^ do begin ID := find_id; // if this type of trigger exists both on the client and on the server // use an uniform numeration - if Trigger.TriggerType = TRIGGER_SOUND then + ClientID := 0; + if (ptg.TriggerType = TRIGGER_SOUND) then begin Inc(gTriggerClientID); ClientID := gTriggerClientID; - end - else - ClientID := 0; + end; TimeOut := 0; ActivateUID := 0; PlayerCollide := False; @@ -2057,32 +2444,89 @@ begin SpawnedCount := 0; end; -// Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê": - if (Trigger.TriggerType = TRIGGER_SOUND) and - (Trigger.Data.SoundName <> '') then - begin - // Åùå íåò òàêîãî çâóêà: - if not g_Sound_Exists(Trigger.Data.SoundName) then - begin - fn := g_ExtractWadName(Trigger.Data.SoundName); + // update cached trigger variables + trigUpdateCacheData(ptg^, ptg.trigDataRec); - if fn = '' then - begin // Çâóê â ôàéëå ñ êàðòîé - mapw := g_ExtractWadName(gMapInfo.Map); - fn := mapw+':'+g_ExtractFilePathName(Trigger.Data.SoundName); - end - else // Çâóê â îòäåëüíîì ôàéëå - fn := GameDir + '/wads/' + Trigger.Data.SoundName; + ptg.userVars := nil; + + try + ptg.exoThink := TExprBase.parseStatList(tgclist, VarToStr(trec.user['exoma_think'])); + except + on e: TExomaParseException do + begin + conwritefln('*** ERROR parsing exoma_think (%s,%s): %s [%s]', [e.tokLine, e.tokCol, e.message, VarToStr(trec.user['exoma_think'])]); + ptg.exoThink := nil; + end; + else + raise; + end; + try + ptg.exoCheck := TExprBase.parse(tgclist, VarToStr(trec.user['exoma_check'])); + except + on e: TExomaParseException do + begin + conwritefln('*** ERROR parsing exoma_check (%s,%s): %s [%s]', [e.tokLine, e.tokCol, e.message, VarToStr(trec.user['exoma_check'])]); + ptg.exoCheck := nil; + end; + else + raise; + end; + try + ptg.exoAction := TExprBase.parseStatList(tgclist, VarToStr(trec.user['exoma_action'])); + except + on e: TExomaParseException do + begin + conwritefln('*** ERROR parsing exoma_action (%s,%s): %s [%s]', [e.tokLine, e.tokCol, e.message, VarToStr(trec.user['exoma_action'])]); + ptg.exoAction := nil; + end; + else + raise; + end; + try + ptg.exoInit := TExprBase.parseStatList(tgclist, VarToStr(trec.user['exoma_init'])); + except + on e: TExomaParseException do + begin + conwritefln('*** ERROR parsing exoma_init (%s,%s): %s [%s]', [e.tokLine, e.tokCol, e.message, VarToStr(trec.user['exoma_init'])]); + ptg.exoInit := nil; + end; + else + raise; + end; + + if (forceInternalIndex < 0) and (ptg.exoInit <> nil) then + begin + //conwritefln('executing trigger init: [%s]', [gTriggers[find_id].exoInit.toString()]); + try + tgscope.me := ptg; + ptg.exoInit.value(tgscope); + tgscope.me := nil; + except + tgscope.me := nil; + conwritefln('*** trigger exoactivate error: %s', [ptg.exoInit.toString()]); + exit; + end; + end; - if not g_Sound_CreateWADEx(Trigger.Data.SoundName, fn) then - g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.Data.SoundName])); + // Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê" + if (ptg.TriggerType = TRIGGER_SOUND) and (ptg.tgcSoundName <> '') then + begin + // Åùå íåò òàêîãî çâóêà + if not g_Sound_Exists(ptg.tgcSoundName) then + begin + fn := e_GetResourcePath(WadDirs, ptg.tgcSoundName, g_ExtractWadName(gMapInfo.Map)); + //e_LogWritefln('loading trigger sound ''%s''', [fn]); + if not g_Sound_CreateWADEx(ptg.tgcSoundName, fn) then + begin + g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, ptg.tgcSoundName])); + end; end; - // Ñîçäàåì îáúåêò çâóêà: - with gTriggers[find_id] do + // Ñîçäàåì îáúåêò çâóêà + with ptg^ do begin Sound := TPlayableSound.Create(); - if not Sound.SetByName(Trigger.Data.SoundName) then + if not Sound.SetByName(ptg.tgcSoundName) then begin Sound.Free(); Sound := nil; @@ -2090,51 +2534,70 @@ begin end; end; -// Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà": - if (Trigger.TriggerType = TRIGGER_MUSIC) and - (Trigger.Data.MusicName <> '') then + // Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà" + if (ptg.TriggerType = TRIGGER_MUSIC) and (ptg.tgcMusicName <> '') then begin - // Åùå íåò òàêîé ìóçûêè: - if not g_Sound_Exists(Trigger.Data.MusicName) then + // Åùå íåò òàêîé ìóçûêè + if not g_Sound_Exists(ptg.tgcMusicName) then begin - fn := g_ExtractWadName(Trigger.Data.MusicName); - - if fn = '' then - begin // Ìóçûêà â ôàéëå ñ êàðòîé - mapw := g_ExtractWadName(gMapInfo.Map); - fn := mapw+':'+g_ExtractFilePathName(Trigger.Data.MusicName); - end - else // Ìóçûêà â ôàéëå ñ êàðòîé - fn := GameDir+'/wads/'+Trigger.Data.MusicName; - - if not g_Sound_CreateWADEx(Trigger.Data.MusicName, fn, True) then - g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.Data.MusicName])); + fn := e_GetResourcePath(WadDirs, ptg.tgcMusicName, g_ExtractWadName(gMapInfo.Map)); + if not g_Sound_CreateWADEx(ptg.tgcMusicName, fn, True) then + begin + g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, ptg.tgcMusicName])); + end; end; end; -// Çàãðóæàåì äàííûå òðèããåðà "Òóðåëü": - if Trigger.TriggerType = TRIGGER_SHOT then - with gTriggers[find_id] do + // Çàãðóæàåì äàííûå òðèããåðà "Òóðåëü" + if (ptg.TriggerType = TRIGGER_SHOT) then + begin + with ptg^ do begin ShotPanelTime := 0; ShotSightTime := 0; ShotSightTimeout := 0; ShotSightTarget := 0; ShotSightTargetN := 0; - ShotAmmoCount := Trigger.Data.ShotAmmo; + ShotAmmoCount := ptg.tgcAmmo; ShotReloadTime := 0; end; + end; Result := find_id; end; + +// sorry; grid doesn't support recursive queries, so we have to do this +type + TSimpleMonsterList = specialize TSimpleList; + +var + tgMonsList: TSimpleMonsterList = nil; + procedure g_Triggers_Update(); var a, b, i: Integer; Affected: array of Integer; + + function monsNear (mon: TMonster): Boolean; + begin + result := false; // don't stop + { + gTriggers[a].ActivateUID := mon.UID; + ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE); + } + tgMonsList.append(mon); + end; + +var + mon: TMonster; + pan: TPanel; begin - if gTriggers = nil then - Exit; + if (tgMonsList = nil) then tgMonsList := TSimpleMonsterList.Create(); + + if gTriggers = nil then Exit; + if gLMSRespawn > LMS_RESPAWN_NONE then Exit; // don't update triggers at all + SetLength(Affected, 0); for a := 0 to High(gTriggers) do @@ -2142,132 +2605,164 @@ begin // Åñòü òðèããåð: if TriggerType <> TRIGGER_NONE then begin - // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè): - if DoorTime > 0 then - DoorTime := DoorTime - 1; - // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ: - if PressTime > 0 then - PressTime := PressTime - 1; - // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè: + // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè) + if DoorTime > 0 then DoorTime := DoorTime - 1; + // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ + if PressTime > 0 then PressTime := PressTime - 1; + // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè: if (TriggerType = TRIGGER_DAMAGE) or (TriggerType = TRIGGER_HEALTH) then + begin for b := 0 to High(Activators) do begin // Óìåíüøàåì âðåìÿ äî ïîâòîðíîãî âîçäåéñòâèÿ: if Activators[b].TimeOut > 0 then - Dec(Activators[b].TimeOut) + begin + Dec(Activators[b].TimeOut); + end else - Continue; + begin + continue; + end; // Ñ÷èòàåì, ÷òî îáúåêò ïîêèíóë çîíó äåéñòâèÿ òðèããåðà - if (Data.DamageInterval = 0) and (Activators[b].TimeOut < 65530) then - Activators[b].TimeOut := 0; + if (tgcInterval = 0) and (Activators[b].TimeOut < 65530) then Activators[b].TimeOut := 0; end; + end; - // Îáðàáàòûâàåì ñïàâíåðû: + // Îáðàáàòûâàåì ñïàâíåðû if Enabled and AutoSpawn then + begin if SpawnCooldown = 0 then begin - // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà: - if (TriggerType = TRIGGER_SPAWNMONSTER) and (Data.MonDelay > 0) then + // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà + if (TriggerType = TRIGGER_SPAWNMONSTER) and (tgcDelay > 0) then begin ActivateUID := 0; ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM); end; - // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò: - if (TriggerType = TRIGGER_SPAWNITEM) and (Data.ItemDelay > 0) then + // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò + if (TriggerType = TRIGGER_SPAWNITEM) and (tgcDelay > 0) then begin ActivateUID := 0; ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM); end; - end else // Óìåíüøàåì âðåìÿ îæèäàíèÿ: + end + else + begin + // Óìåíüøàåì âðåìÿ îæèäàíèÿ Dec(SpawnCooldown); + end; + end; - // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü": + // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü" if TriggerType = TRIGGER_SHOT then begin if ShotPanelTime > 0 then begin Dec(ShotPanelTime); - if ShotPanelTime = 0 then - g_Map_SwitchTexture(ShotPanelType, Data.ShotPanelID); + if ShotPanelTime = 0 then g_Map_SwitchTextureGUID({ShotPanelType,} trigPanelGUID); end; if ShotSightTime > 0 then begin Dec(ShotSightTime); - if ShotSightTime = 0 then - ShotSightTarget := ShotSightTargetN; + if ShotSightTime = 0 then ShotSightTarget := ShotSightTargetN; end; if ShotSightTimeout > 0 then begin Dec(ShotSightTimeout); - if ShotSightTimeout = 0 then - ShotSightTarget := 0; + if ShotSightTimeout = 0 then ShotSightTarget := 0; end; if ShotReloadTime > 0 then begin Dec(ShotReloadTime); - if ShotReloadTime = 0 then - ShotAmmoCount := Data.ShotAmmo; + if ShotReloadTime = 0 then ShotAmmoCount := tgcAmmo; end; end; - // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì: + // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì if Enabled and (TriggerType = TRIGGER_SOUND) and (Sound <> nil) then + begin if (SoundPlayCount > 0) and (not Sound.IsPlaying()) then begin - if Data.PlayCount > 0 then // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî - SoundPlayCount := SoundPlayCount - 1; - if Data.Local then - Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0) + if tgcPlayCount > 0 then Dec(SoundPlayCount); (* looped sound if zero *) + if tgcLocal then + Sound.PlayVolumeAtRect(X, Y, Width, Height, tgcVolume / 255.0) else - Sound.PlayPanVolume((Data.Pan-127.0)/128.0, Data.Volume/255.0); + Sound.PlayPanVolume((tgcPan - 127.0) / 128.0, tgcVolume / 255.0); if Sound.IsPlaying() and g_Game_IsNet and g_Game_IsServer then - MH_SEND_TriggerSound(gTriggers[a]); - end; + MH_SEND_TriggerSound(gTriggers[a]) + end + end; - // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü: - if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (Data.PanelID <> -1) then + // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü + if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (g_Map_PanelByGUID(trigPanelGUID) <> nil) then begin - tr_OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors); + tr_OpenDoor(trigPanelGUID, tgcSilent, tgcD2d); DoorTime := -1; end; - // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü: - if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (Data.PanelID <> -1) then + // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü + if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (g_Map_PanelByGUID(trigPanelGUID) <> nil) then begin - // Óæå çàêðûòà: - if gWalls[Data.PanelID].Enabled then - DoorTime := -1 - else // Ïîêà îòêðûòà - çàêðûâàåì - if tr_CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors) then + pan := g_Map_PanelByGUID(trigPanelGUID); + if (pan <> nil) and pan.isGWall then + begin + // Óæå çàêðûòà + if {gWalls[trigPanelID].Enabled} pan.Enabled then + begin DoorTime := -1; + end + else + begin + // Ïîêà îòêðûòà - çàêðûâàåì + if tr_CloseDoor(trigPanelGUID, tgcSilent, tgcD2d) then DoorTime := -1; + end; + end; end; // Òðèããåð - ðàñøèðèòåëü èëè ïåðåêëþ÷àòåëü, è ïðîøëà çàäåðæêà, è íàæàëè íóæíîå ÷èñëî ðàç: if (TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) and - (PressTime = 0) and (PressCount >= Data.Count) then + (PressTime = 0) and (PressCount >= tgcPressCount) then begin - // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè: + // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè: PressTime := -1; - // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé: - if Data.Count > 0 then - PressCount := PressCount - Data.Count - else - PressCount := 0; + // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé: + if tgcPressCount > 0 then PressCount -= tgcPressCount else PressCount := 0; - // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû: + // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû: for b := 0 to High(gTriggers) do - if g_Collide(Data.tX, Data.tY, Data.tWidth, Data.tHeight, gTriggers[b].X, gTriggers[b].Y, + begin + if g_Collide(tgcTX, tgcTY, tgcTWidth, tgcTHeight, gTriggers[b].X, gTriggers[b].Y, gTriggers[b].Width, gTriggers[b].Height) and - ((b <> a) or (Data.Wait > 0)) then + ((b <> a) or (tgcWait > 0)) then begin // Can be self-activated, if there is Data.Wait - if (not Data.ExtRandom) or gTriggers[b].Enabled then + if (not tgcExtRandom) or gTriggers[b].Enabled then begin SetLength(Affected, Length(Affected) + 1); Affected[High(Affected)] := b; end; end; - // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì: - if (TriggerType = TRIGGER_PRESS) and Data.ExtRandom then + end; + + //HACK! + // if we have panelid, assume that it will switch the moving platform + pan := g_Map_PanelByGUID(trigPanelGUID); + if (pan <> nil) then + begin + case TriggerType of + TRIGGER_PRESS: pan.movingActive := true; // what to do here? + TRIGGER_ON: pan.movingActive := true; + TRIGGER_OFF: pan.movingActive := false; + TRIGGER_ONOFF: pan.movingActive := not pan.movingActive; + end; + if not tgcSilent and (Length(tgcSound) > 0) then + begin + g_Sound_PlayExAt(tgcSound, X, Y); + if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, tgcSound); + end; + end; + + // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì: + if (TriggerType = TRIGGER_PRESS) and tgcExtRandom then begin if (Length(Affected) > 0) then begin @@ -2277,6 +2772,7 @@ begin end; end else //  ïðîòèâíîì ñëó÷àå ðàáîòàåì êàê îáû÷íî: + begin for i := 0 to High(Affected) do begin b := Affected[i]; @@ -2315,6 +2811,7 @@ begin end; end; end; + end; SetLength(Affected, 0); end; @@ -2337,7 +2834,7 @@ begin if gPlayers[b] <> nil then with gPlayers[b] do // Æèâ, åñòü íóæíûå êëþ÷è è îí ðÿäîì: - if Live and ((gTriggers[a].Keys and GetKeys) = gTriggers[a].Keys) and + if alive and ((gTriggers[a].Keys and GetKeys) = gTriggers[a].Keys) and Collide(X, Y, Width, Height) then begin gTriggers[a].ActivateUID := UID; @@ -2362,23 +2859,26 @@ begin ActivateTrigger(gTriggers[a], 0); end else begin - // "Ìîíñòð áëèçêî": + // "Ìîíñòð áëèçêî" if ByteBool(ActivateType and ACTIVATE_MONSTERCOLLIDE) and (TimeOut = 0) and (Keys = 0) then // Åñëè íå íóæíû êëþ÷è - if gMonsters <> nil then - for b := 0 to High(gMonsters) do - if (gMonsters[b] <> nil) then - with gMonsters[b] do - if Collide(X, Y, Width, Height) then - begin - gTriggers[a].ActivateUID := UID; - ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE); - end; + begin + //g_Mons_ForEach(monsNear); + //Alive?! + tgMonsList.reset(); + g_Mons_ForEachAt(gTriggers[a].X, gTriggers[a].Y, gTriggers[a].Width, gTriggers[a].Height, monsNear); + for mon in tgMonsList do + begin + gTriggers[a].ActivateUID := mon.UID; + ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE); + end; + tgMonsList.reset(); // just in case + end; - // "Ìîíñòðîâ íåò": + // "Ìîíñòðîâ íåò" if ByteBool(ActivateType and ACTIVATE_NOMONSTER) and (TimeOut = 0) and (Keys = 0) then - if not g_CollideMonster(X, Y, Width, Height) then + if not g_Mons_IsAnyAliveAt(X, Y, Width, Height) then begin gTriggers[a].ActivateUID := 0; ActivateTrigger(gTriggers[a], ACTIVATE_NOMONSTER); @@ -2391,6 +2891,7 @@ end; procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0); begin + if (ID >= Length(gTriggers)) then exit; gTriggers[ID].ActivateUID := ActivateUID; ActivateTrigger(gTriggers[ID], ActivateType); end; @@ -2472,7 +2973,7 @@ begin end; end; -procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte); +procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateType: Byte; IgnoreTrigger: Integer = -1); var a: Integer; k: Byte; @@ -2498,7 +2999,8 @@ begin rsq := Radius * Radius; for a := 0 to High(gTriggers) do - if (gTriggers[a].TriggerType <> TRIGGER_NONE) and + if (gTriggers[a].ID <> DWORD(IgnoreTrigger)) and + (gTriggers[a].TriggerType <> TRIGGER_NONE) and (gTriggers[a].TimeOut = 0) and ((gTriggers[a].Keys and k) = gTriggers[a].Keys) and ByteBool(gTriggers[a].ActivateType and ActivateType) then @@ -2528,15 +3030,19 @@ begin b := False; for a := 0 to High(gTriggers) do + begin with gTriggers[a] do + begin if (TriggerType = TRIGGER_OPENDOOR) or (TriggerType = TRIGGER_DOOR5) or (TriggerType = TRIGGER_DOOR) then begin - tr_OpenDoor(Data.PanelID, True, Data.d2d_doors); + tr_OpenDoor(trigPanelGUID, True, tgcD2d); if TriggerType = TRIGGER_DOOR5 then DoorTime := 180; b := True; end; + end; + end; if b then g_Sound_PlayEx('SOUND_GAME_DOOROPEN'); end; @@ -2544,240 +3050,313 @@ end; procedure g_Triggers_DecreaseSpawner(ID: DWORD); begin if (gTriggers <> nil) then - if gTriggers[ID].SpawnedCount > 0 then - Dec(gTriggers[ID].SpawnedCount); + begin + if gTriggers[ID].tgcMax > 0 then + begin + if gTriggers[ID].SpawnedCount > 0 then + Dec(gTriggers[ID].SpawnedCount); + end; + if gTriggers[ID].tgcDelay > 0 then + begin + if gTriggers[ID].SpawnCooldown < 0 then + gTriggers[ID].SpawnCooldown := gTriggers[ID].tgcDelay; + end; + end; end; -procedure g_Triggers_Free(); +procedure g_Triggers_Free (); var a: Integer; begin - if gTriggers <> nil then - for a := 0 to High(gTriggers) do + for a := 0 to High(gTriggers) do + begin + if (gTriggers[a].TriggerType = TRIGGER_SOUND) then begin - if gTriggers[a].TriggerType = TRIGGER_SOUND then + if g_Sound_Exists(gTriggers[a].tgcSoundName) then begin - if g_Sound_Exists(gTriggers[a].Data.SoundName) then - g_Sound_Delete(gTriggers[a].Data.SoundName); - - gTriggers[a].Sound.Free(); + g_Sound_Delete(gTriggers[a].tgcSoundName); end; - if gTriggers[a].Activators <> nil then - SetLength(gTriggers[a].Activators, 0); + gTriggers[a].Sound.Free(); end; + if (gTriggers[a].Activators <> nil) then + begin + SetLength(gTriggers[a].Activators, 0); + end; + gTriggers[a].trigDataRec.Free(); + + gTriggers[a].exoThink.Free(); + gTriggers[a].exoCheck.Free(); + gTriggers[a].exoAction.Free(); + gTriggers[a].userVars.Free(); + end; gTriggers := nil; gSecretsCount := 0; SetLength(gMonstersSpawned, 0); end; -procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter); + +procedure g_Triggers_SaveState (st: TStream); var - count, act_count, i, j: Integer; - dw: DWORD; + count, actCount, i, j: Integer; sg: Single; b: Boolean; - p: Pointer; + kv: THashStrVariant.PEntry; + t: LongInt; begin -// Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ: - count := 0; - if gTriggers <> nil then - for i := 0 to High(gTriggers) do - count := count + 1; - - Mem := TBinMemoryWriter.Create((count+1) * 200); - -// Êîëè÷åñòâî òðèããåðîâ: - Mem.WriteInt(count); + // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ + count := Length(gTriggers); - if count = 0 then - Exit; + // Êîëè÷åñòâî òðèããåðîâ + utils.writeInt(st, LongInt(count)); + if (count = 0) then exit; for i := 0 to High(gTriggers) do begin - // Ñèãíàòóðà òðèããåðà: - dw := TRIGGER_SIGNATURE; // 'TRGR' - Mem.WriteDWORD(dw); - // Òèï òðèããåðà: - Mem.WriteByte(gTriggers[i].TriggerType); - // Ñïåöèàëüíûå äàííûå òðèããåðà: - p := @gTriggers[i].Data; - Mem.WriteMemory(p, SizeOf(TTriggerData)); - // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà: - Mem.WriteInt(gTriggers[i].X); - Mem.WriteInt(gTriggers[i].Y); - // Ðàçìåðû: - Mem.WriteWord(gTriggers[i].Width); - Mem.WriteWord(gTriggers[i].Height); - // Âêëþ÷åí ëè òðèããåð: - Mem.WriteBoolean(gTriggers[i].Enabled); - // Òèï àêòèâàöèè òðèããåðà: - Mem.WriteByte(gTriggers[i].ActivateType); - // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè: - Mem.WriteByte(gTriggers[i].Keys); - // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ: - Mem.WriteInt(gTriggers[i].TexturePanel); - // Òèï ýòîé ïàíåëè: - Mem.WriteWord(gTriggers[i].TexturePanelType); - // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè: - Mem.WriteWord(gTriggers[i].TimeOut); - // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð: - Mem.WriteWord(gTriggers[i].ActivateUID); - // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì: - act_count := Length(gTriggers[i].Activators); - Mem.WriteInt(act_count); - for j := 0 to act_count-1 do + // Ñèãíàòóðà òðèããåðà + utils.writeSign(st, 'TRGX'); + utils.writeInt(st, Byte(0)); + // Òèï òðèããåðà + utils.writeInt(st, Byte(gTriggers[i].TriggerType)); + if (gTriggers[i].TriggerType = TRIGGER_NONE) then continue; // empty one + // Ñïåöèàëüíûå äàííûå òðèããåðà: ïîòîì èç êàðòû îïÿòü âûòàùèì; ñîõðàíèì òîëüêî èíäåêñ + utils.writeInt(st, LongInt(gTriggers[i].mapIndex)); + // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà + utils.writeInt(st, LongInt(gTriggers[i].X)); + utils.writeInt(st, LongInt(gTriggers[i].Y)); + // Ðàçìåðû + utils.writeInt(st, Word(gTriggers[i].Width)); + utils.writeInt(st, Word(gTriggers[i].Height)); + // Âêëþ÷åí ëè òðèããåð + utils.writeBool(st, gTriggers[i].Enabled); + // Òèï àêòèâàöèè òðèããåðà + utils.writeInt(st, Byte(gTriggers[i].ActivateType)); + // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè + utils.writeInt(st, Byte(gTriggers[i].Keys)); + // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ + utils.writeInt(st, LongInt(gTriggers[i].TexturePanelGUID)); + // Òèï ýòîé ïàíåëè + //Mem.WriteWord(gTriggers[i].TexturePanelType); + // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) + utils.writeInt(st, LongInt(gTriggers[i].trigPanelGUID)); + // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè + utils.writeInt(st, Word(gTriggers[i].TimeOut)); + // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð + utils.writeInt(st, Word(gTriggers[i].ActivateUID)); + // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì + actCount := Length(gTriggers[i].Activators); + utils.writeInt(st, LongInt(actCount)); + for j := 0 to actCount-1 do begin // UID îáúåêòà - Mem.WriteWord(gTriggers[i].Activators[j].UID); + utils.writeInt(st, Word(gTriggers[i].Activators[j].UID)); // Âðåìÿ îæèäàíèÿ - Mem.WriteWord(gTriggers[i].Activators[j].TimeOut); + utils.writeInt(st, Word(gTriggers[i].Activators[j].TimeOut)); end; - // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà: - Mem.WriteBoolean(gTriggers[i].PlayerCollide); - // Âðåìÿ äî çàêðûòèÿ äâåðè: - Mem.WriteInt(gTriggers[i].DoorTime); - // Çàäåðæêà àêòèâàöèè: - Mem.WriteInt(gTriggers[i].PressTime); - // Ñ÷åò÷èê íàæàòèé: - Mem.WriteInt(gTriggers[i].PressCount); - // Ñïàâíåð àêòèâåí: - Mem.WriteBoolean(gTriggers[i].AutoSpawn); - // Çàäåðæêà ñïàâíåðà: - Mem.WriteInt(gTriggers[i].SpawnCooldown); - // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ: - Mem.WriteInt(gTriggers[i].SpawnedCount); - // Ñêîëüêî ðàç ïðîèãðàí çâóê: - Mem.WriteInt(gTriggers[i].SoundPlayCount); - // Ïðîèãðûâàåòñÿ ëè çâóê? - if gTriggers[i].Sound <> nil then - b := gTriggers[i].Sound.IsPlaying() - else - b := False; - Mem.WriteBoolean(b); + // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà + utils.writeBool(st, gTriggers[i].PlayerCollide); + // Âðåìÿ äî çàêðûòèÿ äâåðè + utils.writeInt(st, LongInt(gTriggers[i].DoorTime)); + // Çàäåðæêà àêòèâàöèè + utils.writeInt(st, LongInt(gTriggers[i].PressTime)); + // Ñ÷åò÷èê íàæàòèé + utils.writeInt(st, LongInt(gTriggers[i].PressCount)); + // Ñïàâíåð àêòèâåí + utils.writeBool(st, gTriggers[i].AutoSpawn); + // Çàäåðæêà ñïàâíåðà + utils.writeInt(st, LongInt(gTriggers[i].SpawnCooldown)); + // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ + utils.writeInt(st, LongInt(gTriggers[i].SpawnedCount)); + // Ñêîëüêî ðàç ïðîèãðàí çâóê + utils.writeInt(st, LongInt(gTriggers[i].SoundPlayCount)); + // Ïðîèãðûâàåòñÿ ëè çâóê? + if (gTriggers[i].Sound <> nil) then b := gTriggers[i].Sound.IsPlaying() else b := false; + utils.writeBool(st, b); if b then begin - // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà: - dw := gTriggers[i].Sound.GetPosition(); - Mem.WriteDWORD(dw); - // Ãðîìêîñòü çâóêà: + // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà + utils.writeInt(st, LongWord(gTriggers[i].Sound.GetPosition())); + // Ãðîìêîñòü çâóêà sg := gTriggers[i].Sound.GetVolume(); - sg := sg / (gSoundLevel/255.0); - Mem.WriteSingle(sg); - // Ñòåðåî ñìåùåíèå çâóêà: + sg := sg/(gSoundLevel/255.0); + //Mem.WriteSingle(sg); + st.WriteBuffer(sg, sizeof(sg)); // sorry + // Ñòåðåî ñìåùåíèå çâóêà sg := gTriggers[i].Sound.GetPan(); - Mem.WriteSingle(sg); + //Mem.WriteSingle(sg); + st.WriteBuffer(sg, sizeof(sg)); // sorry + end; + // uservars + if (gTriggers[i].userVars = nil) then + begin + utils.writeInt(st, LongInt(0)); + end + else + begin + utils.writeInt(st, LongInt(gTriggers[i].userVars.count)); //FIXME: check for overflow + for kv in gTriggers[i].userVars.byKeyValue do + begin + //writeln('<', kv.key, '>:<', VarToStr(kv.value), '>'); + utils.writeStr(st, kv.key); + t := LongInt(varType(kv.value)); + utils.writeInt(st, LongInt(t)); + case t of + varString: utils.writeStr(st, AnsiString(kv.value)); + varBoolean: utils.writeBool(st, Boolean(kv.value)); + varShortInt: utils.writeInt(st, LongInt(kv.value)); + varSmallint: utils.writeInt(st, LongInt(kv.value)); + varInteger: utils.writeInt(st, LongInt(kv.value)); + //varInt64: Mem.WriteInt(Integer(kv.value)); + varByte: utils.writeInt(st, LongInt(kv.value)); + varWord: utils.writeInt(st, LongInt(kv.value)); + varLongWord: utils.writeInt(st, LongInt(kv.value)); + //varQWord: + else raise Exception.CreateFmt('cannot save uservar ''%s''', [kv.key]); + end; + end; end; end; end; -procedure g_Triggers_LoadState(var Mem: TBinMemoryReader); + +procedure g_Triggers_LoadState (st: TStream); var - count, act_count, i, j, a: Integer; + count, actCount, i, j, a: Integer; dw: DWORD; vol, pan: Single; b: Boolean; - p: Pointer; Trig: TTrigger; + mapIndex: Integer; + uvcount: Integer; + vt: LongInt; + vv: Variant; + uvname: AnsiString = ''; + ustr: AnsiString = ''; + uint: LongInt; + ubool: Boolean; begin - if Mem = nil then - Exit; + assert(st <> nil); g_Triggers_Free(); -// Êîëè÷åñòâî òðèããåðîâ: - Mem.ReadInt(count); - - if count = 0 then - Exit; + // Êîëè÷åñòâî òðèããåðîâ + count := utils.readLongInt(st); + if (count = 0) then exit; + if (count < 0) or (count > 1024*1024) then raise XStreamError.Create('invalid trigger count'); for a := 0 to count-1 do begin - // Ñèãíàòóðà òðèããåðà: - Mem.ReadDWORD(dw); - if dw <> TRIGGER_SIGNATURE then // 'TRGR' - begin - raise EBinSizeError.Create('g_Triggers_LoadState: Wrong Trigger Signature'); - end; - // Òèï òðèããåðà: - Mem.ReadByte(Trig.TriggerType); - // Ñïåöèàëüíûå äàííûå òðèããåðà: - Mem.ReadMemory(p, dw); - if dw <> SizeOf(TTriggerData) then + // Ñèãíàòóðà òðèããåðà + if not utils.checkSign(st, 'TRGX') then raise XStreamError.Create('invalid trigger signature'); + if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid trigger version'); + // Òèï òðèããåðà + Trig.TriggerType := utils.readByte(st); + if (Trig.TriggerType = TRIGGER_NONE) then continue; // empty one + // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers'] + mapIndex := utils.readLongInt(st); + i := g_Triggers_CreateWithMapIndex(Trig, a, mapIndex); + // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà + gTriggers[i].X := utils.readLongInt(st); + gTriggers[i].Y := utils.readLongInt(st); + // Ðàçìåðû + gTriggers[i].Width := utils.readWord(st); + gTriggers[i].Height := utils.readWord(st); + // Âêëþ÷åí ëè òðèããåð + gTriggers[i].Enabled := utils.readBool(st); + // Òèï àêòèâàöèè òðèããåðà + gTriggers[i].ActivateType := utils.readByte(st); + // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè + gTriggers[i].Keys := utils.readByte(st); + // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ + gTriggers[i].TexturePanelGUID := utils.readLongInt(st); + // Òèï ýòîé ïàíåëè + //Mem.ReadWord(gTriggers[i].TexturePanelType); + // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) + gTriggers[i].trigPanelGUID := utils.readLongInt(st); + // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè + gTriggers[i].TimeOut := utils.readWord(st); + // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð + gTriggers[i].ActivateUID := utils.readWord(st); + // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì + actCount := utils.readLongInt(st); + if (actCount < 0) or (actCount > 1024*1024) then raise XStreamError.Create('invalid activated object count'); + if (actCount > 0) then begin - raise EBinSizeError.Create('g_Triggers_LoadState: Wrong TriggerData Size'); - end; - Trig.Data := TTriggerData(p^); - // Ñîçäàåì òðèããåð: - i := g_Triggers_Create(Trig); - // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà: - Mem.ReadInt(gTriggers[i].X); - Mem.ReadInt(gTriggers[i].Y); - // Ðàçìåðû: - Mem.ReadWord(gTriggers[i].Width); - Mem.ReadWord(gTriggers[i].Height); - // Âêëþ÷åí ëè òðèããåð: - Mem.ReadBoolean(gTriggers[i].Enabled); - // Òèï àêòèâàöèè òðèããåðà: - Mem.ReadByte(gTriggers[i].ActivateType); - // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè: - Mem.ReadByte(gTriggers[i].Keys); - // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ: - Mem.ReadInt(gTriggers[i].TexturePanel); - // Òèï ýòîé ïàíåëè: - Mem.ReadWord(gTriggers[i].TexturePanelType); - // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè: - Mem.ReadWord(gTriggers[i].TimeOut); - // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð: - Mem.ReadWord(gTriggers[i].ActivateUID); - // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì: - Mem.ReadInt(act_count); - if act_count > 0 then - begin - SetLength(gTriggers[i].Activators, act_count); - for j := 0 to act_count-1 do + SetLength(gTriggers[i].Activators, actCount); + for j := 0 to actCount-1 do begin // UID îáúåêòà - Mem.ReadWord(gTriggers[i].Activators[j].UID); + gTriggers[i].Activators[j].UID := utils.readWord(st); // Âðåìÿ îæèäàíèÿ - Mem.ReadWord(gTriggers[i].Activators[j].TimeOut); + gTriggers[i].Activators[j].TimeOut := utils.readWord(st); end; end; - // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà: - Mem.ReadBoolean(gTriggers[i].PlayerCollide); - // Âðåìÿ äî çàêðûòèÿ äâåðè: - Mem.ReadInt(gTriggers[i].DoorTime); - // Çàäåðæêà àêòèâàöèè: - Mem.ReadInt(gTriggers[i].PressTime); - // Ñ÷åò÷èê íàæàòèé: - Mem.ReadInt(gTriggers[i].PressCount); - // Ñïàâíåð àêòèâåí: - Mem.ReadBoolean(gTriggers[i].AutoSpawn); - // Çàäåðæêà ñïàâíåðà: - Mem.ReadInt(gTriggers[i].SpawnCooldown); - // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ: - Mem.ReadInt(gTriggers[i].SpawnedCount); - // Ñêîëüêî ðàç ïðîèãðàí çâóê: - Mem.ReadInt(gTriggers[i].SoundPlayCount); - // Ïðîèãðûâàåòñÿ ëè çâóê? - Mem.ReadBoolean(b); + // Ñòîèò ëè èãðîê â îáëàñòè òðèããåðà + gTriggers[i].PlayerCollide := utils.readBool(st); + // Âðåìÿ äî çàêðûòèÿ äâåðè + gTriggers[i].DoorTime := utils.readLongInt(st); + // Çàäåðæêà àêòèâàöèè + gTriggers[i].PressTime := utils.readLongInt(st); + // Ñ÷åò÷èê íàæàòèé + gTriggers[i].PressCount := utils.readLongInt(st); + // Ñïàâíåð àêòèâåí + gTriggers[i].AutoSpawn := utils.readBool(st); + // Çàäåðæêà ñïàâíåðà + gTriggers[i].SpawnCooldown := utils.readLongInt(st); + // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ + gTriggers[i].SpawnedCount := utils.readLongInt(st); + // Ñêîëüêî ðàç ïðîèãðàí çâóê + gTriggers[i].SoundPlayCount := utils.readLongInt(st); + // Ïðîèãðûâàåòñÿ ëè çâóê? + b := utils.readBool(st); if b then begin - // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà: - Mem.ReadDWORD(dw); - // Ãðîìêîñòü çâóêà: - Mem.ReadSingle(vol); - // Ñòåðåî ñìåùåíèå çâóêà: - Mem.ReadSingle(pan); - // Çàïóñêàåì çâóê, åñëè åñòü: - if gTriggers[i].Sound <> nil then + // Ïîçèöèÿ ïðîèãðûâàíèÿ çâóêà + dw := utils.readLongWord(st); + // Ãðîìêîñòü çâóêà + //Mem.ReadSingle(vol); + st.ReadBuffer(vol, sizeof(vol)); // sorry + // Ñòåðåî ñìåùåíèå çâóêà + //Mem.ReadSingle(pan); + st.ReadBuffer(pan, sizeof(pan)); // sorry + // Çàïóñêàåì çâóê, åñëè åñòü + if (gTriggers[i].Sound <> nil) then begin gTriggers[i].Sound.PlayPanVolume(pan, vol); gTriggers[i].Sound.Pause(True); gTriggers[i].Sound.SetPosition(dw); end end; + // uservars + gTriggers[i].userVars.Free(); + gTriggers[i].userVars := nil; + uvcount := utils.readLongInt(st); + if (uvcount < 0) or (uvcount > 1024*1024) then raise XStreamError.Create('invalid number of user vars in trigger'); + if (uvcount > 0) then + begin + gTriggers[i].userVars := THashStrVariant.Create(); + vv := Unassigned; + while (uvcount > 0) do + begin + Dec(uvcount); + uvname := utils.readStr(st); + vt := utils.readLongInt(st); + case vt of + varString: begin ustr := utils.readStr(st); vv := ustr; end; + varBoolean: begin ubool := utils.readBool(st); vv := ubool; end; + varShortInt: begin uint := utils.readLongInt(st); vv := ShortInt(uint); end; + varSmallint: begin uint := utils.readLongInt(st); vv := SmallInt(uint); end; + varInteger: begin uint := utils.readLongInt(st); vv := LongInt(uint); end; + varByte: begin uint := utils.readLongInt(st); vv := Byte(uint); end; + varWord: begin uint := utils.readLongInt(st); vv := Word(uint); end; + varLongWord: begin uint := utils.readLongInt(st); vv := LongWord(uint); end; + else raise Exception.CreateFmt('cannot load uservar ''%s''', [uvname]); + end; + gTriggers[i].userVars.put(uvname, vv); + end; + end; end; end; + end.