From 4c4a0406b07cdfd5051e388e8b00f02e008ed140 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Tue, 22 Aug 2017 15:12:24 +0300 Subject: [PATCH] more grid code uglification -- should be a little faster now uglified grid code even more: each proxy now has "enabled" flag, and traces without callbacks (most "did collide with anything?" traces aren't interested in exact collision info) will return simple true/false flag, so we can avoid expensive callback invocation. not working yet, tho: i fucked up flag checking somewhere --- src/game/g_game.pas | 2 +- src/game/g_gfx.pas | 12 ++- src/game/g_grid.pas | 246 +++++++++++++++++++------------------------ src/game/g_map.pas | 132 ++++++++++++++++++----- src/game/g_panel.pas | 3 +- 5 files changed, 228 insertions(+), 167 deletions(-) diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 38fb35a..6cd9970 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -2730,7 +2730,7 @@ type while (gDrawPanelList.count > 0) do begin pan := TPanel(gDrawPanelList.front()); - e_WriteLog(Format('tagmask: 0x%04x; pan.tag: 0x%04x; pan.ArrIdx: %d', [tagmask, pan.tag, pan.ArrIdx]), MSG_NOTIFY); + e_WriteLog(Format('tagmask: 0x%04x; pan.tag: 0x%04x; pan.arrIdx: %d', [tagmask, pan.tag, pan.arrIdx]), MSG_NOTIFY); pan.Draw(); gDrawPanelList.popFront(); end; diff --git a/src/game/g_gfx.pas b/src/game/g_gfx.pas index 7afc4ee..c84ba47 100644 --- a/src/game/g_gfx.pas +++ b/src/game/g_gfx.pas @@ -83,6 +83,8 @@ type State: Byte; ParticleType: Byte; offsetX, offsetY: ShortInt; + // for bubbles + liquidTopY: Integer; // don't float higher than this end; TOnceAnim = record @@ -713,12 +715,13 @@ begin end; end; + procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte); var a: Integer; DevX1, DevX2, DevY1, DevY2: Byte; - l: Integer; + l, liquidx: Integer; begin l := Length(Particles); if l = 0 then @@ -742,8 +745,15 @@ begin (Y >= gMapInfo.Height) or (Y <= 0) then Continue; + (* + // don't spawn bubbles outside of the liquid if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then Continue; + *) + + // trace liquid, so we'll know where it ends; do it in 8px steps for speed + // tracer will return `false` if we started outside of the liquid + if not g_Map_TraceLiquid(X, Y, 0, -8, liquidx, liquidTopY) then continue; VelX := 0; VelY := -1-Random; diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas index d56a243..13c57c9 100644 --- a/src/game/g_grid.pas +++ b/src/game/g_grid.pas @@ -15,7 +15,6 @@ *) // universal spatial grid {$INCLUDE ../shared/a_modes.inc} -{$DEFINE grid_use_buckets} unit g_grid; interface @@ -29,12 +28,12 @@ type type TGridQueryCB = function (obj: ITP; tag: Integer): Boolean is nested; // return `true` to stop type TGridRayQueryCB = function (obj: ITP; tag: Integer; x, y, prevx, prevy: Integer): Boolean is nested; // return `true` to stop + const TagDisabled = $40000000; + private const GridDefaultTileSize = 32; - {$IFDEF grid_use_buckets} GridCellBucketSize = 8; // WARNING! can't be less than 2! - {$ENDIF} private type @@ -53,11 +52,7 @@ type PGridCell = ^TGridCell; TGridCell = record - {$IFDEF grid_use_buckets} bodies: array [0..GridCellBucketSize-1] of Integer; // -1: end of list - {$ELSE} - body: Integer; - {$ENDIF} next: Integer; // in this cell; index in mCells end; @@ -96,6 +91,9 @@ type function inserter (grida: Integer): Boolean; function remover (grida: Integer): Boolean; + function getProxyEnabled (pid: TBodyProxyId): Boolean; inline; + procedure setProxyEnabled (pid: TBodyProxyId; val: Boolean); inline; + public constructor Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer; aTileSize: Integer=GridDefaultTileSize); destructor Destroy (); override; @@ -107,17 +105,26 @@ type procedure resizeBody (body: TBodyProxyId; sx, sy: Integer); procedure moveResizeBody (body: TBodyProxyId; dx, dy, sx, sy: Integer); + function insideGrid (x, y: Integer): Boolean; inline; + //WARNING: can't do recursive queries + // no callback: return `true` on the first hit function forEachInAABB (x, y, w, h: Integer; cb: TGridQueryCB; tagmask: Integer=-1): Boolean; //WARNING: can't do recursive queries + // no callback: return `true` on the first hit function forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1): Boolean; //WARNING: can't do recursive queries // cb with `(nil)` will be called before processing new tile + // no callback: return `true` on the nearest hit function traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): Boolean; overload; + function traceRay (out ex, ey: Integer; x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): Boolean; procedure dumpStats (); + + //WARNING! no sanity checks! + property proxyEnabled[pid: TBodyProxyId]: Boolean read getProxyEnabled write setProxyEnabled; end; @@ -162,11 +169,7 @@ begin // init free list for idx := 0 to High(mCells) do begin - {$IFDEF grid_use_buckets} mCells[idx].bodies[0] := -1; - {$ELSE} - mCells[idx].body := -1; - {$ENDIF} mCells[idx].next := idx+1; end; mCells[High(mCells)].next := -1; // last cell @@ -216,6 +219,37 @@ begin end; +function TBodyGridBase.insideGrid (x, y: Integer): Boolean; inline; +begin + // fix coords + Dec(x, mMinX); + Dec(y, mMinY); + result := (x >= 0) and (y >= 0) and (x < mWidth*mTileSize) and (y < mHeight*mTileSize); +end; + + +function TBodyGridBase.getProxyEnabled (pid: TBodyProxyId): Boolean; inline; +begin + if (pid >= 0) then result := ((mProxies[pid].mTag and TagDisabled) = 0) else result := false; +end; + + +procedure TBodyGridBase.setProxyEnabled (pid: TBodyProxyId; val: Boolean); inline; +begin + if (pid >= 0) then + begin + if val then + begin + mProxies[pid].mTag := mProxies[pid].mTag and not TagDisabled; + end + else + begin + mProxies[pid].mTag := mProxies[pid].mTag or TagDisabled + end; + end; +end; + + function TBodyGridBase.allocCell: Integer; var idx: Integer; @@ -227,11 +261,7 @@ begin SetLength(mCells, mFreeCell+32768); // arbitrary number for idx := mFreeCell to High(mCells) do begin - {$IFDEF grid_use_buckets} mCells[idx].bodies[0] := -1; - {$ELSE} - mCells[idx].body := -1; - {$ENDIF} mCells[idx].next := idx+1; end; mCells[High(mCells)].next := -1; // last cell @@ -239,11 +269,7 @@ begin result := mFreeCell; mFreeCell := mCells[result].next; mCells[result].next := -1; - {$IFDEF grid_use_buckets} mCells[result].bodies[0] := -1; - {$ELSE} - mCells[result].body := -1; - {$ENDIF} Inc(mUsedCells); //e_WriteLog(Format('grid: allocated new cell #%d (total: %d)', [result, mUsedCells]), MSG_NOTIFY); end; @@ -254,11 +280,7 @@ begin if (idx >= 0) and (idx < Length(mCells)) then begin //if mCells[idx].body = -1 then exit; // the thing that should not be - {$IFDEF grid_use_buckets} mCells[idx].bodies[0] := -1; - {$ELSE} - mCells[idx].body := -1; - {$ENDIF} mCells[idx].next := mFreeCell; mFreeCell := idx; Dec(mUsedCells); @@ -339,15 +361,12 @@ function TBodyGridBase.inserter (grida: Integer): Boolean; var cidx: Integer; pc: Integer; - {$IFDEF grid_use_buckets} pi: PGridCell; f: Integer; - {$ENDIF} begin result := false; // never stop // add body to the given grid cell pc := mGrid[grida]; - {$IFDEF grid_use_buckets} if (pc <> -1) then begin pi := @mCells[pc]; @@ -369,13 +388,6 @@ begin mCells[cidx].bodies[1] := -1; mCells[cidx].next := pc; mGrid[grida] := cidx; - {$ELSE} - cidx := allocCell(); - //e_WriteLog(Format(' 01: allocated cell for grid coords (%d,%d), body coords:(%d,%d): #%d', [gx, gy, dx, dy, cidx]), MSG_NOTIFY); - mCells[cidx].body := mUData; - mCells[cidx].next := pc; - mGrid[grida] := cidx; - {$ENDIF} end; @@ -392,13 +404,9 @@ end; function TBodyGridBase.remover (grida: Integer): Boolean; var - {$IFDEF grid_use_buckets} f: Integer; - {$ENDIF} pidx, idx, tmp: Integer; - {$IFDEF grid_use_buckets} pc: PGridCell; - {$ENDIF} begin result := false; // never stop // find and remove cell @@ -407,7 +415,6 @@ begin while (idx >= 0) do begin tmp := mCells[idx].next; - {$IFDEF grid_use_buckets} pc := @mCells[idx]; f := 0; while (f < High(TGridCell.bodies)) do @@ -438,14 +445,6 @@ begin end; Inc(f); end; - {$ELSE} - if (mCells[idx].body = mUData) then - begin - if (pidx = -1) then mGrid[grida] := tmp else mCells[pidx].next := tmp; - freeCell(idx); - exit; // assume that we cannot have one object added to bucket twice - end; - {$ENDIF} pidx := idx; idx := tmp; end; @@ -506,18 +505,18 @@ end; // ////////////////////////////////////////////////////////////////////////// // +// no callback: return `true` on the first hit function TBodyGridBase.forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1): Boolean; var - {$IFDEF grid_use_buckets} f: Integer; - {$ENDIF} idx, curci: Integer; cc: PGridCell = nil; px: PBodyProxyRec; lq: LongWord; + ptag: Integer; begin result := false; - if not assigned(cb) or (tagmask = 0) then exit; + if (tagmask = 0) then exit; // make coords (0,0)-based Dec(x, mMinX); @@ -542,57 +541,45 @@ begin while (curci <> -1) do begin cc := @mCells[curci]; - {$IFDEF grid_use_buckets} for f := 0 to High(TGridCell.bodies) do begin if (cc.bodies[f] = -1) then break; px := @mProxies[cc.bodies[f]]; - if (px.mQueryMark <> lq) and ((px.mTag and tagmask) <> 0) then + if (px.mQueryMark <> lq) then begin - if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then + ptag := px.mTag; + if ((ptag and TagDisabled) = 0) and ((px.mTag and tagmask) <> 0) then begin - px.mQueryMark := lq; - result := cb(px.mObj, px.mTag); - if result then exit; - end; - end; - end; - {$ELSE} - if (cc.body <> -1) then - begin - px := @mProxies[cc.body]; - if (px.mQueryMark <> lq) and ((px.mTag and tagmask) <> 0) then - begin - if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then - begin - px.mQueryMark := lq; - result := cb(px.mObj, px.mTag); - if result then exit; + if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then + begin + px.mQueryMark := lq; + if assigned(cb) then result := cb(px.mObj, px.mTag) else result := true; + if result then exit; + end; end; end; end; - {$ENDIF} curci := cc.next; end; end; +// no callback: return `true` on the first hit function TBodyGridBase.forEachInAABB (x, y, w, h: Integer; cb: TGridQueryCB; tagmask: Integer=-1): Boolean; var idx: Integer; gx, gy: Integer; curci: Integer; - {$IFDEF grid_use_buckets} f: Integer; - {$ENDIF} cc: PGridCell = nil; px: PBodyProxyRec; lq: LongWord; tsize, gw: Integer; x0, y0: Integer; + ptag: Integer; begin result := false; - if (w < 1) or (h < 1) or not assigned(cb) then exit; + if (w < 1) or (h < 1) then exit; x0 := x; y0 := y; @@ -632,39 +619,23 @@ begin while (curci <> -1) do begin cc := @mCells[curci]; - {$IFDEF grid_use_buckets} for f := 0 to High(TGridCell.bodies) do begin if (cc.bodies[f] = -1) then break; px := @mProxies[cc.bodies[f]]; - if (px.mQueryMark <> lq) and ((px.mTag and tagmask) <> 0) then - begin - if (x0 >= px.mX+px.mWidth) or (y0 >= px.mY+px.mHeight) then continue; - if (x0+w <= px.mX) or (y0+h <= px.mY) then continue; - px.mQueryMark := lq; - result := cb(px.mObj, px.mTag); - if result then exit; - end; - end; - {$ELSE} - if (cc.body <> 1) then - begin - px := @mProxies[cc.body]; - if (px.mQueryMark <> lq) and ((px.mTag and tagmask) <> 0) then + if (px.mQueryMark <> lq) then begin - if (x0 >= px.mX+px.mWidth) or (y0 >= px.mY+px.mHeight) or (x0+w <= px.mX) or (y0+h <= px.mY) then - begin - // no intersection - end - else + ptag := px.mTag; + if ((ptag and TagDisabled) = 0) and ((px.mTag and tagmask) <> 0) then begin + if (x0 >= px.mX+px.mWidth) or (y0 >= px.mY+px.mHeight) then continue; + if (x0+w <= px.mX) or (y0+h <= px.mY) then continue; px.mQueryMark := lq; - result := cb(px.mObj, px.mTag); + if assigned(cb) then result := cb(px.mObj, px.mTag) else result := true; if result then exit; end; end; end; - {$ENDIF} curci := cc.next; end; end; @@ -673,7 +644,17 @@ end; // ////////////////////////////////////////////////////////////////////////// // +// no callback: return `true` on the nearest hit function TBodyGridBase.traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): Boolean; +var + ex, ey: Integer; +begin + result := traceRay(ex, ey, x0, y0, x1, y1, cb, tagmask); +end; + + +// no callback: return `true` on the nearest hit +function TBodyGridBase.traceRay (out ex, ey: Integer; x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): Boolean; var i: Integer; dx, dy: Integer; @@ -696,10 +677,13 @@ var lq: LongWord; prevX, prevY: Integer; minx, miny: Integer; + ptag: Integer; + lastDistSq, distSq: Integer; + wasHit: Boolean = false; begin result := false; - if (tagmask = 0) then exit; + if (tagmask = 0) then begin ex := x0; ey := y0; exit; end; // make coords (0,0)-based minx := mMinX; @@ -738,6 +722,7 @@ begin gh := mHeight; maxx := gw*tsize-1; maxy := gh*tsize-1; + lastDistSq := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1; for i := 1 to d do begin @@ -754,13 +739,6 @@ begin // new cell lastGA := ga; ccidx := mGrid[lastGA]; - { - if (ccidx <> -1) then - begin - result := cb(nil, 0, x+minx, y+miny, prevX, prevY); - if result then exit; - end; - } end; end else @@ -768,7 +746,7 @@ begin if (ccidx <> -1) then begin ccidx := -1; - result := cb(nil, 0, x+minx, y+miny, prevX, prevY); + if assigned(cb) then result := cb(nil, 0, x+minx, y+miny, prevX, prevY) else result := wasHit; if result then exit; end; end; @@ -782,52 +760,50 @@ begin while (curci <> -1) do begin cc := @mCells[curci]; - {$IFDEF grid_use_buckets} for f := 0 to High(TGridCell.bodies) do begin if (cc.bodies[f] = -1) then break; px := @mProxies[cc.bodies[f]]; - if (px.mQueryMark <> lq) and ((px.mTag and tagmask) <> 0) then + if (px.mQueryMark <> lq) then begin - if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then + ptag := px.mTag; + if ((ptag and TagDisabled) = 0) and ((px.mTag and tagmask) <> 0) then begin - px.mQueryMark := lq; - result := cb(px.mObj, px.mTag, x, y, prevX, prevY); - if result then exit; - end - else - begin - hasUntried := true; + if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then + begin + px.mQueryMark := lq; + if assigned(cb) then + begin + result := cb(px.mObj, px.mTag, x, y, prevX, prevY); + if result then begin ex := prevX; ey := prevY; exit; end; + end + else + begin + distSq := (prevX-x)*(prevX-x)+(prevY-y)*(prevY-y); + if (distSq < lastDistSq) then + begin + wasHit := true; + lastDistSq := distSq; + ex := prevx; + ey := prevy; + end; + end; + end + else + begin + hasUntried := true; + end; end; end; end; - {$ELSE} - if (cc.body <> -1) then - begin - px := @mProxies[cc.body]; - if (px.mQueryMark <> lq) and ((px.mTag and tagmask) <> 0) then - begin - if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then - begin - px.mQueryMark := lq; - result := cb(px.mObj, px.mTag, x, y, prevX, prevY); - if result then exit; - end - else - begin - hasUntried := true; - end; - end; - end; - {$ENDIF} curci := cc.next; end; if not hasUntried then begin // don't process this cell anymore ccidx := -1; - result := cb(nil, 0, x, y, prevX, prevY); - if result then exit; + if assigned(cb) then result := cb(nil, 0, x, y, prevX, prevY) else result := wasHit; + if result then exit; // don't update lasthit: it is done in real checker end; Dec(x, minx); Dec(y, miny); diff --git a/src/game/g_map.pas b/src/game/g_map.pas index dba67ec..d1d824a 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -99,10 +99,15 @@ type function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean; +// trace liquid, stepping by `dx` and `dy` +// return last seen liquid coords, and `false` if we're started outside of the liquid +function g_Map_TraceLiquid (x, y, dx, dy: Integer; out topx, topy: Integer): Boolean; + procedure g_Map_ProfilersBegin (); procedure g_Map_ProfilersEnd (); + const RESPAWNPOINT_PLAYER1 = 1; RESPAWNPOINT_PLAYER2 = 2; @@ -245,12 +250,11 @@ function dplLess (a, b: TObject): Boolean; var pa, pb: TPanel; begin - //result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx); pa := TPanel(a); pb := TPanel(b); if (pa.tag < pb.tag) then begin result := true; exit; end; if (pa.tag > pb.tag) then begin result := false; exit; end; - result := (pa.ArrIdx < pb.ArrIdx); + result := (pa.arrIdx < pb.arrIdx); end; procedure dplClear (); @@ -271,7 +275,7 @@ var RespawnPoints: Array of TRespawnPoint; FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint; //DOMFlagPoints: Array of TFlagPoint; - gMapGrid: TPanelGrid = nil; + mapGrid: TPanelGrid = nil; //mapTree: TDynAABBTreeMap = nil; @@ -366,6 +370,7 @@ end; // wall index in `gWalls` or -1 function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): Boolean; +(* var lastX, lastY, lastDistSq: Integer; wasHit: Boolean = false; @@ -397,16 +402,21 @@ var end; end; end; - +*) +var + ex, ey: Integer; begin + (* result := false; - if (gMapGrid = nil) then exit; + if (mapGrid = nil) then exit; lastDistSq := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1; lastX := 0; lastY := 0; - result := gMapGrid.traceRay(x0, y0, x1, y1, sqchecker, (GridTagWall or GridTagDoor)); + result := mapGrid.traceRay(x0, y0, x1, y1, sqchecker, (GridTagWall or GridTagDoor)); if (hitx <> nil) then hitx^ := lastX; if (hity <> nil) then hity^ := lastY; + *) + result := mapGrid.traceRay(ex, ey, x0, y0, x1, y1, nil, (GridTagWall or GridTagDoor)); end; @@ -414,24 +424,26 @@ function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean; function checker (pan: TPanel; tag: Integer): Boolean; begin - result := false; // don't stop, ever - + { if ((tag and (GridTagWall or GridTagDoor)) <> 0) then begin - if not pan.Enabled then exit; + result := pan.Enabled; // stop if wall is enabled + exit; end; - - result := (x >= pan.X) and (y >= pan.Y) and (x < pan.X+pan.Width) and (y < pan.Y+pan.Height); - if not result then exit; + } if ((tag and GridTagLift) <> 0) then begin + // stop if the lift of the right type result := ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = 0)) or (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = 1)) or (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = 2)) or (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))); + exit; end; + + result := true; // otherwise, stop anyway, 'cause `forEachAtPoint()` is guaranteed to call this only for correct panels end; var @@ -448,7 +460,16 @@ begin if WordBool(PanelType and PANEL_BLOCKMON) then tagmask := tagmask or GridTagBlockMon; if (tagmask = 0) then exit;// just in case - result := gMapGrid.forEachAtPoint(x, y, checker, tagmask); + if ((tagmask and GridTagLift) <> 0) then + begin + // slow + result := mapGrid.forEachAtPoint(x, y, checker, tagmask); + end + else + begin + // fast + result := mapGrid.forEachAtPoint(x, y, nil, tagmask); + end; end; @@ -660,7 +681,8 @@ begin SetLength(panels^, len + 1); panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures); - panels^[len].ArrIdx := len; + panels^[len].arrIdx := len; + panels^[len].proxyId := -1; panels^[len].tag := panelTypeToTag(PanelRec.PanelType); if sav then panels^[len].SaveIt := True; @@ -1232,14 +1254,15 @@ var pan := panels[idx]; pan.tag := tag; if not pan.visvalid then continue; - gMapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, tag); + pan.proxyId := mapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, tag); + mapGrid.proxyEnabled[pan.proxyId] := pan.Enabled; //mapTree.insertObject(pan, tag, true); // as static object end; end; begin - gMapGrid.Free(); - gMapGrid := nil; + mapGrid.Free(); + mapGrid := nil; //mapTree.Free(); //mapTree := nil; @@ -1255,7 +1278,7 @@ begin e_WriteLog(Format('map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING); - gMapGrid := TPanelGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1); + mapGrid := TPanelGrid.Create(mapX0-512, mapY0-512, mapX1-mapX0+1+512*2, mapY1-mapY0+1+512*2); //mapTree := TDynAABBTreeMap.Create(); addPanelsToGrid(gWalls, PANEL_WALL); @@ -1270,7 +1293,7 @@ begin addPanelsToGrid(gLifts, PANEL_LIFTUP); // it doesn't matter which LIFT type is used here addPanelsToGrid(gBlockMon, PANEL_BLOCKMON); - gMapGrid.dumpStats(); + mapGrid.dumpStats(); //e_WriteLog(Format('tree depth: %d; %d nodes used, %d nodes allocated', [mapTree.computeTreeHeight, mapTree.nodeCount, mapTree.nodeAlloced]), MSG_NOTIFY); //mapTree.forEachLeaf(nil); end; @@ -1307,8 +1330,8 @@ var CurTex, ntn: Integer; begin - gMapGrid.Free(); - gMapGrid := nil; + mapGrid.Free(); + mapGrid := nil; //mapTree.Free(); //mapTree := nil; @@ -2098,6 +2121,7 @@ end; // new algo procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); + function checker (pan: TPanel; tag: Integer): Boolean; begin result := false; // don't stop, ever @@ -2115,13 +2139,14 @@ begin end else} begin - gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore)); + mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore)); end; // list will be rendered in `g_game.DrawPlayer()` end; procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); + function checker (pan: TPanel; tag: Integer): Boolean; begin result := false; // don't stop, ever @@ -2135,7 +2160,7 @@ begin end else} begin - gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); + mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); end; end; @@ -2304,10 +2329,13 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; begin result := false; // don't stop, ever + { if ((tag and (GridTagWall or GridTagDoor)) <> 0) then begin - if not pan.Enabled then exit; + result := pan.Enabled; + exit; end; + } if ((tag and GridTagLift) <> 0) then begin @@ -2322,7 +2350,7 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; if ((tag and GridTagBlockMon) <> 0) then begin - result := ((not b1x3) or (pan.Width+pan.Height >= 64)) and g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height); + result := ((not b1x3) or (pan.Width+pan.Height >= 64)); //and g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height); exit; end; @@ -2361,11 +2389,29 @@ begin begin if (Width = 1) and (Height = 1) then begin - result := gMapGrid.forEachAtPoint(X, Y, checker, tagmask); + if ((tagmask and (GridTagLift or GridTagBlockMon)) <> 0) then + begin + // slow + result := mapGrid.forEachAtPoint(X, Y, checker, tagmask); + end + else + begin + // fast + result := mapGrid.forEachAtPoint(X, Y, nil, tagmask); + end; end else begin - result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask); + if ((tagmask and (GridTagLift or GridTagBlockMon)) <> 0) then + begin + // slow + result := mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask); + end + else + begin + // fast + result := mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask); + end; end; end; end @@ -2418,11 +2464,11 @@ begin begin if (Width = 1) and (Height = 1) then begin - gMapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); + mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); end else begin - gMapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); + mapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); end; end; result := texid; @@ -2434,12 +2480,14 @@ begin if (profMapCollision <> nil) then profMapCollision.sectionEnd(); end; + procedure g_Map_EnableWall(ID: DWORD); begin with gWalls[ID] do begin Enabled := True; g_Mark(X, Y, Width, Height, MARK_DOOR, True); + mapGrid.proxyEnabled[proxyId] := true; if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID); end; @@ -2451,6 +2499,7 @@ begin begin Enabled := False; g_Mark(X, Y, Width, Height, MARK_DOOR, False); + mapGrid.proxyEnabled[proxyId] := false; if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID); end; @@ -2494,6 +2543,7 @@ begin LiftType := t; g_Mark(X, Y, Width, Height, MARK_LIFT, False); + //TODO: make separate lift tags, and change tag here if LiftType = 0 then g_Mark(X, Y, Width, Height, MARK_LIFTUP, True) @@ -2870,4 +2920,28 @@ begin Result := Addr(Arr[PanelByID[PanelID].PArrID]); end; + +// trace liquid, stepping by `dx` and `dy` +// return last seen liquid coords, and `false` if we're started outside of the liquid +function g_Map_TraceLiquid (x, y, dx, dy: Integer; out topx, topy: Integer): Boolean; +const + MaskLiquid = GridTagWater or GridTagAcid1 or GridTagAcid2; +begin + topx := x; + topy := y; + // started outside of the liquid? + if not mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) then begin result := false; exit; end; + if (dx = 0) and (dy = 0) then begin result := false; exit; end; // sanity check + result := true; + while true do + begin + Inc(x, dx); + Inc(y, dy); + if not mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) then exit; // out of the water, just exit + topx := x; + topy := y; + end; +end; + + end. diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index ab99604..19a6af8 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -59,8 +59,9 @@ type Moved: Boolean; LiftType: Byte; LastAnimLoop: Byte; - ArrIdx: Integer; // index in one of internal arrays; sorry + arrIdx: Integer; // index in one of internal arrays; sorry tag: Integer; // used in coldets and such; sorry + proxyId: Integer; // proxy id in map grid (DO NOT USE!) constructor Create(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray; -- 2.29.2