X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_map.pas;h=f0419bf49cf4314ad47ee168b1eb3fd78c87ad8a;hb=36deb8d4595b015f77465c8eaee2bc75e9308d99;hp=cc6d9d2715d304e6b89c553117e3cf745445a540;hpb=5ee3fd108bcad8621ca1d8672ffc6393aece3917;p=d2df-sdl.git diff --git a/src/game/g_map.pas b/src/game/g_map.pas index cc6d9d2..f0419bf 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -14,13 +14,14 @@ * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} +{$DEFINE MAP_DEBUG_ENABLED_FLAG} unit g_map; interface uses e_graphics, g_basic, MAPSTRUCT, g_textures, Classes, - g_phys, wadreader, BinEditor, g_panel, g_grid, z_aabbtree, md5, binheap, xprofiler; + g_phys, wadreader, BinEditor, g_panel, g_grid, md5, binheap, xprofiler; type TMapInfo = record @@ -91,18 +92,29 @@ 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): Integer; +// returns panel or nil +// sets `ex` and `ey` to `x1` and `y1` when no hit was detected +function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): TPanel; + +// returns panel or nil +// sets `ex` and `ey` to `x1` and `y1` when no hit was detected +function g_Map_traceToNearest (x0, y0, x1, y1: Integer; tag: Integer; hitx: PInteger=nil; hity: PInteger=nil): TPanel; type TForEachPanelCB = function (pan: TPanel): Boolean; // return `true` to stop -function g_Map_ForEachPanelAt (x, y: Integer; cb: TForEachPanelCB; panelType: Word): Boolean; +function g_Map_HasAnyPanelAtPoint (x, y: Integer; panelType: Word): Boolean; +function g_Map_PanelAtPoint (x, y: Integer; tagmask: Integer=-1): TPanel; + +// 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_TraceLiquidNonPrecise (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; @@ -152,6 +164,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; @@ -173,15 +187,20 @@ 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; 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 +type + TPanelGrid = specialize TBodyGridBase; + +var + mapGrid: TPanelGrid = nil; + + implementation uses @@ -199,26 +218,6 @@ 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 case panelType of @@ -241,12 +240,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 (); @@ -267,8 +265,6 @@ var RespawnPoints: Array of TRespawnPoint; FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint; //DOMFlagPoints: Array of TFlagPoint; - gMapGrid: TPanelGrid = nil; - mapTree: TDynAABBTreeMap = nil; procedure g_Map_ProfilersBegin (); @@ -292,107 +288,72 @@ end; // wall index in `gWalls` or -1 -function g_Map_traceToNearestWall (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; +function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): TPanel; +var + ex, ey: Integer; +begin + result := mapGrid.traceRay(ex, ey, x0, y0, x1, y1, nil, (GridTagWall or GridTagDoor)); + if (result <> nil) then 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; + if (hitx <> nil) then hitx^ := ex; + if (hity <> nil) then hity^ := ey; + end + else + begin + if (hitx <> nil) then hitx^ := x1; + if (hity <> nil) then hity^ := y1; end; +end; +// returns panel or nil +function g_Map_traceToNearest (x0, y0, x1, y1: Integer; tag: Integer; hitx: PInteger=nil; hity: PInteger=nil): TPanel; var - qr: TDynAABBTreeMap.TSegmentQueryResult; - ray: Ray2D; - hxf, hyf: Single; - hx, hy: Integer; - maxDistSq: Single; + ex, ey: Integer; begin - result := -1; - if (mapTree = nil) then exit; - if mapTree.segmentQuery(qr, x0, y0, x1, y1, sqchecker, (GridTagWall or GridTagDoor)) then + result := mapGrid.traceRay(ex, ey, x0, y0, x1, y1, nil, tag); + if (result <> nil) 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; + if (hitx <> nil) then hitx^ := ex; + if (hity <> nil) then hity^ := ey; + end + else + begin + if (hitx <> nil) then hitx^ := x1; + if (hity <> nil) then hity^ := y1; end; end; -function g_Map_ForEachPanelAt (x, y: Integer; cb: TForEachPanelCB; panelType: Word): Boolean; +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; + } 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))) and - (x >= pan.X) and (y >= pan.Y) and (x < pan.X+pan.Width) and (y < pan.Y+pan.Height); - if result then result := cb(pan);; + (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))); exit; end; - // other shit - result := (x >= pan.X) and (y >= pan.Y) and (x < pan.X+pan.Width) and (y < pan.Y+pan.Height); - if result then result := cb(pan); + 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 not assigned(cb) then exit; - //if (mapTree = nil) then exit; - //function TDynAABBTreeBase.pointQuery (ax, ay: TreeNumber; cb: TQueryOverlapCB; tagmask: Integer=-1): TTreeFlesh; 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; @@ -403,7 +364,24 @@ begin if WordBool(PanelType and PANEL_BLOCKMON) then tagmask := tagmask or GridTagBlockMon; if (tagmask = 0) then exit;// just in case - result := gMapGrid.forEachInAABB(x, y, 1, 1, checker, tagmask); + 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_PanelAtPoint (x, y: Integer; tagmask: Integer=-1): TPanel; +begin + result := nil; + if (tagmask = 0) then exit; + result := mapGrid.forEachAtPoint(x, y, nil, tagmask); end; @@ -615,7 +593,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; @@ -967,7 +946,7 @@ end; procedure CreateArea(Area: TAreaRec_1); var a: Integer; - id: DWORD; + id: DWORD = 0; begin case Area.AreaType of AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2, @@ -1152,6 +1131,7 @@ begin addResToExternalResList(mapHeader.SkyName); end; + procedure mapCreateGrid (); var mapX0: Integer = $3fffffff; @@ -1176,27 +1156,56 @@ var end; end; - procedure addPanelsToGrid (constref panels: TPanelArray; tag: Integer); + procedure addPanelsToGrid (constref panels: TPanelArray); var idx: Integer; pan: TPanel; + newtag: Integer; begin - tag := panelTypeToTag(tag); - for idx := High(panels) downto 0 do + //tag := panelTypeToTag(tag); + for idx := 0 to High(panels) do begin 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 + if (pan.proxyId <> -1) then + begin + {$IF DEFINED(D2F_DEBUG)} + e_WriteLog(Format('DUPLICATE wall #%d(%d) enabled (%d); type:%08x', [Integer(idx), Integer(pan.proxyId), Integer(mapGrid.proxyEnabled[pan.proxyId]), pan.PanelType]), MSG_NOTIFY); + {$ENDIF} + continue; + end; + case pan.PanelType of + PANEL_WALL: newtag := GridTagWall; + PANEL_OPENDOOR, PANEL_CLOSEDOOR: newtag := GridTagDoor; + PANEL_BACK: newtag := GridTagBack; + PANEL_FORE: newtag := GridTagFore; + PANEL_WATER: newtag := GridTagWater; + PANEL_ACID1: newtag := GridTagAcid1; + PANEL_ACID2: newtag := GridTagAcid2; + PANEL_STEP: newtag := GridTagStep; + PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT: newtag := GridTagLift; + PANEL_BLOCKMON: newtag := GridTagBlockMon; + else continue; // oops + end; + pan.tag := newtag; + + pan.proxyId := mapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, newtag); + // "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} end; end; begin - gMapGrid.Free(); - gMapGrid := nil; - mapTree.Free(); - mapTree := nil; + mapGrid.Free(); + mapGrid := nil; calcBoundingBox(gWalls); calcBoundingBox(gRenderBackgrounds); @@ -1208,28 +1217,32 @@ begin calcBoundingBox(gLifts); calcBoundingBox(gBlockMon); - 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); - mapTree := TDynAABBTreeMap.Create(); - - addPanelsToGrid(gWalls, PANEL_WALL); - addPanelsToGrid(gWalls, PANEL_CLOSEDOOR); - addPanelsToGrid(gWalls, PANEL_OPENDOOR); - addPanelsToGrid(gRenderBackgrounds, PANEL_BACK); - addPanelsToGrid(gRenderForegrounds, PANEL_FORE); - addPanelsToGrid(gWater, PANEL_WATER); - addPanelsToGrid(gAcid1, PANEL_ACID1); - addPanelsToGrid(gAcid2, PANEL_ACID2); - addPanelsToGrid(gSteps, PANEL_STEP); - 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); + e_WriteLog(Format('map dimensions: (%d,%d)-(%d,%d); editor size:(0,0)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1, gMapInfo.Width, gMapInfo.Height]), MSG_WARNING); + + if (mapX0 > 0) then mapX0 := 0; + if (mapY0 > 0) then mapY0 := 0; + + if (mapX1 < gMapInfo.Width-1) then mapX1 := gMapInfo.Width-1; + if (mapY1 < gMapInfo.Height-1) then mapY1 := gMapInfo.Height-1; + + mapGrid := TPanelGrid.Create(mapX0-128, mapY0-128, mapX1-mapX0+1+128*2, mapY1-mapY0+1+128*2); + + addPanelsToGrid(gWalls); + addPanelsToGrid(gRenderBackgrounds); + addPanelsToGrid(gRenderForegrounds); + addPanelsToGrid(gWater); + addPanelsToGrid(gAcid1); + addPanelsToGrid(gAcid2); + addPanelsToGrid(gSteps); + addPanelsToGrid(gLifts); // it doesn't matter which LIFT type is used here + addPanelsToGrid(gBlockMon); + + mapGrid.dumpStats(); + + g_Mons_InitTree(mapGrid.gridX0, mapGrid.gridY0, mapGrid.gridWidth, mapGrid.gridHeight); end; + function g_Map_Load(Res: String): Boolean; const DefaultMusRes = 'Standart.wad:STDMUS\MUS1'; @@ -1262,10 +1275,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; @@ -1317,6 +1330,22 @@ begin _textures := MapReader.GetTextures(); _texnummap := nil; + // Çàãðóçêà îïèñàíèÿ êàðòû: + e_WriteLog(' Reading map info...', MSG_NOTIFY); + g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False); + Header := MapReader.GetMapHeader(); + + with gMapInfo do + begin + Name := Header.MapName; + Description := Header.MapDescription; + Author := Header.MapAuthor; + MusicName := Header.MusicName; + SkyName := Header.SkyName; + Height := Header.Height; + Width := Header.Width; + end; + // Äîáàâëåíèå òåêñòóð â Textures[]: if _textures <> nil then begin @@ -1572,6 +1601,10 @@ begin end; end; + // create map grid, init other grids (for monsters, for example) + e_WriteLog('Creating map grid', MSG_NOTIFY); + mapCreateGrid(); + // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû: if (triggers <> nil) and not gLoadGameMode then begin @@ -1637,24 +1670,8 @@ begin CreateMonster(monsters[a]); end; - // Çàãðóçêà îïèñàíèÿ êàðòû: - e_WriteLog(' Reading map info...', MSG_NOTIFY); - g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False); - Header := MapReader.GetMapHeader(); - MapReader.Free(); - with gMapInfo do - begin - Name := Header.MapName; - Description := Header.MapDescription; - Author := Header.MapAuthor; - MusicName := Header.MusicName; - SkyName := Header.SkyName; - Height := Header.Height; - Width := Header.Width; - end; - // Çàãðóçêà íåáà: if gMapInfo.SkyName <> '' then begin @@ -1733,9 +1750,6 @@ begin sfsGCEnable(); // enable releasing unused volumes end; - e_WriteLog('Creating map grid', MSG_NOTIFY); - mapCreateGrid(); - e_WriteLog('Done loading map.', MSG_NOTIFY); Result := True; end; @@ -2053,6 +2067,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 @@ -2064,19 +2079,20 @@ 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); 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 @@ -2084,13 +2100,13 @@ procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; 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)); end; end; @@ -2255,14 +2271,17 @@ end; function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean; +const + SlowMask = GridTagLift or GridTagBlockMon; 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; + exit; end; + } if ((tag and GridTagLift) <> 0) then begin @@ -2270,19 +2289,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 @@ -2301,7 +2321,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); @@ -2311,9 +2331,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 @@ -2341,7 +2386,7 @@ var //2: if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2) = 0) then exit; // allowed: water, acid1, acid2 end; // collision? - 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 := pan.GetTextureID(); // water? water has the highest priority, so stop right here @@ -2357,13 +2402,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 @@ -2374,26 +2426,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('ENABLE: 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('DISABLE: 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); @@ -2434,6 +2502,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) @@ -2810,4 +2879,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_TraceLiquidNonPrecise (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.