X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_map.pas;h=924dc000ada380a2b1b7a9010bffa327148b06fa;hb=6d6df4e3427cd01e03e172984c9d0d391ff38032;hp=8fa48d2735c4922cbd930d9a9c41b8abf22827dd;hpb=834fce43a6f96778d815cf0f8f858dfee0de9058;p=d2df-sdl.git diff --git a/src/game/g_map.pas b/src/game/g_map.pas index 8fa48d2..924dc00 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -20,8 +20,8 @@ unit g_map; interface uses - e_graphics, g_basic, MAPSTRUCT, g_textures, Classes, - g_phys, wadreader, BinEditor, g_panel, g_grid, md5, binheap, xprofiler; + e_graphics, g_basic, MAPDEF, g_textures, Classes, + g_phys, wadreader, BinEditor, g_panel, g_grid, md5, binheap, xprofiler, xparser, xdynrec; type TMapInfo = record @@ -92,23 +92,40 @@ 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; log: Boolean=false): Boolean; +// 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_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_TraceLiquid (x, y, dx, dy: Integer; out topx, topy: Integer): Boolean; +function g_Map_TraceLiquidNonPrecise (x, y, dx, dy: Integer; out topx, topy: Integer): Boolean; procedure g_Map_ProfilersBegin (); procedure g_Map_ProfilersEnd (); +function g_Map_ParseMap (data: Pointer; dataLen: Integer): TDynRecord; + +const + NNF_NO_NAME = 0; + NNF_NAME_BEFORE = 1; + NNF_NAME_EQUALS = 2; + NNF_NAME_AFTER = 3; + +function g_Texture_NumNameFindStart(name: String): Boolean; +function g_Texture_NumNameFindNext(var newName: String): Byte; + const RESPAWNPOINT_PLAYER1 = 1; RESPAWNPOINT_PLAYER2 = 2; @@ -172,7 +189,7 @@ var gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag; //gDOMFlags: array of TFlag; gMapInfo: TMapInfo; - gBackSize: TPoint; + gBackSize: TDFPoint; gDoorMap: array of array of DWORD; gLiftMap: array of array of DWORD; gWADHash: TMD5Digest; @@ -184,17 +201,25 @@ var 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; // DO NOT USE! public for debugging only! + + implementation uses g_main, e_log, SysUtils, g_items, g_gfx, g_console, GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG, - g_options, MAPREADER, g_triggers, g_player, MAPDEF, + g_options, g_triggers, g_player, Math, g_monsters, g_saveload, g_language, g_netmsg, - utils, sfs, + utils, sfs, xstreams, ImagingTypes, Imaging, ImagingUtility, ImagingGif, ImagingNetworkGraphics; @@ -204,8 +229,169 @@ const FLAG_SIGNATURE = $47414C46; // 'FLAG' -type - TPanelGrid = specialize TBodyGridBase; +var + dfmapdef: TDynMapDef = nil; + + +procedure loadMapDefinition (); +var + pr: TTextParser = nil; + st: TStream = nil; + WAD: TWADFile = nil; +begin + if (dfmapdef <> nil) then exit; + try + e_LogWritefln('parsing "mapdef.txt"...', []); + st := openDiskFileRO(DataDir+'mapdef.txt'); + except + st := nil; + e_LogWritefln('local "%smapdef.txt" not found', [DataDir]); + end; + if (st = nil) then + begin + WAD := TWADFile.Create(); + if not WAD.ReadFile(GameWAD) then + begin + //raise Exception.Create('cannot load "game.wad"'); + st := nil; + end + else + begin + st := WAD.openFileStream('mapdef.txt'); + end; + end; + + if (st = nil) then + begin + //raise Exception.Create('cannot open "mapdef.txt"'); + e_LogWritefln('using default "mapdef.txt"...', [], MSG_WARNING); + pr := TStrTextParser.Create(defaultMapDef); + end + else + begin + pr := TFileTextParser.Create(st); + end; + + try + dfmapdef := TDynMapDef.Create(pr); + except on e: Exception do + raise Exception.Create(Format('ERROR in "mapdef.txt" at (%s,%s): %s', [pr.line, pr.col, e.message])); + end; + + st.Free(); + WAD.Free(); +end; + + +function g_Map_ParseMap (data: Pointer; dataLen: Integer): TDynRecord; +var + wst: TSFSMemoryChunkStream = nil; + pr: TTextParser = nil; +begin + result := nil; + if (dataLen < 4) then exit; + loadMapDefinition(); + if (dfmapdef = nil) then raise Exception.Create('internal map loader error'); + + wst := TSFSMemoryChunkStream.Create(data, dataLen); + + if (PAnsiChar(data)[0] = 'M') and (PAnsiChar(data)[1] = 'A') and (PAnsiChar(data)[2] = 'P') and (PByte(data)[3] = 1) then + begin + // binary map + try + result := dfmapdef.parseBinMap(wst); + except on e: Exception do + begin + e_LogWritefln('ERROR: %s', [e.message]); + wst.Free(); + result := nil; + exit; + end; + end; + wst.Free(); + end + else + begin + // text map + pr := TFileTextParser.Create(wst); + try + result := dfmapdef.parseMap(pr); + except on e: Exception do + begin + if (pr <> nil) then e_LogWritefln('ERROR at (%s,%s): %s', [pr.line, pr.col, e.message]) + else e_LogWritefln('ERROR: %s', [e.message]); + pr.Free(); // will free `wst` + result := nil; + exit; + end; + end; + pr.Free(); // will free `wst` + end; +end; + + +var + NNF_PureName: String; // Èìÿ òåêñòóðû áåç öèôð â êîíöå + NNF_FirstNum: Integer; // ×èñëî ó íà÷àëüíîé òåêñòóðû + NNF_CurrentNum: Integer; // Ñëåäóþùåå ÷èñëî ó òåêñòóðû + + +function g_Texture_NumNameFindStart(name: String): Boolean; +var + i: Integer; + +begin + Result := False; + NNF_PureName := ''; + NNF_FirstNum := -1; + NNF_CurrentNum := -1; + + for i := Length(name) downto 1 do + if (name[i] = '_') then // "_" - ñèìâîë íà÷àëà íîìåðíîãî ïîñòôèêñà + begin + if i = Length(name) then + begin // Íåò öèôð â êîíöå ñòðîêè + Exit; + end + else + begin + NNF_PureName := Copy(name, 1, i); + Delete(name, 1, i); + Break; + end; + end; + +// Íå ïåðåâåñòè â ÷èñëî: + if not TryStrToInt(name, NNF_FirstNum) then + Exit; + + NNF_CurrentNum := 0; + + Result := True; +end; + + +function g_Texture_NumNameFindNext(var newName: String): Byte; +begin + if (NNF_PureName = '') or (NNF_CurrentNum < 0) then + begin + newName := ''; + Result := NNF_NO_NAME; + Exit; + end; + + newName := NNF_PureName + IntToStr(NNF_CurrentNum); + + if NNF_CurrentNum < NNF_FirstNum then + Result := NNF_NAME_BEFORE + else + if NNF_CurrentNum > NNF_FirstNum then + Result := NNF_NAME_AFTER + else + Result := NNF_NAME_EQUALS; + + Inc(NNF_CurrentNum); +end; function panelTypeToTag (panelType: Word): Integer; @@ -255,7 +441,6 @@ var RespawnPoints: Array of TRespawnPoint; FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint; //DOMFlagPoints: Array of TFlagPoint; - mapGrid: TPanelGrid = nil; procedure g_Map_ProfilersBegin (); @@ -279,14 +464,30 @@ end; // wall index in `gWalls` or -1 -function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil; log: Boolean=false): Boolean; +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 + 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 ex, ey: Integer; begin - mapGrid.dbgShowTraceLog := log; - result := (mapGrid.traceRay(ex, ey, x0, y0, x1, y1, nil, (GridTagWall or GridTagDoor)) <> nil); - mapGrid.dbgShowTraceLog := false; - if result then + result := mapGrid.traceRay(ex, ey, x0, y0, x1, y1, nil, tag); + if (result <> nil) then begin if (hitx <> nil) then hitx^ := ex; if (hity <> nil) then hity^ := ey; @@ -352,6 +553,14 @@ begin 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; + + function g_Map_IsSpecialTexture(Texture: String): Boolean; begin Result := (Texture = TEXTURE_NAME_WATER) or @@ -585,7 +794,7 @@ begin Width := 1; Height := 1; Anim := False; - TextureID := TEXTURE_NONE; + TextureID := LongWord(TEXTURE_NONE); end; end; @@ -618,13 +827,13 @@ begin TextureName := RecName; if TextureName = TEXTURE_NAME_WATER then - TextureID := TEXTURE_SPECIAL_WATER + TextureID := LongWord(TEXTURE_SPECIAL_WATER) else if TextureName = TEXTURE_NAME_ACID1 then - TextureID := TEXTURE_SPECIAL_ACID1 + TextureID := LongWord(TEXTURE_SPECIAL_ACID1) else if TextureName = TEXTURE_NAME_ACID2 then - TextureID := TEXTURE_SPECIAL_ACID2; + TextureID := LongWord(TEXTURE_SPECIAL_ACID2); Anim := False; end; @@ -1073,7 +1282,7 @@ begin gExternalResources.Add(res); end; -procedure generateExternalResourcesList(mapReader: TMapReader_1); +procedure generateExternalResourcesList({mapReader: TMapReader_1}map: TDynRecord); var textures: TTexturesRec1Array; mapHeader: TMapHeaderRec_1; @@ -1084,7 +1293,7 @@ begin gExternalResources := TStringList.Create; gExternalResources.Clear; - textures := mapReader.GetTextures(); + textures := GetTextures(map); for i := 0 to High(textures) do begin addResToExternalResList(resFile); @@ -1092,7 +1301,7 @@ begin textures := nil; - mapHeader := mapReader.GetMapHeader; + mapHeader := GetMapHeader(map); addResToExternalResList(mapHeader.MusicName); addResToExternalResList(mapHeader.SkyName); @@ -1123,25 +1332,49 @@ 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; - pan.proxyId := mapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, tag); + 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; @@ -1160,21 +1393,26 @@ begin calcBoundingBox(gLifts); calcBoundingBox(gBlockMon); - e_WriteLog(Format('map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING); + e_LogWritefln('map dimensions: (%d,%d)-(%d,%d); editor size:(0,0)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1, gMapInfo.Width, gMapInfo.Height]); + + if (mapX0 > 0) then mapX0 := 0; + if (mapY0 > 0) then mapY0 := 0; - mapGrid := TPanelGrid.Create(mapX0-512, mapY0-512, mapX1-mapX0+1+512*2, mapY1-mapY0+1+512*2); + if (mapX1 < gMapInfo.Width-1) then mapX1 := gMapInfo.Width-1; + if (mapY1 < gMapInfo.Height-1) then mapY1 := gMapInfo.Height-1; - 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); + mapGrid := TPanelGrid.Create(mapX0-128, mapY0-128, mapX1-mapX0+1+128*2, mapY1-mapY0+1+128*2); + //mapGrid := TPanelGrid.Create(0, 0, gMapInfo.Width, gMapInfo.Height); + + 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(); @@ -1188,7 +1426,8 @@ const DefaultSkyRes = 'Standart.wad:STDSKY\SKY0'; var WAD: TWADFile; - MapReader: TMapReader_1; + //MapReader: TMapReader_1; + mapReader: TDynRecord = nil; Header: TMapHeaderRec_1; _textures: TTexturesRec1Array; _texnummap: array of Integer; // `_textures` -> `Textures` @@ -1212,12 +1451,9 @@ var Len: Integer; ok, isAnim, trigRef: Boolean; CurTex, ntn: Integer; - begin mapGrid.Free(); mapGrid := nil; - //mapTree.Free(); - //mapTree := nil; Result := False; gMapInfo.Map := Res; @@ -1238,6 +1474,7 @@ begin WAD.Free(); Exit; end; + //k8: why loader ignores path here? mapResName := g_ExtractFileName(Res); if not WAD.GetMapResource(mapResName, Data, Len) then @@ -1249,11 +1486,78 @@ begin WAD.Free(); - // Çàãðóçêà êàðòû: - e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY); + if (Len < 4) then + begin + e_LogWritefln('invalid map file: ''%s''', [mapResName]); + FreeMem(Data); + exit; + end; + + // Çàãðóçêà êàðòû: + e_LogWritefln('Loading map: %s', [mapResName], MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False); - MapReader := TMapReader_1.Create(); + { + if (PChar(Data)[0] = 'M') and (PChar(Data)[1] = 'A') and (PChar(Data)[2] = 'P') and (PByte(Data)[3] = 1) then + begin + // nothing + end + else + begin + e_LogWritefln('Loading text map: %s', [mapResName]); + loadMapDefinition(); + if (dfmapdef = nil) then raise Exception.Create('internal map loader error'); + //e_LogWritefln('***'#10'%s'#10'***', [dfmapdef.headerType.definition]); + wst := TSFSMemoryChunkStream.Create(Data, Len); + try + pr := TFileTextParser.Create(wst); + e_LogWritefln('parsing text map: %s', [mapResName]); + rec := dfmapdef.parseMap(pr); + except on e: Exception do + begin + if (pr <> nil) then e_LogWritefln('ERROR at (%s,%s): %s', [pr.line, pr.col, e.message]) + else e_LogWritefln('ERROR: %s', [e.message]); + pr.Free(); + wst.Free(); + FreeMem(Data); + exit; + end; + end; + pr.Free(); + //wst.Free(); // pr will do it + e_LogWritefln('writing text map to temporary bin storage...', []); + st := TMemoryStream.Create(); + try + rec.writeBinTo(st); + Len := Integer(st.position); + st.position := 0; + FreeMem(Data); + GetMem(Data, Len); + st.ReadBuffer(Data^, Len); + except on e: Exception do + begin + rec.Free(); + st.Free(); + e_LogWritefln('ERROR: %s', [e.message]); + FreeMem(Data); + exit; + end; + end; + st.Free(); + end; + } + try + mapReader := g_Map_ParseMap(Data, Len); + except + mapReader.Free(); + g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res])); + FreeMem(Data); + MapReader.Free(); + Exit; + end; + + { + MapReader := TMapReader_1.Create(); if not MapReader.LoadMap(Data) then begin g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res])); @@ -1261,14 +1565,31 @@ begin MapReader.Free(); Exit; end; + } FreeMem(Data); generateExternalResourcesList(MapReader); // Çàãðóçêà òåêñòóð: g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False); - _textures := MapReader.GetTextures(); + _textures := GetTextures(mapReader); _texnummap := nil; + // Çàãðóçêà îïèñàíèÿ êàðòû: + e_WriteLog(' Reading map info...', MSG_NOTIFY); + g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False); + Header := GetMapHeader(mapReader); + + 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 @@ -1281,12 +1602,16 @@ begin SetLength(s, 64); CopyMemory(@s[1], @_textures[a].Resource[0], 64); for b := 1 to Length(s) do + begin if s[b] = #0 then begin SetLength(s, b-1); Break; end; + end; + {$IF DEFINED(D2F_DEBUG)} e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY); + {$ENDIF} //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY); // Àíèìèðîâàííàÿ òåêñòóðà: if ByteBool(_textures[a].Anim) then @@ -1315,12 +1640,12 @@ begin gTriggerClientID := 0; e_WriteLog(' Loading triggers...', MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False); - triggers := MapReader.GetTriggers(); + triggers := GetTriggers(mapReader); // Çàãðóçêà ïàíåëåé: e_WriteLog(' Loading panels...', MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False); - panels := MapReader.GetPanels(); + panels := GetPanels(mapReader); // check texture numbers for panels for a := 0 to High(panels) do @@ -1528,32 +1853,44 @@ begin e_WriteLog('Creating map grid', MSG_NOTIFY); mapCreateGrid(); - // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû: if (triggers <> nil) and not gLoadGameMode then begin - e_WriteLog(' Creating triggers...', MSG_NOTIFY); + e_LogWritefln(' Creating triggers (%d)...', [Length(triggers)]); g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False); // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü: for a := 0 to High(triggers) do begin - if triggers[a].TexturePanel <> -1 then - b := panels[TriggersTable[a].TexturePanel].PanelType + if (triggers[a].TexturePanel <> -1) then + begin + if (TriggersTable[a].TexturePanel < 0) or (TriggersTable[a].TexturePanel > High(panels)) then + begin + e_WriteLog('error loading map: invalid panel index for trigger', MSG_FATALERROR); + result := false; + exit; + end; + b := panels[TriggersTable[a].TexturePanel].PanelType; + end else + begin b := 0; - if (triggers[a].TriggerType = TRIGGER_SHOT) and - (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then + end; + if (triggers[a].TriggerType = TRIGGER_SHOT) and (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then + begin c := panels[TriggersTable[a].ShotPanel].PanelType + end else + begin c := 0; + end; CreateTrigger(triggers[a], b, c); end; end; // Çàãðóçêà ïðåäìåòîâ: - e_WriteLog(' Loading triggers...', MSG_NOTIFY); + e_WriteLog(' Loading items...', MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False); - items := MapReader.GetItems(); + items := GetItems(mapReader); // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû: if (items <> nil) and not gLoadGameMode then @@ -1567,7 +1904,7 @@ begin // Çàãðóçêà îáëàñòåé: e_WriteLog(' Loading areas...', MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False); - areas := MapReader.GetAreas(); + areas := GetAreas(mapReader); // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè: if areas <> nil then @@ -1581,7 +1918,7 @@ begin // Çàãðóçêà ìîíñòðîâ: e_WriteLog(' Loading monsters...', MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False); - monsters := MapReader.GetMonsters(); + monsters := GetMonsters(mapReader); gTotalMonsters := 0; @@ -1594,24 +1931,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 @@ -1697,7 +2018,7 @@ end; function g_Map_GetMapInfo(Res: String): TMapInfo; var WAD: TWADFile; - MapReader: TMapReader_1; + MapReader: TDynRecord; Header: TMapHeaderRec_1; FileName: String; Data: Pointer; @@ -1722,8 +2043,8 @@ begin WAD.Free(); + { MapReader := TMapReader_1.Create(); - if not MapReader.LoadMap(Data) then begin g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True); @@ -1737,10 +2058,32 @@ begin Result.Name := Header.MapName; Result.Description := Header.MapDescription; end; + } + try + mapReader := g_Map_ParseMap(Data, Len); + except + mapReader := nil; + end; FreeMem(Data); + //MapReader.Free(); + + if (mapReader <> nil) then Header := GetMapHeader(mapReader) else FillChar(Header, sizeof(Header), 0); MapReader.Free(); + if (Header.Width > 0) and (Header.Height > 0) then + begin + Result.Name := Header.MapName; + Result.Description := Header.MapDescription; + end + else + begin + g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True); + ZeroMemory(@Header, SizeOf(Header)); + Result.Name := _lc[I_GAME_ERROR_MAP_SELECT]; + Result.Description := _lc[I_GAME_ERROR_MAP_SELECT]; + end; + Result.Map := Res; Result.Author := Header.MapAuthor; Result.Height := Header.Height; @@ -1848,7 +2191,7 @@ begin if Textures[a].Anim then g_Frames_DeleteByID(Textures[a].FramesID) else - if Textures[a].TextureID <> TEXTURE_NONE then + if Textures[a].TextureID <> LongWord(TEXTURE_NONE) then e_DeleteTexture(Textures[a].TextureID); Textures := nil; @@ -2018,15 +2361,7 @@ procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); begin dplClear(); //tagmask := panelTypeToTag(PanelType); - - {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} - begin - mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, GridDrawableMask, true); - end; + mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, GridDrawableMask); // list will be rendered in `g_game.DrawPlayer()` end; @@ -2040,14 +2375,7 @@ procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: end; begin - {if gdbg_map_use_tree_draw then - begin - mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); - end - else} - begin - mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor), true); - end; + mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); end; @@ -2201,7 +2529,7 @@ var end; begin - texid := TEXTURE_NONE; + texid := LongWord(TEXTURE_NONE); result := texid; if not checkPanels(gWater) then if not checkPanels(gAcid1) then @@ -2261,43 +2589,30 @@ begin if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('*solids'); if gdbg_map_use_accel_coldet then begin - {if gdbg_map_use_tree_coldet then + if (Width = 1) and (Height = 1) 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); - if (gdbg_map_dump_coldet_tree_queries) and (mapTree.nodesVisited <> 0) then + if ((tagmask and SlowMask) <> 0) then begin - //e_WriteLog(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited]), MSG_NOTIFY); - g_Console_Add(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited])); + // slow + result := (mapGrid.forEachAtPoint(X, Y, checker, tagmask) <> nil); + end + else + begin + // fast + result := (mapGrid.forEachAtPoint(X, Y, nil, tagmask) <> nil); end; end - else} + else begin - if (Width = 1) and (Height = 1) then + if ((tagmask and SlowMask) <> 0) 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; + // slow + result := (mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask) <> nil); 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; + // fast + result := (mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask) <> nil); end; end; end @@ -2341,21 +2656,14 @@ begin if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('liquids'); if gdbg_map_use_accel_coldet then begin - texid := TEXTURE_NONE; - {if gdbg_map_use_tree_coldet then + texid := LongWord(TEXTURE_NONE); + if (Width = 1) and (Height = 1) then begin - mapTree.aabbQuery(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); + mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); end - else} + else begin - 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; + mapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); end; result := texid; end @@ -2382,7 +2690,7 @@ begin 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); + //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; @@ -2400,7 +2708,7 @@ begin 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); + //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; @@ -2696,6 +3004,7 @@ var PAMem.LoadFromMemory(Mem); for i := 0 to Length(panels)-1 do + begin if panels[i].SaveIt then begin // ID ïàíåëè: @@ -2706,7 +3015,10 @@ var end; // Çàãðóæàåì ïàíåëü: panels[i].LoadState(PAMem); + if (panels[i].arrIdx <> i) then raise Exception.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel arrIdx'); + if (panels[i].proxyId >= 0) then mapGrid.proxyEnabled[panels[i].proxyId] := panels[i].Enabled; end; + end; // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí: PAMem.Free(); @@ -2759,7 +3071,7 @@ begin // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé è ñåòêó: g_GFX_Init(); - mapCreateGrid(); + //mapCreateGrid(); ///// Çàãðóæàåì ìóçûêó: ///// // Ñèãíàòóðà ìóçûêè: @@ -2822,7 +3134,7 @@ 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; +function g_Map_TraceLiquidNonPrecise (x, y, dx, dy: Integer; out topx, topy: Integer): Boolean; const MaskLiquid = GridTagWater or GridTagAcid1 or GridTagAcid2; begin