summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 9a9d791)
raw | patch | inline | side by side (parent: 9a9d791)
author | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Sun, 20 Aug 2017 03:35:37 +0000 (06:35 +0300) | ||
committer | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Sun, 20 Aug 2017 05:33:44 +0000 (08:33 +0300) |
diff --git a/src/game/g_basic.pas b/src/game/g_basic.pas
index e001f8567a3af1ad810da064330ec9cb595d0183..626596b01878e2154c7ac0caf6ff9b8f275b97b5 100644 (file)
--- a/src/game/g_basic.pas
+++ b/src/game/g_basic.pas
function g_CollideAround(X1, Y1: Integer; Width1, Height1: Word;
X2, Y2: Integer; Width2, Height2: Word): Boolean;
function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean;
-function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean;
function g_PatchLength(X1, Y1, X2, Y2: Integer): Word;
function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean;
function g_GetAcidHit(X, Y: Integer; Width, Height: Word): Byte;
end;
end;
-function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean;
-begin
- result := g_Mons_AnyAt(X, Y, Width, Height);
-end;
-
function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean;
var
i: Integer;
diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas
index d1149adf46c64d47c5790f5731c2ea56e90ea278..8ff01a629340b582ad58c0cb40046f8b80c251a3 100644 (file)
--- a/src/game/g_grid.pas
+++ b/src/game/g_grid.pas
mProxyCount := 0;
mProxyMaxCount := 0;
mUData := 0;
- mTagMask := 0;
+ mTagMask := -1;
mItCB := nil;
e_WriteLog(Format('created grid with size: %dx%d (tile size: %d); pix: %dx%d', [mWidth, mHeight, mTileSize, mWidth*mTileSize, mHeight*mTileSize]), MSG_NOTIFY);
end;
begin
if (pi.bodies[f] = -1) then break;
px := @mProxies[pi.bodies[f]];
- if (px.mQueryMark <> mLastQuery) and ((px.mTag and mTagMask) <> 0) then
+ if (px.mQueryMark <> mLastQuery) and ((mTagMask = -1) or ((px.mTag and mTagMask) <> 0)) then
begin
//e_WriteLog(Format(' query #%d body hit: (%d,%d)-(%dx%d) tag:%d', [mLastQuery, mCells[idx].body.mX, mCells[idx].body.mY, mCells[idx].body.mWidth, mCells[idx].body.mHeight, mCells[idx].body.mTag]), MSG_NOTIFY);
px.mQueryMark := mLastQuery;
if (mCells[idx].body <> -1) then
begin
px := @mProxies[mCells[idx].body];
- if (px.mQueryMark <> mLastQuery) and ((px.mTag and mTagMask) <> 0) then
+ if (px.mQueryMark <> mLastQuery) and ((mTagMask = -1) or ((px.mTag and mTagMask) <> 0)) then
begin
//e_WriteLog(Format(' query #%d body hit: (%d,%d)-(%dx%d) tag:%d', [mLastQuery, mCells[idx].body.mX, mCells[idx].body.mY, mCells[idx].body.mWidth, mCells[idx].body.mHeight, mCells[idx].body.mTag]), MSG_NOTIFY);
px.mQueryMark := mLastQuery;
diff --git a/src/game/g_items.pas b/src/game/g_items.pas
index 95ea919ca31007ae9c90257f1e49cc1b555e2c85..eb122d80c4535816860eaa4710c775e7b43f7dd6 100644 (file)
--- a/src/game/g_items.pas
+++ b/src/game/g_items.pas
PItem = ^TItem;
TItem = record
private
- treeNode: Integer;
+ //treeNode: Integer;
+ slotIsUsed: Boolean;
arrIdx: Integer; // in ggItems
public
procedure g_Items_RestartRound ();
-function g_ItemValidId (idx: Integer): Boolean; inline;
-function g_ItemByIdx (idx: Integer): PItem;
-function g_ItemObjByIdx (idx: Integer): PObj;
+function g_Items_ValidId (idx: Integer): Boolean; inline;
+function g_Items_ByIdx (idx: Integer): PItem;
+function g_Items_ObjByIdx (idx: Integer): PObj;
-procedure g_Item_EmitPickupSound (idx: Integer); // at item position
-procedure g_Item_EmitPickupSoundAt (idx, x, y: Integer);
+procedure g_Items_EmitPickupSound (idx: Integer); // at item position
+procedure g_Items_EmitPickupSoundAt (idx, x, y: Integer);
type
end;
}
+
// ////////////////////////////////////////////////////////////////////////// //
var
//itemTree: TDynAABBTreeItem = nil;
// ////////////////////////////////////////////////////////////////////////// //
-function g_ItemValidId (idx: Integer): Boolean; inline;
+function g_Items_ValidId (idx: Integer): Boolean; inline;
begin
result := false;
if (idx < 0) or (idx > High(ggItems)) then exit;
- if (ggItems[idx].treeNode = -1) then exit;
+ //if (ggItems[idx].treeNode = -1) then exit;
+ if not ggItems[idx].slotIsUsed then exit;
result := true;
end;
-function g_ItemByIdx (idx: Integer): PItem;
+function g_Items_ByIdx (idx: Integer): PItem;
begin
if (idx < 0) or (idx > High(ggItems)) then raise Exception.Create('g_ItemObjByIdx: invalid index');
result := @ggItems[idx];
- if (result.treeNode = -1) then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
+ //if (result.treeNode = -1) then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
+ if not result.slotIsUsed then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
end;
-function g_ItemObjByIdx (idx: Integer): PObj;
+function g_Items_ObjByIdx (idx: Integer): PObj;
begin
if (idx < 0) or (idx > High(ggItems)) then raise Exception.Create('g_ItemObjByIdx: invalid index');
- if (ggItems[idx].treeNode = -1) then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
+ //if (ggItems[idx].treeNode = -1) then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
+ if not ggItems[idx].slotIsUsed then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
result := @ggItems[idx].Obj;
end;
begin
if (idx < 0) or (idx > High(ggItems)) then raise Exception.Create('releaseItem: invalid item id');
it := @ggItems[idx];
- if (it.treeNode = -1) then raise Exception.Create('releaseItem: trying to release unallocated item');
+ //if (it.treeNode = -1) then raise Exception.Create('releaseItem: trying to release unallocated item');
+ if not it.slotIsUsed then raise Exception.Create('releaseItem: trying to release unallocated item');
if (it.arrIdx <> idx) then raise Exception.Create('releaseItem: arrIdx inconsistency');
//itemTree.removeObject(it.treeNode);
- it.treeNode := -1;
+ //it.treeNode := -1;
+ it.slotIsUsed := false;
if (it.Animation <> nil) then
begin
it.Animation.Free();
for i := olen to High(ggItems) do
begin
it := @ggItems[i];
- it.treeNode := -1;
+ //it.treeNode := -1;
+ it.slotIsUsed := false;
it.arrIdx := i;
it.ItemType := ITEM_NONE;
it.Animation := nil;
for i := olen to High(ggItems) do
begin
it := @ggItems[i];
- it.treeNode := -1;
+ //it.treeNode := -1;
+ it.slotIsUsed := false;
it.arrIdx := i;
it.ItemType := ITEM_NONE;
it.Animation := nil;
end;
it := @ggItems[slot];
- if (it.treeNode = -1) then
+ if {(it.treeNode = -1)} not it.slotIsUsed then
begin
// this is unused slot; get it, and rebuild id list
if rebuildFreeList then
freeIds.clear();
for i := 0 to High(ggItems) do
begin
- if (i <> slot) and (ggItems[i].treeNode = -1) then freeIds.insert(i);
+ if (i <> slot) and {(ggItems[i].treeNode = -1)} (not it.slotIsUsed) then freeIds.insert(i);
end;
end;
end
begin
// it will be readded
//itemTree.removeObject(it.treeNode);
- it.treeNode := -1;
+ //it.treeNode := -1;
+ it.slotIsUsed := false;
end;
result := slot;
it := @ggItems[find_id];
+ //if (it.treeNode <> -1) then raise Exception.Create('g_Items_Create: trying to reuse already allocated item');
+ if (it.arrIdx <> find_id) then raise Exception.Create('g_Items_Create: arrIdx inconsistency');
+ //it.treeNode := -1;
+ //it.arrIdx := find_id;
+ it.slotIsUsed := true;
+
it.ItemType := ItemType;
it.Respawnable := Respawnable;
if g_Game_IsServer and (ITEM_RESPAWNTIME = 0) then it.Respawnable := False;
it.Live := True;
it.QuietRespawn := False;
- if (it.treeNode <> -1) then raise Exception.Create('g_Items_Create: trying to reuse already allocated item');
- if (it.arrIdx <> find_id) then raise Exception.Create('g_Items_Create: arrIdx inconsistency');
- //it.treeNode := -1;
- //it.arrIdx := find_id;
-
g_Obj_Init(@it.Obj);
it.Obj.X := X;
it.Obj.Y := Y;
+2. I_MEGA,I_INVL,I_SUPER
3. I_STIM,I_MEDI,I_ARM1,I_ARM2,I_AQUA,I_KEYR,I_KEYG,I_KEYB,I_SUIT,I_RTORCH,I_GTORCH,I_BTORCH,I_GOR1,I_FCAN
}
- g_Item_EmitPickupSoundAt(i, gPlayers[j].Obj.X, gPlayers[j].Obj.Y);
+ g_Items_EmitPickupSoundAt(i, gPlayers[j].Obj.X, gPlayers[j].Obj.Y);
// Íàäî óáðàòü ñ êàðòû, åñëè ýòî íå êëþ÷, êîòîðûì íóæíî ïîäåëèòüñÿ ñ äðóãèì èãðîêîì
if r then
//x, y: Integer;
{$ENDIF}
begin
- if not g_ItemValidId(ID) then raise Exception.Create('g_Items_Remove: invalid item id');
+ if not g_Items_ValidId(ID) then raise Exception.Create('g_Items_Remove: invalid item id');
it := @ggItems[ID];
if (it.arrIdx <> ID) then raise Exception.Create('g_Items_Remove: arrIdx desync');
// ////////////////////////////////////////////////////////////////////////// //
-procedure g_Item_EmitPickupSound (idx: Integer);
+procedure g_Items_EmitPickupSound (idx: Integer);
var
it: PItem;
begin
- if not g_ItemValidId(idx) then exit;
+ if not g_Items_ValidId(idx) then exit;
it := @ggItems[idx];
- g_Item_EmitPickupSoundAt(idx, it.Obj.X, it.Obj.Y);
+ g_Items_EmitPickupSoundAt(idx, it.Obj.X, it.Obj.Y);
end;
-procedure g_Item_EmitPickupSoundAt (idx, x, y: Integer);
+procedure g_Items_EmitPickupSoundAt (idx, x, y: Integer);
var
it: PItem;
begin
- if not g_ItemValidId(idx) then exit;
+ if not g_Items_ValidId(idx) then exit;
it := @ggItems[idx];
if gSoundEffectsDF then
index af98abae75f8936317a489592ebc0656dbb6e000..59b5506a5ee732d02bde51f54f49820dedc7a1c2 100644 (file)
--- a/src/game/g_monsters.pas
+++ b/src/game/g_monsters.pas
FFireAttacker: Word;
vilefire: TAnimation;
+ treeNode: Integer; // node in dyntree or -1
+ arrIdx: Integer; // in gMonsters
+
FDieTriggers: Array of Integer;
FSpawnTrigger: Integer;
// can return null
function g_Mons_ByIdx_NC (uid: Integer): TMonster; inline;
-function g_Mons_AnyAt (x, y: Integer; width, height: Integer): Boolean;
+function g_Mons_IsAnyAliveAt (x, y: Integer; width, height: Integer): Boolean;
+
+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;
+
+
+var
+ gmon_debug_use_sqaccel: Boolean = true;
implementation
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;
+ g_language, g_netmsg, z_aabbtree;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+type
+ TDynAABBTreeMonsBase = specialize TDynAABBTreeBase<TMonster>;
+
+ 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;
+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;
+end;
+
+
+var
+ monsTree: TDynAABBTreeMons = nil;
+
+
+//WARNING! call this after monster position was changed, or coldet will not work right!
+procedure TMonster.positionChanged ();
+var
+ x, y: Integer;
+begin
+ {$IF DEFINED(D2F_DEBUG)}
+ //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
+ 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);
+ {$ENDIF}
+ end
+ else
+ begin
+ monsTree.getNodeXY(treeNode, 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}
+
+ {$IFDEF TRUE}
+ monsTree.updateObject(treeNode);
+ {$ELSE}
+ monsTree.removeObject(treeNode);
+ treeNode := monsTree.insertObject(self);
+ {$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);
+ {$ENDIF}
+ end;
+end;
+
+// ////////////////////////////////////////////////////////////////////////// //
const
ANIM_SLEEP = 0;
ANIM_GO = 1;
MAX_ATM = 89; // Âðåìÿ îæèäàíèÿ ïîñëå ïîòåðè öåëè
MAX_SOUL = 512; // Îãðàíè÷åíèå Lost_Soul'îâ
+
var
gMonsters: array of TMonster;
pt_ys: Integer = 1;
soulcount: Integer = 0;
-function FindMonster(): DWORD;
+
+function allocMonster(): DWORD;
var
- i: Integer;
+ i, olen: Integer;
begin
- if gMonsters <> nil then
- for i := 0 to High(gMonsters) do
- if gMonsters[i] = nil then
- begin
- Result := i;
- Exit;
- end;
-
- if gMonsters = nil then
- begin
- SetLength(gMonsters, 32);
- Result := 0;
- end
- else
+ for i := 0 to High(gMonsters) do
+ begin
+ if (gMonsters[i] = nil) then
begin
- Result := High(gMonsters) + 1;
- SetLength(gMonsters, Length(gMonsters) + 32);
+ result := i;
+ exit;
end;
+ end;
+
+ olen := Length(gMonsters);
+ if (olen = 0) then
+ begin
+ SetLength(gMonsters, 64);
+ result := 0;
+ end
+ else
+ begin
+ result := olen;
+ SetLength(gMonsters, Length(gMonsters)+32);
+ end;
end;
+
function IsFriend(a, b: Byte): Boolean;
begin
Result := True;
end;
function isCorpse(o: PObj; immediately: Boolean): Integer;
+
+ function monsCollCheck (mon: TMonster; atag: Integer): Boolean;
+ begin
+ result := false; // don't stop
+ if (mon.FState = STATE_DEAD) and g_Obj_Collide(o, @mon.FObj) then
+ begin
+ case mon.FMonsterType of // Íå âîñêðåñèòü:
+ MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER,
+ MONSTER_VILE, MONSTER_BARREL, MONSTER_ROBO: exit;
+ end;
+ // Îñòàëüíûõ ìîæíî âîñêðåñèòü
+ result := true;
+ end;
+ end;
+
var
a: Integer;
+ mon: TMonster;
begin
- Result := -1;
-
-// Åñëè íóæíà âåðîÿòíîñòü:
- if not immediately then
- if Random(8) <> 0 then
- Exit;
+ result := -1;
- if gMonsters = nil then
- Exit;
+ // Åñëè íóæíà âåðîÿòíîñòü
+ if not immediately and (Random(8) <> 0) then exit;
-// Èùåì ìåðòâûõ ìîíñòðîâ ïîáëèçîñòè:
- for a := 0 to High(gMonsters) do
- if (gMonsters[a] <> nil) and (gMonsters[a].FState = STATE_DEAD) then
- if g_Obj_Collide(o, @gMonsters[a].FObj) then
+ // Èùåì ìåðòâûõ ìîíñòðîâ ïîáëèçîñòè
+ 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);
+ if (mon <> nil) then result := mon.arrIdx;
+ end
+ else
+ begin
+ for a := 0 to High(gMonsters) do
+ begin
+ if (gMonsters[a] <> nil) and (gMonsters[a].FState = STATE_DEAD) and g_Obj_Collide(o, @gMonsters[a].FObj) then
+ begin
case gMonsters[a].FMonsterType of // Íå âîñêðåñèòü:
MONSTER_SOUL, MONSTER_PAIN, MONSTER_CYBER, MONSTER_SPIDER,
MONSTER_VILE, MONSTER_BARREL, MONSTER_ROBO: Continue;
Exit;
end;
end;
+ end;
+ end;
+ end;
end;
procedure g_Monsters_LoadData();
g_Sound_CreateWADEx('SOUND_MONSTER_SPIDER_WALK', GameWAD+':MSOUNDS\SPIDER_WALK');
g_Sound_CreateWADEx('SOUND_MONSTER_FISH_ATTACK', GameWAD+':MSOUNDS\FISH_ATTACK');
+
+ monsTree := TDynAABBTreeMons.Create();
end;
procedure g_Monsters_FreeData();
g_Sound_Delete('SOUND_MONSTER_SPIDER_WALK');
g_Sound_Delete('SOUND_MONSTER_FISH_ATTACK');
+
+ monsTree.Free();
end;
procedure g_Monsters_Init();
for a := 0 to High(gMonsters) do
gMonsters[a].Free();
+ monsTree.reset();
gMonsters := nil;
end;
Direction: TDirection; AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster;
var
find_id: DWORD;
+ mon: TMonster;
begin
result := nil;
soulcount := soulcount + 1;
end;
- find_id := FindMonster();
+ find_id := allocMonster();
- gMonsters[find_id] := TMonster.Create(MonsterType, find_id, ForcedUID);
+ mon := TMonster.Create(MonsterType, find_id, ForcedUID);
+ gMonsters[find_id] := mon;
+ mon.arrIdx := find_id;
+ mon.treeNode := -1;
// Íàñòðàèâàåì ïîëîæåíèå
- with gMonsters[find_id] do
+ with mon do
begin
if AdjCoord then
begin
FStartY := GameY;
end;
- result := {find_id}gMonsters[find_id];
+ mon.positionChanged();
+
+ result := mon;
end;
procedure g_Monsters_killedp();
FFirePainTime := 0;
FFireAttacker := 0;
+ treeNode := -1;
+ arrIdx := -1;
+
if FMonsterType in [MONSTER_ROBO, MONSTER_BARREL] then
FBloodKind := BLOOD_SPARKS
else
it := g_Items_Create(FObj.X + (FObj.Rect.Width div 2),
FObj.Y + (FObj.Rect.Height div 2),
c, True, False);
- g_Obj_Push(g_ItemObjByIdx(it), (FObj.Vel.X div 2)-3+Random(7),
- (FObj.Vel.Y div 2)-Random(4));
+ g_Obj_Push(g_Items_ObjByIdx(it), (FObj.Vel.X div 2)-3+Random(7),
+ (FObj.Vel.Y div 2)-Random(4));
positionChanged(); // this updates spatial accelerators
if g_Game_IsServer and g_Game_IsNet then
MH_SEND_ItemSpawn(True, it);
vilefire.Free();
+ 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);
+ end;
+
inherited Destroy();
end;
FObj.X := X - FObj.Rect.X;
FObj.Y := Y - FObj.Rect.Y;
+ positionChanged();
if dir = 1 then
FDirection := D_LEFT
if g_Obj_CollideLevel(@FObj, 0, 1) or g_Obj_StayOnStep(@FObj) then
begin // "Ñòîèò" òâåðäî
// Ðûáà òðåïûõàåòñÿ íà ïîâåðõíîñòè:
- if FObj.Accel.Y = 0 then
- FObj.Vel.Y := -6;
+ if FObj.Accel.Y = 0 then FObj.Vel.Y := -6;
FObj.Accel.X := FObj.Accel.X - 8 + Random(17);
end;
begin
g_Obj_PushA(@gGibs[a].Obj, b, Random(61)); // íàïðàâî
end;
- positionChanged(); // this updates spatial accelerators
end;
end;
end;
end;
end;
-//WARNING! call this after monster position was changed, or coldet will not work right!
-procedure TMonster.positionChanged ();
-begin
-end;
-
// ////////////////////////////////////////////////////////////////////////// //
function g_Mons_ForEach (cb: TEachMonsterCB): Boolean;
end;
-function g_Mons_AnyAt (x, y: Integer; width, height: Integer): Boolean;
+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));
+ end;
+
var
idx: Integer;
begin
result := false;
if (width < 1) or (height < 1) then exit;
- for idx := 0 to High(gMonsters) do
+ if gmon_debug_use_sqaccel then
begin
- if (gMonsters[idx] <> nil) and gMonsters[idx].Live then
+ result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil);
+ end
+ else
+ begin
+ for idx := 0 to High(gMonsters) do
begin
- if g_Obj_Collide(x, y, width, height, @gMonsters[idx].Obj) then
+ if (gMonsters[idx] <> nil) and gMonsters[idx].Live then
begin
- result := True;
- exit;
+ if g_Obj_Collide(x, y, width, height, @gMonsters[idx].Obj) then
+ begin
+ result := true;
+ exit;
+ end;
+ end;
+ end;
+ end;
+end;
+
+
+function g_Mons_ForEachAt (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean;
+
+ 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);
+ end;
+
+var
+ idx: Integer;
+begin
+ result := false;
+ if (width < 1) or (height < 1) then exit;
+
+ if gmon_debug_use_sqaccel then
+ begin
+ result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil);
+ end
+ else
+ begin
+ 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 := cb(idx, gMonsters[idx]);
+ if result then exit;
+ end;
+ end;
+ end;
+ end;
+end;
+
+
+function g_Mons_ForEachAtAlive (x, y: Integer; width, height: Integer; cb: TEachMonsterCB): Boolean;
+
+ 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);
+ end;
+
+var
+ idx: Integer;
+begin
+ result := false;
+ if (width < 1) or (height < 1) then exit;
+
+ if gmon_debug_use_sqaccel then
+ begin
+ if (width = 1) and (height = 1) then
+ begin
+ result := (monsTree.pointQuery(x, y, monsCollCheck) <> nil);
+ end
+ else
+ begin
+ result := (monsTree.aabbQuery(x, y, width, height, monsCollCheck) <> nil);
+ end;
+ end
+ else
+ begin
+ 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 := cb(idx, gMonsters[idx]);
+ if result then exit;
+ end;
end;
end;
end;
diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index 7499fc260112bda3621a18db0fcb416f737d0a21..94326281ae68a2627669144725ed9f0b9aae50c0 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
@@ -1190,7 +1190,7 @@ procedure MH_SEND_ItemSpawn(Quiet: Boolean; IID: Word; ID: Integer = NET_EVERYON
var
it: PItem;
begin
- it := g_ItemByIdx(IID);
+ it := g_Items_ByIdx(IID);
NetOut.Write(Byte(NET_MSG_ISPAWN));
NetOut.Write(IID);
g_Items_Create(X, Y, T, Fall, False, False, ID);
- it := g_ItemByIdx(ID);
+ it := g_Items_ByIdx(ID);
it.Obj.Vel.X := VX;
it.Obj.Vel.Y := VY;
ID := M.ReadWord();
Quiet := M.ReadByte() <> 0;
- if not g_ItemValidId(ID) then exit;
+ if not g_Items_ValidId(ID) then exit;
- if not Quiet then g_Item_EmitPickupSound(ID);
+ if not Quiet then g_Items_EmitPickupSound(ID);
g_Items_Remove(ID);
end;
diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index 75366d34590e693d5c82b50f235ee20adcc27f04..c1b7c087645cce6d7e413ff3237812e18e5a06ca 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
id: DWORD;
begin
id := g_Items_Create(FObj.X, FObj.Y, t, True, False);
- it := g_ItemByIdx(id);
+ it := g_Items_ByIdx(id);
if KillType = K_EXTRAHARDKILL then // -7..+7; -8..0
begin
g_Obj_Push(@it.Obj, (FObj.Vel.X div 2)-7+Random(15),
index ec3bb7144f67e6ae7f1c2f05c62890134968af8a..4fefb5d34b612cda301c2ed28f1734235b8e8867 100644 (file)
--- a/src/game/g_triggers.pas
+++ b/src/game/g_triggers.pas
with gWalls[PanelID] do
begin
if g_CollidePlayer(X, Y, Width, Height) or
- g_CollideMonster(X, Y, Width, Height) then Exit;
+ g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
if not Enabled then
begin
with gWalls[gDoorMap[c, b]] do
begin
if g_CollidePlayer(X, Y, Width, Height) or
- g_CollideMonster(X, Y, Width, Height) then Exit;
+ g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
end;
if not NoSound then
if Data.ItemMax > 0 then
begin
- it := g_ItemByIdx(iid);
+ it := g_Items_ByIdx(iid);
it.SpawnTrigger := ID;
Inc(SpawnedCount);
end;
case Data.ItemEffect of
EFFECT_TELEPORT: begin
- it := g_ItemByIdx(iid);
+ it := g_Items_ByIdx(iid);
if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
begin
Anim := TAnimation.Create(FramesID, False, 3);
NET_GFX_TELE);
end;
EFFECT_RESPAWN: begin
- it := g_ItemByIdx(iid);
+ it := g_Items_ByIdx(iid);
if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
begin
Anim := TAnimation.Create(FramesID, False, 4);
NET_GFX_RESPAWN);
end;
EFFECT_FIRE: begin
- it := g_ItemByIdx(iid);
+ it := g_Items_ByIdx(iid);
if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
begin
Anim := TAnimation.Create(FramesID, False, 4);
a, b, i: Integer;
Affected: array of Integer;
- function monsNear (monidx: Integer; mon: TMonster): Boolean;
+ {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
gTriggers[a].ActivateUID := mon.UID;
ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE);
end;
+ end;}
+
+ function monsNear (monidx: Integer; mon: TMonster): Boolean;
+ begin
+ result := false; // don't stop
+ gTriggers[a].ActivateUID := mon.UID;
+ ActivateTrigger(gTriggers[a], ACTIVATE_MONSTERCOLLIDE);
end;
begin
if ByteBool(ActivateType and ACTIVATE_MONSTERCOLLIDE) and
(TimeOut = 0) and (Keys = 0) then // Åñëè íå íóæíû êëþ÷è
begin
- g_Mons_ForEach(monsNear);
+ //g_Mons_ForEach(monsNear);
+ g_Mons_ForEachAt(gTriggers[a].X, gTriggers[a].Y, gTriggers[a].Width, gTriggers[a].Height, monsNear);
end;
// "Ìîíñòðîâ íåò"
if ByteBool(ActivateType and ACTIVATE_NOMONSTER) and
(TimeOut = 0) and (Keys = 0) then
- if not g_CollideMonster(X, Y, Width, Height) then
+ if not g_Mons_IsAnyAliveAt(X, Y, Width, Height) then
begin
gTriggers[a].ActivateUID := 0;
ActivateTrigger(gTriggers[a], ACTIVATE_NOMONSTER);
diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas
index 2cdfe87a09935a9dac8cebba83412243a47ed6cf..f8028eef33fc30d94871d95b80759ae45421593c 100644 (file)
--- a/src/game/g_weapons.pas
+++ b/src/game/g_weapons.pas
function GunHit(X, Y: Integer; vx, vy: Integer; dmg: Integer;
SpawnerUID: Word; AllowPush: Boolean): Byte;
- function monsCheck (monidx: Integer; mon: TMonster): Boolean;
+ {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
+ if mon.Live and mon.Collide(X, Y) then
begin
if HitMonster(mon, dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
begin
result := true;
end;
end;
+ end;}
+
+ function monsCheck (monidx: Integer; mon: TMonster): Boolean;
+ begin
+ result := false; // don't stop
+ 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;
var
if Result <> 0 then Exit;
- if g_Mons_ForEach(monsCheck) then result := 2;
+ //if g_Mons_ForEach(monsCheck) then result := 2;
+ if g_Mons_ForEachAtAlive(X, Y, 1, 1, monsCheck) then result := 2;
end;
procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
index 3371a1ea82e90e17db293748e4c43b581ba4ce72..996230d258244b9fed0818eca65ab2ecb3a3074a 100644 (file)
--- a/src/game/z_aabbtree.pas
+++ b/src/game/z_aabbtree.pas
constructor Create (var aabb: AABB2D); overload;
constructor Create (var aabb0, aabb1: AABB2D); overload;
+ constructor CreateWH (ax, ay, w, h: TreeNumber);
+
procedure copyFrom (var aabb: AABB2D); inline;
procedure setDims (x0, y0, x1, y1: TreeNumber); inline;
// this method creates a new leaf node in the tree and returns the id of the corresponding node or -1 on error
// AABB for static object will not be "fat" (simple optimization)
// WARNING! inserting the same object several times *WILL* break everything!
- function insertObject (flesh: TTreeFlesh; tag: Integer; staticObject: Boolean=false): Integer;
+ function insertObject (flesh: TTreeFlesh; tag: Integer=-1; staticObject: Boolean=false): Integer;
// remove an object from the tree
// WARNING: ids of removed objects can be reused on later insertions!
setMergeTwo(aabb0, aabb1);
end;
+constructor AABB2D.CreateWH (ax, ay, w, h: TreeNumber);
+begin
+ minX := ax;
+ minY := ay;
+ maxX := ax+w-1;
+ maxY := ay+h-1;
+end;
+
function AABB2D.getvalid (): Boolean; inline; begin result := (minX <= maxX) and (minY <= maxY); end;
{$IFDEF aabbtree_use_floats}
begin
// call visitor on it
{$IFDEF aabbtree_query_count}Inc(mNodesDeepVisited);{$ENDIF}
- if ((node.tag and tagmask) <> 0) then
+ if (tagmask = -1) or ((node.tag and tagmask) <> 0) then
begin
if assigned(visitor) then
begin