From e0ef894b62b50d6a7bd7e1dfa42ee3f1a839403a Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Sun, 20 Aug 2017 03:21:14 +0300 Subject: [PATCH 1/1] no more public `gMonsters` --- src/game/g_basic.pas | 33 ++--- src/game/g_game.pas | 118 +++++++++--------- src/game/g_map.pas | 51 ++++---- src/game/g_monsters.pas | 195 +++++++++++++++++++---------- src/game/g_netmsg.pas | 19 +-- src/game/g_player.pas | 71 +++++------ src/game/g_saveload.pas | 2 +- src/game/g_triggers.pas | 268 +++++++++++++++++++++++----------------- src/game/g_weapons.pas | 190 ++++++++++++++++------------ 9 files changed, 540 insertions(+), 407 deletions(-) diff --git a/src/game/g_basic.pas b/src/game/g_basic.pas index 8430c9f..e001f85 100644 --- a/src/game/g_basic.pas +++ b/src/game/g_basic.pas @@ -144,20 +144,8 @@ begin end; function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean; -var - a: Integer; begin - Result := False; - - if gMonsters = nil then Exit; - - for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) and gMonsters[a].Live then - if g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then - begin - Result := True; - Exit; - end; + result := g_Mons_AnyAt(X, Y, Width, Height); end; function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean; @@ -240,19 +228,12 @@ begin UID_MONSTER: begin - repeat - Result := UID_MAX_PLAYER+$1+Random(UID_MAX_MONSTER-UID_MAX_GAME-UID_MAX_PLAYER+$1); - - ok := True; - if gMonsters <> nil then - for i := 0 to High(gMonsters) do - if gMonsters[i] <> nil then - if Result = gMonsters[i].UID then - begin - ok := False; - Break; - end; - until ok; + //FIXME!!! + while true do + begin + result := UID_MAX_PLAYER+$1+Random(UID_MAX_MONSTER-UID_MAX_GAME-UID_MAX_PLAYER+$1); + if (g_Monsters_Get(result) = nil) then break; + end; end; end; end; diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 497567b..2a52ecc 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -1439,6 +1439,24 @@ var a: Byte; w: Word; i, b: Integer; + + function sendMonsPos (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon.MonsterType = MONSTER_BARREL) then + begin + if (mon.GameVelX <> 0) or (mon.GameVelY <> 0) then MH_SEND_MonsterPos(mon.UID); + end + else + if (mon.MonsterState <> MONSTATE_SLEEP) then + begin + if (mon.MonsterState <> MONSTATE_DEAD) or (mon.GameVelX <> 0) or (mon.GameVelY <> 0) then + begin + MH_SEND_MonsterPos(mon.UID); + end; + end; + end; + begin g_ResetDynlights(); // Ïîðà âûêëþ÷àòü èãðó: @@ -1808,22 +1826,7 @@ begin if gPlayers[I] <> nil then MH_SEND_PlayerPos(True, gPlayers[I].UID); - if gMonsters <> nil then - for I := 0 to High(gMonsters) do - if gMonsters[I] <> nil then - begin - if (gMonsters[I].MonsterType = MONSTER_BARREL) then - begin - if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then - MH_SEND_MonsterPos(gMonsters[I].UID); - end - else - if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then - if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or - (gMonsters[I].GameVelX <> 0) or - (gMonsters[I].GameVelY <> 0) then - MH_SEND_MonsterPos(gMonsters[I].UID); - end; + g_Mons_ForEach(sendMonsPos); NetTimeToReliable := 0; NetTimeToUpdate := NetUpdateRate; @@ -1835,22 +1838,7 @@ begin if gPlayers[I] <> nil then MH_SEND_PlayerPos(False, gPlayers[I].UID); - if gMonsters <> nil then - for I := 0 to High(gMonsters) do - if gMonsters[I] <> nil then - begin - if (gMonsters[I].MonsterType = MONSTER_BARREL) then - begin - if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then - MH_SEND_MonsterPos(gMonsters[I].UID); - end - else - if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then - if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or - (gMonsters[I].GameVelX <> 0) or - (gMonsters[I].GameVelY <> 0) then - MH_SEND_MonsterPos(gMonsters[I].UID); - end; + g_Mons_ForEach(sendMonsPos); NetTimeToUpdate := 0; end; @@ -2453,6 +2441,28 @@ end; procedure DrawMinimap(p: TPlayer; RenderRect: e_graphics.TRect); var a, aX, aY, aX2, aY2, Scale, ScaleSz: Integer; + + function monDraw (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + with mon do + begin + if Live then + begin + // Ëåâûé âåðõíèé óãîë + aX := Obj.X div ScaleSz + 1; + aY := Obj.Y div ScaleSz + 1; + // Ðàçìåðû + aX2 := max(Obj.Rect.Width div ScaleSz, 1); + aY2 := max(Obj.Rect.Height div ScaleSz, 1); + // Ïðàâûé íèæíèé óãîë + aX2 := aX + aX2 - 1; + aY2 := aY + aY2 - 1; + e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0); + end; + end; + end; + begin if (gMapInfo.Width > RenderRect.Right - RenderRect.Left) or (gMapInfo.Height > RenderRect.Bottom - RenderRect.Top) then @@ -2621,25 +2631,8 @@ begin end; end; end; - if gMonsters <> nil then - begin - // Ðèñóåì ìîíñòðîâ: - for a := 0 to High(gMonsters) do - if gMonsters[a] <> nil then with gMonsters[a] do - if Live then begin - // Ëåâûé âåðõíèé óãîë: - aX := Obj.X div ScaleSz + 1; - aY := Obj.Y div ScaleSz + 1; - // Ðàçìåðû: - aX2 := max(Obj.Rect.Width div ScaleSz, 1); - aY2 := max(Obj.Rect.Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0); - end; - end; + // Ðèñóåì ìîíñòðîâ + g_Mons_ForEach(monDraw); end; end; @@ -4175,6 +4168,13 @@ end; procedure g_Game_RestartRound(NoMapRestart: Boolean = False); var i, n, nb, nr: Integer; + + function monRespawn (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if not mon.FNoRespawn then mon.Respawn(); + end; + begin if not g_Game_IsServer then Exit; if gLMSRespawn = LMS_RESPAWN_NONE then Exit; @@ -4243,11 +4243,8 @@ begin g_Items_RestartRound(); - for i := Low(gMonsters) to High(gMonsters) do - begin - if (gMonsters[i] <> nil) and not gMonsters[i].FNoRespawn then - gMonsters[i].Respawn; - end; + + g_Mons_ForEach(monRespawn); gLMSSoftSpawn := False; end; @@ -5003,6 +5000,7 @@ var a, b: Integer; cmd: string; //pt: TPoint; + mon: TMonster; begin // Êîìàíäû îòëàäî÷íîãî ðåæèìà: if gDebugMode then @@ -5080,12 +5078,14 @@ begin else begin with gPlayer1.Obj do - b := g_Monsters_Create(a, + begin + mon := g_Monsters_Create(a, X + Rect.X + (Rect.Width div 2), Y + Rect.Y + Rect.Height, gPlayer1.Direction, True); - if (Length(P) > 2) and (b >= 0) then - gMonsters[b].MonsterBehaviour := Min(Max(StrToIntDef(P[2], BH_NORMAL), BH_NORMAL), BH_GOOD); + end; + if (Length(P) > 2) and (mon <> nil) then + mon.MonsterBehaviour := Min(Max(StrToIntDef(P[2], BH_NORMAL), BH_NORMAL), BH_GOOD); end; end; end diff --git a/src/game/g_map.pas b/src/game/g_map.pas index 0543abe..b79c972 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -935,45 +935,52 @@ end; procedure CreateMonster(monster: TMonsterRec_1); var - a, i: Integer; + a: Integer; + mon: TMonster; begin if g_Game_IsClient then Exit; if (gGameSettings.GameType = GT_SINGLE) or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then begin - i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y, - TDirection(monster.Direction)); + mon := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y, TDirection(monster.Direction)); if gTriggers <> nil then + begin for a := 0 to High(gTriggers) do - if gTriggers[a].TriggerType in [TRIGGER_PRESS, - TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then - if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then - gMonsters[i].AddTrigger(a); + begin + if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then + begin + if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a); + end; + end; + end; - if monster.MonsterType <> MONSTER_BARREL then - Inc(gTotalMonsters); + if monster.MonsterType <> MONSTER_BARREL then Inc(gTotalMonsters); end; end; procedure g_Map_ReAdd_DieTriggers(); -var - i, a: Integer; -begin - if g_Game_IsClient then Exit; - for i := 0 to High(gMonsters) do - if gMonsters[i] <> nil then + function monsDieTrig (monidx: Integer; mon: TMonster): Boolean; + var + a: Integer; + begin + result := false; // don't stop + mon.ClearTriggers(); + for a := 0 to High(gTriggers) do + begin + if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then begin - gMonsters[i].ClearTriggers(); - - for a := 0 to High(gTriggers) do - if gTriggers[a].TriggerType in [TRIGGER_PRESS, - TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then - if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then - gMonsters[i].AddTrigger(a); + if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a); end; + end; + end; + +begin + if g_Game_IsClient then Exit; + + g_Mons_ForEach(monsDieTrig); end; function extractWadName(resourceName: string): string; diff --git a/src/game/g_monsters.pas b/src/game/g_monsters.pas index 6906260..af98aba 100644 --- a/src/game/g_monsters.pas +++ b/src/game/g_monsters.pas @@ -161,8 +161,8 @@ procedure g_Monsters_LoadData(); procedure g_Monsters_FreeData(); procedure g_Monsters_Init(); procedure g_Monsters_Free(); -function g_Monsters_Create(MonsterType: Byte; X, Y: Integer; - Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): Integer; +function g_Monsters_Create(MonsterType: Byte; X, Y: Integer; + Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; procedure g_Monsters_Update(); procedure g_Monsters_Draw(); procedure g_Monsters_DrawHealth(); @@ -174,8 +174,20 @@ function g_Monsters_GetIDByName(name: String): Integer; function g_Monsters_GetNameByID(MonsterType: Byte): String; function g_Monsters_GetKilledBy(MonsterType: Byte): String; -var - gMonsters: array of TMonster; + +type + TEachMonsterCB = function (monidx: Integer; mon: TMonster): Boolean is nested; // return `true` to stop + +function g_Mons_ForEach (cb: TEachMonsterCB): Boolean; + +// throws on invalid uid +function g_Mons_ByIdx (uid: Integer): TMonster; inline; + +// can return null +function g_Mons_ByIdx_NC (uid: Integer): TMonster; inline; + +function g_Mons_AnyAt (x, y: Integer; width, height: Integer): Boolean; + implementation @@ -385,6 +397,9 @@ const MAX_ATM = 89; // Âðåìÿ îæèäàíèÿ ïîñëå ïîòåðè öåëè MAX_SOUL = 512; // Îãðàíè÷åíèå Lost_Soul'îâ +var + gMonsters: array of TMonster; + var pt_x: Integer = 0; pt_xs: Integer = 1; @@ -985,40 +1000,39 @@ begin end; function g_Monsters_Create(MonsterType: Byte; X, Y: Integer; - Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): Integer; + Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster; var find_id: DWORD; begin - Result := -1; + result := nil; -// Íåò òàêîãî ìîíñòðà: - if (MonsterType > MONSTER_MAN) or (MonsterType = 0) then - Exit; + // Íåò òàêîãî ìîíñòðà + if (MonsterType > MONSTER_MAN) or (MonsterType = 0) then exit; -// Ñîáëþäàåì îãðàíè÷åíèå Lost_Soul'îâ: + // Ñîáëþäàåì îãðàíè÷åíèå Lost_Soul'îâ if MonsterType = MONSTER_SOUL then - if soulcount > MAX_SOUL then - Exit - else - soulcount := soulcount + 1; + begin + if soulcount > MAX_SOUL then exit; + soulcount := soulcount + 1; + end; find_id := FindMonster(); gMonsters[find_id] := TMonster.Create(MonsterType, find_id, ForcedUID); -// Íàñòðàèâàåì ïîëîæåíèå: + // Íàñòðàèâàåì ïîëîæåíèå with gMonsters[find_id] do begin if AdjCoord then - begin - FObj.X := X-FObj.Rect.X - (FObj.Rect.Width div 2); - FObj.Y := Y-FObj.Rect.Y - FObj.Rect.Height; - end + begin + FObj.X := X-FObj.Rect.X - (FObj.Rect.Width div 2); + FObj.Y := Y-FObj.Rect.Y - FObj.Rect.Height; + end else - begin - FObj.X := X-FObj.Rect.X; - FObj.Y := Y-FObj.Rect.Y; - end; + begin + FObj.X := X-FObj.Rect.X; + FObj.Y := Y-FObj.Rect.Y; + end; FDirection := Direction; FStartDirection := Direction; @@ -1026,7 +1040,7 @@ begin FStartY := GameY; end; - Result := find_id; + result := {find_id}gMonsters[find_id]; end; procedure g_Monsters_killedp(); @@ -1172,39 +1186,35 @@ end; procedure g_Monsters_LoadState(var Mem: TBinMemoryReader); var - count, i, a: Integer; + count, a: Integer; b: Byte; + mon: TMonster; begin - if Mem = nil then - Exit; + if Mem = nil then exit; g_Monsters_Free(); -// Çàãðóæàåì èíôîðìàöèþ öåëåóêàçàòåëÿ: + // Çàãðóæàåì èíôîðìàöèþ öåëåóêàçàòåëÿ Mem.ReadInt(pt_x); Mem.ReadInt(pt_xs); Mem.ReadInt(pt_y); Mem.ReadInt(pt_ys); -// Êîëè÷åñòâî ìîíñòðîâ: + // Êîëè÷åñòâî ìîíñòðîâ Mem.ReadInt(count); - if count = 0 then - Exit; + if count = 0 then exit; -// Çàãðóæàåì ìîíñòðîâ: + // Çàãðóæàåì ìîíñòðîâ for a := 0 to count-1 do begin - // Òèï ìîíñòðà: + // Òèï ìîíñòðà Mem.ReadByte(b); - // Ñîçäàåì ìîíñòðà: - i := g_Monsters_Create(b, 0, 0, D_LEFT); - if i < 0 then - begin - raise EBinSizeError.Create('g_Monsters_LoadState: ID = -1 (Can''t create)'); - end; - // Çàãðóæàåì äàííûå ìîíñòðà: - gMonsters[i].LoadState(Mem); + // Ñîçäàåì ìîíñòðà + mon := g_Monsters_Create(b, 0, 0, D_LEFT); + if mon = nil then raise EBinSizeError.Create('g_Monsters_LoadState: ID = -1 (Can''t create)'); + // Çàãðóæàåì äàííûå ìîíñòðà + mon.LoadState(Mem); end; end; @@ -2004,6 +2014,7 @@ var st: Word; o, co: TObj; fall: Boolean; + mon: TMonster; label _end; begin @@ -2681,32 +2692,32 @@ _end: // Pain_Elemental ïðè ñìåðòè âûïóñêàåò 3 Lost_Soul'à: if (FMonsterType = MONSTER_PAIN) then begin - sx := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-30, - FObj.Y+FObj.Rect.Y+20, D_LEFT); - if sx <> -1 then + mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-30, + FObj.Y+FObj.Rect.Y+20, D_LEFT); + if mon <> nil then begin - gMonsters[sx].SetState(STATE_GO); - gMonsters[sx].FNoRespawn := True; + mon.SetState(STATE_GO); + mon.FNoRespawn := True; Inc(gTotalMonsters); if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); end; - sx := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), - FObj.Y+FObj.Rect.Y+20, D_RIGHT); - if sx <> -1 then + mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2), + FObj.Y+FObj.Rect.Y+20, D_RIGHT); + if mon <> nil then begin - gMonsters[sx].SetState(STATE_GO); - gMonsters[sx].FNoRespawn := True; + mon.SetState(STATE_GO); + mon.FNoRespawn := True; Inc(gTotalMonsters); if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); end; - sx := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-15, - FObj.Y+FObj.Rect.Y, D_RIGHT); - if sx <> -1 then + mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-15, + FObj.Y+FObj.Rect.Y, D_RIGHT); + if mon <> nil then begin - gMonsters[sx].SetState(STATE_GO); - gMonsters[sx].FNoRespawn := True; + mon.SetState(STATE_GO); + mon.FNoRespawn := True; Inc(gTotalMonsters); if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); end; @@ -2870,17 +2881,17 @@ _end: g_Weapon_ball2(wx, wy, tx, ty, FUID); MONSTER_PAIN: begin // Ñîçäàåì Lost_Soul: - sx := g_Monsters_Create(MONSTER_SOUL, FObj.X+(FObj.Rect.Width div 2), - FObj.Y+FObj.Rect.Y, FDirection); + mon := g_Monsters_Create(MONSTER_SOUL, FObj.X+(FObj.Rect.Width div 2), + FObj.Y+FObj.Rect.Y, FDirection); - if sx <> -1 then + if mon <> nil then begin // Öåëü - öåëü Pain_Elemental'à. Ëåòèì ê íåé: - gMonsters[sx].FTargetUID := FTargetUID; + mon.FTargetUID := FTargetUID; GetPos(FTargetUID, @o); - gMonsters[sx].FTargetTime := 0; - gMonsters[sx].FNoRespawn := True; - gMonsters[sx].SetState(STATE_GO); - gMonsters[sx].shoot(@o, True); + mon.FTargetTime := 0; + mon.FNoRespawn := True; + mon.SetState(STATE_GO); + mon.shoot(@o, True); Inc(gTotalMonsters); if g_Game_IsNet then MH_SEND_MonsterSpawn(gMonsters[sx].UID); @@ -4243,4 +4254,60 @@ procedure TMonster.positionChanged (); begin end; + +// ////////////////////////////////////////////////////////////////////////// // +function g_Mons_ForEach (cb: TEachMonsterCB): Boolean; +var + idx: Integer; +begin + result := false; + if (gMonsters = nil) or not assigned(cb) then exit; + for idx := 0 to High(gMonsters) do + begin + if (gMonsters[idx] <> nil) then + begin + result := cb(idx, gMonsters[idx]); + if result then exit; + end; + end; +end; + + +// throws on invalid uid +function g_Mons_ByIdx (uid: Integer): TMonster; inline; +begin + result := g_Mons_ByIdx_NC(uid); + if (result = nil) then raise Exception.Create('g_Mons_ByIdx: invalid monster id'); +end; + + +// can return null +function g_Mons_ByIdx_NC (uid: Integer): TMonster; inline; +begin + if (uid < 0) or (uid > High(gMonsters)) then begin result := nil; exit; end; + result := gMonsters[uid]; +end; + + +function g_Mons_AnyAt (x, y: Integer; width, height: Integer): Boolean; +var + idx: Integer; +begin + result := false; + if (width < 1) or (height < 1) then exit; + + for idx := 0 to High(gMonsters) do + begin + if (gMonsters[idx] <> nil) and gMonsters[idx].Live then + begin + if g_Obj_Collide(x, y, width, height, @gMonsters[idx].Obj) then + begin + result := True; + exit; + end; + end; + end; +end; + + end. diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas index 33273f8..a60f95f 100644 --- a/src/game/g_netmsg.pas +++ b/src/game/g_netmsg.pas @@ -634,6 +634,12 @@ procedure MH_SEND_Everything(CreatePlayers: Boolean = False; ID: Integer = NET_E MH_SEND_ItemSpawn(True, it.myid, ID); end; + function sendMonSpawn (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + MH_SEND_MonsterSpawn(mon.UID, ID); + end; + var I: Integer; begin @@ -654,11 +660,7 @@ begin end; g_Items_ForEachAlive(sendItemRespawn, true); // backwards - - if gMonsters <> nil then - for I := 0 to High(gMonsters) do - if gMonsters[I] <> nil then - MH_SEND_MonsterSpawn(gMonsters[I].UID, ID); + g_Mons_ForEach(sendMonSpawn); if gWalls <> nil then for I := Low(gWalls) to High(gWalls) do @@ -2697,14 +2699,15 @@ end; procedure MC_RECV_MonsterDelete(P: Pointer); var ID: Integer; - M: TMonster; + M, mon: TMonster; begin ID := e_Raw_Read_Word(P); M := g_Monsters_Get(ID); if M = nil then Exit; - gMonsters[ID].SetState(5); - gMonsters[ID].MonsterRemoved := True; + mon := g_Mons_ByIdx(ID); + mon.SetState(5); + mon.MonsterRemoved := True; end; procedure MC_RECV_TimeSync(P: Pointer); diff --git a/src/game/g_player.pas b/src/game/g_player.pas index 0ee9365..75366d3 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -6302,6 +6302,41 @@ var mon: TMonster; pla, tpla: TPlayer; vsPlayer, vsMonster, ok: Boolean; + + + function monsUpdate (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and (mon.Live) and (mon.MonsterType <> MONSTER_BARREL) then + begin + if not TargetOnScreen(mon.Obj.X+mon.Obj.Rect.X, mon.Obj.Y+mon.Obj.Rect.Y) then exit; + + x2 := mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2); + y2 := mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2); + + // Åñëè ìîíñòð íà ýêðàíå è íå ïðèêðûò ñòåíîé + if g_TraceVector(x1, y1, x2, y2) then + begin + // Äîáàâëÿåì ê ñïèñêó âîçìîæíûõ öåëåé + SetLength(targets, Length(targets)+1); + with targets[High(targets)] do + begin + UID := mon.UID; + X := mon.Obj.X; + Y := mon.Obj.Y; + cX := x2; + cY := y2; + Rect := mon.Obj.Rect; + Dist := g_PatchLength(x1, y1, x2, y2); + Line := (y1+4 < Target.Y + mon.Obj.Rect.Y + mon.Obj.Rect.Height) and + (y1-4 > Target.Y + mon.Obj.Rect.Y); + Visible := True; + IsPlayer := False; + end; + end; + end; + end; + begin vsPlayer := LongBool(gGameSettings.Options and GAME_OPTION_BOTVSPLAYER); vsMonster := LongBool(gGameSettings.Options and GAME_OPTION_BOTVSMONSTER); @@ -6431,41 +6466,7 @@ begin end; // Ìîíñòðû: - if vsMonster and (gMonsters <> nil) then - for a := 0 to High(gMonsters) do - if (gMonsters[a] <> nil) and (gMonsters[a].Live) and - (gMonsters[a].MonsterType <> MONSTER_BARREL) then - begin - mon := gMonsters[a]; - - if not TargetOnScreen(mon.Obj.X + mon.Obj.Rect.X, - mon.Obj.Y + mon.Obj.Rect.Y) then - Continue; - - x2 := mon.Obj.X + mon.Obj.Rect.X + (mon.Obj.Rect.Width div 2); - y2 := mon.Obj.Y + mon.Obj.Rect.Y + (mon.Obj.Rect.Height div 2); - - // Åñëè ìîíñòð íà ýêðàíå è íå ïðèêðûò ñòåíîé: - if g_TraceVector(x1, y1, x2, y2) then - begin - // Äîáàâëÿåì ê ñïèñêó âîçìîæíûõ öåëåé: - SetLength(targets, Length(targets)+1); - with targets[High(targets)] do - begin - UID := mon.UID; - X := mon.Obj.X; - Y := mon.Obj.Y; - cX := x2; - cY := y2; - Rect := mon.Obj.Rect; - Dist := g_PatchLength(x1, y1, x2, y2); - Line := (y1+4 < Target.Y + mon.Obj.Rect.Y + mon.Obj.Rect.Height) and - (y1-4 > Target.Y + mon.Obj.Rect.Y); - Visible := True; - IsPlayer := False; - end; - end; - end; + if vsMonster then g_Mons_ForEach(monsUpdate); end; // Åñëè åñòü âîçìîæíûå öåëè: diff --git a/src/game/g_saveload.pas b/src/game/g_saveload.pas index 40cf5cc..aaf01b5 100644 --- a/src/game/g_saveload.pas +++ b/src/game/g_saveload.pas @@ -565,7 +565,7 @@ begin ///// ///// // Èùåì òðèããåðû ñ óñëîâèåì ñìåðòè ìîíñòðîâ: - if (gMonsters <> nil) and (gTriggers <> nil) then + if {(gMonsters <> nil) and} (gTriggers <> nil) then g_Map_ReAdd_DieTriggers(); // Çàêðûâàåì ôàéë çàãðóçêè: diff --git a/src/game/g_triggers.pas b/src/game/g_triggers.pas index 7238c80..ec3bb71 100644 --- a/src/game/g_triggers.pas +++ b/src/game/g_triggers.pas @@ -209,18 +209,36 @@ end; procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean); var a, b, c: Integer; + wx, wy, wh, ww: Integer; + + function monsDamage (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and mon.Live and g_Obj_Collide(wx, wy, ww, wh, @mon.Obj) then + begin + mon.Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + end; + end; + begin if PanelID = -1 then Exit; 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'); end; + end; + + wx := gWalls[PanelID].X; + wy := gWalls[PanelID].Y; + ww := gWalls[PanelID].Width; + wh := gWalls[PanelID].Height; with gWalls[PanelID] do begin @@ -230,11 +248,7 @@ begin gPlayers[a].Collide(X, Y, Width, Height) then gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); - 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); if not Enabled then g_Map_EnableWall(PanelID); end; @@ -247,30 +261,41 @@ begin 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; end; + end; if c <> -1 then Break; end; 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 @@ -279,14 +304,18 @@ begin gPlayers[a].Collide(X, Y, Width, Height) then gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP); + g_Mons_ForEach(monsDamage); + (* 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); + *) if not Enabled then g_Map_EnableWall(gDoorMap[c, b]); end; + end; end; end; @@ -946,7 +975,7 @@ var animonce: Boolean; p: TPlayer; m: TMonster; - i, k, wx, wy, xd, yd: Integer; + idx, k, wx, wy, xd, yd: Integer; iid: LongWord; coolDown: Boolean; pAngle: Real; @@ -955,6 +984,44 @@ var UIDType: Byte; TargetUID: Word; it: PItem; + mon: TMonster; + + function monsShotTarget (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and mon.Live 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 (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and mon.Live 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 (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and mon.Live 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; + begin Result := False; if g_Game_IsClient then @@ -1184,7 +1251,7 @@ begin if (Data.MonMax > 0) and (SpawnedCount >= Data.MonMax) then Break; - i := g_Monsters_Create(Data.MonType, + mon := g_Monsters_Create(Data.MonType, Data.MonPos.X, Data.MonPos.Y, TDirection(Data.MonDir), True); @@ -1192,27 +1259,27 @@ begin // Çäîðîâüå: if (Data.MonHealth > 0) then - gMonsters[i].SetHealth(Data.MonHealth); + mon.SetHealth(Data.MonHealth); // Óñòàíàâëèâàåì ïîâåäåíèå: - gMonsters[i].MonsterBehaviour := Data.MonBehav; - gMonsters[i].FNoRespawn := True; + mon.MonsterBehaviour := Data.MonBehav; + 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(); + mon.WakeUp(); if Data.MonType <> 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; + mon.SpawnTrigger := ID; Inc(SpawnedCount); end; @@ -1222,13 +1289,13 @@ begin 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_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 @@ -1236,13 +1303,13 @@ begin 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_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 @@ -1250,13 +1317,13 @@ begin 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_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; @@ -1766,10 +1833,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 @@ -1833,12 +1900,12 @@ begin end; // Íàçíà÷àåì âðåìÿ ñëåäóþùåãî âîçäåéñòâèÿ if TriggerType = TRIGGER_DAMAGE then - i := Data.DamageInterval + idx := Data.DamageInterval else - i := Data.HealInterval; + idx := Data.HealInterval; 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; @@ -1863,75 +1930,58 @@ begin case Data.ShotTarget 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 - tr_ShotAimCheck(Trigger, @(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; + g_Mons_ForEach(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 - tr_ShotAimCheck(Trigger, @(gPlayers[i].Obj)) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].Live 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 - tr_ShotAimCheck(Trigger, @(gPlayers[i].Obj)) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].Live 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 - tr_ShotAimCheck(Trigger, @(gPlayers[i].Obj)) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].Live 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 - tr_ShotAimCheck(Trigger, @(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; + g_Mons_ForEach(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 - tr_ShotAimCheck(Trigger, @(gPlayers[i].Obj)) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].Live 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; @@ -1939,25 +1989,16 @@ 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 - tr_ShotAimCheck(Trigger, @(gPlayers[i].Obj)) then + for idx := Low(gPlayers) to High(gPlayers) do + if (gPlayers[idx] <> nil) and gPlayers[idx].Live 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 - tr_ShotAimCheck(Trigger, @(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 g_Mons_ForEach(monShotTargetPlrMon); end; else begin @@ -1991,9 +2032,9 @@ begin TRIGGER_EFFECT: begin - i := Data.FXCount; + idx := Data.FXCount; - while i > 0 do + while idx > 0 do begin case Data.FXPos of TRIGGER_EFFECT_POS_CENTER: @@ -2020,7 +2061,7 @@ begin tr_MakeEffect(wx, wy, xd, yd, Data.FXType, Data.FXSubType, Data.FXColorR, Data.FXColorG, Data.FXColorB, True, False); - Dec(i); + Dec(idx); end; TimeOut := Data.FXWait; end; @@ -2154,6 +2195,17 @@ procedure g_Triggers_Update(); var a, b, i: Integer; Affected: array of Integer; + + function monsNear (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.Collide(gTriggers[a].X, gTriggers[a].Y, gTriggers[a].Width, gTriggers[a].Height) then + begin + gTriggers[a].ActivateUID := mon.UID; + ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE); + end; + end; + begin if gTriggers = nil then Exit; @@ -2384,20 +2436,14 @@ 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); + end; - // "Ìîíñòðîâ íåò": + // "Ìîíñòðîâ íåò" if ByteBool(ActivateType and ACTIVATE_NOMONSTER) and (TimeOut = 0) and (Keys = 0) then if not g_CollideMonster(X, Y, Width, Height) then diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas index 3585ef2..2cdfe87 100644 --- a/src/game/g_weapons.pas +++ b/src/game/g_weapons.pas @@ -244,9 +244,21 @@ begin end; procedure CheckTrap(ID: DWORD; dm: Integer; t: Byte); + var a, b, c, d, i1, i2: Integer; pl, mn: WArray; + + function monsWaterCheck (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if mon.Live and mon.Collide(gWater[WaterMap[a][c]]) and (not InWArray(monidx, mn)) and (i2 < 1023) then //FIXME + begin + i2 += 1; + mn[i2] := monidx; + end; + end; + begin if (gWater = nil) or (WaterMap = nil) then Exit; @@ -280,18 +292,7 @@ begin end; end; - if gMonsters <> nil then - begin - for d := 0 to High(gMonsters) do - if (gMonsters[d] <> nil) and (gMonsters[d].Live) then - if gMonsters[d].Collide(gWater[WaterMap[a][c]]) then - if not InWArray(d, mn) then - if i2 < 1023 then - begin - i2 := i2+1; - mn[i2] := d; - end; - end; + g_Mons_ForEach(monsWaterCheck); end; if i1 <> -1 then @@ -300,7 +301,7 @@ begin if i2 <> -1 then for d := 0 to i2 do - gMonsters[mn[d]].Damage(dm, 0, 0, Shots[ID].SpawnerUID, t); + g_Mons_ByIdx(mn[d]).Damage(dm, 0, 0, Shots[ID].SpawnerUID, t); end; pl := nil; @@ -377,7 +378,7 @@ begin if (p.UID = SpawnerUID) and (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then Exit; - if g_Game_IsServer then + if g_Game_IsServer then begin if (t <> HIT_FLAME) or (p.FFireTime = 0) or (vx <> 0) or (vy <> 0) then p.Damage(d, SpawnerUID, vx, vy, t); @@ -390,6 +391,20 @@ end; function GunHit(X, Y: Integer; vx, vy: Integer; dmg: Integer; SpawnerUID: Word; AllowPush: Boolean): Byte; + + function monsCheck (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and mon.Live and mon.Collide(X, Y) then + begin + if HitMonster(mon, dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then + begin + if AllowPush then mon.Push(vx, vy); + result := true; + end; + end; + end; + var i, h: Integer; begin @@ -408,20 +423,29 @@ begin if Result <> 0 then Exit; - h := High(gMonsters); + if g_Mons_ForEach(monsCheck) then result := 2; +end; - if h <> -1 then - for i := 0 to h do - if (gMonsters[i] <> nil) and gMonsters[i].Live and gMonsters[i].Collide(X, Y) then - if HitMonster(gMonsters[i], dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then +procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word); + + function monsCheck (monidx: Integer; mon: TMonster): Boolean; + begin + result := false; // don't stop + if (mon <> nil) and (mon.Live) and (mon.UID <> SpawnerUID) then + begin + with mon do + begin + if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2), + Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and + g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2), + Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then begin - if AllowPush then gMonsters[i].Push(vx, vy); - Result := 2; - Exit; + if HitMonster(mon, 50, 0, 0, SpawnerUID, HIT_SOME) then mon.BFGHit(); end; -end; + end; + end; + end; -procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word); var i, h: Integer; st: Byte; @@ -470,17 +494,7 @@ begin gPlayers[i].BFGHit(); end; - h := High(gMonsters); - - if h <> -1 then - for i := 0 to h do - if (gMonsters[i] <> nil) and (gMonsters[i].Live) and (gMonsters[i].UID <> SpawnerUID) then - with gMonsters[i] do - if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2), - Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and - g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2), - Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then - if HitMonster(gMonsters[i], 50, 0, 0, SpawnerUID, HIT_SOME) then gMonsters[i].BFGHit(); + g_Mons_ForEach(monsCheck); end; function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord; @@ -694,7 +708,7 @@ begin Shots[i].Stopped := 0; if Shots[i].ShotType in [WEAPON_ROCKETLAUNCHER, WEAPON_BFG] then Shots[i].Timeout := 900 // ~25 sec - else + else begin if Shots[i].ShotType = WEAPON_FLAMETHROWER then Shots[i].Timeout := SHOT_FLAME_LIFETIME @@ -740,25 +754,29 @@ var end; end; end; - function MonsterHit(): Boolean; - var - i: Integer; + + function monsCheckHit (monidx: Integer; mon: TMonster): Boolean; begin - Result := False; - h := High(gMonsters); + result := false; // don't stop + if (mon <> nil) and mon.Live and g_Obj_Collide(obj, @mon.Obj) then + begin + if HitMonster(mon, d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then + begin + if (t <> HIT_FLAME) then + begin + mon.Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4, + (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4); + end; + result := True; + end; + end; + end; - if h <> -1 then - for i := 0 to h do - if (gMonsters[i] <> nil) and gMonsters[i].Live and g_Obj_Collide(obj, @gMonsters[i].Obj) then - if HitMonster(gMonsters[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then - begin - if t <> HIT_FLAME then - gMonsters[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4, - (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4); - Result := True; - break; - end; + function MonsterHit(): Boolean; + begin + result := g_Mons_ForEach(monsCheckHit); end; + begin Result := 0; @@ -854,8 +872,44 @@ end; function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean; var - i, h, r, dx, dy, m, mm: Integer; + r: Integer; + + function monsExCheck (monidx: Integer; mon: TMonster): Boolean; + var + dx, dy, mm: Integer; + begin + result := false; // don't stop + if mon <> nil then + begin + with mon do + begin + dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X; + dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y; + + if dx > 1000 then dx := 1000; + if dy > 1000 then dy := 1000; + + if (dx*dx+dy*dy < r) then + begin + //m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, Obj.Rect.Width, Obj.Rect.Height); + + mm := Max(abs(dx), abs(dy)); + if mm = 0 then mm := 1; + + if mon.Live then + HitMonster(mon, ((mon.Obj.Rect.Width div 4)*10*(rad-mm)) div rad, + 0, 0, SpawnerUID, HIT_ROCKET); + + mon.Push((dx*7) div mm, (dy*7) div mm); + end; + end; + end; + end; + +var + i, h, dx, dy, m, mm: Integer; _angle: SmallInt; + begin Result := False; @@ -889,34 +943,8 @@ begin end; end; - h := High(gMonsters); - - if h <> -1 then - for i := 0 to h do - if gMonsters[i] <> nil then - with gMonsters[i] do - begin - dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X; - dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y; - - if dx > 1000 then dx := 1000; - if dy > 1000 then dy := 1000; - - if dx*dx+dy*dy < r then - begin - //m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, - // Obj.Rect.Width, Obj.Rect.Height); - - mm := Max(abs(dx), abs(dy)); - if mm = 0 then mm := 1; - - if gMonsters[i].Live then - HitMonster(gMonsters[i], ((gMonsters[i].Obj.Rect.Width div 4)*10*(rad-mm)) div rad, - 0, 0, SpawnerUID, HIT_ROCKET); + g_Mons_ForEach(monsExCheck); - gMonsters[i].Push((dx*7) div mm, (dy*7) div mm); - end; - end; h := High(gCorpses); @@ -1545,7 +1573,7 @@ begin throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16); triggers := nil; - + g_Frames_Get(FramesID, 'FRAMES_WEAPON_BSPFIRE'); Animation := TAnimation.Create(FramesID, True, 4); end; -- 2.29.2