X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_map.pas;h=7d6f3dddd37d8472a5340620de86bdea06d6cb2f;hb=faef8ad22cbb1b4375647136c9ddca6705a8e21f;hp=f3e15a21ef10847f71df7a34d342ff75b3dece9b;hpb=51343dcc874e5db55f029b0750892ca2da971c24;p=d2df-sdl.git diff --git a/src/game/g_map.pas b/src/game/g_map.pas index f3e15a2..7d6f3dd 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -14,6 +14,7 @@ * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} +{$DEFINE MAP_DEBUG_ENABLED_FLAG} unit g_map; interface @@ -67,7 +68,7 @@ procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); procedure g_Map_DrawBack(dx, dy: Integer); function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; - PanelType: Word; b1x3: Boolean): Boolean; + PanelType: Word; b1x3: Boolean=false): Boolean; function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD; procedure g_Map_EnableWall(ID: DWORD); procedure g_Map_DisableWall(ID: DWORD); @@ -91,9 +92,23 @@ procedure g_Map_LoadState(Var Mem: TBinMemoryReader); procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); +// returns wall index in `gWalls` or -1 +function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): Boolean; + +type + TForEachPanelCB = function (pan: TPanel): Boolean; // return `true` to stop + +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; @@ -143,6 +158,8 @@ const GridTagLift = 1 shl 8; GridTagBlockMon = 1 shl 9; + GridDrawableMask = (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore); + var gWalls: TPanelArray; @@ -164,14 +181,15 @@ var gdbg_map_use_accel_render: Boolean = true; gdbg_map_use_accel_coldet: Boolean = true; - gdbg_map_use_tree_draw: Boolean = false; - gdbg_map_use_tree_coldet: Boolean = false; - gdbg_map_dump_coldet_tree_queries: Boolean = false; + //gdbg_map_use_tree_draw: Boolean = false; + //gdbg_map_use_tree_coldet: Boolean = false; + //gdbg_map_dump_coldet_tree_queries: Boolean = false; profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY! gDrawPanelList: TBinaryHeapObj = nil; // binary heap of all walls we have to render, populated by `g_Map_CollectDrawPanels()` function panelTypeToTag (panelType: Word): Integer; // returns GridTagXXX + implementation uses @@ -189,6 +207,29 @@ const FLAG_SIGNATURE = $47414C46; // 'FLAG' +type + TPanelGrid = specialize TBodyGridBase; + + { + TDynAABBTreePanelBase = specialize TDynAABBTreeBase; + + TDynAABBTreeMap = class(TDynAABBTreePanelBase) + function getFleshAABB (out aabb: AABB2D; pan: TPanel; tag: Integer): Boolean; override; + end; + { + +{ +function TDynAABBTreeMap.getFleshAABB (out aabb: AABB2D; pan: TPanel; tag: Integer): Boolean; +begin + result := false; + if (pan = nil) then begin aabb := AABB2D.Create(0, 0, 0, 0); exit; end; + aabb := AABB2D.Create(pan.X, pan.Y, pan.X+pan.Width-1, pan.Y+pan.Height-1); + if (pan.Width < 1) or (pan.Height < 1) then exit; + if not aabb.valid then raise Exception.Create('wutafuuuuuuu?!'); + result := true; +end; +} + function panelTypeToTag (panelType: Word): Integer; begin @@ -212,12 +253,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 (); @@ -232,37 +272,14 @@ type PArrID: Integer; end; -type - TDynAABBTreeMap = class(TDynAABBTree) - function getFleshAABB (var aabb: AABB2D; flesh: TTreeFlesh): Boolean; override; - end; - -function TDynAABBTreeMap.getFleshAABB (var aabb: AABB2D; flesh: TTreeFlesh): Boolean; -var - pan: TPanel; -begin - result := false; - if (flesh = nil) then begin aabb := AABB2D.Create(0, 0, 0, 0); exit; end; - //pan := (flesh as TPanel); - pan := TPanel(flesh); - aabb := AABB2D.Create(pan.X, pan.Y, pan.X+pan.Width, pan.Y+pan.Height); - if (pan.Width < 1) or (pan.Height < 1) then exit; - //if (pan.Width = 1) then aabb.maxX += 1; - //if (pan.Height = 1) then aabb.maxY += 1; - //if (pan.Width < 3) or (pan.Height < 3) then exit; - //aabb := AABB2D.Create(pan.X, pan.Y, pan.X+pan.Width-2, pan.Y+pan.Height-2); - if not aabb.valid then raise Exception.Create('wutafuuuuuuu?!'); - result := aabb.valid; -end; - var PanelById: array of TPanelID; Textures: TLevelTextureArray; RespawnPoints: Array of TRespawnPoint; FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint; //DOMFlagPoints: Array of TFlagPoint; - gMapGrid: TBodyGrid = nil; - mapTree: TDynAABBTree = nil; + mapGrid: TPanelGrid = nil; + //mapTree: TDynAABBTreeMap = nil; procedure g_Map_ProfilersBegin (); @@ -285,6 +302,180 @@ begin end; +// wall index in `gWalls` or -1 +(* +function g_Map_traceToNearestWallOld (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): Integer; + + function sqchecker (pan: TPanel; var ray: Ray2D): Single; + var + aabb: AABB2D; + tmin: Single; + begin + result := -666.0; // invalid + if not pan.Enabled then exit; + aabb := AABB2D.CreateWH(pan.X, pan.Y, pan.Width, pan.Height); + if not aabb.valid then exit; + if aabb.intersects(ray, @tmin) then + begin + //if (tmin*tmin > maxDistSq) then exit; + if (tmin >= 0.0) then + begin + //e_WriteLog(Format('sqchecker(%d,%d,%d,%d): panel #%d (%d,%d)-(%d,%d); tmin=%f', [x0, y0, x1, y1, pan.arrIdx, pan.X, pan.Y, pan.Width, pan.Height, tmin]), MSG_NOTIFY); + //if (tmin < 0.0) then tmin := 0.0; + result := tmin; + end; + end; + end; + +var + qr: TDynAABBTreeMap.TSegmentQueryResult; + ray: Ray2D; + hxf, hyf: Single; + hx, hy: Integer; + maxDistSq: Single; +begin + result := -1; + if (mapTree = nil) then exit; + if mapTree.segmentQuery(qr, x0, y0, x1, y1, sqchecker, (GridTagWall or GridTagDoor)) then + begin + maxDistSq := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0); + if (qr.flesh <> nil) and (qr.time*qr.time <= maxDistSq) then + begin + result := qr.flesh.arrIdx; + if (hitx <> nil) or (hity <> nil) then + begin + ray := Ray2D.Create(x0, y0, x1, y1); + hxf := ray.origX+ray.dirX*qr.time; + hyf := ray.origY+ray.dirY*qr.time; + while true do + begin + hx := trunc(hxf); + hy := trunc(hyf); + if (hx >= qr.flesh.X) and (hy >= qr.flesh.Y) and (hx < qr.flesh.X+qr.flesh.Width) and (hy < qr.flesh.Y+qr.flesh.Height) then + begin + // go back a little + hxf -= ray.dirX; + hyf -= ray.dirY; + end + else + begin + break; + end; + end; + if (hitx <> nil) then hitx^ := hx; + if (hity <> nil) then hity^ := hy; + end; + end; + end; +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; + + // pan=nil: before processing new tile + function sqchecker (pan: TPanel; tag: Integer; x, y, prevx, prevy: Integer): Boolean; + var + distSq: Integer; + begin + if (pan = nil) then + begin + // stop if something was hit at the previous tile + result := wasHit; + end + else + begin + result := false; + if ((tag and (GridTagWall or GridTagDoor)) <> 0) then + begin + if not pan.Enabled then exit; + end; + distSq := (prevx-x0)*(prevx-x0)+(prevy-y0)*(prevy-y0); + if (distSq < lastDistSq) then + begin + wasHit := true; + lastDistSq := distSq; + lastX := prevx; + lastY := prevy; + end; + end; + end; +*) +var + ex, ey: Integer; +begin + (* + result := false; + if (mapGrid = nil) then exit; + lastDistSq := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1; + lastX := 0; + lastY := 0; + 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)) <> nil); +end; + + +function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean; + + function checker (pan: TPanel; tag: Integer): Boolean; + begin + { + if ((tag and (GridTagWall or GridTagDoor)) <> 0) then + begin + result := pan.Enabled; // stop if wall is enabled + exit; + end; + } + + 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 + tagmask: Integer = 0; +begin + result := false; + + if WordBool(PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR)) then tagmask := tagmask or (GridTagWall or GridTagDoor); + if WordBool(PanelType and PANEL_WATER) then tagmask := tagmask or GridTagWater; + if WordBool(PanelType and PANEL_ACID1) then tagmask := tagmask or GridTagAcid1; + if WordBool(PanelType and PANEL_ACID2) then tagmask := tagmask or GridTagAcid2; + if WordBool(PanelType and PANEL_STEP) then tagmask := tagmask or GridTagStep; + if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then tagmask := tagmask or GridTagLift; + if WordBool(PanelType and PANEL_BLOCKMON) then tagmask := tagmask or GridTagBlockMon; + + if (tagmask = 0) then exit;// just in case + if ((tagmask and GridTagLift) <> 0) then + begin + // slow + result := (mapGrid.forEachAtPoint(x, y, checker, tagmask) <> nil); + end + else + begin + // fast + result := (mapGrid.forEachAtPoint(x, y, nil, tagmask) <> nil); + end; +end; + + function g_Map_IsSpecialTexture(Texture: String): Boolean; begin Result := (Texture = TEXTURE_NAME_WATER) or @@ -493,7 +684,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; @@ -939,45 +1131,52 @@ end; procedure CreateMonster(monster: TMonsterRec_1); var - a, i: Integer; + a: Integer; + mon: TMonster; begin if g_Game_IsClient then Exit; if (gGameSettings.GameType = GT_SINGLE) or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then begin - i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y, - TDirection(monster.Direction)); + mon := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y, TDirection(monster.Direction)); if gTriggers <> nil then + begin for a := 0 to High(gTriggers) do - if gTriggers[a].TriggerType in [TRIGGER_PRESS, - TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then - if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then - gMonsters[i].AddTrigger(a); + begin + if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then + begin + if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a); + end; + end; + end; - if monster.MonsterType <> MONSTER_BARREL then - Inc(gTotalMonsters); + if monster.MonsterType <> MONSTER_BARREL then Inc(gTotalMonsters); end; end; procedure g_Map_ReAdd_DieTriggers(); -var - i, a: Integer; -begin - if g_Game_IsClient then Exit; - for i := 0 to High(gMonsters) do - if gMonsters[i] <> nil then + function monsDieTrig (mon: TMonster): Boolean; + var + a: Integer; + begin + result := false; // don't stop + mon.ClearTriggers(); + for a := 0 to High(gTriggers) do + begin + if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then begin - gMonsters[i].ClearTriggers(); - - for a := 0 to High(gTriggers) do - if gTriggers[a].TriggerType in [TRIGGER_PRESS, - TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then - if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then - gMonsters[i].AddTrigger(a); + if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a); end; + end; + end; + +begin + if g_Game_IsClient then Exit; + + g_Mons_ForEach(monsDieTrig); end; function extractWadName(resourceName: string): string; @@ -1030,7 +1229,7 @@ var mapX1: Integer = -$3fffffff; mapY1: Integer = -$3fffffff; - procedure calcBoundingBox (var panels: TPanelArray); + procedure calcBoundingBox (constref panels: TPanelArray); var idx: Integer; pan: TPanel; @@ -1047,7 +1246,7 @@ var end; end; - procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer); + procedure addPanelsToGrid (constref panels: TPanelArray; tag: Integer); var idx: Integer; pan: TPanel; @@ -1058,16 +1257,24 @@ 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); - mapTree.insertObject(pan, tag, true); // as static object + pan.proxyId := mapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, tag); + // "enabled" flag has meaning only for doors and walls (engine assumes it); but meh... + mapGrid.proxyEnabled[pan.proxyId] := pan.Enabled; + {$IFDEF MAP_DEBUG_ENABLED_FLAG} + if ((tag and (GridTagWall or GridTagDoor)) <> 0) then + begin + e_WriteLog(Format('INSERTED wall #%d(%d) enabled (%d)', [Integer(idx), Integer(pan.proxyId), Integer(mapGrid.proxyEnabled[pan.proxyId])]), MSG_NOTIFY); + end; + {$ENDIF} + //mapTree.insertObject(pan, tag, true); // as static object end; end; begin - gMapGrid.Free(); - gMapGrid := nil; - mapTree.Free(); - mapTree := nil; + mapGrid.Free(); + mapGrid := nil; + //mapTree.Free(); + //mapTree := nil; calcBoundingBox(gWalls); calcBoundingBox(gRenderBackgrounds); @@ -1081,8 +1288,8 @@ begin e_WriteLog(Format('map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING); - gMapGrid := TBodyGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1); - mapTree := TDynAABBTreeMap.Create(); + mapGrid := TPanelGrid.Create(mapX0-512, mapY0-512, mapX1-mapX0+1+512*2, mapY1-mapY0+1+512*2); + //mapTree := TDynAABBTreeMap.Create(); addPanelsToGrid(gWalls, PANEL_WALL); addPanelsToGrid(gWalls, PANEL_CLOSEDOOR); @@ -1096,9 +1303,9 @@ begin addPanelsToGrid(gLifts, PANEL_LIFTUP); // it doesn't matter which LIFT type is used here addPanelsToGrid(gBlockMon, PANEL_BLOCKMON); - gMapGrid.dumpStats(); - e_WriteLog(Format('tree depth: %d; %d nodes used, %d nodes allocated', [mapTree.computeTreeHeight, mapTree.nodeCount, mapTree.nodeAlloced]), MSG_NOTIFY); - mapTree.forEachLeaf(nil); + 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; function g_Map_Load(Res: String): Boolean; @@ -1133,10 +1340,10 @@ var CurTex, ntn: Integer; begin - gMapGrid.Free(); - gMapGrid := nil; - mapTree.Free(); - mapTree := nil; + mapGrid.Free(); + mapGrid := nil; + //mapTree.Free(); + //mapTree := nil; Result := False; gMapInfo.Map := Res; @@ -1894,7 +2101,7 @@ end; // old algo procedure g_Map_DrawPanels (PanelType: Word); - procedure DrawPanels (var panels: TPanelArray; drawDoors: Boolean=False); + procedure DrawPanels (constref panels: TPanelArray; drawDoors: Boolean=False); var idx: Integer; begin @@ -1924,16 +2131,11 @@ end; // new algo procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); - function checker (obj: TObject; tag: Integer): Boolean; - var - pan: TPanel; + + function checker (pan: TPanel; tag: Integer): Boolean; begin result := false; // don't stop, ever - //pan := (obj as TPanel); - pan := TPanel(obj); - //if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end; if ((tag and GridTagDoor) <> 0) <> pan.Door then exit; - //dplAddPanel(pan); gDrawPanelList.insert(pan); end; @@ -1941,46 +2143,34 @@ begin dplClear(); //tagmask := panelTypeToTag(PanelType); - if gdbg_map_use_tree_draw then + {if gdbg_map_use_tree_draw then begin mapTree.aabbQuery(x0, y0, wdt, hgt, checker, (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore)); end - else + 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, GridDrawableMask, true); end; // list will be rendered in `g_game.DrawPlayer()` - (* - while (gDrawPanelList.count > 0) do - begin - //(gDrawPanelList.front() as TPanel).Draw(); - TPanel(gDrawPanelList.front()).Draw(); - gDrawPanelList.popFront(); - end; - *) end; procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); - function checker (obj: TObject; tag: Integer): Boolean; - var - pan: TPanel; + + function checker (pan: TPanel; tag: Integer): Boolean; begin result := false; // don't stop, ever - //if (tag <> GridTagWall) and (tag <> GridTagDoor) then exit; // only walls - //pan := (obj as TPanel); - pan := TPanel(obj); pan.DrawShadowVolume(lightX, lightY, radius); end; begin - if gdbg_map_use_tree_draw then + {if gdbg_map_use_tree_draw then begin mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); end - else + 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), true); end; end; @@ -1994,7 +2184,7 @@ begin end; function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word; - PanelType: Word; b1x3: Boolean): Boolean; + PanelType: Word; b1x3: Boolean=false): Boolean; var a, h: Integer; begin @@ -2117,7 +2307,7 @@ function g_Map_CollideLiquid_TextureOld(X, Y: Integer; Width, Height: Word): DWO var texid: DWORD; - function checkPanels (var panels: TPanelArray): Boolean; + function checkPanels (constref panels: TPanelArray): Boolean; var a: Integer; begin @@ -2145,17 +2335,17 @@ end; function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean; - function checker (obj: TObject; tag: Integer): Boolean; - var - pan: TPanel; +const + SlowMask = GridTagLift or GridTagBlockMon; + function checker (pan: TPanel; tag: Integer): Boolean; begin - result := false; // don't stop, ever - pan := TPanel(obj); - + { 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 @@ -2163,19 +2353,20 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; ((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))) and - g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height); + (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))) {and + g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height)}; exit; end; 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; // other shit - result := g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height); + //result := g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height); + result := true; // i found her! end; var @@ -2194,7 +2385,7 @@ begin if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('*solids'); if gdbg_map_use_accel_coldet then begin - if gdbg_map_use_tree_coldet then + {if gdbg_map_use_tree_coldet then begin //e_WriteLog(Format('coldet query: x=%d; y=%d; w=%d; h=%d', [X, Y, Width, Height]), MSG_NOTIFY); result := (mapTree.aabbQuery(X, Y, Width, Height, checker, tagmask) <> nil); @@ -2204,9 +2395,34 @@ begin g_Console_Add(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited])); end; end - else + else} begin - result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask); + if (Width = 1) and (Height = 1) then + begin + if ((tagmask and SlowMask) <> 0) then + begin + // slow + result := (mapGrid.forEachAtPoint(X, Y, checker, tagmask) <> nil); + end + else + begin + // fast + result := (mapGrid.forEachAtPoint(X, Y, nil, tagmask) <> nil); + end; + end + else + begin + if ((tagmask and SlowMask) <> 0) then + begin + // slow + result := (mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask) <> nil); + end + else + begin + // fast + result := (mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask) <> nil); + end; + end; end; end else @@ -2223,9 +2439,7 @@ var texid: DWORD; // slightly different from the old code, but meh... - function checker (obj: TObject; tag: Integer): Boolean; - var - pan: TPanel; + function checker (pan: TPanel; tag: Integer): Boolean; begin result := false; // don't stop, ever //if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2)) = 0) then exit; @@ -2236,10 +2450,9 @@ var //2: if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2) = 0) then exit; // allowed: water, acid1, acid2 end; // collision? - pan := (obj as TPanel); - if not g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height) then exit; + //if not g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height) then exit; // yeah - texid := TPanel(obj).GetTextureID(); + texid := pan.GetTextureID(); // water? water has the highest priority, so stop right here if ((tag and GridTagWater) <> 0) then begin cctype := 0; result := true; exit; end; // acid2? @@ -2253,13 +2466,20 @@ begin if gdbg_map_use_accel_coldet then begin texid := TEXTURE_NONE; - if gdbg_map_use_tree_coldet then + {if gdbg_map_use_tree_coldet then begin mapTree.aabbQuery(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); end - else + else} begin - gMapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); + if (Width = 1) and (Height = 1) then + begin + mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); + end + else + begin + mapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); + end; end; result := texid; end @@ -2270,26 +2490,42 @@ begin if (profMapCollision <> nil) then profMapCollision.sectionEnd(); end; + procedure g_Map_EnableWall(ID: DWORD); +var + pan: TPanel; begin - with gWalls[ID] do - begin - Enabled := True; - g_Mark(X, Y, Width, Height, MARK_DOOR, True); + pan := gWalls[ID]; + pan.Enabled := True; + g_Mark(pan.X, pan.Y, pan.Width, pan.Height, MARK_DOOR, True); - if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID); - end; + mapGrid.proxyEnabled[pan.proxyId] := true; + //if (pan.proxyId >= 0) then mapGrid.proxyEnabled[pan.proxyId] := true + //else pan.proxyId := mapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, GridTagDoor); + + if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(gWalls[ID].PanelType, ID); + + {$IFDEF MAP_DEBUG_ENABLED_FLAG} + e_WriteLog(Format('wall #%d(%d) enabled (%d) (%d,%d)-(%d,%d)', [Integer(ID), Integer(pan.proxyId), Integer(mapGrid.proxyEnabled[pan.proxyId]), pan.x, pan.y, pan.width, pan.height]), MSG_NOTIFY); + {$ENDIF} end; procedure g_Map_DisableWall(ID: DWORD); +var + pan: TPanel; begin - with gWalls[ID] do - begin - Enabled := False; - g_Mark(X, Y, Width, Height, MARK_DOOR, False); + pan := gWalls[ID]; + pan.Enabled := False; + g_Mark(pan.X, pan.Y, pan.Width, pan.Height, MARK_DOOR, False); - if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID); - end; + mapGrid.proxyEnabled[pan.proxyId] := false; + //if (pan.proxyId >= 0) then begin mapGrid.removeBody(pan.proxyId); pan.proxyId := -1; end; + + if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(pan.PanelType, ID); + + {$IFDEF MAP_DEBUG_ENABLED_FLAG} + e_WriteLog(Format('wall #%d(%d) disabled (%d) (%d,%d)-(%d,%d)', [Integer(ID), Integer(pan.proxyId), Integer(mapGrid.proxyEnabled[pan.proxyId]), pan.x, pan.y, pan.width, pan.height]), MSG_NOTIFY); + {$ENDIF} end; procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0); @@ -2330,6 +2566,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) @@ -2706,4 +2943,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 (mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) = nil) 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 (mapGrid.forEachAtPoint(x, y, nil, MaskLiquid) = nil) then exit; // out of the water, just exit + topx := x; + topy := y; + end; +end; + + end.