index 55a02104f4a56e602de638d507b13490936100cf..719a2b759d9da4b136d3c97275d411f187963cae 100644 (file)
--- a/src/game/g_monsters.pas
+++ b/src/game/g_monsters.pas
interface
uses
- g_basic, e_graphics, g_phys, g_textures,
- g_saveload, BinEditor, g_panel;
+ g_basic, e_graphics, g_phys, g_textures, g_grid,
+ g_saveload, BinEditor, g_panel, xprofiler;
const
MONSTATE_SLEEP = 0;
FFireAttacker: Word;
vilefire: TAnimation;
- treeNode: Integer; // node in dyntree or -1
+ {$IF DEFINED(D2F_DEBUG)}
+ public
+ {$ENDIF}
+ proxyId: Integer; // node in dyntree or -1
arrIdx: Integer; // in gMonsters
+ {$IF DEFINED(D2F_DEBUG)}
+ private
+ {$ENDIF}
FDieTriggers: Array of Integer;
FSpawnTrigger: Integer;
procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
+ procedure getMapBox (out x, y, w, h: Integer); inline;
+
property MonsterType: Byte read FMonsterType;
property MonsterHealth: Integer read FHealth write FHealth;
property MonsterAmmo: Integer read FAmmo write FAmmo;
end;
+// will be called from map loader
+procedure g_Mons_InitTree (x, y, w, h: Integer);
+
procedure g_Monsters_LoadData ();
procedure g_Monsters_FreeData ();
procedure g_Monsters_Init ();
type
- TEachMonsterCB = function (monidx: Integer; mon: TMonster): Boolean is nested; // return `true` to stop
+ TEachMonsterCB = function (mon: TMonster): Boolean is nested; // return `true` to stop
// throws on invalid uid
function g_Mons_ByIdx (uid: Integer): TMonster; inline;
@@ -200,45 +211,95 @@ function g_Mons_ForEachAliveAt (x, y: Integer; width, height: Integer; cb: TEach
function g_Mons_getNewTrapFrameId (): DWord;
+type
+ TMonsAlongLineCB = function (mon: TMonster; tag: Integer): Boolean is nested;
+
+function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster;
+
+
var
gmon_debug_use_sqaccel: Boolean = true;
+//HACK!
+procedure g_Mons_ProfilersBegin ();
+procedure g_Mons_ProfilersEnd ();
+
+procedure g_Mons_LOS_Start (); inline;
+procedure g_Mons_LOS_End (); inline;
+
+var
+ profMonsLOS: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY!
+
+
+type
+ TMonsterGrid = specialize TBodyGridBase<TMonster>;
+
+var
+ monsGrid: TMonsterGrid = nil;
+
+
+var
+ gmon_debug_think: Boolean = true;
+
+
implementation
uses
e_log, g_main, g_sound, g_gfx, g_player, g_game,
g_weapons, g_triggers, MAPDEF, g_items, g_options,
g_console, g_map, Math, SysUtils, g_menu, wadreader,
- g_language, g_netmsg, z_aabbtree;
+ g_language, g_netmsg;
// ////////////////////////////////////////////////////////////////////////// //
-var
- monCheckTrapLastFrameId: DWord;
+procedure g_Mons_ProfilersBegin ();
+begin
+ if (profMonsLOS = nil) then profMonsLOS := TProfiler.Create('LOS CALC', g_profile_history_size);
+ profMonsLOS.mainBegin(g_profile_los);
+ if g_profile_los then
+ begin
+ profMonsLOS.sectionBegin('loscalc');
+ profMonsLOS.sectionEnd();
+ end;
+end;
+
+procedure g_Mons_ProfilersEnd ();
+begin
+ if (profMonsLOS <> nil) and (g_profile_los) then profMapCollision.mainEnd();
+end;
+
+procedure g_Mons_LOS_Start (); inline;
+begin
+ profMonsLOS.sectionBeginAccum('loscalc');
+end;
+
+procedure g_Mons_LOS_End (); inline;
+begin
+ profMonsLOS.sectionEnd();
+end;
// ////////////////////////////////////////////////////////////////////////// //
-type
- TDynAABBTreeMonsBase = specialize TDynAABBTreeBase<TMonster>;
+var
+ monCheckTrapLastFrameId: DWord;
- TDynAABBTreeMons = class(TDynAABBTreeMonsBase)
- function getFleshAABB (out aabb: AABB2D; flesh: TMonster; tag: Integer): Boolean; override;
- end;
-function TDynAABBTreeMons.getFleshAABB (out aabb: AABB2D; flesh: TMonster; tag: Integer): Boolean;
+procedure TMonster.getMapBox (out x, y, w, h: Integer); inline;
begin
- result := false;
- if (flesh = nil) then raise Exception.Create('DynTree: trying to get dimensions of inexistant monsters');
- if (flesh.Obj.Rect.Width < 1) or (flesh.Obj.Rect.Height < 1) then raise Exception.Create('DynTree: monster without size, wtf?!');
- aabb := AABB2D.CreateWH(flesh.Obj.X+flesh.Obj.Rect.X, flesh.Obj.Y+flesh.Obj.Rect.Y, flesh.Obj.Rect.Width, flesh.Obj.Rect.Height);
- if not aabb.valid then raise Exception.Create('wutafuuuuuuu?!');
- result := true;
+ x := FObj.X+FObj.Rect.X;
+ y := FObj.Y+FObj.Rect.Y;
+ w := FObj.Rect.Width;
+ h := FObj.Rect.Height;
end;
-var
- monsTree: TDynAABBTreeMons = nil;
+// ////////////////////////////////////////////////////////////////////////// //
+function g_Mons_AlongLine (x0, y0, x1, y1: Integer; cb: TMonsAlongLineCB; log: Boolean=false): TMonster;
+begin
+ if not assigned(cb) then begin result := nil; exit; end;
+ result := monsGrid.forEachAlongLine(x0, y0, x1, y1, cb, -1, log);
+end;
//WARNING! call this after monster position was changed, or coldet will not work right!
var
x, y: Integer;
begin
- {$IF DEFINED(D2F_DEBUG)}
+ {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
//e_WriteLog(Format('monster #%d(%u): pos=(%d,%d); rpos=(%d,%d)', [arrIdx, UID, FObj.X, FObj.Y, FObj.Rect.X, FObj.Rect.Y]), MSG_NOTIFY);
{$ENDIF}
- if (treeNode = -1) then
+ if (proxyId = -1) then
begin
- treeNode := monsTree.insertObject(self, 0);
- {$IF DEFINED(D2F_DEBUG)}
- monsTree.getNodeXY(treeNode, x, y);
- e_WriteLog(Format('monster #%d(%u): inserted into the tree; nodeid=%d; x=%d; y=%d', [arrIdx, UID, treeNode, x, y]), MSG_NOTIFY);
+ proxyId := monsGrid.insertBody(self, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height);
+ {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
+ monsGrid.getBodyXY(proxyId, x, y);
+ e_WriteLog(Format('monster #%d(%u): inserted into the grid; proxyid=%d; x=%d; y=%d', [arrIdx, UID, proxyId, x, y]), MSG_NOTIFY);
{$ENDIF}
end
else
begin
- monsTree.getNodeXY(treeNode, x, y);
+ monsGrid.getBodyXY(proxyId, x, y);
if (FObj.X+FObj.Rect.X = x) and (FObj.Y+FObj.Rect.Y = y) then exit; // nothing to do
- {$IF DEFINED(D2F_DEBUG)}e_WriteLog(Format('monster #%d(%u): updating tree; nodeid=%d; x=%d; y=%d', [arrIdx, UID, treeNode, x, y]), MSG_NOTIFY);{$ENDIF}
+ {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}e_WriteLog(Format('monster #%d(%u): updating tree; proxyid=%d; x=%d; y=%d', [arrIdx, UID, proxyId, x, y]), MSG_NOTIFY);{$ENDIF}
- {$IFDEF TRUE}
- monsTree.updateObject(treeNode);
+ {$IF TRUE}
+ monsGrid.moveBody(proxyId, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y);
{$ELSE}
- monsTree.removeObject(treeNode);
- treeNode := monsTree.insertObject(self);
+ monsGrid.removeBody(proxyId);
+ proxyId := monsGrid.insertBody(self, FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, FObj.Rect.Width, FObj.Rect.Height);
{$ENDIF}
- {$IF DEFINED(D2F_DEBUG)}
- monsTree.getNodeXY(treeNode, x, y);
- e_WriteLog(Format('monster #%d(%u): updated tree; nodeid=%d; x=%d; y=%d', [arrIdx, UID, treeNode, x, y]), MSG_NOTIFY);
+ {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
+ monsGrid.getBodyXY(proxyId, x, y);
+ e_WriteLog(Format('monster #%d(%u): updated tree; proxyid=%d; x=%d; y=%d', [arrIdx, UID, proxyId, x, y]), MSG_NOTIFY);
{$ENDIF}
end;
end;
Result := False;
end;
+
function BehaviourDamage(SpawnerUID: Word; BH, SelfType: Byte): Boolean;
var
m: TMonster;
end;
end;
+
function canShoot(m: Byte): Boolean;
begin
Result := False;
end;
end;
-function isCorpse(o: PObj; immediately: Boolean): Integer;
+
+function isCorpse (o: PObj; immediately: Boolean): Integer;
function monsCollCheck (mon: TMonster; atag: Integer): Boolean;
begin
+ atag := atag; // shut up, fpc!
result := false; // don't stop
if (mon.FState = STATE_DEAD) and g_Obj_Collide(o, @mon.FObj) then
begin
// Èùåì ìåðòâûõ ìîíñòðîâ ïîáëèçîñòè
if gmon_debug_use_sqaccel then
begin
- mon := monsTree.aabbQuery(o.X+o.Rect.X, o.Y+o.Rect.Y, o.Rect.Width, o.Rect.Height, monsCollCheck);
+ mon := monsGrid.forEachInAABB(o.X+o.Rect.X, o.Y+o.Rect.Y, o.Rect.Width, o.Rect.Height, monsCollCheck);
if (mon <> nil) then result := mon.arrIdx;
end
else
g_Sound_CreateWADEx('SOUND_MONSTER_FISH_ATTACK', GameWAD+':MSOUNDS\FISH_ATTACK');
- monsTree := TDynAABBTreeMons.Create();
clearUidMap();
monCheckTrapLastFrameId := 0;
end;
g_Sound_Delete('SOUND_MONSTER_SPIDER_WALK');
g_Sound_Delete('SOUND_MONSTER_FISH_ATTACK');
-
- monsTree.Free();
end;
procedure g_Monsters_Init();
var
a: Integer;
begin
- monsTree.reset();
+ monsGrid.Free();
+ monsGrid := nil;
for a := 0 to High(gMonsters) do gMonsters[a].Free();
gMonsters := nil;
clearUidMap();
monCheckTrapLastFrameId := 0;
end;
+
+// will be called from map loader
+procedure g_Mons_InitTree (x, y, w, h: Integer);
+begin
+ monsGrid.Free();
+ monsGrid := TMonsterGrid.Create(x, y, w, h);
+end;
+
+
function g_Monsters_Create(MonsterType: Byte; X, Y: Integer;
Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster;
var
mon := TMonster.Create(MonsterType, find_id, ForcedUID);
gMonsters[find_id] := mon;
mon.arrIdx := find_id;
- mon.treeNode := -1;
+ mon.proxyId := -1;
uidMap[mon.FUID] := mon;
gMon := True; // Äëÿ ðàáîòû BlockMon'à
- for a := 0 to High(gMonsters) do
+ if (gmon_debug_think) then
begin
- if (gMonsters[a] = nil) then continue;
- if not gMonsters[a].FRemoved then
+ for a := 0 to High(gMonsters) do
begin
- if g_Game_IsClient then
- gMonsters[a].ClientUpdate()
+ 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
- gMonsters[a].Update();
- end
- else
- begin
- gMonsters[a].Free();
- gMonsters[a] := nil;
+ begin
+ gMonsters[a].Free();
+ gMonsters[a] := nil;
+ end;
end;
end;
constructor TMonster.Create(MonsterType: Byte; aID: Integer; ForcedUID: Integer = -1);
var
a: Integer;
- FramesID: DWORD;
+ FramesID: DWORD = 0;
s: String;
res: Boolean;
begin
FFirePainTime := 0;
FFireAttacker := 0;
- treeNode := -1;
+ proxyId := -1;
arrIdx := -1;
trapCheckFrameId := 0;
vilefire.Free();
- if (treeNode <> -1) then
+ if (proxyId <> -1) then
begin
- if monsTree.isValidId(treeNode) then
+ if (monsGrid <> nil) then
begin
- {$IF DEFINED(D2F_DEBUG)}
- e_WriteLog(Format('monster #%d(%u): removed from tree; nodeid=%d', [arrIdx, UID, treeNode]), MSG_NOTIFY);
+ monsGrid.removeBody(proxyId);
+ {$IF DEFINED(D2F_DEBUG_MONS_MOVE)}
+ e_WriteLog(Format('monster #%d(%u): removed from tree; proxyid=%d', [arrIdx, UID, proxyId]), MSG_NOTIFY);
{$ENDIF}
- monsTree.removeObject(treeNode);
end;
+ proxyId := -1;
end;
- if (arrIdx <> -1) then
- begin
- gMonsters[arrIdx] := nil;
- end;
+ if (arrIdx <> -1) and (arrIdx < Length(gMonsters)) then gMonsters[arrIdx] := nil;
+ arrIdx := -1;
uidMap[FUID] := nil;
mon := gMonsters[idx];
if (mon <> nil) then
begin
- result := cb(idx, gMonsters[idx]);
+ result := cb(mon);
if result then exit;
end;
end;
mon := gMonsters[idx];
if (mon <> nil) and mon.Live then
begin
- result := cb(idx, gMonsters[idx]);
+ result := cb(mon);
if result then exit;
end;
end;
@@ -4477,7 +4551,7 @@ function g_Mons_IsAnyAliveAt (x, y: Integer; width, height: Integer): Boolean;
function monsCollCheck (mon: TMonster; atag: Integer): Boolean;
begin
- result := (mon.Live and g_Obj_Collide(x, y, width, height, @mon.Obj));
+ result := mon.Live;// and g_Obj_Collide(x, y, width, height, @mon.Obj));
end;
var
if (width < 1) or (height < 1) then exit;
if gmon_debug_use_sqaccel then
begin
- result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil);
+ result := (monsGrid.forEachInAABB(x, y, width, height, monsCollCheck) <> nil);
end
else
begin
@@ -4512,8 +4586,7 @@ function g_Mons_ForEachAt (x, y: Integer; width, height: Integer; cb: TEachMonst
function monsCollCheck (mon: TMonster; atag: Integer): Boolean;
begin
- result := false;
- if g_Obj_Collide(x, y, width, height, @mon.Obj) then result := cb(mon.arrIdx, mon);
+ result := cb(mon);
end;
var
if (width < 1) or (height < 1) then exit;
if gmon_debug_use_sqaccel then
begin
- result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil);
+ result := (monsGrid.forEachInAABB(x, y, width, height, monsCollCheck) <> nil);
end
else
begin
begin
if g_Obj_Collide(x, y, width, height, @mon.Obj) then
begin
- result := cb(idx, mon);
+ result := cb(mon);
if result then exit;
end;
end;
@@ -4548,8 +4621,9 @@ function g_Mons_ForEachAliveAt (x, y: Integer; width, height: Integer; cb: TEach
function monsCollCheck (mon: TMonster; atag: Integer): Boolean;
begin
- result := false;
- if mon.Live and g_Obj_Collide(x, y, width, height, @mon.Obj) then result := cb(mon.arrIdx, mon);
+ //result := false;
+ //if mon.Live and g_Obj_Collide(x, y, width, height, @mon.Obj) then result := cb(mon);
+ if mon.Live then result := cb(mon) else result := false;
end;
var
begin
if (width = 1) and (height = 1) then
begin
- result := (monsTree.pointQuery(x, y, monsCollCheck) <> nil);
+ result := (monsGrid.forEachAtPoint(x, y, monsCollCheck) <> nil);
end
else
begin
- result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil);
+ result := (monsGrid.forEachInAABB(x, y, width, height, monsCollCheck) <> nil);
end;
end
else
begin
if g_Obj_Collide(x, y, width, height, @mon.Obj) then
begin
- result := cb(idx, mon);
+ result := cb(mon);
if result then exit;
end;
end;