diff --git a/src/game/g_items.pas b/src/game/g_items.pas
index 95ea919ca31007ae9c90257f1e49cc1b555e2c85..253a0311607bbc2f12f27e4ee4c6a85f2b234e99 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);
+
+procedure g_Items_AddDynLights();
type
var
gItemsTexturesID: Array [1..ITEM_MAX] of DWORD;
- gMaxDist: Integer = 1;
+ gMaxDist: Integer = 1; // for sounds
ITEM_RESPAWNTIME: Integer = 60 * 36;
implementation
g_basic, e_graphics, g_sound, g_main, g_gfx, g_map,
Math, g_game, g_triggers, g_console, SysUtils, g_player, g_net, g_netmsg,
e_log,
- g_grid, z_aabbtree, binheap;
+ g_grid, binheap, idpool;
var
ggItems: Array of TItem = nil;
-// ////////////////////////////////////////////////////////////////////////// //
-{
-type
- TDynAABBTreeItemBase = specialize TDynAABBTreeBase<Integer>;
-
- TDynAABBTreeItem = class(TDynAABBTreeItemBase)
- function getFleshAABB (out aabb: AABB2D; flesh: Integer; tag: Integer): Boolean; override;
- end;
-
-function TDynAABBTreeItem.getFleshAABB (out aabb: AABB2D; flesh: Integer; tag: Integer): Boolean;
-var
- it: PItem;
-begin
- result := false;
- if (flesh < 0) or (flesh > High(ggItems)) then raise Exception.Create('DynTree: trying to get dimensions of inexistant item');
- it := @ggItems[flesh];
- if (it.Obj.Rect.Width < 1) or (it.Obj.Rect.Height < 1) then exit;
- aabb := AABB2D.Create(it.Obj.X, it.Obj.Y, it.Obj.X+it.Obj.Rect.Width-1, it.Obj.Y+it.Obj.Rect.Height-1);
- if not aabb.valid then raise Exception.Create('wutafuuuuuuu?!');
- result := true;
-end;
-}
-
// ////////////////////////////////////////////////////////////////////////// //
var
- //itemTree: TDynAABBTreeItem = nil;
- freeIds: TBinaryHeapInt = nil; // free item ids
+ freeIds: TIdPool = 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 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 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 not ggItems[idx].slotIsUsed then raise Exception.Create('g_ItemObjByIdx: requested inexistent item');
result := @ggItems[idx].Obj;
end;
// ////////////////////////////////////////////////////////////////////////// //
procedure TItem.positionChanged ();
-//var
-// x, y: Integer;
begin
- (*
- if (treeNode = -1) then
- begin
- treeNode := itemTree.insertObject(arrIdx, 0, true); // static object
- {$IF DEFINED(D2F_DEBUG)}
- itemTree.getNodeXY(treeNode, x, y);
- e_WriteLog(Format('item #%d: inserted into the tree; nodeid=%d; x=%d; y=%d', [arrIdx, treeNode, x, y]), MSG_NOTIFY);
- {$ENDIF}
- end
- else
- begin
- itemTree.getNodeXY(treeNode, x, y);
- if (Obj.X = x) and (Obj.Y = y) then exit; // nothing to do
- {$IF DEFINED(D2F_DEBUG)}e_WriteLog(Format('item #%d: updating tree; nodeid=%d; x=%d; y=%d', [arrIdx, treeNode, x, y]), MSG_NOTIFY);{$ENDIF}
-
- {$IFDEF TRUE}
- itemTree.updateObject(treeNode);
- {$ELSE}
- itemTree.removeObject(treeNode);
- treeNode := itemTree.insertObject(arrIdx, 0, true); // static object
- {$ENDIF}
-
- {$IF DEFINED(D2F_DEBUG)}
- itemTree.getNodeXY(treeNode, x, y);
- e_WriteLog(Format('item #%d: updated tree; nodeid=%d; x=%d; y=%d', [arrIdx, treeNode, x, y]), MSG_NOTIFY);
- {$ENDIF}
- end;
- *)
end;
InitTextures();
- //itemTree := TDynAABBTreeItem.Create();
- freeIds := binHeapNewIntLess();
+ freeIds := TIdPool.Create();
end;
g_Texture_Delete('ITEM_MEDKIT_BLACK');
g_Texture_Delete('ITEM_JETPACK');
- //itemTree.Free();
freeIds.Free();
+ freeIds := nil;
end;
it: PItem;
begin
if (idx < 0) or (idx > High(ggItems)) then raise Exception.Create('releaseItem: invalid item id');
+ if not freeIds.hasAlloced[LongWord(idx)] then raise Exception.Create('releaseItem: trying to release unallocated item (0)');
it := @ggItems[idx];
- 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 (1)');
if (it.arrIdx <> idx) then raise Exception.Create('releaseItem: arrIdx inconsistency');
- //itemTree.removeObject(it.treeNode);
- it.treeNode := -1;
+ it.slotIsUsed := false;
if (it.Animation <> nil) then
begin
it.Animation.Free();
it.Live := False;
it.SpawnTrigger := -1;
it.ItemType := ITEM_NONE;
- freeIds.insert(it.arrIdx);
+ freeIds.release(LongWord(idx));
end;
-function allocItem (): DWORD;
+procedure growItemArrayTo (newsz: Integer);
var
i, olen: Integer;
it: PItem;
begin
- if (freeIds.count = 0) then
+ if (newsz < Length(ggItems)) then exit;
+ // no free slots
+ olen := Length(ggItems);
+ SetLength(ggItems, newsz);
+ for i := olen to High(ggItems) do
begin
- // no free slots
- olen := Length(ggItems);
- SetLength(ggItems, olen+64);
- for i := olen to High(ggItems) do
- begin
- it := @ggItems[i];
- it.treeNode := -1;
- it.arrIdx := i;
- it.ItemType := ITEM_NONE;
- it.Animation := nil;
- it.Live := false;
- it.SpawnTrigger := -1;
- it.Respawnable := false;
- freeIds.insert(i);
- end;
+ it := @ggItems[i];
+ it.slotIsUsed := false;
+ it.arrIdx := i;
+ it.ItemType := ITEM_NONE;
+ it.Animation := nil;
+ it.Live := false;
+ it.SpawnTrigger := -1;
+ it.Respawnable := false;
+ //if not freeIds.hasFree[LongWord(i)] then raise Exception.Create('internal error in item idx manager');
end;
+end;
- result := freeIds.front;
- freeIds.popFront();
- if (result > High(ggItems)) then raise Exception.Create('allocItem: freeid list corrupted');
- if (ggItems[result].arrIdx <> result) then raise Exception.Create('allocItem: arrIdx inconsistency');
+function allocItem (): DWORD;
+begin
+ result := freeIds.alloc();
+ if (result >= Length(ggItems)) then growItemArrayTo(Integer(result)+64);
+ if (Integer(result) > High(ggItems)) then raise Exception.Create('allocItem: freeid list corrupted');
+ if (ggItems[result].arrIdx <> Integer(result)) then raise Exception.Create('allocItem: arrIdx inconsistency');
end;
// it will be slow if the slot is free (we have to rebuild the heap)
function wantItemSlot (slot: Integer): Integer;
var
- i, olen: Integer;
+ olen: Integer;
it: PItem;
- rebuildFreeList: Boolean = true;
begin
if (slot < 0) or (slot > $0fffffff) then raise Exception.Create('wantItemSlot: bad item slot request');
// do we need to grow item storate?
olen := Length(ggItems);
- if (slot >= olen) then
- begin
- // need more spice!
- SetLength(ggItems, slot+64);
- // add free slots to free list
- for i := olen to High(ggItems) do
- begin
- it := @ggItems[i];
- it.treeNode := -1;
- it.arrIdx := i;
- it.ItemType := ITEM_NONE;
- it.Animation := nil;
- it.Live := false;
- it.SpawnTrigger := -1;
- it.Respawnable := false;
- if (i <> slot) then freeIds.insert(i);
- end;
- rebuildFreeList := false;
- end;
+ if (slot >= olen) then growItemArrayTo(slot+64);
it := @ggItems[slot];
- if (it.treeNode = -1) then
+ if not it.slotIsUsed then
begin
- // this is unused slot; get it, and rebuild id list
- if rebuildFreeList then
- begin
- freeIds.clear();
- for i := 0 to High(ggItems) do
- begin
- if (i <> slot) and (ggItems[i].treeNode = -1) then freeIds.insert(i);
- end;
- end;
+ freeIds.alloc(LongWord(slot));
end
else
begin
- // it will be readded
- //itemTree.removeObject(it.treeNode);
- it.treeNode := -1;
+ if not freeIds.hasAlloced[slot] then raise Exception.Create('wantItemSlot: internal error in item idx manager');
end;
+ it.slotIsUsed := false;
result := slot;
end;
for i := 0 to High(ggItems) do ggItems[i].Animation.Free();
ggItems := nil;
end;
- //if (itemTree <> nil) then itemTree.reset();
freeIds.clear();
end;
begin
if ForcedID < 0 then find_id := allocItem() else find_id := wantItemSlot(ForcedID);
- {$IF DEFINED(D2F_DEBUG)}e_WriteLog(Format('allocated item #%d', [Integer(find_id)]), MSG_NOTIFY);{$ENDIF}
+ //{$IF DEFINED(D2F_DEBUG)}e_WriteLog(Format('allocated item #%d', [Integer(find_id)]), MSG_NOTIFY);{$ENDIF}
it := @ggItems[find_id];
+ if (it.arrIdx <> Integer(find_id)) then raise Exception.Create('g_Items_Create: arrIdx inconsistency');
+ //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
with ggItems[i] do
begin
- if g_Collide(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height, sX, sY, sWidth, sHeight) then
+ if g_dbg_scale_05 or g_Collide(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height, sX, sY, sWidth, sHeight) then
begin
if (Animation = nil) then
begin
var
it: PItem;
trig: Integer;
-{$IF DEFINED(D2F_DEBUG)}
- //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');
-
- {$IF DEFINED(D2F_DEBUG)}
- //itemTree.getNodeXY(it.treeNode, x, y);
- //e_WriteLog(Format('removing item #%d: updating tree; nodeid=%d; x=%d; y=%d (%d,%d)', [it.arrIdx, it.treeNode, x, y, it.Obj.X, it.Obj.Y]), MSG_NOTIFY);
- {$ENDIF}
+ if (it.arrIdx <> Integer(ID)) then raise Exception.Create('g_Items_Remove: arrIdx desync');
trig := it.SpawnTrigger;
// ////////////////////////////////////////////////////////////////////////// //
-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
end;
end;
+
+procedure g_Items_AddDynLights();
+var
+ f: Integer;
+ it: PItem;
+begin
+ for f := 0 to High(ggItems) do
+ begin
+ it := @ggItems[f];
+ if not it.Live then continue;
+ case it.ItemType of
+ ITEM_KEY_RED: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 24, 1.0, 0.0, 0.0, 0.6);
+ ITEM_KEY_GREEN: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 24, 0.0, 1.0, 0.0, 0.6);
+ ITEM_KEY_BLUE: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 24, 0.0, 0.0, 1.0, 0.6);
+ ITEM_ARMOR_GREEN: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 42, 0.0, 1.0, 0.0, 0.6);
+ ITEM_ARMOR_BLUE: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 42, 0.0, 0.0, 1.0, 0.6);
+ ITEM_SPHERE_BLUE: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 32, 0.0, 1.0, 0.0, 0.6);
+ ITEM_SPHERE_WHITE: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 32, 1.0, 1.0, 1.0, 0.6);
+ ITEM_INVUL: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 32, 1.0, 0.0, 0.0, 0.6);
+ ITEM_INVIS: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 32, 1.0, 1.0, 0.0, 0.6);
+ ITEM_BOTTLE: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 16, 0.0, 0.0, 0.8, 0.6);
+ ITEM_HELMET: g_AddDynLight(it.Obj.X+(it.Obj.Rect.Width div 2), it.Obj.Y+(it.Obj.Rect.Height div 2), 16, 0.0, 0.8, 0.0, 0.6);
+ end;
+ end;
+end;
+
+
end.