X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_triggers.pas;h=3a1bec2ccbf37a95c84c49de76b6da6bc45c10c0;hb=HEAD;hp=e49a4ef493e49baed5ab454213ceae3125545729;hpb=dd969f579db2bf70f6ddfcb5d377b2b95b994a6e;p=d2df-sdl.git diff --git a/src/game/g_triggers.pas b/src/game/g_triggers.pas index e49a4ef..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 @@ -19,13 +18,11 @@ unit g_triggers; interface uses - Variants, + SysUtils, Variants, Classes, MAPDEF, e_graphics, g_basic, g_sound, - BinEditor, xdynrec, hashtable, exoma; + xdynrec, hashtable, exoma; type - THashStrVariant = specialize THashBase; - TActivator = record UID: Word; TimeOut: Word; @@ -43,7 +40,7 @@ type ActivateType: Byte; Keys: Byte; TexturePanelGUID: Integer; - TexturePanelType: Word; + //TexturePanelType: Word; TimeOut: Word; ActivateUID: Word; @@ -57,7 +54,7 @@ type AutoSpawn: Boolean; SpawnCooldown: Integer; SpawnedCount: Integer; - ShotPanelType: Word; + //ShotPanelType: Word; ShotPanelTime: Integer; ShotSightTime: Integer; ShotSightTimeout: Integer; @@ -81,7 +78,7 @@ type function trigCenter (): TDFPoint; inline; end; -function g_Triggers_Create(Trigger: TTrigger; trec: TDynRecord; forceInternalIndex: Integer=-1): 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; @@ -91,8 +88,8 @@ procedure g_Triggers_PressC(CX, CY: Integer; Radius: Word; UID: Word; ActivateTy 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); var @@ -108,8 +105,8 @@ uses 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, utils, xparser; + wadreader, g_main, e_log, g_language, e_res, + g_options, g_net, g_netmsg, utils, xparser, xstreams; const TRIGGER_SIGNATURE = $58475254; // 'TRGX' @@ -139,12 +136,53 @@ type 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 + 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); - monsprops := TPropHash.Create(TMonster); - platprops := TPropHash.Create(TPanel); + plrprops := TPropHash.Create(TPlayer, 'e'); + monsprops := TPropHash.Create(TMonster, 'e'); + platprops := TPropHash.Create(TPanel, 'e'); me := nil; end; @@ -196,7 +234,7 @@ begin if (Length(afldname) > 4) and (afldname[1] = 'u') and (afldname[2] = 's') and (afldname[3] = 'e') and (afldname[4] = 'r') then begin - if (me.userVars = nil) then me.userVars := THashStrVariant.Create(hsihash, hsiequ); + if (me.userVars = nil) then me.userVars := THashStrVariant.Create(); me.userVars.put(afldname, aval); exit; end; @@ -209,6 +247,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // var tgscope: TTrigScope = nil; + tgclist: TMyConstList = nil; // ////////////////////////////////////////////////////////////////////////// // @@ -552,17 +591,17 @@ begin 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 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; @@ -686,37 +725,37 @@ begin 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; @@ -728,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; @@ -766,6 +805,12 @@ 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; @@ -796,7 +841,7 @@ begin begin if (trigPanelGUID <> -1) and (ShotPanelTime = 0) then begin - g_Map_SwitchTextureGUID(ShotPanelType, trigPanelGUID); + g_Map_SwitchTextureGUID({ShotPanelType,} trigPanelGUID); ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà end; @@ -807,7 +852,7 @@ begin dx += Random(tgcAccuracy)-Random(tgcAccuracy); dy += Random(tgcAccuracy)-Random(tgcAccuracy); - tr_SpawnShot(tgcShotType, wx, wy, dx, dy, not tgcQuiet, TargetUID); + tr_SpawnShot(tgcShotType, wx, wy, dx, dy, tgcShotSound, TargetUID); end else begin @@ -839,7 +884,7 @@ begin 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); + TRIGGER_EFFECT_BUBBLE: g_Game_Effect_Bubbles(X, Y, 1, 0, 0, Silent); end; end; @@ -1179,7 +1224,7 @@ begin if not Trigger.Enabled then exit; if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then exit; - if (gLMSRespawn = LMS_RESPAWN_WARMUP) then exit; + if (gLMSRespawn > LMS_RESPAWN_NONE) then exit; if (Trigger.exoCheck <> nil) then begin @@ -1189,10 +1234,12 @@ begin tvval := Trigger.exoCheck.value(tgscope); tgscope.me := nil; if not Boolean(tvval) then exit; - except - tgscope.me := nil; - conwritefln('trigger exocheck error: %s', [Trigger.exoCheck.toString()]); - 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; @@ -1207,10 +1254,12 @@ begin tgscope.me := @Trigger; Trigger.exoAction.value(tgscope); tgscope.me := nil; - except - tgscope.me := nil; - conwritefln('trigger exoactivate error: %s', [Trigger.exoAction.toString()]); - exit; + except on e: Exception do + begin + tgscope.me := nil; + conwritefln('trigger exoactivate error: %s [%s]', [e.message, Trigger.exoAction.toString()]); + exit; + end; end; end; @@ -1300,11 +1349,13 @@ 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; @@ -1417,7 +1468,7 @@ begin for k := 1 to tgcMonsCount do begin if (actType = ACTIVATE_CUSTOM) and (tgcDelay > 0) then - SpawnCooldown := tgcDelay; + SpawnCooldown := -1; // Çàäåðæêà âûñòàâèòñÿ ìîíñòðîì ïðè óíè÷òîæåíèè if (tgcMax > 0) and (SpawnedCount >= tgcMax) then Break; @@ -1447,11 +1498,8 @@ begin gMonstersSpawned[High(gMonstersSpawned)] := mon.UID; end; - if tgcMax > 0 then - begin - mon.SpawnTrigger := ID; - Inc(SpawnedCount); - end; + mon.SpawnTrigger := ID; + if tgcMax > 0 then Inc(SpawnedCount); case tgcEffect of EFFECT_TELEPORT: begin @@ -1532,7 +1580,7 @@ begin for k := 1 to tgcItemCount do begin if (actType = ACTIVATE_CUSTOM) and (tgcDelay > 0) then - SpawnCooldown := tgcDelay; + SpawnCooldown := -1; // Çàäåðæêà âûñòàâèòñÿ èòåìîì ïðè óíè÷òîæåíèè if (tgcMax > 0) and (SpawnedCount >= tgcMax) then Break; @@ -1541,12 +1589,9 @@ begin Result := True; - if tgcMax > 0 then - begin - it := g_Items_ByIdx(iid); - it.SpawnTrigger := ID; - Inc(SpawnedCount); - end; + it := g_Items_ByIdx(iid); + it.SpawnTrigger := ID; + if tgcMax > 0 then Inc(SpawnedCount); case tgcEffect of EFFECT_TELEPORT: begin @@ -1660,7 +1705,7 @@ begin 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, tgcScoreCount); // Red Scores + Inc(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Scores if tgcScoreCon then begin @@ -1687,7 +1732,7 @@ begin 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, tgcScoreCount); // Red Fouls + Dec(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Fouls if tgcScoreCon then begin @@ -1714,7 +1759,7 @@ begin 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, tgcScoreCount); // Blue Scores + Inc(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Scores if tgcScoreCon then begin @@ -1741,7 +1786,7 @@ begin 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, tgcScoreCount); // Blue Fouls + Dec(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Fouls if tgcScoreCon then begin @@ -1772,7 +1817,7 @@ begin begin if (tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then begin - Inc(gTeamStat[TEAM_RED].Goals, tgcScoreCount); // Red Scores + Inc(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Scores if tgcScoreCon then begin @@ -1790,7 +1835,7 @@ begin end; if (tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then begin - Dec(gTeamStat[TEAM_RED].Goals, tgcScoreCount); // Red Fouls + Dec(gTeamStat[TEAM_RED].Score, tgcScoreCount); // Red Fouls if tgcScoreCon then begin @@ -1808,7 +1853,7 @@ begin end; if (tgcScoreAction = TRIGGER_SCORE_ACTION_ADD) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then begin - Inc(gTeamStat[TEAM_BLUE].Goals, tgcScoreCount); // Blue Scores + Inc(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Scores if tgcScoreCon then begin @@ -1826,7 +1871,7 @@ begin end; if (tgcScoreAction = TRIGGER_SCORE_ACTION_SUB) and (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then begin - Dec(gTeamStat[TEAM_BLUE].Goals, tgcScoreCount); // Blue Fouls + Dec(gTeamStat[TEAM_BLUE].Score, tgcScoreCount); // Blue Fouls if tgcScoreCon then begin @@ -1846,7 +1891,7 @@ begin end; end; // Âûèãðûø - if (tgcScoreAction = TRIGGER_SCORE_ACTION_WIN) and (gGameSettings.GoalLimit > 0) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_WIN) and (gGameSettings.ScoreLimit > 0) then begin // Ñâîåé èëè ÷óæîé êîìàíäû if (tgcScoreTeam in [TRIGGER_SCORE_TEAM_MINE_RED, TRIGGER_SCORE_TEAM_MINE_BLUE]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then @@ -1855,9 +1900,9 @@ begin 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].Goals < SmallInt(gGameSettings.GoalLimit) then + if gTeamStat[TEAM_RED].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_RED].Score := gGameSettings.ScoreLimit; if tgcScoreCon then begin @@ -1880,9 +1925,9 @@ begin 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].Goals < SmallInt(gGameSettings.GoalLimit) then + if gTeamStat[TEAM_BLUE].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_BLUE].Score := gGameSettings.ScoreLimit; if tgcScoreCon then begin @@ -1908,24 +1953,24 @@ begin begin if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then // Red Wins begin - if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then + 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; end; if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then // Blue Wins begin - if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then + 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 (tgcScoreAction = TRIGGER_SCORE_ACTION_LOOSE) and (gGameSettings.GoalLimit > 0) then + if (tgcScoreAction = TRIGGER_SCORE_ACTION_LOOSE) and (gGameSettings.ScoreLimit > 0) then begin // Ñâîåé èëè ÷óæîé êîìàíäû if (tgcScoreTeam in [TRIGGER_SCORE_TEAM_MINE_RED, TRIGGER_SCORE_TEAM_MINE_BLUE]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then @@ -1933,9 +1978,9 @@ begin p := g_Player_Get(ActivateUID); 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].Goals < SmallInt(gGameSettings.GoalLimit) then + if gTeamStat[TEAM_RED].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_RED].Score := gGameSettings.ScoreLimit; if tgcScoreCon then if tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED then @@ -1954,9 +1999,9 @@ begin end; 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].Goals < SmallInt(gGameSettings.GoalLimit) then + if gTeamStat[TEAM_BLUE].Score < SmallInt(gGameSettings.ScoreLimit) then begin - gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit; + gTeamStat[TEAM_BLUE].Score := gGameSettings.ScoreLimit; if tgcScoreCon then if tgcScoreTeam = TRIGGER_SCORE_TEAM_MINE_RED then @@ -1979,17 +2024,17 @@ begin begin if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_BLUE) then // Red Wins begin - if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then + 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; end; if (tgcScoreTeam = TRIGGER_SCORE_TEAM_FORCE_RED) then // Blue Wins begin - if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then + 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; @@ -2057,7 +2102,14 @@ begin // Íàíîñèì óðîí èãðîêó if (TriggerType = TRIGGER_DAMAGE) and (tgcAmount > 0) then - p.Damage(tgcAmount, 0, 0, 0, HIT_SOME); + 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 (tgcAmount > 0) then @@ -2077,7 +2129,10 @@ begin // Íàíîñèì óðîí ìîíñòðó if (TriggerType = TRIGGER_DAMAGE) and (tgcAmount > 0) then - m.Damage(tgcAmount, 0, 0, 0, HIT_SOME); + begin + m.Damage(tgcAmount, 0, 0, 0, tgcKind); + if (tgcKind = HIT_FLAME) then m.CatchFire(0); + end; // Ëå÷èì ìîíñòðà if (TriggerType = TRIGGER_HEALTH) and (tgcAmount > 0) then @@ -2258,63 +2313,57 @@ begin Dec(idx); end; TimeOut := tgcWait; + result := true; end; end; end; if Result {and (Trigger.TexturePanel <> -1)} then begin - g_Map_SwitchTextureGUID(Trigger.TexturePanelType, Trigger.TexturePanelGUID, IfThen(animonce, 2, 1)); + g_Map_SwitchTextureGUID({Trigger.TexturePanelType,} Trigger.TexturePanelGUID, IfThen(animonce, 2, 1)); end; end; -function g_Triggers_CreateWithMapIndex (Trigger: TTrigger; arridx, mapidx: Integer): DWORD; +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'); - //Trigger.trigDataRec := triggers.itemAt[mapidx]; - //if (Trigger.trigDataRec = nil) then raise Exception.Create('LOAD: internal error in trigger loader'); - //Trigger.mapId := Trigger.trigDataRec.id; - Trigger.mapIndex := mapidx; - { - if (Trigger.trigDataRec.trigRec <> nil) then - begin - Trigger.trigDataRec := Trigger.trigDataRec.trigRec.clone(nil); - end - else - begin - Trigger.trigDataRec := nil; - end; - } - result := g_Triggers_Create(Trigger, triggers.itemAt[mapidx], arridx); + aTrigger.mapIndex := mapidx; + result := g_Triggers_Create(aTrigger, triggers.itemAt[mapidx], arridx); end; -function g_Triggers_Create(Trigger: TTrigger; trec: TDynRecord; forceInternalIndex: Integer=-1): DWORD; +function g_Triggers_Create (aTrigger: TTrigger; trec: TDynRecord; forceInternalIndex: Integer=-1): DWORD; var find_id: DWORD; - fn, mapw: AnsiString; + fn: AnsiString; f, olen: Integer; + ptg: PTrigger; begin if (tgscope = nil) then tgscope := TTrigScope.Create(); + if (tgclist = nil) then tgclist := TMyConstList.Create(); // Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà - if (Trigger.TriggerType = TRIGGER_EXIT) and - (not LongBool(gGameSettings.Options and GAME_OPTION_ALLOWEXIT)) then - Trigger.TriggerType := TRIGGER_NONE; + if (aTrigger.TriggerType = TRIGGER_EXIT) and + (not (TGameOption.ALLOW_EXIT in gGameSettings.Options)) then + begin + aTrigger.TriggerType := TRIGGER_NONE; + end; // Åñëè ìîíñòðû çàïðåùåíû, îòìåíÿåì òðèããåð - if (Trigger.TriggerType = TRIGGER_SPAWNMONSTER) and - (not LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS)) and + 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 += 1; + if (aTrigger.TriggerType = TRIGGER_SECRET) then gSecretsCount += 1; if (forceInternalIndex < 0) then begin @@ -2352,37 +2401,35 @@ begin gTriggers[f].userVars := nil; find_id := DWORD(forceInternalIndex); end; - gTriggers[find_id] := Trigger; + gTriggers[find_id] := aTrigger; + ptg := @gTriggers[find_id]; - Trigger.mapId := trec.id; + ptg.mapId := trec.id; // clone trigger data if (trec.trigRec = nil) then begin - gTriggers[find_id].trigDataRec := nil; + ptg.trigDataRec := nil; //HACK! - if (gTriggers[find_id].TriggerType <> TRIGGER_SECRET) then + if (ptg.TriggerType <> TRIGGER_SECRET) then begin - e_LogWritefln('trigger of type %s has no triggerdata; wtf?!', [gTriggers[find_id].TriggerType], MSG_WARNING); + e_LogWritefln('trigger of type %s has no triggerdata; wtf?!', [ptg.TriggerType], TMsgType.Warning); end; end else begin - gTriggers[find_id].trigDataRec := trec.trigRec.clone(nil); + 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 - begin - ClientID := 0; end; TimeOut := 0; ActivateUID := 0; @@ -2398,77 +2445,88 @@ begin end; // update cached trigger variables - trigUpdateCacheData(gTriggers[find_id], gTriggers[find_id].trigDataRec); + trigUpdateCacheData(ptg^, ptg.trigDataRec); - gTriggers[find_id].userVars := nil; //THashStrVariant.Create(hsihash, hsiequ); + ptg.userVars := nil; try - gTriggers[find_id].exoThink := TExprBase.parseStatList(VarToStr(trec.user['exoma_think'])); + ptg.exoThink := TExprBase.parseStatList(tgclist, VarToStr(trec.user['exoma_think'])); except - conwritefln('*** ERROR parsing exoma_think: [%s]', [VarToStr(trec.user['exoma_think'])]); - gTriggers[find_id].exoThink := nil; + 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 - gTriggers[find_id].exoCheck := TExprBase.parse(VarToStr(trec.user['exoma_check'])); + ptg.exoCheck := TExprBase.parse(tgclist, VarToStr(trec.user['exoma_check'])); except - conwritefln('*** ERROR parsing exoma_check: [%s]', [VarToStr(trec.user['exoma_check'])]); - gTriggers[find_id].exoCheck := nil; + 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 - gTriggers[find_id].exoAction := TExprBase.parseStatList(VarToStr(trec.user['exoma_action'])); + ptg.exoAction := TExprBase.parseStatList(tgclist, VarToStr(trec.user['exoma_action'])); except - conwritefln('*** ERROR parsing exoma_action: [%s]', [VarToStr(trec.user['exoma_action'])]); - gTriggers[find_id].exoAction := nil; + 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 - gTriggers[find_id].exoInit := TExprBase.parseStatList(VarToStr(trec.user['exoma_init'])); + ptg.exoInit := TExprBase.parseStatList(tgclist, VarToStr(trec.user['exoma_init'])); except - conwritefln('*** ERROR parsing exoma_init: [%s]', [VarToStr(trec.user['exoma_init'])]); - gTriggers[find_id].exoInit := nil; + 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 (gTriggers[find_id].exoInit <> nil) then + if (forceInternalIndex < 0) and (ptg.exoInit <> nil) then begin //conwritefln('executing trigger init: [%s]', [gTriggers[find_id].exoInit.toString()]); try - tgscope.me := @gTriggers[find_id]; - gTriggers[find_id].exoInit.value(tgscope); + tgscope.me := ptg; + ptg.exoInit.value(tgscope); tgscope.me := nil; except tgscope.me := nil; - conwritefln('*** trigger exoactivate error: %s', [gTriggers[find_id].exoInit.toString()]); + conwritefln('*** trigger exoactivate error: %s', [ptg.exoInit.toString()]); exit; end; end; // Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê" - if (Trigger.TriggerType = TRIGGER_SOUND) and (Trigger.tgcSoundName <> '') then + if (ptg.TriggerType = TRIGGER_SOUND) and (ptg.tgcSoundName <> '') then begin // Åùå íåò òàêîãî çâóêà - if not g_Sound_Exists(Trigger.tgcSoundName) then + if not g_Sound_Exists(ptg.tgcSoundName) then begin - fn := g_ExtractWadName(Trigger.tgcSoundName); - if fn = '' then - begin // Çâóê â ôàéëå ñ êàðòîé - mapw := g_ExtractWadName(gMapInfo.Map); - fn := mapw+':'+g_ExtractFilePathName(Trigger.tgcSoundName); - end - else // Çâóê â îòäåëüíîì ôàéëå + 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 - fn := GameDir + '/wads/' + Trigger.tgcSoundName; - end; - - if not g_Sound_CreateWADEx(Trigger.tgcSoundName, fn) then - begin - g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.tgcSoundName])); + 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.tgcSoundName) then + if not Sound.SetByName(ptg.tgcSoundName) then begin Sound.Free(); Sound := nil; @@ -2477,41 +2535,30 @@ begin end; // Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà" - if (Trigger.TriggerType = TRIGGER_MUSIC) and (Trigger.tgcMusicName <> '') then + if (ptg.TriggerType = TRIGGER_MUSIC) and (ptg.tgcMusicName <> '') then begin // Åùå íåò òàêîé ìóçûêè - if not g_Sound_Exists(Trigger.tgcMusicName) then + if not g_Sound_Exists(ptg.tgcMusicName) then begin - fn := g_ExtractWadName(Trigger.tgcMusicName); - - if fn = '' then - begin // Ìóçûêà â ôàéëå ñ êàðòîé - mapw := g_ExtractWadName(gMapInfo.Map); - fn := mapw+':'+g_ExtractFilePathName(Trigger.tgcMusicName); - end - else // Ìóçûêà â ôàéëå ñ êàðòîé - begin - fn := GameDir+'/wads/'+Trigger.tgcMusicName; - end; - - if not g_Sound_CreateWADEx(Trigger.tgcMusicName, fn, True) then + 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, Trigger.tgcMusicName])); + g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, ptg.tgcMusicName])); end; end; end; // Çàãðóæàåì äàííûå òðèããåðà "Òóðåëü" - if Trigger.TriggerType = TRIGGER_SHOT then + if (ptg.TriggerType = TRIGGER_SHOT) then begin - with gTriggers[find_id] do + with ptg^ do begin ShotPanelTime := 0; ShotSightTime := 0; ShotSightTimeout := 0; ShotSightTarget := 0; ShotSightTargetN := 0; - ShotAmmoCount := Trigger.tgcAmmo; + ShotAmmoCount := ptg.tgcAmmo; ShotReloadTime := 0; end; end; @@ -2548,8 +2595,9 @@ var begin if (tgMonsList = nil) then tgMonsList := TSimpleMonsterList.Create(); - if gTriggers = nil then - Exit; + 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 @@ -2611,7 +2659,7 @@ begin if ShotPanelTime > 0 then begin Dec(ShotPanelTime); - if ShotPanelTime = 0 then g_Map_SwitchTextureGUID(ShotPanelType, trigPanelGUID); + if ShotPanelTime = 0 then g_Map_SwitchTextureGUID({ShotPanelType,} trigPanelGUID); end; if ShotSightTime > 0 then begin @@ -2635,17 +2683,14 @@ begin begin if (SoundPlayCount > 0) and (not Sound.IsPlaying()) then begin - if tgcPlayCount > 0 then SoundPlayCount -= 1; // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî + if tgcPlayCount > 0 then Dec(SoundPlayCount); (* looped sound if zero *) if tgcLocal then - begin - Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), tgcVolume/255.0); - end + Sound.PlayVolumeAtRect(X, Y, Width, Height, tgcVolume / 255.0) else - begin - Sound.PlayPanVolume((tgcPan-127.0)/128.0, tgcVolume/255.0); - end; - if Sound.IsPlaying() and g_Game_IsNet and g_Game_IsServer then MH_SEND_TriggerSound(gTriggers[a]); - end; + 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 end; // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü @@ -3005,11 +3050,20 @@ 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 (); var a: Integer; @@ -3042,123 +3096,120 @@ begin end; -procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter); +procedure g_Triggers_SaveState (st: TStream); var count, actCount, i, j: Integer; - dw: DWORD; sg: Single; b: Boolean; kv: THashStrVariant.PEntry; - //it: THashStrVariant.TKeyValEnumerator; - //uname: AnsiString; t: LongInt; begin // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ count := Length(gTriggers); - Mem := TBinMemoryWriter.Create((count+1)*200); // Êîëè÷åñòâî òðèããåðîâ - Mem.WriteInt(count); + utils.writeInt(st, LongInt(count)); if (count = 0) then exit; for i := 0 to High(gTriggers) do begin // Ñèãíàòóðà òðèããåðà - dw := TRIGGER_SIGNATURE; // 'TRGX' - Mem.WriteDWORD(dw); + utils.writeSign(st, 'TRGX'); + utils.writeInt(st, Byte(0)); // Òèï òðèããåðà - Mem.WriteByte(gTriggers[i].TriggerType); + utils.writeInt(st, Byte(gTriggers[i].TriggerType)); if (gTriggers[i].TriggerType = TRIGGER_NONE) then continue; // empty one // Ñïåöèàëüíûå äàííûå òðèããåðà: ïîòîì èç êàðòû îïÿòü âûòàùèì; ñîõðàíèì òîëüêî èíäåêñ - Mem.WriteInt(gTriggers[i].mapIndex); + utils.writeInt(st, LongInt(gTriggers[i].mapIndex)); // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà - Mem.WriteInt(gTriggers[i].X); - Mem.WriteInt(gTriggers[i].Y); + utils.writeInt(st, LongInt(gTriggers[i].X)); + utils.writeInt(st, LongInt(gTriggers[i].Y)); // Ðàçìåðû - Mem.WriteWord(gTriggers[i].Width); - Mem.WriteWord(gTriggers[i].Height); + utils.writeInt(st, Word(gTriggers[i].Width)); + utils.writeInt(st, Word(gTriggers[i].Height)); // Âêëþ÷åí ëè òðèããåð - Mem.WriteBoolean(gTriggers[i].Enabled); + utils.writeBool(st, gTriggers[i].Enabled); // Òèï àêòèâàöèè òðèããåðà - Mem.WriteByte(gTriggers[i].ActivateType); + utils.writeInt(st, Byte(gTriggers[i].ActivateType)); // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè - Mem.WriteByte(gTriggers[i].Keys); + utils.writeInt(st, Byte(gTriggers[i].Keys)); // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ - Mem.WriteInt(gTriggers[i].TexturePanelGUID); + utils.writeInt(st, LongInt(gTriggers[i].TexturePanelGUID)); // Òèï ýòîé ïàíåëè - Mem.WriteWord(gTriggers[i].TexturePanelType); + //Mem.WriteWord(gTriggers[i].TexturePanelType); // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) - Mem.WriteInt(gTriggers[i].trigPanelGUID); + utils.writeInt(st, LongInt(gTriggers[i].trigPanelGUID)); // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè - Mem.WriteWord(gTriggers[i].TimeOut); + utils.writeInt(st, Word(gTriggers[i].TimeOut)); // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð - Mem.WriteWord(gTriggers[i].ActivateUID); + utils.writeInt(st, Word(gTriggers[i].ActivateUID)); // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì actCount := Length(gTriggers[i].Activators); - Mem.WriteInt(actCount); + 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); + utils.writeBool(st, gTriggers[i].PlayerCollide); // Âðåìÿ äî çàêðûòèÿ äâåðè - Mem.WriteInt(gTriggers[i].DoorTime); + utils.writeInt(st, LongInt(gTriggers[i].DoorTime)); // Çàäåðæêà àêòèâàöèè - Mem.WriteInt(gTriggers[i].PressTime); + utils.writeInt(st, LongInt(gTriggers[i].PressTime)); // Ñ÷åò÷èê íàæàòèé - Mem.WriteInt(gTriggers[i].PressCount); + utils.writeInt(st, LongInt(gTriggers[i].PressCount)); // Ñïàâíåð àêòèâåí - Mem.WriteBoolean(gTriggers[i].AutoSpawn); + utils.writeBool(st, gTriggers[i].AutoSpawn); // Çàäåðæêà ñïàâíåðà - Mem.WriteInt(gTriggers[i].SpawnCooldown); + utils.writeInt(st, LongInt(gTriggers[i].SpawnCooldown)); // Ñ÷åò÷èê ñîçäàíèÿ îáúåêòîâ - Mem.WriteInt(gTriggers[i].SpawnedCount); + utils.writeInt(st, LongInt(gTriggers[i].SpawnedCount)); // Ñêîëüêî ðàç ïðîèãðàí çâóê - Mem.WriteInt(gTriggers[i].SoundPlayCount); + utils.writeInt(st, LongInt(gTriggers[i].SoundPlayCount)); // Ïðîèãðûâàåòñÿ ëè çâóê? if (gTriggers[i].Sound <> nil) then b := gTriggers[i].Sound.IsPlaying() else b := false; - Mem.WriteBoolean(b); + 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 - Mem.WriteInt(0); + utils.writeInt(st, LongInt(0)); end else begin - Mem.WriteInt(gTriggers[i].userVars.count); + 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), '>'); - Mem.WriteString(kv.key); + utils.writeStr(st, kv.key); t := LongInt(varType(kv.value)); - Mem.WriteInt(t); + utils.writeInt(st, LongInt(t)); case t of - varString: Mem.WriteString(AnsiString(kv.value)); - varBoolean: Mem.WriteBoolean(Boolean(kv.value)); - varShortInt: Mem.WriteInt(Integer(kv.value)); - varSmallint: Mem.WriteInt(Integer(kv.value)); - varInteger: Mem.WriteInt(Integer(kv.value)); + 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: Mem.WriteInt(Integer(kv.value)); - varWord: Mem.WriteInt(Integer(kv.value)); - varLongWord: 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; @@ -3168,7 +3219,7 @@ begin end; -procedure g_Triggers_LoadState (var Mem: TBinMemoryReader); +procedure g_Triggers_LoadState (st: TStream); var count, actCount, i, j, a: Integer; dw: DWORD; @@ -3179,93 +3230,97 @@ var uvcount: Integer; vt: LongInt; vv: Variant; - uvname: AnsiString; - ustr: AnsiString; + uvname: AnsiString = ''; + ustr: AnsiString = ''; uint: LongInt; ubool: Boolean; begin - if (Mem = nil) then exit; + assert(st <> nil); g_Triggers_Free(); // Êîëè÷åñòâî òðèããåðîâ - Mem.ReadInt(count); + 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); // 'TRGX' - if (dw <> TRIGGER_SIGNATURE) then raise EBinSizeError.Create('g_Triggers_LoadState: Wrong Trigger Signature'); + 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'); // Òèï òðèããåðà - Mem.ReadByte(Trig.TriggerType); - // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers'] + Trig.TriggerType := utils.readByte(st); if (Trig.TriggerType = TRIGGER_NONE) then continue; // empty one - Mem.ReadInt(mapIndex); + // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers'] + mapIndex := utils.readLongInt(st); i := g_Triggers_CreateWithMapIndex(Trig, a, mapIndex); - // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà: - 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].TexturePanelGUID); - // Òèï ýòîé ïàíåëè: - Mem.ReadWord(gTriggers[i].TexturePanelType); - // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû) - Mem.ReadInt(gTriggers[i].trigPanelGUID); - // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè: - Mem.ReadWord(gTriggers[i].TimeOut); - // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð: - Mem.ReadWord(gTriggers[i].ActivateUID); - // Ñïèñîê UID-îâ îáúåêòîâ, êîòîðûå íàõîäèëèñü ïîä âîçäåéñòâèåì: - Mem.ReadInt(actCount); - if actCount > 0 then + // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà + 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 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); @@ -3275,26 +3330,26 @@ begin // uservars gTriggers[i].userVars.Free(); gTriggers[i].userVars := nil; - Mem.ReadInt(uvcount); + 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(hsihash, hsiequ); + gTriggers[i].userVars := THashStrVariant.Create(); vv := Unassigned; while (uvcount > 0) do begin Dec(uvcount); - uvname := ''; - Mem.ReadString(uvname); - Mem.ReadInt(vt); + uvname := utils.readStr(st); + vt := utils.readLongInt(st); case vt of - varString: begin ustr := ''; Mem.ReadString(ustr); vv := ustr; end; - varBoolean: begin Mem.ReadBoolean(ubool); vv := ubool; end; - varShortInt: begin Mem.ReadInt(uint); vv := ShortInt(uint); end; - varSmallint: begin Mem.ReadInt(uint); vv := SmallInt(uint); end; - varInteger: begin Mem.ReadInt(uint); vv := LongInt(uint); end; - varByte: begin Mem.ReadInt(uint); vv := Byte(uint); end; - varWord: begin Mem.ReadInt(uint); vv := Word(uint); end; - varLongWord: begin Mem.ReadInt(uint); vv := LongWord(uint); end; + 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);