index 59b5506a5ee732d02bde51f54f49820dedc7a1c2..f5f69a93d5eea3b621a153db5d821dd334c49545 100644 (file)
--- a/src/game/g_monsters.pas
+++ b/src/game/g_monsters.pas
public
FNoRespawn: Boolean;
FFireTime: Integer;
+ trapCheckFrameId: DWord; // for `g_weapons.CheckTrap()`
constructor Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1);
destructor Destroy(); override;
property StartID: Integer read FStartID;
end;
-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): TMonster;
-procedure g_Monsters_Update();
-procedure g_Monsters_Draw();
-procedure g_Monsters_DrawHealth();
-function g_Monsters_Get(UID: Word): TMonster;
-procedure g_Monsters_killedp();
-procedure g_Monsters_SaveState(var Mem: TBinMemoryWriter);
-procedure g_Monsters_LoadState(var Mem: TBinMemoryReader);
-function g_Monsters_GetIDByName(name: String): Integer;
-function g_Monsters_GetNameByID(MonsterType: Byte): String;
-function g_Monsters_GetKilledBy(MonsterType: Byte): String;
+
+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): TMonster;
+procedure g_Monsters_Update ();
+procedure g_Monsters_Draw ();
+procedure g_Monsters_DrawHealth ();
+function g_Monsters_ByUID (UID: Word): TMonster;
+procedure g_Monsters_killedp ();
+procedure g_Monsters_SaveState (var Mem: TBinMemoryWriter);
+procedure g_Monsters_LoadState (var Mem: TBinMemoryReader);
+function g_Monsters_GetIDByName (name: String): Integer;
+function g_Monsters_GetNameByID (MonsterType: Byte): String;
+function g_Monsters_GetKilledBy (MonsterType: Byte): String;
type
function g_Mons_ForEachAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean;
function g_Mons_ForEachAtAlive (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean;
+function g_Mons_getNewTrapFrameId (): DWord;
+
var
gmon_debug_use_sqaccel: Boolean = true;
g_language, g_netmsg, z_aabbtree;
+// ////////////////////////////////////////////////////////////////////////// //
+var
+ monCheckTrapLastFrameId: DWord;
+
+
// ////////////////////////////////////////////////////////////////////////// //
type
TDynAABBTreeMonsBase = specialize TDynAABBTreeBase<TMonster>;
var
gMonsters: array of TMonster;
+ uidMap: array [0..65535] of TMonster; // monster knows it's index
+
+
+procedure clearUidMap ();
+var
+ idx: Integer;
+begin
+ for idx := 0 to High(uidMap) do uidMap[idx] := nil;
+end;
+
+
+function g_Mons_getNewTrapFrameId (): DWord;
+var
+ f: Integer;
+begin
+ Inc(monCheckTrapLastFrameId);
+ if monCheckTrapLastFrameId = 0 then
+ begin
+ // wraparound
+ monCheckTrapLastFrameId := 1;
+ for f := 0 to High(gMonsters) do
+ begin
+ if (gMonsters[f] <> nil) then gMonsters[f].trapCheckFrameId := 0;
+ end;
+ end;
+ result := monCheckTrapLastFrameId;
+end;
+
var
pt_x: Integer = 0;
UIDType := g_GetUIDType(SpawnerUID);
if UIDType = UID_MONSTER then
begin
- m := g_Monsters_Get(SpawnerUID);
+ m := g_Monsters_ByUID(SpawnerUID);
if m = nil then Exit;
MonsterType := m.FMonsterType;
end;
g_Sound_CreateWADEx('SOUND_MONSTER_FISH_ATTACK', GameWAD+':MSOUNDS\FISH_ATTACK');
monsTree := TDynAABBTreeMons.Create();
+ clearUidMap();
+ monCheckTrapLastFrameId := 0;
end;
procedure g_Monsters_FreeData();
var
a: Integer;
begin
- if gMonsters <> nil then
- for a := 0 to High(gMonsters) do
- gMonsters[a].Free();
-
monsTree.reset();
+ for a := 0 to High(gMonsters) do gMonsters[a].Free();
gMonsters := nil;
+ clearUidMap();
+ monCheckTrapLastFrameId := 0;
end;
function g_Monsters_Create(MonsterType: Byte; X, Y: Integer;
mon.arrIdx := find_id;
mon.treeNode := -1;
+ uidMap[mon.FUID] := mon;
+
// Íàñòðàèâàåì ïîëîæåíèå
with mon do
begin
var
a: Integer;
begin
-// Öåëåóêàçàòåëü:
+ // Öåëåóêàçàòåëü
if gTime mod (GAME_TICK*2) = 0 then
begin
pt_x := pt_x+pt_xs;
pt_y := pt_y+pt_ys;
- if Abs(pt_x) > 246 then
- pt_xs := -pt_xs;
- if Abs(pt_y) > 100 then
- pt_ys := -pt_ys;
+ if abs(pt_x) > 246 then pt_xs := -pt_xs;
+ if abs(pt_y) > 100 then pt_ys := -pt_ys;
end;
gMon := True; // Äëÿ ðàáîòû BlockMon'à
- if gMonsters <> nil then
- for a := 0 to High(gMonsters) do
- if (gMonsters[a] <> nil) then
- if not gMonsters[a].FRemoved then
- begin
- if g_Game_IsClient then
- gMonsters[a].ClientUpdate()
- else
- gMonsters[a].Update();
- end
- else
- begin
- gMonsters[a].Free();
- gMonsters[a] := nil;
- end;
+ for a := 0 to High(gMonsters) do
+ begin
+ if (gMonsters[a] = nil) then continue;
+ if not gMonsters[a].FRemoved then
+ begin
+ if g_Game_IsClient then
+ gMonsters[a].ClientUpdate()
+ else
+ gMonsters[a].Update();
+ end
+ else
+ begin
+ gMonsters[a].Free();
+ gMonsters[a] := nil;
+ end;
+ end;
gMon := False;
end;
end;
end;
-function g_Monsters_Get(UID: Word): TMonster;
-var
- a: Integer;
+function g_Monsters_ByUID (UID: Word): TMonster;
+//var a: Integer;
begin
+ result := uidMap[UID];
+ {
Result := nil;
-
if gMonsters <> nil then
for a := 0 to High(gMonsters) do
if (gMonsters[a] <> nil) and
Result := gMonsters[a];
Break;
end;
+ }
end;
procedure g_Monsters_SaveState(var Mem: TBinMemoryWriter);
treeNode := -1;
arrIdx := -1;
+ trapCheckFrameId := 0;
if FMonsterType in [MONSTER_ROBO, MONSTER_BARREL] then
FBloodKind := BLOOD_SPARKS
end;
// Òåïåðü öåëü - óäàðèâøèé, åñëè òîëüêî íå ñàì ñåáÿ:
- if (SpawnerUID <> FUID) and
- (BehaviourDamage(SpawnerUID, FBehaviour, FMonsterType)) then
+ if (SpawnerUID <> FUID) and (BehaviourDamage(SpawnerUID, FBehaviour, FMonsterType)) then
begin
FTargetUID := SpawnerUID;
FTargetTime := 0;
if FHealth < FMaxHealth then
begin
IncMax(FHealth, Value, FMaxHealth);
- if g_Game_IsServer and g_Game_IsNet then
- MH_SEND_MonsterState(FUID);
+ if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterState(FUID);
Result := True;
end;
end;
if (treeNode <> -1) then
begin
- {$IF DEFINED(D2F_DEBUG)}
- e_WriteLog(Format('monster #%d(%u): removed from tree; nodeid=%d', [arrIdx, UID, treeNode]), MSG_NOTIFY);
- {$ENDIF}
- monsTree.removeObject(treeNode);
+ if monsTree.isValidId(treeNode) then
+ begin
+ {$IF DEFINED(D2F_DEBUG)}
+ e_WriteLog(Format('monster #%d(%u): removed from tree; nodeid=%d', [arrIdx, UID, treeNode]), MSG_NOTIFY);
+ {$ENDIF}
+ monsTree.removeObject(treeNode);
+ end;
end;
+ if (arrIdx <> -1) then
+ begin
+ gMonsters[arrIdx] := nil;
+ end;
+
+ uidMap[FUID] := nil;
+
inherited Destroy();
end;
begin
FObj.Accel.X := FObj.Accel.X + vx;
FObj.Accel.Y := FObj.Accel.Y + vy;
- if g_Game_IsServer and g_Game_IsNet then
- MH_SEND_MonsterPos(FUID);
+ if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterPos(FUID);
end;
procedure TMonster.SetState(State: Byte; ForceAnim: Byte = 255);
NET_GFX_TELE);
end;
- if g_Game_IsServer and g_Game_IsNet then
- MH_SEND_MonsterPos(FUID);
+ if g_Game_IsServer and g_Game_IsNet then MH_SEND_MonsterPos(FUID);
Result := True;
end;
begin
FFireTime := 100;
FFireAttacker := Attacker;
- if g_Game_IsNet and g_Game_IsServer then
- MH_SEND_MonsterState(FUID);
+ if g_Game_IsNet and g_Game_IsServer then MH_SEND_MonsterState(FUID);
end;
procedure TMonster.OnFireFlame(Times: DWORD = 1);