From 6d6df4e3427cd01e03e172984c9d0d391ff38032 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Wed, 30 Aug 2017 04:27:34 +0300 Subject: [PATCH] no more old mapreader: use textmap reader both for text and for binary maps --- src/engine/e_graphics.pas | 9 +- src/game/Doom2DF.dpr | 2 - src/game/g_game.pas | 14 +- src/game/g_gui.pas | 33 +- src/game/g_holmes.pas | 4 +- src/game/g_main.pas | 2 +- src/game/g_map.pas | 353 +++++++--- src/game/g_menu.pas | 2 +- src/game/g_monsters.pas | 4 +- src/game/g_panel.pas | 28 +- src/game/g_phys.pas | 8 +- src/game/g_player.pas | 10 +- src/game/g_playermodel.pas | 18 +- src/game/g_saveload.pas | 2 +- src/game/g_textures.pas | 6 +- src/game/g_triggers.pas | 2 +- src/game/g_weapons.pas | 2 +- src/shared/MAPDEF.pas | 534 +++++++-------- src/shared/MAPREADER.pas | 424 ------------ src/shared/MAPSTRUCT.pas | 144 ----- src/shared/mapdef.inc | 1148 +++++++++++++++++++++++++++++++++ src/shared/mapdef.txt | 2 +- src/shared/mapstructio.inc | 685 -------------------- src/shared/mapstructsizes.inc | 25 - src/shared/wadreader.pas | 2 +- src/shared/xdynrec.pas | 204 ++++-- src/shared/xparser.pas | 9 +- src/shared/zmapgen.dpr | 53 ++ 28 files changed, 1945 insertions(+), 1784 deletions(-) delete mode 100644 src/shared/MAPREADER.pas delete mode 100644 src/shared/MAPSTRUCT.pas create mode 100644 src/shared/mapdef.inc delete mode 100644 src/shared/mapstructio.inc delete mode 100644 src/shared/mapstructsizes.inc create mode 100644 src/shared/zmapgen.dpr diff --git a/src/engine/e_graphics.pas b/src/engine/e_graphics.pas index 83664b1..b7ddd2c 100644 --- a/src/engine/e_graphics.pas +++ b/src/engine/e_graphics.pas @@ -29,9 +29,6 @@ type X, Y: Integer; end; - TPoint = MAPDEF.TPoint; // TODO: create an utiltypes.pas or something - // for other types like rect as well - TPoint2f = record X, Y: Double; end; @@ -49,7 +46,7 @@ type R, G, B: Byte; end; - PPoint = ^TPoint; + PDFPoint = ^TDFPoint; PPoint2f = ^TPoint2f; PRect = ^TRect; PRectWH = ^TRectWH; @@ -65,7 +62,7 @@ procedure e_ResizeWindow(Width, Height: Integer); procedure e_Draw(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean; Blending: Boolean; Mirror: TMirrorType = M_NONE); procedure e_DrawAdv(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean; - Blending: Boolean; Angle: Single; RC: PPoint; Mirror: TMirrorType = M_NONE); + Blending: Boolean; Angle: Single; RC: PDFPoint; Mirror: TMirrorType = M_NONE); procedure e_DrawSize(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean; Blending: Boolean; Width, Height: Word; Mirror: TMirrorType = M_NONE); procedure e_DrawSizeMirror(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean; @@ -683,7 +680,7 @@ begin end; procedure e_DrawAdv(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean; - Blending: Boolean; Angle: Single; RC: PPoint; Mirror: TMirrorType = M_NONE); + Blending: Boolean; Angle: Single; RC: PDFPoint; Mirror: TMirrorType = M_NONE); begin if e_NoGraphics then Exit; diff --git a/src/game/Doom2DF.dpr b/src/game/Doom2DF.dpr index bfd07a5..a66e792 100644 --- a/src/game/Doom2DF.dpr +++ b/src/game/Doom2DF.dpr @@ -59,8 +59,6 @@ uses sfsPlainFS in '../sfs/sfsPlainFS.pas', sfsZipFS in '../sfs/sfsZipFS.pas', wadreader in '../shared/wadreader.pas', - MAPSTRUCT in '../shared/MAPSTRUCT.pas', - MAPREADER in '../shared/MAPREADER.pas', MAPDEF in '../shared/MAPDEF.pas', CONFIG in '../shared/CONFIG.pas', g_basic in 'g_basic.pas', diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 9336894..1cf4808 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -20,7 +20,7 @@ interface uses g_basic, g_player, e_graphics, Classes, g_res_downloader, - SysUtils, g_sound, g_gui, MAPSTRUCT, wadreader, md5, xprofiler; + SysUtils, g_sound, g_gui, MAPDEF, wadreader, md5, xprofiler; type TGameSettings = record @@ -63,7 +63,7 @@ type THearPoint = record Active: Boolean; - Coords: TPoint; + Coords: TDFPoint; end; function g_Game_IsNet(): Boolean; @@ -209,9 +209,9 @@ var gPlayer1Settings: TPlayerSettings; gPlayer2Settings: TPlayerSettings; gGameOn: Boolean; - gPlayerScreenSize: TPoint; - gPlayer1ScreenCoord: TPoint; - gPlayer2ScreenCoord: TPoint; + gPlayerScreenSize: TDFPoint; + gPlayer1ScreenCoord: TDFPoint; + gPlayer2ScreenCoord: TDFPoint; gPlayer1: TPlayer = nil; gPlayer2: TPlayer = nil; gPlayerDrawn: TPlayer = nil; @@ -338,7 +338,7 @@ uses g_textures, g_main, g_window, g_menu, e_input, e_log, g_console, g_items, g_map, g_panel, g_playermodel, g_gfx, g_options, g_weapons, Math, - g_triggers, MAPDEF, g_monsters, e_sound, CONFIG, + g_triggers, g_monsters, e_sound, CONFIG, BinEditor, g_language, g_net, SDL, ENet, e_msg, g_netmsg, g_netmaster, GL, GLExt, utils, sfs, g_holmes; @@ -5017,7 +5017,7 @@ procedure DebugCommands(P: SArray); var a, b: Integer; cmd: string; - //pt: TPoint; + //pt: TDFPoint; mon: TMonster; begin // Êîìàíäû îòëàäî÷íîãî ðåæèìà: diff --git a/src/game/g_gui.pas b/src/game/g_gui.pas index 5c60e10..45b2364 100644 --- a/src/game/g_gui.pas +++ b/src/game/g_gui.pas @@ -19,7 +19,7 @@ unit g_gui; interface uses - e_graphics, e_input, e_log, g_playermodel, g_basic, MAPSTRUCT, wadreader; + e_graphics, e_input, e_log, g_playermodel, g_basic, MAPDEF, wadreader; const MAINMENU_HEADER_COLOR: TRGB = (R:255; G:255; B:255); @@ -348,7 +348,7 @@ type TGUIMapPreview = class(TGUIControl) private FMapData: array of TPreviewPanel; - FMapSize: TPoint; + FMapSize: TDFPoint; FScale: Single; public constructor Create(); @@ -546,8 +546,8 @@ implementation uses GL, GLExt, g_textures, g_sound, SysUtils, - g_game, Math, StrUtils, g_player, g_options, MAPREADER, - g_map, MAPDEF, g_weapons; + g_game, Math, StrUtils, g_player, g_options, + g_map, g_weapons, xdynrec; var Box: Array [0..8] of DWORD; @@ -2775,7 +2775,7 @@ end; procedure TGUIMapPreview.SetMap(Res: string); var WAD: TWADFile; - MapReader: TMapReader_1; + //MapReader: TMapReader_1; panels: TPanelsRec1Array; header: TMapHeaderRec_1; a: Integer; @@ -2783,7 +2783,13 @@ var Data: Pointer; Len: Integer; rX, rY: Single; + map: TDynRecord = nil; begin + FMapSize.X := 0; + FMapSize.Y := 0; + FScale := 0.0; + FMapData := nil; + FileName := g_ExtractWadName(Res); WAD := TWADFile.Create(); @@ -2802,8 +2808,15 @@ begin WAD.Free(); - MapReader := TMapReader_1.Create(); + try + map := g_Map_ParseMap(Data, Len); + except + map.Free(); + raise; + end; + { + MapReader := TMapReader_1.Create(); if not MapReader.LoadMap(Data) then begin FreeMem(Data); @@ -2814,11 +2827,12 @@ begin FMapData := nil; Exit; end; + } FreeMem(Data); - panels := MapReader.GetPanels(); - header := MapReader.GetMapHeader(); + panels := GetPanels(map); + header := GetMapHeader(map); FMapSize.X := header.Width div 16; FMapSize.Y := header.Height div 16; @@ -2863,7 +2877,8 @@ begin panels := nil; - MapReader.Free(); + //MapReader.Free(); + map.Free(); end; procedure TGUIMapPreview.ClearMap(); diff --git a/src/game/g_holmes.pas b/src/game/g_holmes.pas index ae7c7b4..dfa8a00 100644 --- a/src/game/g_holmes.pas +++ b/src/game/g_holmes.pas @@ -102,7 +102,7 @@ implementation uses SysUtils, Classes, GL, SDL2, - MAPDEF, g_options, utils, hashtable, xparser; + MAPDEF, g_main, g_options, utils, hashtable, xparser; var @@ -1206,7 +1206,7 @@ begin // load bindings from file try - st := openDiskFileRO('holmes.rc'); + st := openDiskFileRO(GameDir+'holmes.rc'); pr := TFileTextParser.Create(st); conwriteln('parsing "holmes.rc"...'); while (pr.tokType <> pr.TTEOF) do diff --git a/src/game/g_main.pas b/src/game/g_main.pas index 7864bed..1b131f1 100644 --- a/src/game/g_main.pas +++ b/src/game/g_main.pas @@ -40,7 +40,7 @@ uses e_graphics, e_input, g_game, g_console, g_gui, e_sound, g_options, g_sound, g_player, g_weapons, SysUtils, g_triggers, MAPDEF, g_map, - MAPSTRUCT, g_menu, g_language, g_net, + g_menu, g_language, g_net, utils, conbuf, envvars; var diff --git a/src/game/g_map.pas b/src/game/g_map.pas index 4bb340d..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 @@ -115,6 +115,17 @@ 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; @@ -178,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; @@ -206,9 +217,9 @@ 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, xparser, xdynrec, xstreams, + utils, sfs, xstreams, ImagingTypes, Imaging, ImagingUtility, ImagingGif, ImagingNetworkGraphics; @@ -218,7 +229,6 @@ const FLAG_SIGNATURE = $47414C46; // 'FLAG' -{$IF DEFINED(D2D_NEW_MAP_READER)} var dfmapdef: TDynMapDef = nil; @@ -240,12 +250,27 @@ begin if (st = nil) then begin WAD := TWADFile.Create(); - if not WAD.ReadFile(GameWAD) then raise Exception.Create('cannot load "game.wad"'); - st := WAD.openFileStream('mapdef.txt'); + 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 raise Exception.Create('cannot open "mapdef.txt"'); - pr := TFileTextParser.Create(st); + 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); @@ -256,7 +281,117 @@ begin st.Free(); WAD.Free(); end; -{$ENDIF} + + +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; @@ -659,7 +794,7 @@ begin Width := 1; Height := 1; Anim := False; - TextureID := TEXTURE_NONE; + TextureID := LongWord(TEXTURE_NONE); end; end; @@ -692,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; @@ -1147,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; @@ -1158,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); @@ -1166,7 +1301,7 @@ begin textures := nil; - mapHeader := mapReader.GetMapHeader; + mapHeader := GetMapHeader(map); addResToExternalResList(mapHeader.MusicName); addResToExternalResList(mapHeader.SkyName); @@ -1291,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` @@ -1315,12 +1451,6 @@ var Len: Integer; ok, isAnim, trigRef: Boolean; CurTex, ntn: Integer; - {$IF DEFINED(D2D_NEW_MAP_READER)} - pr: TTextParser = nil; - st: TStream = nil; - wst: TSFSMemoryChunkStream = nil; - rec: TDynRecord; - {$ENDIF} begin mapGrid.Free(); mapGrid := nil; @@ -1367,58 +1497,67 @@ begin e_LogWritefln('Loading map: %s', [mapResName], MSG_NOTIFY); g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False); - {$IF DEFINED(D2D_NEW_MAP_READER)} - 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; + { + 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; - 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; + 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); - 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; + exit; end; - st.Free(); end; - {$ENDIF} + 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])); @@ -1426,18 +1565,19 @@ 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 := MapReader.GetMapHeader(); + Header := GetMapHeader(mapReader); with gMapInfo do begin @@ -1500,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 @@ -1716,28 +1856,41 @@ begin // Åñëè íå 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 @@ -1751,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 @@ -1765,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; @@ -1865,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; @@ -1890,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); @@ -1905,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; @@ -2016,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; @@ -2354,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 @@ -2481,7 +2656,7 @@ begin if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('liquids'); if gdbg_map_use_accel_coldet then begin - texid := TEXTURE_NONE; + texid := LongWord(TEXTURE_NONE); if (Width = 1) and (Height = 1) then begin mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2)); diff --git a/src/game/g_menu.pas b/src/game/g_menu.pas index 0905cdc..5371f41 100644 --- a/src/game/g_menu.pas +++ b/src/game/g_menu.pas @@ -45,7 +45,7 @@ uses g_gui, g_textures, e_graphics, g_main, g_window, g_game, g_map, g_basic, g_console, g_sound, g_gfx, g_player, g_options, g_weapons, e_log, SysUtils, CONFIG, g_playermodel, DateUtils, - MAPSTRUCT, wadreader, Math, g_saveload, + MAPDEF, wadreader, Math, g_saveload, e_texture, GL, GLExt, g_language, g_net, g_netmsg, g_netmaster, g_items, e_input; diff --git a/src/game/g_monsters.pas b/src/game/g_monsters.pas index 2b70da6..5ec0099 100644 --- a/src/game/g_monsters.pas +++ b/src/game/g_monsters.pas @@ -452,8 +452,8 @@ const LeftAnim: Boolean; wX, wY: Integer; // Îòêóäà âûëåòèò ïóëÿ AnimSpeed: Array [ANIM_SLEEP..ANIM_PAIN] of Byte; - AnimDeltaRight: Array [ANIM_SLEEP..ANIM_PAIN] of TPoint; - AnimDeltaLeft: Array [ANIM_SLEEP..ANIM_PAIN] of TPoint; + AnimDeltaRight: Array [ANIM_SLEEP..ANIM_PAIN] of TDFPoint; + AnimDeltaLeft: Array [ANIM_SLEEP..ANIM_PAIN] of TDFPoint; end = // SLEEP GO DIE MESS ATTACK ATTACK2 PAIN ((LeftAnim: False; wX: 54; wY: 32; AnimSpeed:(3, 2, 3, 2, 3, 0, 4); //DEMON AnimDeltaRight: ((X: 1; Y: 4), (X: 1; Y: 4), (X: 0; Y: 4), (X: 0; Y: 4), (X: 2; Y: 6), (X: 2; Y: 6), (X: 2; Y: 5)); diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index 96bd7f1..c562934 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -19,7 +19,7 @@ unit g_panel; interface uses - MAPSTRUCT, BinEditor, g_textures; + MAPDEF, BinEditor, g_textures; type TAddTextureArray = Array of @@ -94,7 +94,7 @@ type implementation uses - SysUtils, g_basic, g_map, MAPDEF, g_game, e_graphics, + SysUtils, g_basic, g_map, g_game, e_graphics, g_console, g_language, e_log, GL; const @@ -187,11 +187,11 @@ begin case PanelRec.PanelType of PANEL_WATER: - FTextureIDs[0].Tex := TEXTURE_SPECIAL_WATER; + FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_WATER); PANEL_ACID1: - FTextureIDs[0].Tex := TEXTURE_SPECIAL_ACID1; + FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID1); PANEL_ACID2: - FTextureIDs[0].Tex := TEXTURE_SPECIAL_ACID2; + FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID2); end; FCurTexture := 0; @@ -289,16 +289,16 @@ begin else begin // Îáû÷íàÿ òåêñòóðà case FTextureIDs[FCurTexture].Tex of - TEXTURE_SPECIAL_WATER: + LongWord(TEXTURE_SPECIAL_WATER): e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1, 0, 0, 255, 0, B_FILTER); - TEXTURE_SPECIAL_ACID1: + LongWord(TEXTURE_SPECIAL_ACID1): e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1, 0, 128, 0, 0, B_FILTER); - TEXTURE_SPECIAL_ACID2: + LongWord(TEXTURE_SPECIAL_ACID2): e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1, 128, 0, 0, 0, B_FILTER); - TEXTURE_NONE: + LongWord(TEXTURE_NONE): if g_Texture_Get('NOTEXTURE', NoTextureID) then begin e_GetTextureSize(NoTextureID, @NW, @NH); @@ -354,10 +354,10 @@ begin if not FTextureIDs[FCurTexture].Anim then begin case FTextureIDs[FCurTexture].Tex of - TEXTURE_SPECIAL_WATER: exit; - TEXTURE_SPECIAL_ACID1: exit; - TEXTURE_SPECIAL_ACID2: exit; - TEXTURE_NONE: exit; + LongWord(TEXTURE_SPECIAL_WATER): exit; + LongWord(TEXTURE_SPECIAL_ACID1): exit; + LongWord(TEXTURE_SPECIAL_ACID2): exit; + LongWord(TEXTURE_NONE): exit; end; end; if (X+Width < lightX-radius) then exit; @@ -498,7 +498,7 @@ end; function TPanel.GetTextureID(): DWORD; begin - Result := TEXTURE_NONE; + Result := LongWord(TEXTURE_NONE); if (FCurTexture >= 0) then begin diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas index 7780b3b..498bd75 100644 --- a/src/game/g_phys.pas +++ b/src/game/g_phys.pas @@ -461,13 +461,13 @@ _move: Obj^.Rect.Width, Obj^.Rect.Height*2 div 3); case wtx of - TEXTURE_SPECIAL_WATER: + LongWord(TEXTURE_SPECIAL_WATER): g_Obj_Splash(Obj, 3); - TEXTURE_SPECIAL_ACID1: + LongWord(TEXTURE_SPECIAL_ACID1): g_Obj_Splash(Obj, 2); - TEXTURE_SPECIAL_ACID2: + LongWord(TEXTURE_SPECIAL_ACID2): g_Obj_Splash(Obj, 1); - TEXTURE_NONE: + LongWord(TEXTURE_NONE): ; else g_Obj_Splash(Obj, 0); diff --git a/src/game/g_player.pas b/src/game/g_player.pas index ebbd204..488cee9 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -20,7 +20,7 @@ interface uses e_graphics, g_playermodel, g_basic, g_textures, - g_weapons, g_phys, g_sound, g_saveload, MAPSTRUCT, + g_weapons, g_phys, g_sound, g_saveload, MAPDEF, BinEditor, g_panel; const @@ -524,7 +524,7 @@ implementation uses e_log, g_map, g_items, g_console, SysUtils, g_gfx, Math, - g_options, g_triggers, g_menu, MAPDEF, g_game, g_grid, + g_options, g_triggers, g_menu, g_game, g_grid, wadreader, g_main, g_monsters, CONFIG, g_language, g_net, g_netmsg, g_window, GL, g_holmes; @@ -563,7 +563,7 @@ const ANGLE_LEFTUP = 125; ANGLE_LEFTDOWN = -145; PLAYER_HEADRECT: TRectWH = (X:24; Y:12; Width:20; Height:12); - WEAPONPOINT: Array [TDirection] of TPoint = ((X:16; Y:32), (X:47; Y:32)); + WEAPONPOINT: Array [TDirection] of TDFPoint = ((X:16; Y:32), (X:47; Y:32)); BOT_MAXJUMP = 84; BOT_LONGDIST = 300; BOT_UNSAFEDIST = 128; @@ -1711,7 +1711,7 @@ end; procedure g_Player_DrawCorpses(); var i: Integer; - a: TPoint; + a: TDFPoint; begin if gGibs <> nil then for i := 0 to High(gGibs) do @@ -1742,7 +1742,7 @@ end; procedure g_Player_DrawShells(); var i: Integer; - a: TPoint; + a: TDFPoint; begin if gShells <> nil then for i := 0 to High(gShells) do diff --git a/src/game/g_playermodel.pas b/src/game/g_playermodel.pas index 3c121db..72f5fb2 100644 --- a/src/game/g_playermodel.pas +++ b/src/game/g_playermodel.pas @@ -19,7 +19,7 @@ unit g_playermodel; interface uses - g_textures, g_basic, g_weapons, e_graphics, wadreader; + MAPDEF, g_textures, g_basic, g_weapons, e_graphics, wadreader; const A_STAND = 0; @@ -78,7 +78,7 @@ type TGibsArray = Array of TGibSprite; TWeaponPoints = Array [WP_FIRST + 1..WP_LAST] of Array [A_STAND..A_LAST] of - Array [D_LEFT..D_RIGHT] of Array of TPoint; + Array [D_LEFT..D_RIGHT] of Array of TDFPoint; TPlayerModel = class (TObject) private @@ -95,7 +95,7 @@ type FCurrentWeapon: Byte; FDrawWeapon: Boolean; FFlag: Byte; - FFlagPoint: TPoint; + FFlagPoint: TDFPoint; FFlagAngle: SmallInt; FFlagAnim: TAnimation; FFire: Boolean; @@ -141,7 +141,7 @@ type TPlayerModelInfo = record Info: TModelInfo; ModelSpeed: Array [A_STAND..A_PAIN] of Byte; - FlagPoint: TPoint; + FlagPoint: TDFPoint; FlagAngle: SmallInt; WeaponPoints: TWeaponPoints; Gibs: TGibsArray; @@ -158,10 +158,10 @@ const W_ACT_NORMAL = 0; W_ACT_FIRE = 1; - FLAG_BASEPOINT: TPoint = (X:16; Y:43); - FLAG_DEFPOINT: TPoint = (X:32; Y:16); + FLAG_BASEPOINT: TDFPoint = (X:16; Y:43); + FLAG_DEFPOINT: TDFPoint = (X:32; Y:16); FLAG_DEFANGLE = -20; - WEAPONBASE: Array [WP_FIRST + 1..WP_LAST] of TPoint = + WEAPONBASE: Array [WP_FIRST + 1..WP_LAST] of TDFPoint = ((X:8; Y:4), (X:8; Y:8), (X:16; Y:16), (X:16; Y:24), (X:16; Y:16), (X:24; Y:24), (X:16; Y:16), (X:24; Y:24), (X:16; Y:16), (X:8; Y:8)); @@ -198,7 +198,7 @@ begin end; end; -function GetPoint(var str: String; var point: TPoint): Boolean; +function GetPoint(var str: String; var point: TDFPoint): Boolean; var a, x, y: Integer; s: String; @@ -802,7 +802,7 @@ procedure TPlayerModel.Draw(X, Y: Integer; Alpha: Byte = 0); var Mirror: TMirrorType; pos, act: Byte; - p: TPoint; + p: TDFPoint; begin // Ôëàãè: if Direction = D_LEFT then diff --git a/src/game/g_saveload.pas b/src/game/g_saveload.pas index e6a1ca2..5a13098 100644 --- a/src/game/g_saveload.pas +++ b/src/game/g_saveload.pas @@ -42,7 +42,7 @@ implementation uses g_game, g_items, g_map, g_monsters, g_triggers, g_basic, g_main, SysUtils, Math, wadreader, - MAPSTRUCT, MAPDEF, g_weapons, g_player, g_console, + MAPDEF, g_weapons, g_player, g_console, e_log, g_language; const diff --git a/src/game/g_textures.pas b/src/game/g_textures.pas index 660e999..0209800 100644 --- a/src/game/g_textures.pas +++ b/src/game/g_textures.pas @@ -19,7 +19,7 @@ unit g_textures; interface uses - e_graphics, BinEditor, ImagingTypes, Imaging, ImagingUtility; + e_graphics, MAPDEF, BinEditor, ImagingTypes, Imaging, ImagingUtility; Type TLevelTexture = record @@ -55,7 +55,7 @@ Type constructor Create(FramesID: DWORD; Loop: Boolean; Speed: Byte); destructor Destroy(); override; procedure Draw(X, Y: Integer; Mirror: TMirrorType); - procedure DrawEx(X, Y: Integer; Mirror: TMirrorType; RPoint: TPoint; + procedure DrawEx(X, Y: Integer; Mirror: TMirrorType; RPoint: TDFPoint; Angle: SmallInt); procedure Reset(); procedure Update(); @@ -785,7 +785,7 @@ begin FEnabled := True; end; -procedure TAnimation.DrawEx(X, Y: Integer; Mirror: TMirrorType; RPoint: TPoint; +procedure TAnimation.DrawEx(X, Y: Integer; Mirror: TMirrorType; RPoint: TDFPoint; Angle: SmallInt); begin if not FEnabled then diff --git a/src/game/g_triggers.pas b/src/game/g_triggers.pas index 3b1f911..c327fdb 100644 --- a/src/game/g_triggers.pas +++ b/src/game/g_triggers.pas @@ -19,7 +19,7 @@ unit g_triggers; interface uses - MAPSTRUCT, e_graphics, MAPDEF, g_basic, g_sound, + MAPDEF, e_graphics, g_basic, g_sound, BinEditor; type diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas index aa78ebd..5d6a784 100644 --- a/src/game/g_weapons.pas +++ b/src/game/g_weapons.pas @@ -2497,7 +2497,7 @@ procedure g_Weapon_Draw(); var i: Integer; a: SmallInt; - p: TPoint; + p: TDFPoint; begin if Shots = nil then Exit; diff --git a/src/shared/MAPDEF.pas b/src/shared/MAPDEF.pas index f6678e9..12e0562 100644 --- a/src/shared/MAPDEF.pas +++ b/src/shared/MAPDEF.pas @@ -28,330 +28,248 @@ MAPDEF.PAS interface uses - MAPSTRUCT; + xdynrec; + -// *** WARNING! *** -// keep all constants in sync with "mapdesc.txt"! -// or even better: regenerate this part directly from "mapdesc.txt". const - PANEL_NONE = 0; - PANEL_WALL = 1; - PANEL_BACK = 2; - PANEL_FORE = 4; - PANEL_WATER = 8; - PANEL_ACID1 = 16; - PANEL_ACID2 = 32; - PANEL_STEP = 64; - PANEL_LIFTUP = 128; - PANEL_LIFTDOWN = 256; - PANEL_OPENDOOR = 512; - PANEL_CLOSEDOOR = 1024; - PANEL_BLOCKMON = 2048; - PANEL_LIFTLEFT = 4096; - PANEL_LIFTRIGHT = 8192; - - PANEL_FLAG_BLENDING = 1; - PANEL_FLAG_HIDE = 2; - PANEL_FLAG_WATERTEXTURES = 4; - - EFFECT_NONE = 0; - EFFECT_TELEPORT = 1; - EFFECT_RESPAWN = 2; - EFFECT_FIRE = 3; - - ITEM_NONE = 0; - ITEM_MEDKIT_SMALL = 1; - ITEM_MEDKIT_LARGE = 2; - ITEM_MEDKIT_BLACK = 3; - ITEM_ARMOR_GREEN = 4; - ITEM_ARMOR_BLUE = 5; - ITEM_SPHERE_BLUE = 6; - ITEM_SPHERE_WHITE = 7; - ITEM_SUIT = 8; - ITEM_OXYGEN = 9; - ITEM_INVUL = 10; - ITEM_WEAPON_SAW = 11; - ITEM_WEAPON_SHOTGUN1 = 12; - ITEM_WEAPON_SHOTGUN2 = 13; - ITEM_WEAPON_CHAINGUN = 14; - ITEM_WEAPON_ROCKETLAUNCHER = 15; - ITEM_WEAPON_PLASMA = 16; - ITEM_WEAPON_BFG = 17; - ITEM_WEAPON_SUPERPULEMET = 18; - ITEM_AMMO_BULLETS = 19; - ITEM_AMMO_BULLETS_BOX = 20; - ITEM_AMMO_SHELLS = 21; - ITEM_AMMO_SHELLS_BOX = 22; - ITEM_AMMO_ROCKET = 23; - ITEM_AMMO_ROCKET_BOX = 24; - ITEM_AMMO_CELL = 25; - ITEM_AMMO_CELL_BIG = 26; - ITEM_AMMO_BACKPACK = 27; - ITEM_KEY_RED = 28; - ITEM_KEY_GREEN = 29; - ITEM_KEY_BLUE = 30; - ITEM_WEAPON_KASTET = 31; - ITEM_WEAPON_PISTOL = 32; - ITEM_BOTTLE = 33; - ITEM_HELMET = 34; - ITEM_JETPACK = 35; - ITEM_INVIS = 36; - ITEM_WEAPON_FLAMETHROWER = 37; - ITEM_AMMO_FUELCAN = 38; - - ITEM_MAX = 38; // store the last item's id in here - // use this in for loops - - ITEM_OPTION_ONLYDM = 1; - ITEM_OPTION_FALL = 2; - - AREA_NONE = 0; - AREA_PLAYERPOINT1 = 1; - AREA_PLAYERPOINT2 = 2; - AREA_DMPOINT = 3; - AREA_REDFLAG = 4; - AREA_BLUEFLAG = 5; - AREA_DOMFLAG = 6; - AREA_REDTEAMPOINT = 7; - AREA_BLUETEAMPOINT = 8; - - MONSTER_NONE = 0; - MONSTER_DEMON = 1; - MONSTER_IMP = 2; - MONSTER_ZOMBY = 3; - MONSTER_SERG = 4; - MONSTER_CYBER = 5; - MONSTER_CGUN = 6; - MONSTER_BARON = 7; - MONSTER_KNIGHT = 8; - MONSTER_CACO = 9; - MONSTER_SOUL = 10; - MONSTER_PAIN = 11; - MONSTER_SPIDER = 12; - MONSTER_BSP = 13; - MONSTER_MANCUB = 14; - MONSTER_SKEL = 15; - MONSTER_VILE = 16; - MONSTER_FISH = 17; - MONSTER_BARREL = 18; - MONSTER_ROBO = 19; - MONSTER_MAN = 20; - - TRIGGER_NONE = 0; - TRIGGER_EXIT = 1; - TRIGGER_TELEPORT = 2; - TRIGGER_OPENDOOR = 3; - TRIGGER_CLOSEDOOR = 4; - TRIGGER_DOOR = 5; - TRIGGER_DOOR5 = 6; - TRIGGER_CLOSETRAP = 7; - TRIGGER_TRAP = 8; - TRIGGER_PRESS = 9; - TRIGGER_SECRET = 10; - TRIGGER_LIFTUP = 11; - TRIGGER_LIFTDOWN = 12; - TRIGGER_LIFT = 13; - TRIGGER_TEXTURE = 14; - TRIGGER_ON = 15; - TRIGGER_OFF = 16; - TRIGGER_ONOFF = 17; - TRIGGER_SOUND = 18; - TRIGGER_SPAWNMONSTER = 19; - TRIGGER_SPAWNITEM = 20; - TRIGGER_MUSIC = 21; - TRIGGER_PUSH = 22; - TRIGGER_SCORE = 23; - TRIGGER_MESSAGE = 24; - TRIGGER_DAMAGE = 25; - TRIGGER_HEALTH = 26; - TRIGGER_SHOT = 27; - TRIGGER_EFFECT = 28; - TRIGGER_SCRIPT = 29; - TRIGGER_MAX = 29; - - TRIGGER_SHOT_PISTOL = 0; - TRIGGER_SHOT_BULLET = 1; - TRIGGER_SHOT_SHOTGUN = 2; - TRIGGER_SHOT_SSG = 3; - TRIGGER_SHOT_IMP = 4; - TRIGGER_SHOT_PLASMA = 5; - TRIGGER_SHOT_SPIDER = 6; - TRIGGER_SHOT_CACO = 7; - TRIGGER_SHOT_BARON = 8; - TRIGGER_SHOT_MANCUB = 9; - TRIGGER_SHOT_REV = 10; - TRIGGER_SHOT_ROCKET = 11; - TRIGGER_SHOT_BFG = 12; - TRIGGER_SHOT_EXPL = 13; - TRIGGER_SHOT_BFGEXPL = 14; - TRIGGER_SHOT_MAX = 14; - - TRIGGER_SHOT_TARGET_NONE = 0; - TRIGGER_SHOT_TARGET_MON = 1; - TRIGGER_SHOT_TARGET_PLR = 2; - TRIGGER_SHOT_TARGET_RED = 3; - TRIGGER_SHOT_TARGET_BLUE = 4; - TRIGGER_SHOT_TARGET_MONPLR = 5; - TRIGGER_SHOT_TARGET_PLRMON = 6; - - TRIGGER_SHOT_AIM_DEFAULT = 0; - TRIGGER_SHOT_AIM_ALLMAP = 1; - TRIGGER_SHOT_AIM_TRACE = 2; - TRIGGER_SHOT_AIM_TRACEALL = 3; - - TRIGGER_EFFECT_PARTICLE = 0; - TRIGGER_EFFECT_ANIMATION = 1; - - TRIGGER_EFFECT_SLIQUID = 0; - TRIGGER_EFFECT_LLIQUID = 1; - TRIGGER_EFFECT_DLIQUID = 2; - TRIGGER_EFFECT_BLOOD = 3; - TRIGGER_EFFECT_SPARK = 4; - TRIGGER_EFFECT_BUBBLE = 5; - TRIGGER_EFFECT_MAX = 5; - - TRIGGER_EFFECT_POS_CENTER = 0; - TRIGGER_EFFECT_POS_AREA = 1; - - ACTIVATE_PLAYERCOLLIDE = 1; - ACTIVATE_MONSTERCOLLIDE = 2; - ACTIVATE_PLAYERPRESS = 4; - ACTIVATE_MONSTERPRESS = 8; - ACTIVATE_SHOT = 16; - ACTIVATE_NOMONSTER = 32; - ACTIVATE_CUSTOM = 255; - - KEY_RED = 1; - KEY_GREEN = 2; - KEY_BLUE = 4; - KEY_REDTEAM = 8; - KEY_BLUETEAM = 16; + MAP_SIGNATURE = 'MAP'; + +const TEXTURE_NAME_WATER = '_water_0'; TEXTURE_NAME_ACID1 = '_water_1'; TEXTURE_NAME_ACID2 = '_water_2'; - TEXTURE_SPECIAL_WATER = DWORD(-1); - TEXTURE_SPECIAL_ACID1 = DWORD(-2); - TEXTURE_SPECIAL_ACID2 = DWORD(-3); - TEXTURE_NONE = DWORD(-4); type - TPoint = packed record + TDFPoint = packed record X, Y: LongInt; end; - TTriggerData = record - case Byte of - 0: (Default: Byte128); - TRIGGER_EXIT: (MapName: Char16); - TRIGGER_TELEPORT: (TargetPoint: TPoint; - d2d_teleport: Boolean; - silent_teleport: Boolean; - TlpDir: Byte); - TRIGGER_OPENDOOR, - TRIGGER_CLOSEDOOR, - TRIGGER_DOOR, - TRIGGER_DOOR5, - TRIGGER_CLOSETRAP, - TRIGGER_TRAP, - TRIGGER_LIFTUP, - TRIGGER_LIFTDOWN, - TRIGGER_LIFT: (PanelID: Integer; - NoSound: Boolean; - d2d_doors: Boolean); - TRIGGER_PRESS, - TRIGGER_ON, - TRIGGER_OFF, - TRIGGER_ONOFF: (tX, tY: Integer; - tWidth, tHeight: Word; - Wait: Word; - Count: Word; - MonsterID: Integer; - ExtRandom: Boolean); - TRIGGER_SECRET: (); - TRIGGER_TEXTURE: (ActivateOnce: Boolean; - AnimOnce: Boolean); - TRIGGER_SOUND: (SoundName: Char64; - Volume: Byte; - Pan: Byte; - Local: Boolean; - PlayCount: Byte; - SoundSwitch: Boolean); - TRIGGER_SPAWNMONSTER: (MonPos: TPoint; - MonType: Byte; - MonHealth: Integer; - MonDir: Byte; - MonActive: Boolean; - MonCount: Integer; - MonEffect: Byte; - MonMax: Word; - MonDelay: Word; - MonBehav: Byte); - TRIGGER_SPAWNITEM: (ItemPos: TPoint; - ItemType: Byte; - ItemFalls: Boolean; - ItemOnlyDM: Boolean; - ItemCount: Integer; - ItemEffect: Byte; - ItemMax: Word; - ItemDelay: Word); - TRIGGER_MUSIC: (MusicName: Char64; - MusicAction: Byte); - TRIGGER_PUSH: (PushAngle: Word; - PushForce: Byte; - ResetVel: Boolean); - TRIGGER_SCORE: (ScoreAction: Byte; - ScoreCount: Byte; - ScoreTeam: Byte; - ScoreCon, - ScoreMsg: Boolean); - TRIGGER_MESSAGE: (MessageKind: Byte; - MessageSendTo: Byte; - MessageText: Char100; - MessageTime: Word); - TRIGGER_DAMAGE: (DamageValue: Word; - DamageInterval: Word); - TRIGGER_HEALTH: (HealValue: Word; - HealInterval: Word; - HealMax: Boolean; - HealSilent: Boolean); - TRIGGER_SHOT: (ShotPos: TPoint; - ShotType: Byte; - ShotTarget: Byte; - ShotSound: Boolean; - ShotAim: Byte; - ShotPanelID: Integer; - ShotIntSight: Word; - ShotAngle: Word; - ShotWait: Word; - ShotAccuracy: Word; - ShotAmmo: Word; - ShotIntReload: Word); - TRIGGER_EFFECT: (FXCount: Byte; - FXType: Byte; - FXSubType: Byte; - FXColorR: Byte; - FXColorG: Byte; - FXColorB: Byte; - FXPos: Byte; - FXWait: Word; - FXVelX: ShortInt; - FXVelY: ShortInt; - FXSpreadL: Byte; - FXSpreadR: Byte; - FXSpreadU: Byte; - FXSpreadD: Byte); - TRIGGER_SCRIPT: (SCRProc: Char64; - SCRArg: Integer); - end; + Char16 = packed array[0..15] of Char; + Char32 = packed array[0..31] of Char; + Char64 = packed array[0..63] of Char; + Char100 = packed array[0..99] of Char; + Char256 = packed array[0..255] of Char; + Byte128 = packed array[0..127] of Byte; + +{$INCLUDE mapdef.inc} + +type + TTexturesRec1Array = array of TTextureRec_1; + TPanelsRec1Array = array of TPanelRec_1; + TItemsRec1Array = array of TItemRec_1; + TMonsterRec1Array = array of TMonsterRec_1; + TAreasRec1Array = array of TAreaRec_1; + TTriggersRec1Array = array of TTriggerRec_1; + + +function GetMapHeader (rec: TDynRecord): TMapHeaderRec_1; +function GetTextures (rec: TDynRecord): TTexturesRec1Array; +function GetPanels (rec: TDynRecord): TPanelsRec1Array; +function GetItems (rec: TDynRecord): TItemsRec1Array; +function GetAreas (rec: TDynRecord): TAreasRec1Array; +function GetMonsters (rec: TDynRecord): TMonsterRec1Array; +function GetTriggers (rec: TDynRecord): TTriggersRec1Array; -{$INCLUDE mapstructsizes.inc} implementation -uses SysUtils; +uses + e_log, xparser, xstreams; + + +function GetMapHeader (rec: TDynRecord): TMapHeaderRec_1; +var + ws: TSFSMemoryChunkStream = nil; +begin + FillChar(result, sizeof(result), 0); + if (rec = nil) then exit; + try + ws := TSFSMemoryChunkStream.Create(@result, sizeof(result)); + rec.writeBinTo(ws, -1, true); // only fields + except // sorry + FillChar(result, sizeof(result), 0); + end; + ws.Free(); +end; + + +function GetTextures (rec: TDynRecord): TTexturesRec1Array; +var + ws: TSFSMemoryChunkStream = nil; + fld: TDynField; + f: Integer; +begin + result := nil; + fld := rec.field['texture']; + if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.list.count = 0) then exit; + ws := TSFSMemoryChunkStream.Create(nil, 0); + try + SetLength(result, fld.list.count); + for f := 0 to fld.list.count-1 do + begin + FillChar(result[f], sizeof(result[f]), 0); + ws.setup(@result[f], sizeof(result[f])); + fld.list[f].writeBinTo(ws, -1, true); // only fields + end; + except + result := nil; + end; + ws.Free(); +end; + + +function GetPanels (rec: TDynRecord): TPanelsRec1Array; +var + ws: TSFSMemoryChunkStream = nil; + fld: TDynField; + f: Integer; +begin + result := nil; + fld := rec.field['panel']; + if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.list.count = 0) then exit; + ws := TSFSMemoryChunkStream.Create(nil, 0); + try + SetLength(result, fld.list.count); + for f := 0 to fld.list.count-1 do + begin + FillChar(result[f], sizeof(result[f]), 0); + ws.setup(@result[f], sizeof(result[f])); + fld.list[f].writeBinTo(ws, -1, true); // only fields + end; + except + result := nil; + end; + ws.Free(); +end; + + +function GetItems (rec: TDynRecord): TItemsRec1Array; +var + ws: TSFSMemoryChunkStream = nil; + fld: TDynField; + f: Integer; +begin + result := nil; + fld := rec.field['item']; + if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.list.count = 0) then exit; + ws := TSFSMemoryChunkStream.Create(nil, 0); + try + SetLength(result, fld.list.count); + for f := 0 to fld.list.count-1 do + begin + FillChar(result[f], sizeof(result[f]), 0); + ws.setup(@result[f], sizeof(result[f])); + fld.list[f].writeBinTo(ws, -1, true); // only fields + end; + except + result := nil; + end; + ws.Free(); +end; + + +function GetAreas (rec: TDynRecord): TAreasRec1Array; +var + ws: TSFSMemoryChunkStream = nil; + fld: TDynField; + f: Integer; +begin + result := nil; + fld := rec.field['area']; + if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.list.count = 0) then exit; + ws := TSFSMemoryChunkStream.Create(nil, 0); + try + SetLength(result, fld.list.count); + for f := 0 to fld.list.count-1 do + begin + FillChar(result[f], sizeof(result[f]), 0); + ws.setup(@result[f], sizeof(result[f])); + fld.list[f].writeBinTo(ws, -1, true); // only fields + end; + except + result := nil; + end; + ws.Free(); +end; + + +function GetMonsters (rec: TDynRecord): TMonsterRec1Array; +var + ws: TSFSMemoryChunkStream = nil; + fld: TDynField; + f: Integer; +begin + result := nil; + fld := rec.field['monster']; + if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.list.count = 0) then exit; + ws := TSFSMemoryChunkStream.Create(nil, 0); + try + SetLength(result, fld.list.count); + for f := 0 to fld.list.count-1 do + begin + FillChar(result[f], sizeof(result[f]), 0); + ws.setup(@result[f], sizeof(result[f])); + fld.list[f].writeBinTo(ws, -1, true); // only fields + end; + except + result := nil; + end; + ws.Free(); +end; + + +function GetTriggers (rec: TDynRecord): TTriggersRec1Array; +var + ws: TSFSMemoryChunkStream = nil; + fld: TDynField; + f: Integer; + //wr: TTextWriter; + //fo: File; +begin + result := nil; + fld := rec.field['trigger']; + if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.list.count = 0) then exit; + ws := TSFSMemoryChunkStream.Create(nil, 0); + try + //wr := TFileTextWriter.Create('z00.txt'); + SetLength(result, fld.list.count); + for f := 0 to fld.list.count-1 do + begin + FillChar(result[f], sizeof(result[f]), 0); + //e_LogWritefln(': trigger #%s; TexturePanel=%s', [f, result[f].TexturePanel]); + ws.setup(@result[f], sizeof(result[f])); + fld.list[f].writeBinTo(ws, -1, true); // only fields + { + e_LogWritefln(': trigger #%s; X=%s; Y=%s; Width=%s; Height=%s; Enabled=%s; TexturePanel=%s; TriggerType=%s; ActivateType=%s; Keys=%s', [f, + result[f].X, + result[f].Y, + result[f].Width, + result[f].Height, + result[f].Enabled, + result[f].TexturePanel, + result[f].TriggerType, + result[f].ActivateType, + result[f].Keys + ]); + //e_LogWritefln('***'#10'%s'#10'***', [); + fld.list[f].writeTo(wr); + if (f = 0) then + begin + AssignFile(fo, 'z00.bin'); + Rewrite(fo, 1); + BlockWrite(fo, result[f], sizeof(result[f])); + CloseFile(fo); + end; + } + end; + //wr.Free(); + except + result := nil; + end; + ws.Free(); +end; -{$INCLUDE mapstructio.inc} end. diff --git a/src/shared/MAPREADER.pas b/src/shared/MAPREADER.pas deleted file mode 100644 index 4ea7beb..0000000 --- a/src/shared/MAPREADER.pas +++ /dev/null @@ -1,424 +0,0 @@ -(* Copyright (C) DooM 2D:Forever Developers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *) -{$INCLUDE a_modes.inc} -unit MAPREADER; - -{ ------------------------------------ -MAPREADER.PAS ÂÅÐÑÈß ÎÒ 13.11.07 - -Ïîääåðæêà êàðò âåðñèè 1 ------------------------------------ -} - -interface - -uses - MAPSTRUCT; - -type - TDataBlock = packed record - Block: TBlock; - Data: Pointer; - end; - - TDataBlocksArray = packed array of TDataBlock; - - TMapReader = class(TObject) - private - FError: Byte; - FVersion: Byte; - FDataBlocks: TDataBlocksArray; - function GetBlocks(BlocksType: Byte): TDataBlocksArray; - public - constructor Create(); - destructor Destroy(); override; - function LoadMap(Data: Pointer): Boolean; - procedure FreeMap(); - function HandledVersion(): Byte; virtual; - - property GetError: Byte read FError; - property GetVersion: Byte read FVersion; - end; - - TMapReader_1 = class(TMapReader) - private - public - function GetMapHeader(): TMapHeaderRec_1; - function GetTextures(): TTexturesRec1Array; - function GetPanels(): TPanelsRec1Array; - function GetItems(): TItemsRec1Array; - function GetAreas(): TAreasRec1Array; - function GetMonsters(): TMonsterRec1Array; - function GetTriggers(): TTriggersRec1Array; - function HandledVersion(): Byte; override; - end; - -const - MAP_ERROR_NONE = $00; - MAP_ERROR_SIGNATURE = $01; - MAP_ERROR_VERSION = $02; - - 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; - -implementation - -uses - SysUtils, BinEditor, MAPDEF; - -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; - -{ T M a p R e a d e r _ 1 : } - -function TMapReader_1.GetAreas(): TAreasRec1Array; -var - TempDataBlocks: TDataBlocksArray; - a: Integer; - b, Size: NativeUInt; -begin - Result := nil; - - TempDataBlocks := GetBlocks(BLOCK_AREAS); - - if TempDataBlocks = nil then Exit; - - size := SizeOf_TAreaRec_1; - - for a := 0 to High(TempDataBlocks) do - for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do - begin - SetLength(Result, Length(Result)+1); - //CopyMemory(@Result[High(Result)], Pointer(LongWord(TempDataBlocks[a].Data)+b*size), size); - mb_Read_TAreaRec_1(Result[High(Result)], Pointer(NativeUInt(TempDataBlocks[a].Data)+b*size)^, size); - end; - - TempDataBlocks := nil; -end; - -function TMapReader_1.GetItems(): TItemsRec1Array; -var - TempDataBlocks: TDataBlocksArray; - a: Integer; - b, Size: NativeUInt; -begin - Result := nil; - - TempDataBlocks := GetBlocks(BLOCK_ITEMS); - - if TempDataBlocks = nil then Exit; - - size := SizeOf_TItemRec_1; - - for a := 0 to High(TempDataBlocks) do - for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do - begin - SetLength(Result, Length(Result)+1); - //CopyMemory(@Result[High(Result)], Pointer(LongWord(TempDataBlocks[a].Data)+b*size), size); - mb_Read_TItemRec_1(Result[High(Result)], Pointer(NativeUInt(TempDataBlocks[a].Data)+b*size)^, size); - end; - - TempDataBlocks := nil; -end; - -function TMapReader_1.GetMapHeader(): TMapHeaderRec_1; -var - TempDataBlocks: TDataBlocksArray; -begin - ZeroMemory(@Result, SizeOf(TMapHeaderRec_1)); - - TempDataBlocks := GetBlocks(BLOCK_HEADER); - - if TempDataBlocks = nil then Exit; - - //CopyMemory(@Result, TempDataBlocks[0].Data, SizeOf(TMapHeaderRec_1)); - mb_Read_TMapHeaderRec_1(Result, TempDataBlocks[0].Data^, SizeOf_TMapHeaderRec_1); - - TempDataBlocks := nil; -end; - -function TMapReader_1.GetMonsters(): TMonsterRec1Array; -var - TempDataBlocks: TDataBlocksArray; - a: Integer; - b, Size: NativeUInt; -begin - Result := nil; - - TempDataBlocks := GetBlocks(BLOCK_MONSTERS); - - if TempDataBlocks = nil then Exit; - - size := SizeOf_TMonsterRec_1; - - for a := 0 to High(TempDataBlocks) do - for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do - begin - SetLength(Result, Length(Result)+1); - //CopyMemory(@Result[High(Result)], Pointer(LongWord(TempDataBlocks[a].Data)+b*size), size); - mb_Read_TMonsterRec_1(Result[High(Result)], Pointer(NativeUInt(TempDataBlocks[a].Data)+b*size)^, size); - end; - - TempDataBlocks := nil; -end; - -function TMapReader_1.GetPanels(): TPanelsRec1Array; -var - TempDataBlocks: TDataBlocksArray; - a: Integer; - b, Size: NativeUInt; -begin - Result := nil; - - TempDataBlocks := GetBlocks(BLOCK_PANELS); - - if TempDataBlocks = nil then Exit; - - size := SizeOf_TPanelRec_1; - - for a := 0 to High(TempDataBlocks) do - for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do - begin - SetLength(Result, Length(Result)+1); - //CopyMemory(@Result[High(Result)], Pointer(LongWord(TempDataBlocks[a].Data)+b*size), size); - mb_Read_TPanelRec_1(Result[High(Result)], Pointer(NativeUInt(TempDataBlocks[a].Data)+b*size)^, size); - end; - - TempDataBlocks := nil; -end; - -function TMapReader_1.GetTextures(): TTexturesRec1Array; -var - TempDataBlocks: TDataBlocksArray; - a: Integer; - b, Size: NativeUInt; -begin - Result := nil; - - TempDataBlocks := GetBlocks(BLOCK_TEXTURES); - - if TempDataBlocks = nil then Exit; - - size := SizeOf_TTextureRec_1; - - for a := 0 to High(TempDataBlocks) do - for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do - begin - SetLength(Result, Length(Result)+1); - //CopyMemory(@Result[High(Result)], Pointer(LongWord(TempDataBlocks[a].Data)+b*size), size); - mb_Read_TTextureRec_1(Result[High(Result)], Pointer(NativeUInt(TempDataBlocks[a].Data)+b*size)^, size); - end; - - TempDataBlocks := nil; -end; - -function TMapReader_1.GetTriggers(): TTriggersRec1Array; -var - TempDataBlocks: TDataBlocksArray; - a: Integer; - b: NativeUInt; - Size: LongWord; - trdata: TTriggerData; -begin - Result := nil; - - TempDataBlocks := GetBlocks(BLOCK_TRIGGERS); - - if TempDataBlocks = nil then Exit; - - size := SizeOf_TTriggerRec_1; - - for a := 0 to High(TempDataBlocks) do - for b := 0 to (TempDataBlocks[a].Block.BlockSize div size)-1 do - begin - SetLength(Result, Length(Result)+1); - //CopyMemory(@Result[High(Result)], Pointer(LongWord(TempDataBlocks[a].Data)+b*size), size); - mb_Read_TTriggerRec_1(Result[High(Result)], Pointer(NativeUInt(TempDataBlocks[a].Data)+b*size)^, size); - if (Result[High(Result)].TriggerType <> 0) then - begin - // preprocess trigger data - ZeroMemory(@trdata, SizeOf(trdata)); - mb_Read_TriggerData(trdata, Result[High(Result)].TriggerType, Result[High(Result)].DATA, sizeof(trdata)); - Result[High(Result)].DATA := trdata.Default; - end; - end; - - TempDataBlocks := nil; -end; - -function TMapReader_1.HandledVersion: Byte; -begin - Result := $01; -end; - -{ T M a p R e a d e r : } - -constructor TMapReader.Create(); -begin - FDataBlocks := nil; - FError := MAP_ERROR_NONE; - FVersion := $00; -end; - -destructor TMapReader.Destroy(); -begin - FreeMap(); - - inherited; -end; - -procedure TMapReader.FreeMap(); -var - a: Integer; -begin - if FDataBlocks <> nil then - for a := 0 to High(FDataBlocks) do - if FDataBlocks[a].Data <> nil then FreeMem(FDataBlocks[a].Data); - - FDataBlocks := nil; - FVersion := $00; - FError := MAP_ERROR_NONE; -end; - -function TMapReader.GetBlocks(BlocksType: Byte): TDataBlocksArray; -var - a: Integer; -begin - Result := nil; - - if FDataBlocks = nil then Exit; - - for a := 0 to High(FDataBlocks) do - if FDataBlocks[a].Block.BlockType = BlocksType then - begin - SetLength(Result, Length(Result)+1); - Result[High(Result)] := FDataBlocks[a]; - end; -end; - -function TMapReader.HandledVersion(): Byte; -begin - Result := $00; -end; - -function TMapReader.LoadMap(Data: Pointer): Boolean; -var - adr: NativeUInt; - _id: Integer; - Sign: array[0..2] of Char; - Ver: Byte; -begin - Result := False; - - CopyMemory(@Sign[0], Data, 3); - if Sign <> MAP_SIGNATURE then - begin - FError := MAP_ERROR_SIGNATURE; - Exit; - end; - adr := 3; - - CopyMemory(@Ver, Pointer(NativeUInt(Data)+adr), 1); - FVersion := Ver; - if Ver > HandledVersion() then - begin - FError := MAP_ERROR_VERSION; - Exit; - end; - adr := adr+1; - - repeat - SetLength(FDataBlocks, Length(FDataBlocks)+1); - _id := High(FDataBlocks); - - CopyMemory(@FDataBlocks[_id].Block, Pointer(NativeUInt(Data)+adr), SizeOf(TBlock)); - adr := adr+SizeOf(TBlock); - - FDataBlocks[_id].Data := GetMemory(FDataBlocks[_id].Block.BlockSize); - - CopyMemory(FDataBlocks[_id].Data, Pointer(NativeUInt(Data)+adr), FDataBlocks[_id].Block.BlockSize); - - adr := adr+FDataBlocks[_id].Block.BlockSize; - until FDataBlocks[_id].Block.BlockType = BLOCK_NONE; - - Result := True; -end; - -end. diff --git a/src/shared/MAPSTRUCT.pas b/src/shared/MAPSTRUCT.pas deleted file mode 100644 index f2bc726..0000000 --- a/src/shared/MAPSTRUCT.pas +++ /dev/null @@ -1,144 +0,0 @@ -(* Copyright (C) DooM 2D:Forever Developers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *) -{$INCLUDE a_modes.inc} -{$M+} -unit MAPSTRUCT; - -{ ------------------------------------ -MAPSTRUCT.PAS ÂÅÐÑÈß ÎÒ 13.11.07 - -Ïîääåðæêà êàðò âåðñèè 1 ------------------------------------ -} - -{ - Êàðòà ïðåäñòàâëÿåò ñîáîþ WAD, â êîòîðîì ðåñóðñû â êîðíå - ñîáñòâåííî ñàìè êàðòû - (MAP01, MAP02 è ò.ä.). - - Áëîêè çàêàí÷èâàþòñÿ íóëåâûì áëîêîì (BlockType=BLOCK_NONE) - - Ñòðóêòóðà êàðòû (MAP01, MAP02...): - -------------------------------------- - SIGNATURE | Byte[3] | 'MAP' - VERSION | Byte | $01 - BLOCK1 | TBlock | - BLOCK1DATA | RAW | - ... | ...... | - BLOCKN | TBlock | - BLOCKNDATA | RAW | - -------------------------------------- - - Ñòðóêòóðà áëîêà: - -------------------------------------- - BLOCKTYPE | Byte | (BLOCK_TEXTURES, BLOCK_PANELS,...) - RESERVED | LongWord | $00000000 - BLOCKSIZE | LongWord | Ñêîëüêî ýòîò áëîê â ðàçìåðå (áàéò ïîñëå record'à) - -------------------------------------- -} - -interface - -const - MAP_SIGNATURE = 'MAP'; - BLOCK_NONE = 0; - BLOCK_TEXTURES = 1; - BLOCK_PANELS = 2; - BLOCK_ITEMS = 3; - BLOCK_AREAS = 4; - BLOCK_MONSTERS = 5; - BLOCK_TRIGGERS = 6; - BLOCK_HEADER = 7; - -type - Char16 = packed array[0..15] of Char; - Char32 = packed array[0..31] of Char; - Char64 = packed array[0..63] of Char; - Char100 = packed array[0..99] of Char; - Char256 = packed array[0..255] of Char; - Byte128 = packed array[0..127] of Byte; - - TMapHeaderRec_1 = packed record - MapName: Char32; - MapAuthor: Char32; - MapDescription: Char256; - MusicName: Char64; - SkyName: Char64; - Width: Word; - Height: Word; - end; - - TTextureRec_1 = packed record - Resource: Char64; - Anim: Byte; - end; - - TPanelRec_1 = packed record - X, Y: Integer; - Width, - Height: Word; - TextureNum: Word; - PanelType: Word; - Alpha: Byte; - Flags: Byte; - end; - - TItemRec_1 = packed record - X, Y: Integer; - ItemType: Byte; - Options: Byte; - end; - - TMonsterRec_1 = packed record - X, Y: Integer; - MonsterType: Byte; - Direction: Byte; - end; - - TAreaRec_1 = packed record - X, Y: Integer; - AreaType: Byte; - Direction: Byte; - end; - - TTriggerRec_1 = packed record - X, Y: Integer; - Width, - Height: Word; - Enabled: Byte; - TexturePanel: Integer; - TriggerType: Byte; - ActivateType: Byte; - Keys: Byte; - DATA: Byte128; //WARNING! should be exactly equal to sizeof(TTriggerData) - end; - - TBlock = packed record - BlockType: Byte; - Reserved: LongWord; - BlockSize: LongWord; - end; - - TTexturesRec1Array = array of TTextureRec_1; - TPanelsRec1Array = array of TPanelRec_1; - TItemsRec1Array = array of TItemRec_1; - TMonsterRec1Array = array of TMonsterRec_1; - TAreasRec1Array = array of TAreaRec_1; - TTriggersRec1Array = array of TTriggerRec_1; - -implementation - -end. diff --git a/src/shared/mapdef.inc b/src/shared/mapdef.inc new file mode 100644 index 0000000..595dff4 --- /dev/null +++ b/src/shared/mapdef.inc @@ -0,0 +1,1148 @@ +// *** WARNING! *** +// regenerate this part directly from "mapdef.txt" with 'zmapgen', NEVER manually change anything here! + + +// ////////////////////////////////////////////////////////////////////////// // +// enums and bitsets + +// TextureSpecial +const + TEXTURE_SPECIAL_WATER = -1; + TEXTURE_SPECIAL_ACID1 = -2; + TEXTURE_SPECIAL_ACID2 = -3; + TEXTURE_NONE = -4; + +// DirType +const + DIR_LEFT = 0; + DIR_RIGHT = 1; + DIR_SOMETHING2 = 2; + +// TriggerType +const + TRIGGER_NONE = 0; + TRIGGER_EXIT = 1; + TRIGGER_TELEPORT = 2; + TRIGGER_OPENDOOR = 3; + TRIGGER_CLOSEDOOR = 4; + TRIGGER_DOOR = 5; + TRIGGER_DOOR5 = 6; + TRIGGER_CLOSETRAP = 7; + TRIGGER_TRAP = 8; + TRIGGER_PRESS = 9; + TRIGGER_SECRET = 10; + TRIGGER_LIFTUP = 11; + TRIGGER_LIFTDOWN = 12; + TRIGGER_LIFT = 13; + TRIGGER_TEXTURE = 14; + TRIGGER_ON = 15; + TRIGGER_OFF = 16; + TRIGGER_ONOFF = 17; + TRIGGER_SOUND = 18; + TRIGGER_SPAWNMONSTER = 19; + TRIGGER_SPAWNITEM = 20; + TRIGGER_MUSIC = 21; + TRIGGER_PUSH = 22; + TRIGGER_SCORE = 23; + TRIGGER_MESSAGE = 24; + TRIGGER_DAMAGE = 25; + TRIGGER_HEALTH = 26; + TRIGGER_SHOT = 27; + TRIGGER_EFFECT = 28; + TRIGGER_SCRIPT = 29; + TRIGGER_MAX = 29; + +// PanelType +const + PANEL_NONE = 0; + PANEL_WALL = 1; + PANEL_BACK = 2; + PANEL_FORE = 4; + PANEL_WATER = 8; + PANEL_ACID1 = 16; + PANEL_ACID2 = 32; + PANEL_STEP = 64; + PANEL_LIFTUP = 128; + PANEL_LIFTDOWN = 256; + PANEL_OPENDOOR = 512; + PANEL_CLOSEDOOR = 1024; + PANEL_BLOCKMON = 2048; + PANEL_LIFTLEFT = 4096; + PANEL_LIFTRIGHT = 8192; + +// PanelFlag +const + PANEL_FLAG_NONE = 0; + PANEL_FLAG_BLENDING = 1; + PANEL_FLAG_HIDE = 2; + PANEL_FLAG_WATERTEXTURES = 4; + +// EffectAction +const + EFFECT_NONE = 0; + EFFECT_TELEPORT = 1; + EFFECT_RESPAWN = 2; + EFFECT_FIRE = 3; + +// Item +const + ITEM_NONE = 0; + ITEM_MEDKIT_SMALL = 1; + ITEM_MEDKIT_LARGE = 2; + ITEM_MEDKIT_BLACK = 3; + ITEM_ARMOR_GREEN = 4; + ITEM_ARMOR_BLUE = 5; + ITEM_SPHERE_BLUE = 6; + ITEM_SPHERE_WHITE = 7; + ITEM_SUIT = 8; + ITEM_OXYGEN = 9; + ITEM_INVUL = 10; + ITEM_WEAPON_SAW = 11; + ITEM_WEAPON_SHOTGUN1 = 12; + ITEM_WEAPON_SHOTGUN2 = 13; + ITEM_WEAPON_CHAINGUN = 14; + ITEM_WEAPON_ROCKETLAUNCHER = 15; + ITEM_WEAPON_PLASMA = 16; + ITEM_WEAPON_BFG = 17; + ITEM_WEAPON_SUPERPULEMET = 18; + ITEM_AMMO_BULLETS = 19; + ITEM_AMMO_BULLETS_BOX = 20; + ITEM_AMMO_SHELLS = 21; + ITEM_AMMO_SHELLS_BOX = 22; + ITEM_AMMO_ROCKET = 23; + ITEM_AMMO_ROCKET_BOX = 24; + ITEM_AMMO_CELL = 25; + ITEM_AMMO_CELL_BIG = 26; + ITEM_AMMO_BACKPACK = 27; + ITEM_KEY_RED = 28; + ITEM_KEY_GREEN = 29; + ITEM_KEY_BLUE = 30; + ITEM_WEAPON_KASTET = 31; + ITEM_WEAPON_PISTOL = 32; + ITEM_BOTTLE = 33; + ITEM_HELMET = 34; + ITEM_JETPACK = 35; + ITEM_INVIS = 36; + ITEM_WEAPON_FLAMETHROWER = 37; + ITEM_AMMO_FUELCAN = 38; + ITEM_MAX = 38; + +// ItemOption +const + ITEM_OPTION_NONE = 0; + ITEM_OPTION_ONLYDM = 1; + ITEM_OPTION_FALL = 2; + +// AreaType +const + AREA_NONE = 0; + AREA_PLAYERPOINT1 = 1; + AREA_PLAYERPOINT2 = 2; + AREA_DMPOINT = 3; + AREA_REDFLAG = 4; + AREA_BLUEFLAG = 5; + AREA_DOMFLAG = 6; + AREA_REDTEAMPOINT = 7; + AREA_BLUETEAMPOINT = 8; + +// Monster +const + MONSTER_NONE = 0; + MONSTER_DEMON = 1; + MONSTER_IMP = 2; + MONSTER_ZOMBY = 3; + MONSTER_SERG = 4; + MONSTER_CYBER = 5; + MONSTER_CGUN = 6; + MONSTER_BARON = 7; + MONSTER_KNIGHT = 8; + MONSTER_CACO = 9; + MONSTER_SOUL = 10; + MONSTER_PAIN = 11; + MONSTER_SPIDER = 12; + MONSTER_BSP = 13; + MONSTER_MANCUB = 14; + MONSTER_SKEL = 15; + MONSTER_VILE = 16; + MONSTER_FISH = 17; + MONSTER_BARREL = 18; + MONSTER_ROBO = 19; + MONSTER_MAN = 20; + +// TriggerShot +const + TRIGGER_SHOT_PISTOL = 0; + TRIGGER_SHOT_BULLET = 1; + TRIGGER_SHOT_SHOTGUN = 2; + TRIGGER_SHOT_SSG = 3; + TRIGGER_SHOT_IMP = 4; + TRIGGER_SHOT_PLASMA = 5; + TRIGGER_SHOT_SPIDER = 6; + TRIGGER_SHOT_CACO = 7; + TRIGGER_SHOT_BARON = 8; + TRIGGER_SHOT_MANCUB = 9; + TRIGGER_SHOT_REV = 10; + TRIGGER_SHOT_ROCKET = 11; + TRIGGER_SHOT_BFG = 12; + TRIGGER_SHOT_EXPL = 13; + TRIGGER_SHOT_BFGEXPL = 14; + TRIGGER_SHOT_MAX = 14; + +// TriggerShotTarget +const + TRIGGER_SHOT_TARGET_NONE = 0; + TRIGGER_SHOT_TARGET_MON = 1; + TRIGGER_SHOT_TARGET_PLR = 2; + TRIGGER_SHOT_TARGET_RED = 3; + TRIGGER_SHOT_TARGET_BLUE = 4; + TRIGGER_SHOT_TARGET_MONPLR = 5; + TRIGGER_SHOT_TARGET_PLRMON = 6; + +// TriggerShotAim +const + TRIGGER_SHOT_AIM_DEFAULT = 0; + TRIGGER_SHOT_AIM_ALLMAP = 1; + TRIGGER_SHOT_AIM_TRACE = 2; + TRIGGER_SHOT_AIM_TRACEALL = 3; + +// TriggerEffect +const + TRIGGER_EFFECT_PARTICLE = 0; + TRIGGER_EFFECT_ANIMATION = 1; + +// TriggerEffectType +const + TRIGGER_EFFECT_SLIQUID = 0; + TRIGGER_EFFECT_LLIQUID = 1; + TRIGGER_EFFECT_DLIQUID = 2; + TRIGGER_EFFECT_BLOOD = 3; + TRIGGER_EFFECT_SPARK = 4; + TRIGGER_EFFECT_BUBBLE = 5; + TRIGGER_EFFECT_MAX = 5; + +// TriggerEffectPos +const + TRIGGER_EFFECT_POS_CENTER = 0; + TRIGGER_EFFECT_POS_AREA = 1; + +// ActivateType +const + ACTIVATE_NONE = 0; + ACTIVATE_PLAYERCOLLIDE = 1; + ACTIVATE_MONSTERCOLLIDE = 2; + ACTIVATE_PLAYERPRESS = 4; + ACTIVATE_MONSTERPRESS = 8; + ACTIVATE_SHOT = 16; + ACTIVATE_NOMONSTER = 32; + ACTIVATE_CUSTOM = 255; + +// Key +const + KEY_NONE = 0; + KEY_RED = 1; + KEY_GREEN = 2; + KEY_BLUE = 4; + KEY_REDTEAM = 8; + KEY_BLUETEAM = 16; + + +// ////////////////////////////////////////////////////////////////////////// // +// records +type + TMapHeaderRec_1 = packed record + MapName: Char32; + MapAuthor: Char32; + MapDescription: Char256; + MusicName: Char64; + SkyName: Char64; + Width, Height: Word; + end; + + TTextureRec_1 = packed record + Resource: Char64; + Anim: Boolean; + end; + + TPanelRec_1 = packed record + X, Y: Integer; + Width, Height: Word; + TextureNum: Word; + PanelType: Word; + Alpha: Byte; + Flags: Byte; + end; + + TItemRec_1 = packed record + X, Y: Integer; + ItemType: Byte; + Options: Byte; + end; + + TMonsterRec_1 = packed record + X, Y: Integer; + MonsterType: Byte; + Direction: Byte; + end; + + TAreaRec_1 = packed record + X, Y: Integer; + AreaType: Byte; + Direction: Byte; + end; + + TTriggerRec_1 = packed record + X, Y: Integer; + Width, Height: Word; + Enabled: Boolean; + TexturePanel: LongInt; + TriggerType: Byte; + ActivateType: Byte; + Keys: Byte; + DATA: Byte128; + end; + + + +// ////////////////////////////////////////////////////////////////////////// // +// triggerdata +type + TTriggerData = record + case Byte of + 0: (Default: Byte128); + TRIGGER_EXIT: ( + MapName: Char16; + ); + TRIGGER_TELEPORT: ( + TargetPoint: TDFPoint; + d2d_teleport: Boolean; + silent_teleport: Boolean; + TlpDir: Byte; + ); + TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT: ( + PanelID: LongInt; + NoSound: Boolean; + d2d_doors: Boolean; + ); + TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF: ( + tX, tY: Integer; + tWidth, tHeight: Word; + Wait: Word; + Count: Word; + MonsterID: LongInt; + ExtRandom: Boolean; + ); + TRIGGER_SECRET: ( + ); + TRIGGER_TEXTURE: ( + ActivateOnce: Boolean; + AnimOnce: Boolean; + ); + TRIGGER_SOUND: ( + SoundName: Char64; + Volume: Byte; + Pan: Byte; + Local: Boolean; + PlayCount: Byte; + SoundSwitch: Boolean; + ); + TRIGGER_SPAWNMONSTER: ( + MonPos: TDFPoint; + MonType: Byte; + MonHealth: LongInt; + MonDir: Byte; + MonActive: Boolean; + MonCount: LongInt; + MonEffect: Byte; + MonMax: Word; + MonDelay: Word; + MonBehav: Byte; + ); + TRIGGER_SPAWNITEM: ( + ItemPos: TDFPoint; + ItemType: Byte; + ItemFalls: Boolean; + ItemOnlyDM: Boolean; + ItemCount: LongInt; + ItemEffect: Byte; + ItemMax: Word; + ItemDelay: Word; + ); + TRIGGER_MUSIC: ( + MusicName: Char64; + MusicAction: Byte; + ); + TRIGGER_PUSH: ( + PushAngle: Word; + PushForce: Byte; + ResetVel: Boolean; + ); + TRIGGER_SCORE: ( + ScoreAction: Byte; + ScoreCount: Byte; + ScoreTeam: Byte; + ScoreCon: Boolean; + ScoreMsg: Boolean; + ); + TRIGGER_MESSAGE: ( + MessageKind: Byte; + MessageSendTo: Byte; + MessageText: Char100; + MessageTime: Word; + ); + TRIGGER_DAMAGE: ( + DamageValue: Word; + DamageInterval: Word; + ); + TRIGGER_HEALTH: ( + HealValue: Word; + HealInterval: Word; + HealMax: Boolean; + HealSilent: Boolean; + ); + TRIGGER_SHOT: ( + ShotPos: TDFPoint; + ShotType: Byte; + ShotTarget: Byte; + ShotSound: Boolean; + ShotAim: ShortInt; + ShotPanelID: LongInt; + ShotIntSight: Word; + ShotAngle: Word; + ShotWait: Word; + ShotAccuracy: Word; + ShotAmmo: Word; + ShotIntReload: Word; + ); + TRIGGER_EFFECT: ( + FXCount: Byte; + FXType: Byte; + FXSubType: Byte; + FXColorR: Byte; + FXColorG: Byte; + FXColorB: Byte; + FXPos: Byte; + FXWait: Word; + FXVelX: ShortInt; + FXVelY: ShortInt; + FXSpreadL: Byte; + FXSpreadR: Byte; + FXSpreadU: Byte; + FXSpreadD: Byte; + ); + end; + + +const defaultMapDef: AnsiString = ''+ + #47#47#32#121#101#115#44#32#116#104#105#115#32#102#105#108#101#32#115#101+ + #114#118#101#115#32#98#111#116#104#32#97#115#32#102#111#114#109#97#116#32+ + #100#101#115#99#114#105#112#116#105#111#110#32#97#110#100#32#97#115#32#116+ + #101#109#112#108#97#116#101#32#102#111#114#32#99#111#100#101#32#103#101#110+ + #101#114#97#116#105#111#110#10#47#47#32#116#104#101#32#101#110#103#105#110+ + #101#32#119#105#108#108#32#117#115#101#32#116#104#105#115#32#100#101#115#99+ + #114#105#112#116#105#111#110#32#116#111#32#112#111#112#117#108#97#116#101#32+ + #116#104#101#32#99#111#114#114#101#115#112#111#110#100#105#110#103#32#114+ + #101#99#111#114#100#115#32#102#114#111#109#32#77#65#80#42#46#112#97#115#10+ + #47#47#32#97#108#115#111#44#32#116#104#101#32#101#110#103#105#110#101#32#119+ + #105#108#108#32#107#101#101#112#32#116#104#101#32#108#111#97#100#101#100#32+ + #109#97#112#32#97#115#32#97#32#108#105#115#116#32#111#102#32#116#104#101#115+ + #101#32#115#116#114#117#99#116#117#114#101#115#10#10#47#47#32#110#111#116+ + #101#115#58#10#47#47#32#32#32#102#105#101#108#100#32#119#105#116#104#111#117+ + #116#32#111#102#102#115#101#116#32#105#115#32#110#111#116#32#105#110#32#98+ + #105#110#97#114#121#32#102#111#114#109#97#116#10#47#47#32#32#32#102#105#101+ + #108#100#115#32#119#105#116#104#32#96#111#109#105#116#100#101#102#97#117#108+ + #116#96#32#119#111#110#39#116#32#98#101#32#119#114#105#116#116#101#110#32+ + #119#104#101#110#32#116#104#101#121#32#99#111#110#116#97#105#110#32#100#101+ + #102#97#117#108#116#32#118#97#108#117#101#115#10#47#47#32#32#32#102#105#101+ + #108#100#115#32#119#105#116#104#32#96#105#110#116#101#114#110#97#108#96#32+ + #119#111#110#39#116#32#98#101#32#119#114#105#116#116#101#110#32#116#111#32+ + #97#110#121#32#102#105#108#101#32#101#118#101#114#32#40#97#110#100#32#119+ + #111#110#39#116#32#98#101#32#114#101#97#100#41#10#47#47#32#32#32#96#117#98+ + #121#116#101#96#32#105#115#32#117#110#115#105#103#110#101#100#32#98#121#116+ + #101#44#32#97#110#100#32#96#98#121#116#101#96#32#105#115#32#115#105#103#110+ + #101#100#32#98#121#116#101#10#47#47#32#32#32#97#108#108#32#115#116#114#105+ + #110#103#115#32#97#114#101#32#105#110#32#117#116#102#45#56#10#47#47#32#32#32+ + #115#116#114#117#99#116#32#119#105#116#104#32#96#104#101#97#100#101#114#96+ + #32#102#108#97#103#32#119#105#108#108#32#99#111#110#116#97#105#110#32#97#108+ + #108#32#111#116#104#101#114#32#115#116#114#117#99#116#115#32#97#110#100#32+ + #105#116#39#115#32#111#119#110#32#102#105#101#108#100#115#10#47#47#32#32#32+ + #32#32#97#115#32#116#111#112#45#108#101#118#101#108#32#101#110#116#105#116+ + #105#101#115#10#47#47#32#32#32#105#110#32#98#105#110#97#114#121#44#32#96#115+ + #105#122#101#96#32#105#115#32#116#119#111#32#117#115#104#111#114#116#115#10+ + #47#47#32#32#32#96#97#115#32#120#121#96#32#119#105#108#108#32#117#115#101#32+ + #96#88#96#32#97#110#100#32#96#89#96#32#102#111#114#32#112#111#105#110#116+ + #115#10#47#47#32#32#32#96#97#115#32#116#120#121#96#32#119#105#108#108#32#117+ + #115#101#32#96#116#88#96#32#97#110#100#32#96#116#89#96#32#102#111#114#32#112+ + #111#105#110#116#115#10#47#47#32#32#32#96#97#115#32#119#104#96#32#119#105+ + #108#108#32#117#115#101#32#96#87#105#100#116#104#96#32#97#110#100#32#96#72+ + #101#105#103#104#116#96#32#102#111#114#32#115#105#122#101#10#47#47#32#32#32+ + #96#97#115#32#116#119#104#96#32#119#105#108#108#32#117#115#101#32#96#116#87+ + #105#100#116#104#96#32#97#110#100#32#96#116#72#101#105#103#104#116#96#32#102+ + #111#114#32#115#105#122#101#10#10#10#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#10#47#47#32#109#97#105+ + #110#32#98#108#111#99#107#115#10#84#77#97#112#72#101#97#100#101#114#82#101+ + #99#95#49#32#105#115#32#34#109#97#112#34#32#115#105#122#101#32#52#53#50#32+ + #98#121#116#101#115#32#104#101#97#100#101#114#32#98#105#110#98#108#111#99+ + #107#32#55#32#123#10#32#32#47#47#95#32#105#115#32#34#118#101#114#115#105#111+ + #110#34#32#116#121#112#101#32#117#105#110#116#32#109#105#110#118#97#108#117+ + #101#32#49#32#109#97#120#118#97#108#117#101#32#49#59#10#32#32#77#97#112#78+ + #97#109#101#32#105#115#32#34#110#97#109#101#34#32#116#121#112#101#32#99#104+ + #97#114#91#51#50#93#32#111#102#102#115#101#116#32#48#59#10#32#32#77#97#112+ + #65#117#116#104#111#114#32#105#115#32#34#97#117#116#104#111#114#34#32#116+ + #121#112#101#32#99#104#97#114#91#51#50#93#32#111#102#102#115#101#116#32#51+ + #50#32#100#101#102#97#117#108#116#32#34#34#32#111#109#105#116#100#101#102#97+ + #117#108#116#59#10#32#32#77#97#112#68#101#115#99#114#105#112#116#105#111#110+ + #32#105#115#32#34#100#101#115#99#114#105#112#116#105#111#110#34#32#116#121+ + #112#101#32#99#104#97#114#91#50#53#54#93#32#111#102#102#115#101#116#32#54#52+ + #32#100#101#102#97#117#108#116#32#34#34#32#111#109#105#116#100#101#102#97+ + #117#108#116#59#10#32#32#77#117#115#105#99#78#97#109#101#32#105#115#32#34+ + #109#117#115#105#99#34#32#116#121#112#101#32#99#104#97#114#91#54#52#93#32+ + #111#102#102#115#101#116#32#51#50#48#32#100#101#102#97#117#108#116#32#39#83+ + #116#97#110#100#97#114#116#46#119#97#100#58#68#50#68#77#85#83#92#208#159#208+ + #160#208#158#208#161#208#162#208#158#208#162#208#144#39#32#111#109#105#116+ + #100#101#102#97#117#108#116#59#10#32#32#83#107#121#78#97#109#101#32#105#115+ + #32#34#115#107#121#34#32#116#121#112#101#32#99#104#97#114#91#54#52#93#32#111+ + #102#102#115#101#116#32#51#56#52#32#100#101#102#97#117#108#116#32#39#83#116+ + #97#110#100#97#114#116#46#119#97#100#58#68#50#68#83#75#89#92#82#83#75#89#49+ + #39#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#87#105+ + #100#116#104#32#105#115#32#34#119#105#100#116#104#34#32#116#121#112#101#32+ + #117#115#104#111#114#116#32#111#102#102#115#101#116#32#52#52#56#59#10#32#32+ + #47#47#72#101#105#103#104#116#32#105#115#32#34#104#101#105#103#104#116#34#32+ + #116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#52+ + #53#48#59#10#32#32#83#105#122#101#32#105#115#32#34#115#105#122#101#34#32#116+ + #121#112#101#32#115#105#122#101#32#111#102#102#115#101#116#32#52#52#56#32#97+ + #115#32#119#104#59#10#32#32#47#47#32#110#111#116#32#105#110#32#98#105#110#97+ + #114#121#10#32#32#84#105#116#108#101#32#105#115#32#34#116#105#116#108#101#34+ + #32#116#121#112#101#32#115#116#114#105#110#103#32#100#101#102#97#117#108#116+ + #32#34#34#32#32#111#109#105#116#100#101#102#97#117#108#116#59#10#125#10#10+ + #84#84#101#120#116#117#114#101#82#101#99#95#49#32#105#115#32#34#116#101#120+ + #116#117#114#101#34#32#115#105#122#101#32#54#53#32#98#121#116#101#115#32#98+ + #105#110#98#108#111#99#107#32#49#32#123#10#32#32#82#101#115#111#117#114#99+ + #101#32#105#115#32#34#112#97#116#104#34#32#116#121#112#101#32#99#104#97#114+ + #91#54#52#93#32#111#102#102#115#101#116#32#48#59#10#32#32#65#110#105#109#32+ + #105#115#32#34#97#110#105#109#97#116#101#100#34#32#116#121#112#101#32#98#111+ + #111#108#32#111#102#102#115#101#116#32#54#52#32#100#101#102#97#117#108#116+ + #32#102#97#108#115#101#32#111#109#105#116#100#101#102#97#117#108#116#59#10+ + #32#32#47#47#32#105#110#116#101#114#110#97#108#115#10#32#32#84#101#120#73+ + #100#120#32#105#115#32#34#116#101#120#105#100#120#34#32#116#121#112#101#32+ + #117#105#110#116#32#105#110#116#101#114#110#97#108#59#10#125#10#10#84#80#97+ + #110#101#108#82#101#99#95#49#32#105#115#32#34#112#97#110#101#108#34#32#115+ + #105#122#101#32#49#56#32#98#121#116#101#115#32#98#105#110#98#108#111#99#107+ + #32#50#32#123#10#32#32#47#47#88#32#105#115#32#34#120#34#32#116#121#112#101+ + #32#105#110#116#32#111#102#102#115#101#116#32#48#59#10#32#32#47#47#89#32#105+ + #115#32#34#121#34#32#116#121#112#101#32#105#110#116#32#111#102#102#115#101+ + #116#32#52#59#10#32#32#80#111#115#32#105#115#32#34#112#111#115#105#116#105+ + #111#110#34#32#116#121#112#101#32#112#111#105#110#116#32#111#102#102#115#101+ + #116#32#48#32#97#115#32#120#121#59#10#32#32#47#47#87#105#100#116#104#32#105+ + #115#32#34#119#105#100#116#104#34#32#116#121#112#101#32#117#115#104#111#114+ + #116#32#111#102#102#115#101#116#32#56#59#10#32#32#47#47#72#101#105#103#104+ + #116#32#105#115#32#34#104#101#105#103#104#116#34#32#116#121#112#101#32#117+ + #115#104#111#114#116#32#111#102#102#115#101#116#32#49#48#59#10#32#32#83#105+ + #122#101#32#105#115#32#34#115#105#122#101#34#32#116#121#112#101#32#115#105+ + #122#101#32#111#102#102#115#101#116#32#56#32#97#115#32#119#104#32#97#115#32+ + #119#104#59#10#32#32#84#101#120#116#117#114#101#78#117#109#32#105#115#32#34+ + #116#101#120#116#117#114#101#34#32#116#121#112#101#32#117#115#104#111#114+ + #116#32#111#102#102#115#101#116#32#49#50#32#116#101#120#116#117#114#101#59+ + #10#32#32#80#97#110#101#108#84#121#112#101#32#105#115#32#34#116#121#112#101+ + #34#32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116+ + #32#49#52#32#98#105#116#115#101#116#32#117#110#105#113#117#101#32#80#97#110+ + #101#108#84#121#112#101#59#10#32#32#65#108#112#104#97#32#105#115#32#34#97+ + #108#112#104#97#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#49#54#32#100#101#102#97#117#108#116#32#48#32#111#109#105#116+ + #100#101#102#97#117#108#116#59#10#32#32#70#108#97#103#115#32#105#115#32#34+ + #102#108#97#103#115#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102+ + #102#115#101#116#32#49#55#32#98#105#116#115#101#116#32#80#97#110#101#108#70+ + #108#97#103#32#100#101#102#97#117#108#116#32#80#65#78#69#76#95#70#76#65#71+ + #95#78#79#78#69#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47+ + #47#32#110#111#116#32#105#110#32#98#105#110#97#114#121#10#32#32#47#47#73#100+ + #32#105#115#32#34#105#100#34#32#116#121#112#101#32#115#116#114#105#110#103+ + #32#100#101#102#97#117#108#116#32#34#34#32#111#109#105#116#100#101#102#97+ + #117#108#116#59#10#32#32#47#47#32#105#110#116#101#114#110#97#108#115#10#32+ + #32#80#97#110#73#100#120#32#105#115#32#34#112#97#110#105#100#120#34#32#116+ + #121#112#101#32#117#105#110#116#32#105#110#116#101#114#110#97#108#59#10#125+ + #10#10#84#73#116#101#109#82#101#99#95#49#32#105#115#32#34#105#116#101#109#34+ + #32#115#105#122#101#32#49#48#32#98#121#116#101#115#32#98#105#110#98#108#111+ + #99#107#32#51#32#123#10#32#32#47#47#88#32#105#115#32#34#120#34#32#116#121+ + #112#101#32#105#110#116#32#111#102#102#115#101#116#32#48#59#10#32#32#47#47+ + #89#32#105#115#32#34#121#34#32#116#121#112#101#32#105#110#116#32#111#102#102+ + #115#101#116#32#52#59#10#32#32#80#111#115#32#105#115#32#34#112#111#115#105+ + #116#105#111#110#34#32#116#121#112#101#32#112#111#105#110#116#32#111#102#102+ + #115#101#116#32#48#32#97#115#32#120#121#59#10#32#32#73#116#101#109#84#121+ + #112#101#32#105#115#32#34#116#121#112#101#34#32#116#121#112#101#32#117#98+ + #121#116#101#32#111#102#102#115#101#116#32#56#32#101#110#117#109#32#73#116+ + #101#109#59#10#32#32#79#112#116#105#111#110#115#32#105#115#32#34#111#112#116+ + #105#111#110#115#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#57#32#98#105#116#115#101#116#32#73#116#101#109#79#112#116+ + #105#111#110#32#100#101#102#97#117#108#116#32#73#84#69#77#95#79#80#84#73#79+ + #78#95#78#79#78#69#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32+ + #47#47#32#110#111#116#32#105#110#32#98#105#110#97#114#121#10#32#32#47#47#73+ + #100#32#105#115#32#34#105#100#34#32#116#121#112#101#32#115#116#114#105#110+ + #103#32#100#101#102#97#117#108#116#32#34#34#32#111#109#105#116#100#101#102+ + #97#117#108#116#59#10#32#32#47#47#32#105#110#116#101#114#110#97#108#115#10+ + #32#32#73#116#101#109#73#100#120#32#105#115#32#34#105#116#101#109#105#100+ + #120#34#32#116#121#112#101#32#117#105#110#116#32#105#110#116#101#114#110#97+ + #108#59#10#125#10#10#84#77#111#110#115#116#101#114#82#101#99#95#49#32#105+ + #115#32#34#109#111#110#115#116#101#114#34#32#115#105#122#101#32#49#48#32#98+ + #121#116#101#115#32#98#105#110#98#108#111#99#107#32#53#32#123#10#32#32#47#47+ + #88#32#105#115#32#34#120#34#32#116#121#112#101#32#105#110#116#32#111#102#102+ + #115#101#116#32#48#59#10#32#32#47#47#89#32#105#115#32#34#121#34#32#116#121+ + #112#101#32#105#110#116#32#111#102#102#115#101#116#32#52#59#10#32#32#80#111+ + #115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116#121#112#101+ + #32#112#111#105#110#116#32#111#102#102#115#101#116#32#48#32#97#115#32#120+ + #121#59#10#32#32#77#111#110#115#116#101#114#84#121#112#101#32#105#115#32#34+ + #116#121#112#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#56#32#101#110#117#109#32#77#111#110#115#116#101#114#59#10#32+ + #32#68#105#114#101#99#116#105#111#110#32#105#115#32#34#100#105#114#101#99+ + #116#105#111#110#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#57#32#101#110#117#109#32#68#105#114#84#121#112#101#32#100+ + #101#102#97#117#108#116#32#68#73#82#95#76#69#70#84#32#111#109#105#116#100+ + #101#102#97#117#108#116#59#10#32#32#47#47#32#110#111#116#32#105#110#32#98+ + #105#110#97#114#121#10#32#32#47#47#73#100#32#105#115#32#34#105#100#34#32#116+ + #121#112#101#32#115#116#114#105#110#103#32#100#101#102#97#117#108#116#32#34+ + #34#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#32#105+ + #110#116#101#114#110#97#108#115#10#32#32#77#111#110#115#73#100#120#32#105+ + #115#32#34#109#111#110#115#105#100#120#34#32#116#121#112#101#32#117#105#110+ + #116#32#105#110#116#101#114#110#97#108#59#10#125#10#10#84#65#114#101#97#82+ + #101#99#95#49#32#105#115#32#34#97#114#101#97#34#32#115#105#122#101#32#49#48+ + #32#98#121#116#101#115#32#98#105#110#98#108#111#99#107#32#52#32#123#10#32#32+ + #47#47#88#32#105#115#32#34#120#34#32#116#121#112#101#32#105#110#116#32#111+ + #102#102#115#101#116#32#48#59#10#32#32#47#47#89#32#105#115#32#34#121#34#32+ + #116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#52#59#10#32#32+ + #80#111#115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116#121+ + #112#101#32#112#111#105#110#116#32#111#102#102#115#101#116#32#48#32#97#115+ + #32#120#121#59#10#32#32#65#114#101#97#84#121#112#101#32#105#115#32#34#116+ + #121#112#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115+ + #101#116#32#56#32#101#110#117#109#32#65#114#101#97#84#121#112#101#59#10#32+ + #32#68#105#114#101#99#116#105#111#110#32#105#115#32#34#100#105#114#101#99+ + #116#105#111#110#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#57#32#101#110#117#109#32#68#105#114#84#121#112#101#32#100+ + #101#102#97#117#108#116#32#68#73#82#95#76#69#70#84#32#111#109#105#116#100+ + #101#102#97#117#108#116#59#10#32#32#47#47#32#110#111#116#32#105#110#32#98+ + #105#110#97#114#121#10#32#32#47#47#73#100#32#105#115#32#34#105#100#34#32#116+ + #121#112#101#32#115#116#114#105#110#103#32#100#101#102#97#117#108#116#32#34+ + #34#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#32#105+ + #110#116#101#114#110#97#108#115#10#32#32#65#114#101#97#73#100#120#32#105#115+ + #32#34#97#114#101#97#105#100#120#34#32#116#121#112#101#32#117#105#110#116#32+ + #105#110#116#101#114#110#97#108#59#10#125#10#10#84#84#114#105#103#103#101+ + #114#82#101#99#95#49#32#105#115#32#34#116#114#105#103#103#101#114#34#32#115+ + #105#122#101#32#49#52#56#32#98#121#116#101#115#32#98#105#110#98#108#111#99+ + #107#32#54#32#123#10#32#32#47#47#88#32#105#115#32#34#120#34#32#116#121#112+ + #101#32#105#110#116#32#111#102#102#115#101#116#32#48#59#10#32#32#47#47#89#32+ + #105#115#32#34#121#34#32#116#121#112#101#32#105#110#116#32#111#102#102#115+ + #101#116#32#52#59#10#32#32#80#111#115#32#105#115#32#34#112#111#115#105#116+ + #105#111#110#34#32#116#121#112#101#32#112#111#105#110#116#32#111#102#102#115+ + #101#116#32#48#32#97#115#32#120#121#59#10#32#32#47#47#87#105#100#116#104#32+ + #105#115#32#34#119#105#100#116#104#34#32#116#121#112#101#32#117#115#104#111+ + #114#116#32#111#102#102#115#101#116#32#56#59#10#32#32#47#47#72#101#105#103+ + #104#116#32#105#115#32#34#104#101#105#103#104#116#34#32#116#121#112#101#32+ + #117#115#104#111#114#116#32#111#102#102#115#101#116#32#49#48#59#10#32#32#83+ + #105#122#101#32#105#115#32#34#115#105#122#101#34#32#116#121#112#101#32#115+ + #105#122#101#32#111#102#102#115#101#116#32#56#32#97#115#32#119#104#59#10#32+ + #32#69#110#97#98#108#101#100#32#105#115#32#34#101#110#97#98#108#101#100#34+ + #32#116#121#112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#49#50#32+ + #100#101#102#97#117#108#116#32#116#114#117#101#32#111#109#105#116#100#101+ + #102#97#117#108#116#59#10#32#32#84#101#120#116#117#114#101#80#97#110#101#108+ + #32#105#115#32#34#116#101#120#116#117#114#101#112#97#110#101#108#34#32#116+ + #121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#49#51#32#112#97+ + #110#101#108#32#100#101#102#97#117#108#116#32#110#117#108#108#32#111#109#105+ + #116#100#101#102#97#117#108#116#59#10#32#32#84#114#105#103#103#101#114#84+ + #121#112#101#32#105#115#32#34#116#121#112#101#34#32#116#121#112#101#32#117+ + #98#121#116#101#32#111#102#102#115#101#116#32#49#55#32#101#110#117#109#32#84+ + #114#105#103#103#101#114#84#121#112#101#59#10#32#32#65#99#116#105#118#97#116+ + #101#84#121#112#101#32#105#115#32#34#97#99#116#105#118#97#116#101#116#121+ + #112#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101+ + #116#32#49#56#32#98#105#116#115#101#116#32#65#99#116#105#118#97#116#101#84+ + #121#112#101#59#10#32#32#75#101#121#115#32#105#115#32#34#107#101#121#115#34+ + #32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116#32#49+ + #57#32#98#105#116#115#101#116#32#75#101#121#32#100#101#102#97#117#108#116#32+ + #75#69#89#95#78#79#78#69#32#111#109#105#116#100#101#102#97#117#108#116#59#10+ + #32#32#47#47#87#65#82#78#73#78#71#58#32#34#116#114#105#103#100#97#116#97#34+ + #32#77#85#83#84#32#98#101#32#100#101#102#105#110#101#100#32#98#101#102#111+ + #114#101#32#34#116#121#112#101#34#44#32#97#110#100#32#34#116#121#112#101#34+ + #32#77#85#83#84#32#98#101#32#110#97#109#101#100#32#34#116#121#112#101#34#32+ + #40#102#111#114#32#110#111#119#44#32#99#97#110#32#98#101#32#99#104#97#110+ + #103#101#100#32#108#97#116#101#114#41#10#32#32#68#65#84#65#32#105#115#32#34+ + #116#114#105#103#103#101#114#100#97#116#97#34#32#116#121#112#101#32#116#114+ + #105#103#100#97#116#97#91#49#50#56#93#32#111#102#102#115#101#116#32#50#48#59+ + #32#47#47#32#116#104#101#32#111#110#108#121#32#115#112#101#99#105#97#108#32+ + #110#101#115#116#101#100#32#115#116#114#117#99#116#117#114#101#10#32#32#47+ + #47#32#110#111#116#32#105#110#32#98#105#110#97#114#121#10#32#32#47#47#73#100+ + #32#105#115#32#34#105#100#34#32#116#121#112#101#32#115#116#114#105#110#103+ + #32#100#101#102#97#117#108#116#32#34#34#32#111#109#105#116#100#101#102#97+ + #117#108#116#59#10#32#32#47#47#32#105#110#116#101#114#110#97#108#115#10#32+ + #32#84#114#105#103#73#100#120#32#105#115#32#34#116#114#105#103#105#100#120+ + #34#32#116#121#112#101#32#117#105#110#116#32#105#110#116#101#114#110#97#108+ + #59#10#125#10#10#10#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#10#47#42#10#101#110#117#109#32#123#10#32+ + #32#84#69#88#84#85#82#69#95#78#65#77#69#95#87#65#84#69#82#32#61#32#39#95#119+ + #97#116#101#114#95#48#39#44#10#32#32#84#69#88#84#85#82#69#95#78#65#77#69#95+ + #65#67#73#68#49#32#61#32#39#95#119#97#116#101#114#95#49#39#44#10#32#32#84#69+ + #88#84#85#82#69#95#78#65#77#69#95#65#67#73#68#50#32#61#32#39#95#119#97#116+ + #101#114#95#50#39#44#10#125#10#42#47#10#10#101#110#117#109#32#84#101#120#116+ + #117#114#101#83#112#101#99#105#97#108#32#123#10#32#32#84#69#88#84#85#82#69+ + #95#83#80#69#67#73#65#76#95#87#65#84#69#82#32#61#32#45#49#44#10#32#32#84#69+ + #88#84#85#82#69#95#83#80#69#67#73#65#76#95#65#67#73#68#49#32#61#32#45#50#44+ + #10#32#32#84#69#88#84#85#82#69#95#83#80#69#67#73#65#76#95#65#67#73#68#50#32+ + #61#32#45#51#44#10#32#32#84#69#88#84#85#82#69#95#78#79#78#69#32#61#32#45#52+ + #44#10#125#10#10#47#47#32#100#105#114#101#99#116#105#111#110#115#10#101#110+ + #117#109#32#68#105#114#84#121#112#101#32#123#10#32#32#68#73#82#95#76#69#70+ + #84#44#32#47#47#32#48#10#32#32#68#73#82#95#82#73#71#72#84#44#32#47#47#32#49+ + #10#32#32#68#73#82#95#83#79#77#69#84#72#73#78#71#50#44#32#47#47#32#50#10#125+ + #10#10#47#47#32#116#114#105#103#103#101#114#115#10#101#110#117#109#32#84#114+ + #105#103#103#101#114#84#121#112#101#32#123#10#32#32#84#82#73#71#71#69#82#95+ + #78#79#78#69#44#32#47#47#32#48#10#32#32#84#82#73#71#71#69#82#95#69#88#73#84+ + #44#32#47#47#32#49#10#32#32#84#82#73#71#71#69#82#95#84#69#76#69#80#79#82#84+ + #44#32#47#47#32#50#10#32#32#84#82#73#71#71#69#82#95#79#80#69#78#68#79#79#82+ + #44#32#47#47#32#51#10#32#32#84#82#73#71#71#69#82#95#67#76#79#83#69#68#79#79+ + #82#44#32#47#47#32#52#10#32#32#84#82#73#71#71#69#82#95#68#79#79#82#44#32#47+ + #47#32#53#10#32#32#84#82#73#71#71#69#82#95#68#79#79#82#53#44#32#47#47#32#54+ + #10#32#32#84#82#73#71#71#69#82#95#67#76#79#83#69#84#82#65#80#44#32#47#47#32+ + #55#10#32#32#84#82#73#71#71#69#82#95#84#82#65#80#44#32#47#47#32#56#10#32#32+ + #84#82#73#71#71#69#82#95#80#82#69#83#83#44#32#47#47#32#57#10#32#32#84#82#73+ + #71#71#69#82#95#83#69#67#82#69#84#44#32#47#47#32#49#48#10#32#32#84#82#73#71+ + #71#69#82#95#76#73#70#84#85#80#44#32#47#47#32#49#49#10#32#32#84#82#73#71#71+ + #69#82#95#76#73#70#84#68#79#87#78#44#32#47#47#32#49#50#10#32#32#84#82#73#71+ + #71#69#82#95#76#73#70#84#44#32#47#47#32#49#51#10#32#32#84#82#73#71#71#69#82+ + #95#84#69#88#84#85#82#69#44#32#47#47#32#49#52#10#32#32#84#82#73#71#71#69#82+ + #95#79#78#44#32#47#47#32#49#53#10#32#32#84#82#73#71#71#69#82#95#79#70#70#44+ + #32#47#47#32#49#54#10#32#32#84#82#73#71#71#69#82#95#79#78#79#70#70#44#32#47+ + #47#32#49#55#10#32#32#84#82#73#71#71#69#82#95#83#79#85#78#68#44#32#47#47#32+ + #49#56#10#32#32#84#82#73#71#71#69#82#95#83#80#65#87#78#77#79#78#83#84#69#82+ + #44#32#47#47#32#49#57#10#32#32#84#82#73#71#71#69#82#95#83#80#65#87#78#73#84+ + #69#77#44#32#47#47#32#50#48#10#32#32#84#82#73#71#71#69#82#95#77#85#83#73#67+ + #44#32#47#47#32#50#49#10#32#32#84#82#73#71#71#69#82#95#80#85#83#72#44#32#47+ + #47#32#50#50#10#32#32#84#82#73#71#71#69#82#95#83#67#79#82#69#44#32#47#47#32+ + #50#51#10#32#32#84#82#73#71#71#69#82#95#77#69#83#83#65#71#69#44#32#47#47#32+ + #50#52#10#32#32#84#82#73#71#71#69#82#95#68#65#77#65#71#69#44#32#47#47#32#50+ + #53#10#32#32#84#82#73#71#71#69#82#95#72#69#65#76#84#72#44#32#47#47#32#50#54+ + #10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#44#32#47#47#32#50#55#10#32#32+ + #84#82#73#71#71#69#82#95#69#70#70#69#67#84#44#32#47#47#32#50#56#10#32#32#84+ + #82#73#71#71#69#82#95#83#67#82#73#80#84#44#32#47#47#32#50#57#10#32#32#47#47+ + #10#32#32#84#82#73#71#71#69#82#95#77#65#88#32#61#32#77#65#88#44#10#125#10#10+ + #47#47#32#34#97#115#32#88#88#88#34#32#109#101#97#110#115#32#34#103#101#110+ + #101#114#97#116#101#32#116#104#105#115#32#105#100#101#110#116#105#102#105+ + #101#114#32#102#111#114#32#112#97#115#99#97#108#32#115#111#117#114#99#101+ + #115#10#98#105#116#115#101#116#32#80#97#110#101#108#84#121#112#101#32#123#10+ + #32#32#80#65#78#69#76#95#78#79#78#69#32#61#32#48#44#32#47#47#32#48#10#32#32+ + #80#65#78#69#76#95#87#65#76#76#44#32#47#47#32#49#10#32#32#80#65#78#69#76#95+ + #66#65#67#75#44#32#47#47#32#50#10#32#32#80#65#78#69#76#95#70#79#82#69#44#32+ + #47#47#32#52#10#32#32#80#65#78#69#76#95#87#65#84#69#82#44#32#47#47#32#56#10+ + #32#32#80#65#78#69#76#95#65#67#73#68#49#44#32#47#47#32#49#54#10#32#32#80#65+ + #78#69#76#95#65#67#73#68#50#44#32#47#47#32#51#50#10#32#32#80#65#78#69#76#95+ + #83#84#69#80#44#32#47#47#32#54#52#10#32#32#80#65#78#69#76#95#76#73#70#84#85+ + #80#44#32#47#47#32#49#50#56#10#32#32#80#65#78#69#76#95#76#73#70#84#68#79#87+ + #78#44#32#47#47#32#50#53#54#10#32#32#80#65#78#69#76#95#79#80#69#78#68#79#79+ + #82#44#32#47#47#32#53#49#50#10#32#32#80#65#78#69#76#95#67#76#79#83#69#68#79+ + #79#82#44#32#47#47#32#49#48#50#52#10#32#32#80#65#78#69#76#95#66#76#79#67#75+ + #77#79#78#44#32#47#47#32#50#48#52#56#10#32#32#80#65#78#69#76#95#76#73#70#84+ + #76#69#70#84#44#32#47#47#32#52#48#57#54#10#32#32#80#65#78#69#76#95#76#73#70+ + #84#82#73#71#72#84#44#32#47#47#32#56#49#57#50#10#125#10#10#98#105#116#115+ + #101#116#32#80#97#110#101#108#70#108#97#103#32#123#10#32#32#80#65#78#69#76+ + #95#70#76#65#71#95#78#79#78#69#32#61#32#48#44#32#47#47#32#48#10#32#32#80#65+ + #78#69#76#95#70#76#65#71#95#66#76#69#78#68#73#78#71#44#32#47#47#32#49#10#32+ + #32#80#65#78#69#76#95#70#76#65#71#95#72#73#68#69#44#32#47#47#32#50#10#32#32+ + #80#65#78#69#76#95#70#76#65#71#95#87#65#84#69#82#84#69#88#84#85#82#69#83#44+ + #32#47#47#32#52#10#125#10#10#101#110#117#109#32#69#102#102#101#99#116#65#99+ + #116#105#111#110#32#123#10#32#32#69#70#70#69#67#84#95#78#79#78#69#44#32#47+ + #47#32#48#10#32#32#69#70#70#69#67#84#95#84#69#76#69#80#79#82#84#44#32#47#47+ + #32#49#10#32#32#69#70#70#69#67#84#95#82#69#83#80#65#87#78#44#32#47#47#32#50+ + #10#32#32#69#70#70#69#67#84#95#70#73#82#69#44#32#47#47#32#51#10#125#10#10+ + #101#110#117#109#32#73#116#101#109#32#123#10#32#32#73#84#69#77#95#78#79#78+ + #69#44#32#47#47#32#48#10#32#32#73#84#69#77#95#77#69#68#75#73#84#95#83#77#65+ + #76#76#44#32#47#47#32#49#10#32#32#73#84#69#77#95#77#69#68#75#73#84#95#76#65+ + #82#71#69#44#32#47#47#32#50#10#32#32#73#84#69#77#95#77#69#68#75#73#84#95#66+ + #76#65#67#75#44#32#47#47#32#51#10#32#32#73#84#69#77#95#65#82#77#79#82#95#71+ + #82#69#69#78#44#32#47#47#32#52#10#32#32#73#84#69#77#95#65#82#77#79#82#95#66+ + #76#85#69#44#32#47#47#32#53#10#32#32#73#84#69#77#95#83#80#72#69#82#69#95#66+ + #76#85#69#44#32#47#47#32#54#10#32#32#73#84#69#77#95#83#80#72#69#82#69#95#87+ + #72#73#84#69#44#32#47#47#32#55#10#32#32#73#84#69#77#95#83#85#73#84#44#32#47+ + #47#32#56#10#32#32#73#84#69#77#95#79#88#89#71#69#78#44#32#47#47#32#57#10#32+ + #32#73#84#69#77#95#73#78#86#85#76#44#32#47#47#32#49#48#10#32#32#73#84#69#77+ + #95#87#69#65#80#79#78#95#83#65#87#44#32#47#47#32#49#49#10#32#32#73#84#69#77+ + #95#87#69#65#80#79#78#95#83#72#79#84#71#85#78#49#44#32#47#47#32#49#50#10#32+ + #32#73#84#69#77#95#87#69#65#80#79#78#95#83#72#79#84#71#85#78#50#44#32#47#47+ + #32#49#51#10#32#32#73#84#69#77#95#87#69#65#80#79#78#95#67#72#65#73#78#71#85+ + #78#44#32#47#47#32#49#52#10#32#32#73#84#69#77#95#87#69#65#80#79#78#95#82#79+ + #67#75#69#84#76#65#85#78#67#72#69#82#44#32#47#47#32#49#53#10#32#32#73#84#69+ + #77#95#87#69#65#80#79#78#95#80#76#65#83#77#65#44#32#47#47#32#49#54#10#32#32+ + #73#84#69#77#95#87#69#65#80#79#78#95#66#70#71#44#32#47#47#32#49#55#10#32#32+ + #73#84#69#77#95#87#69#65#80#79#78#95#83#85#80#69#82#80#85#76#69#77#69#84#44+ + #32#47#47#32#49#56#10#32#32#73#84#69#77#95#65#77#77#79#95#66#85#76#76#69#84+ + #83#44#32#47#47#32#49#57#10#32#32#73#84#69#77#95#65#77#77#79#95#66#85#76#76+ + #69#84#83#95#66#79#88#44#32#47#47#32#50#48#10#32#32#73#84#69#77#95#65#77#77+ + #79#95#83#72#69#76#76#83#44#32#47#47#32#50#49#10#32#32#73#84#69#77#95#65#77+ + #77#79#95#83#72#69#76#76#83#95#66#79#88#44#32#47#47#32#50#50#10#32#32#73#84+ + #69#77#95#65#77#77#79#95#82#79#67#75#69#84#44#32#47#47#32#50#51#10#32#32#73+ + #84#69#77#95#65#77#77#79#95#82#79#67#75#69#84#95#66#79#88#44#32#47#47#32#50+ + #52#10#32#32#73#84#69#77#95#65#77#77#79#95#67#69#76#76#44#32#47#47#32#50#53+ + #10#32#32#73#84#69#77#95#65#77#77#79#95#67#69#76#76#95#66#73#71#44#32#47#47+ + #32#50#54#10#32#32#73#84#69#77#95#65#77#77#79#95#66#65#67#75#80#65#67#75#44+ + #32#47#47#32#50#55#10#32#32#73#84#69#77#95#75#69#89#95#82#69#68#44#32#47#47+ + #32#50#56#10#32#32#73#84#69#77#95#75#69#89#95#71#82#69#69#78#44#32#47#47#32+ + #50#57#10#32#32#73#84#69#77#95#75#69#89#95#66#76#85#69#44#32#47#47#32#51#48+ + #10#32#32#73#84#69#77#95#87#69#65#80#79#78#95#75#65#83#84#69#84#44#32#47#47+ + #32#51#49#10#32#32#73#84#69#77#95#87#69#65#80#79#78#95#80#73#83#84#79#76#44+ + #32#47#47#32#51#50#10#32#32#73#84#69#77#95#66#79#84#84#76#69#44#32#47#47#32+ + #51#51#10#32#32#73#84#69#77#95#72#69#76#77#69#84#44#32#47#47#32#51#52#10#32+ + #32#73#84#69#77#95#74#69#84#80#65#67#75#44#32#47#47#32#51#53#10#32#32#73#84+ + #69#77#95#73#78#86#73#83#44#32#47#47#32#51#54#10#32#32#73#84#69#77#95#87#69+ + #65#80#79#78#95#70#76#65#77#69#84#72#82#79#87#69#82#44#32#47#47#32#51#55#10+ + #32#32#73#84#69#77#95#65#77#77#79#95#70#85#69#76#67#65#78#44#32#47#47#32#51+ + #56#10#32#32#47#47#10#32#32#73#84#69#77#95#77#65#88#32#61#32#77#65#88#44#32+ + #47#47#32#115#116#111#114#101#32#116#104#101#32#108#97#115#116#32#105#116+ + #101#109#39#115#32#105#100#32#105#110#32#104#101#114#101#32#117#115#101#32+ + #116#104#105#115#32#105#110#32#102#111#114#32#108#111#111#112#115#10#125#10+ + #10#98#105#116#115#101#116#32#73#116#101#109#79#112#116#105#111#110#32#123+ + #10#32#32#73#84#69#77#95#79#80#84#73#79#78#95#78#79#78#69#32#61#32#48#44#32+ + #47#47#32#48#10#32#32#73#84#69#77#95#79#80#84#73#79#78#95#79#78#76#89#68#77+ + #44#32#47#47#32#49#10#32#32#73#84#69#77#95#79#80#84#73#79#78#95#70#65#76#76+ + #44#32#47#47#32#50#10#125#10#10#101#110#117#109#32#65#114#101#97#84#121#112+ + #101#32#123#10#32#32#65#82#69#65#95#78#79#78#69#44#32#47#47#32#48#10#32#32+ + #65#82#69#65#95#80#76#65#89#69#82#80#79#73#78#84#49#44#32#47#47#32#49#10#32+ + #32#65#82#69#65#95#80#76#65#89#69#82#80#79#73#78#84#50#44#32#47#47#32#50#10+ + #32#32#65#82#69#65#95#68#77#80#79#73#78#84#44#32#47#47#32#51#10#32#32#65#82+ + #69#65#95#82#69#68#70#76#65#71#44#32#47#47#32#52#10#32#32#65#82#69#65#95#66+ + #76#85#69#70#76#65#71#44#32#47#47#32#53#10#32#32#65#82#69#65#95#68#79#77#70+ + #76#65#71#44#32#47#47#32#54#10#32#32#65#82#69#65#95#82#69#68#84#69#65#77#80+ + #79#73#78#84#44#32#47#47#32#55#10#32#32#65#82#69#65#95#66#76#85#69#84#69#65+ + #77#80#79#73#78#84#44#32#47#47#32#56#10#125#10#10#101#110#117#109#32#77#111+ + #110#115#116#101#114#32#123#10#32#32#77#79#78#83#84#69#82#95#78#79#78#69#44+ + #32#47#47#32#48#10#32#32#77#79#78#83#84#69#82#95#68#69#77#79#78#44#32#47#47+ + #32#49#10#32#32#77#79#78#83#84#69#82#95#73#77#80#44#32#47#47#32#50#10#32#32+ + #77#79#78#83#84#69#82#95#90#79#77#66#89#44#32#47#47#32#51#10#32#32#77#79#78+ + #83#84#69#82#95#83#69#82#71#44#32#47#47#32#52#10#32#32#77#79#78#83#84#69#82+ + #95#67#89#66#69#82#44#32#47#47#32#53#10#32#32#77#79#78#83#84#69#82#95#67#71+ + #85#78#44#32#47#47#32#54#10#32#32#77#79#78#83#84#69#82#95#66#65#82#79#78#44+ + #32#47#47#32#55#10#32#32#77#79#78#83#84#69#82#95#75#78#73#71#72#84#44#32#47+ + #47#32#56#10#32#32#77#79#78#83#84#69#82#95#67#65#67#79#44#32#47#47#32#57#10+ + #32#32#77#79#78#83#84#69#82#95#83#79#85#76#44#32#47#47#32#49#48#10#32#32#77+ + #79#78#83#84#69#82#95#80#65#73#78#44#32#47#47#32#49#49#10#32#32#77#79#78#83+ + #84#69#82#95#83#80#73#68#69#82#44#32#47#47#32#49#50#10#32#32#77#79#78#83#84+ + #69#82#95#66#83#80#44#32#47#47#32#49#51#10#32#32#77#79#78#83#84#69#82#95#77+ + #65#78#67#85#66#44#32#47#47#32#49#52#10#32#32#77#79#78#83#84#69#82#95#83#75+ + #69#76#44#32#47#47#32#49#53#10#32#32#77#79#78#83#84#69#82#95#86#73#76#69#44+ + #32#47#47#32#49#54#10#32#32#77#79#78#83#84#69#82#95#70#73#83#72#44#32#47#47+ + #32#49#55#10#32#32#77#79#78#83#84#69#82#95#66#65#82#82#69#76#44#32#47#47#32+ + #49#56#10#32#32#77#79#78#83#84#69#82#95#82#79#66#79#44#32#47#47#32#49#57#10+ + #32#32#77#79#78#83#84#69#82#95#77#65#78#44#32#47#47#32#50#48#10#125#10#10+ + #101#110#117#109#32#84#114#105#103#103#101#114#83#104#111#116#32#123#10#32+ + #32#84#82#73#71#71#69#82#95#83#72#79#84#95#80#73#83#84#79#76#44#32#47#47#32+ + #48#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#66#85#76#76#69#84#44#32+ + #47#47#32#49#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#83#72#79#84#71+ + #85#78#44#32#47#47#32#50#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#83+ + #83#71#44#32#47#47#32#51#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#73+ + #77#80#44#32#47#47#32#52#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#80+ + #76#65#83#77#65#44#32#47#47#32#53#10#32#32#84#82#73#71#71#69#82#95#83#72#79+ + #84#95#83#80#73#68#69#82#44#32#47#47#32#54#10#32#32#84#82#73#71#71#69#82#95+ + #83#72#79#84#95#67#65#67#79#44#32#47#47#32#55#10#32#32#84#82#73#71#71#69#82+ + #95#83#72#79#84#95#66#65#82#79#78#44#32#47#47#32#56#10#32#32#84#82#73#71#71+ + #69#82#95#83#72#79#84#95#77#65#78#67#85#66#44#32#47#47#32#57#10#32#32#84#82+ + #73#71#71#69#82#95#83#72#79#84#95#82#69#86#44#32#47#47#32#49#48#10#32#32#84+ + #82#73#71#71#69#82#95#83#72#79#84#95#82#79#67#75#69#84#44#32#47#47#32#49#49+ + #10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#66#70#71#44#32#47#47#32#49+ + #50#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#69#88#80#76#44#32#47#47+ + #32#49#51#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#66#70#71#69#88#80+ + #76#44#32#47#47#32#49#52#10#32#32#47#47#10#32#32#84#82#73#71#71#69#82#95#83+ + #72#79#84#95#77#65#88#32#61#32#77#65#88#44#10#125#10#10#101#110#117#109#32+ + #84#114#105#103#103#101#114#83#104#111#116#84#97#114#103#101#116#32#123#10+ + #32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#84#65#82#71#69#84#95#78#79#78+ + #69#44#32#47#47#32#48#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#84#65+ + #82#71#69#84#95#77#79#78#44#32#47#47#32#49#10#32#32#84#82#73#71#71#69#82#95+ + #83#72#79#84#95#84#65#82#71#69#84#95#80#76#82#44#32#47#47#32#50#10#32#32#84+ + #82#73#71#71#69#82#95#83#72#79#84#95#84#65#82#71#69#84#95#82#69#68#44#32#47+ + #47#32#51#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#84#65#82#71#69#84+ + #95#66#76#85#69#44#32#47#47#32#52#10#32#32#84#82#73#71#71#69#82#95#83#72#79+ + #84#95#84#65#82#71#69#84#95#77#79#78#80#76#82#44#32#47#47#32#53#10#32#32#84+ + #82#73#71#71#69#82#95#83#72#79#84#95#84#65#82#71#69#84#95#80#76#82#77#79#78+ + #44#32#47#47#32#54#10#125#10#10#101#110#117#109#32#84#114#105#103#103#101+ + #114#83#104#111#116#65#105#109#32#123#10#32#32#84#82#73#71#71#69#82#95#83#72+ + #79#84#95#65#73#77#95#68#69#70#65#85#76#84#44#32#47#47#32#48#10#32#32#84#82+ + #73#71#71#69#82#95#83#72#79#84#95#65#73#77#95#65#76#76#77#65#80#44#32#47#47+ + #32#49#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#65#73#77#95#84#82#65+ + #67#69#44#32#47#47#32#50#10#32#32#84#82#73#71#71#69#82#95#83#72#79#84#95#65+ + #73#77#95#84#82#65#67#69#65#76#76#44#32#47#47#32#51#10#125#10#10#101#110#117+ + #109#32#84#114#105#103#103#101#114#69#102#102#101#99#116#32#123#10#32#32#84+ + #82#73#71#71#69#82#95#69#70#70#69#67#84#95#80#65#82#84#73#67#76#69#44#32#47+ + #47#32#48#10#32#32#84#82#73#71#71#69#82#95#69#70#70#69#67#84#95#65#78#73#77+ + #65#84#73#79#78#44#32#47#47#32#49#10#125#10#10#101#110#117#109#32#84#114#105+ + #103#103#101#114#69#102#102#101#99#116#84#121#112#101#32#123#10#32#32#84#82+ + #73#71#71#69#82#95#69#70#70#69#67#84#95#83#76#73#81#85#73#68#44#32#47#47#32+ + #48#10#32#32#84#82#73#71#71#69#82#95#69#70#70#69#67#84#95#76#76#73#81#85#73+ + #68#44#32#47#47#32#49#10#32#32#84#82#73#71#71#69#82#95#69#70#70#69#67#84#95+ + #68#76#73#81#85#73#68#44#32#47#47#32#50#10#32#32#84#82#73#71#71#69#82#95#69+ + #70#70#69#67#84#95#66#76#79#79#68#44#32#47#47#32#51#10#32#32#84#82#73#71#71+ + #69#82#95#69#70#70#69#67#84#95#83#80#65#82#75#44#32#47#47#32#52#10#32#32#84+ + #82#73#71#71#69#82#95#69#70#70#69#67#84#95#66#85#66#66#76#69#44#32#47#47#32+ + #53#10#32#32#84#82#73#71#71#69#82#95#69#70#70#69#67#84#95#77#65#88#32#61#32+ + #77#65#88#44#10#125#10#10#101#110#117#109#32#84#114#105#103#103#101#114#69+ + #102#102#101#99#116#80#111#115#32#123#10#32#32#84#82#73#71#71#69#82#95#69#70+ + #70#69#67#84#95#80#79#83#95#67#69#78#84#69#82#44#32#47#47#32#48#10#32#32#84+ + #82#73#71#71#69#82#95#69#70#70#69#67#84#95#80#79#83#95#65#82#69#65#44#32#47+ + #47#32#49#10#125#10#10#98#105#116#115#101#116#32#65#99#116#105#118#97#116+ + #101#84#121#112#101#32#123#10#32#32#65#67#84#73#86#65#84#69#95#78#79#78#69+ + #32#61#32#48#44#32#47#47#32#48#10#32#32#65#67#84#73#86#65#84#69#95#80#76#65+ + #89#69#82#67#79#76#76#73#68#69#44#32#47#47#32#49#10#32#32#65#67#84#73#86#65+ + #84#69#95#77#79#78#83#84#69#82#67#79#76#76#73#68#69#44#32#47#47#32#50#10#32+ + #32#65#67#84#73#86#65#84#69#95#80#76#65#89#69#82#80#82#69#83#83#44#32#47#47+ + #32#52#10#32#32#65#67#84#73#86#65#84#69#95#77#79#78#83#84#69#82#80#82#69#83+ + #83#44#32#47#47#32#56#10#32#32#65#67#84#73#86#65#84#69#95#83#72#79#84#44#32+ + #47#47#32#49#54#10#32#32#65#67#84#73#86#65#84#69#95#78#79#77#79#78#83#84#69+ + #82#44#32#47#47#32#51#50#10#32#32#65#67#84#73#86#65#84#69#95#67#85#83#84#79+ + #77#32#61#32#50#53#53#44#32#47#47#32#110#111#116#101#32#116#104#97#116#32#34+ + #100#105#114#101#99#116#32#97#115#115#105#103#110#34#32#102#105#101#108#100+ + #32#100#111#101#115#110#39#116#32#97#102#102#101#99#116#32#98#105#116#32#99+ + #111#117#110#116#101#114#10#125#10#10#98#105#116#115#101#116#32#75#101#121+ + #32#123#10#32#32#75#69#89#95#78#79#78#69#32#61#32#48#44#32#47#47#32#48#10#32+ + #32#75#69#89#95#82#69#68#44#32#47#47#32#49#10#32#32#75#69#89#95#71#82#69#69+ + #78#44#32#47#47#32#50#10#32#32#75#69#89#95#66#76#85#69#44#32#47#47#32#52#10+ + #32#32#75#69#89#95#82#69#68#84#69#65#77#44#32#47#47#32#56#10#32#32#75#69#89+ + #95#66#76#85#69#84#69#65#77#44#32#47#47#32#49#54#10#125#10#10#10#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47#47+ + #47#10#47#47#32#118#97#114#105#111#117#115#32#116#114#105#103#103#101#114+ + #115#10#84#114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#84#82#73+ + #71#71#69#82#95#69#88#73#84#32#123#10#32#32#77#97#112#78#97#109#101#32#105+ + #115#32#34#109#97#112#34#32#116#121#112#101#32#99#104#97#114#91#49#54#93#32+ + #111#102#102#115#101#116#32#48#59#10#125#10#10#84#114#105#103#103#101#114#68+ + #97#116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#84#69#76#69#80#79#82#84+ + #32#123#10#32#32#84#97#114#103#101#116#80#111#105#110#116#32#105#115#32#34+ + #116#97#114#103#101#116#34#32#116#121#112#101#32#112#111#105#110#116#32#111+ + #102#102#115#101#116#32#48#59#10#32#32#100#50#100#95#116#101#108#101#112#111+ + #114#116#32#105#115#32#34#100#50#100#34#32#116#121#112#101#32#98#111#111#108+ + #32#111#102#102#115#101#116#32#56#32#100#101#102#97#117#108#116#32#102#97+ + #108#115#101#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#115+ + #105#108#101#110#116#95#116#101#108#101#112#111#114#116#32#105#115#32#34#115+ + #105#108#101#110#116#34#32#116#121#112#101#32#98#111#111#108#32#111#102#102+ + #115#101#116#32#57#32#100#101#102#97#117#108#116#32#102#97#108#115#101#32+ + #111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#84#108#112#68#105+ + #114#32#105#115#32#34#100#105#114#101#99#116#105#111#110#34#32#116#121#112+ + #101#32#117#98#121#116#101#32#111#102#102#115#101#116#32#49#48#32#101#110+ + #117#109#32#68#105#114#84#121#112#101#32#100#101#102#97#117#108#116#32#68#73+ + #82#95#76#69#70#84#32#111#109#105#116#100#101#102#97#117#108#116#59#10#125+ + #10#10#84#114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#40#84#82#73+ + #71#71#69#82#95#79#80#69#78#68#79#79#82#44#32#84#82#73#71#71#69#82#95#67#76+ + #79#83#69#68#79#79#82#44#32#84#82#73#71#71#69#82#95#68#79#79#82#44#32#84#82+ + #73#71#71#69#82#95#68#79#79#82#53#44#32#84#82#73#71#71#69#82#95#67#76#79#83+ + #69#84#82#65#80#44#32#84#82#73#71#71#69#82#95#84#82#65#80#44#32#84#82#73#71+ + #71#69#82#95#76#73#70#84#85#80#44#32#84#82#73#71#71#69#82#95#76#73#70#84#68+ + #79#87#78#44#32#84#82#73#71#71#69#82#95#76#73#70#84#41#32#123#10#32#32#80#97+ + #110#101#108#73#68#32#105#115#32#34#112#97#110#101#108#105#100#34#32#116#121+ + #112#101#32#105#110#116#32#111#102#102#115#101#116#32#48#32#112#97#110#101+ + #108#59#10#32#32#78#111#83#111#117#110#100#32#105#115#32#34#115#105#108#101+ + #110#116#34#32#116#121#112#101#32#98#111#111#108#32#111#102#102#115#101#116+ + #32#52#32#100#101#102#97#117#108#116#32#102#97#108#115#101#32#111#109#105+ + #116#100#101#102#97#117#108#116#59#10#32#32#100#50#100#95#100#111#111#114+ + #115#32#105#115#32#34#100#50#100#34#32#116#121#112#101#32#98#111#111#108#32+ + #111#102#102#115#101#116#32#53#32#100#101#102#97#117#108#116#32#102#97#108+ + #115#101#32#111#109#105#116#100#101#102#97#117#108#116#59#10#125#10#10#84+ + #114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#40#84#82#73#71#71#69+ + #82#95#80#82#69#83#83#44#32#84#82#73#71#71#69#82#95#79#78#44#32#84#82#73#71+ + #71#69#82#95#79#70#70#44#32#84#82#73#71#71#69#82#95#79#78#79#70#70#41#32#123+ + #10#32#32#47#47#116#88#32#105#115#32#34#116#120#34#32#116#121#112#101#32#105+ + #110#116#32#111#102#102#115#101#116#32#48#59#10#32#32#47#47#116#89#32#105+ + #115#32#34#116#121#34#32#116#121#112#101#32#105#110#116#32#111#102#102#115+ + #101#116#32#52#59#10#32#32#80#111#115#32#105#115#32#34#112#111#115#105#116+ + #105#111#110#34#32#116#121#112#101#32#112#111#105#110#116#32#111#102#102#115+ + #101#116#32#48#32#97#115#32#116#120#121#59#10#32#32#47#47#116#87#105#100#116+ + #104#32#105#115#32#34#119#105#100#116#104#34#32#116#121#112#101#32#117#115+ + #104#111#114#116#32#111#102#102#115#101#116#32#56#59#10#32#32#47#47#116#72+ + #101#105#103#104#116#32#105#115#32#34#104#101#105#103#104#116#34#32#116#121+ + #112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#49#48#59+ + #10#32#32#83#105#122#101#32#105#115#32#34#115#105#122#101#34#32#116#121#112+ + #101#32#115#105#122#101#32#111#102#102#115#101#116#32#56#32#97#115#32#116+ + #119#104#59#10#32#32#87#97#105#116#32#105#115#32#34#119#97#105#116#34#32#116+ + #121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#49#50+ + #59#10#32#32#67#111#117#110#116#32#105#115#32#34#99#111#117#110#116#34#32+ + #116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#49+ + #52#59#10#32#32#77#111#110#115#116#101#114#73#68#32#105#115#32#34#109#111+ + #110#115#116#101#114#105#100#34#32#116#121#112#101#32#105#110#116#32#111#102+ + #102#115#101#116#32#49#54#32#109#111#110#115#116#101#114#59#10#32#32#69#120+ + #116#82#97#110#100#111#109#32#105#115#32#34#101#120#116#114#97#110#100#111+ + #109#34#32#116#121#112#101#32#98#111#111#108#32#111#102#102#115#101#116#32+ + #50#48#59#10#125#10#10#84#114#105#103#103#101#114#68#97#116#97#32#102#111+ + #114#32#84#82#73#71#71#69#82#95#83#69#67#82#69#84#32#123#10#125#10#10#84#114+ + #105#103#103#101#114#68#97#116#97#32#102#111#114#32#84#82#73#71#71#69#82#95+ + #84#69#88#84#85#82#69#32#123#10#32#32#65#99#116#105#118#97#116#101#79#110#99+ + #101#32#105#115#32#34#97#99#116#105#118#97#116#101#111#110#99#101#34#32#116+ + #121#112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#48#59#10#32#32+ + #65#110#105#109#79#110#99#101#32#105#115#32#34#97#110#105#109#97#116#101#111+ + #110#99#101#34#32#116#121#112#101#32#98#111#111#108#32#111#102#102#115#101+ + #116#32#49#59#10#125#10#10#84#114#105#103#103#101#114#68#97#116#97#32#102+ + #111#114#32#84#82#73#71#71#69#82#95#83#79#85#78#68#32#123#10#32#32#83#111+ + #117#110#100#78#97#109#101#32#105#115#32#34#115#111#117#110#100#110#97#109+ + #101#34#32#116#121#112#101#32#99#104#97#114#91#54#52#93#32#111#102#102#115+ + #101#116#32#48#59#10#32#32#86#111#108#117#109#101#32#105#115#32#34#118#111+ + #108#117#109#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#54#52#59#10#32#32#80#97#110#32#105#115#32#34#112#97#110#34+ + #32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116#32#54+ + #53#59#10#32#32#76#111#99#97#108#32#105#115#32#34#108#111#99#97#108#34#32+ + #116#121#112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#54#54#59#10+ + #32#32#80#108#97#121#67#111#117#110#116#32#105#115#32#34#112#108#97#121#99+ + #111#117#110#116#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+ + #115#101#116#32#54#55#59#10#32#32#83#111#117#110#100#83#119#105#116#99#104+ + #32#105#115#32#34#115#111#117#110#100#115#119#105#116#99#104#34#32#116#121+ + #112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#54#56#59#10#125#10+ + #10#84#114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#84#82#73#71#71+ + #69#82#95#83#80#65#87#78#77#79#78#83#84#69#82#32#123#10#32#32#77#111#110#80+ + #111#115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116#121#112+ + #101#32#112#111#105#110#116#32#111#102#102#115#101#116#32#48#59#10#32#32#77+ + #111#110#84#121#112#101#32#105#115#32#34#116#121#112#101#34#32#116#121#112+ + #101#32#117#98#121#116#101#32#111#102#102#115#101#116#32#56#59#10#32#32#77+ + #111#110#72#101#97#108#116#104#32#105#115#32#34#104#101#97#108#116#104#34#32+ + #116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#49#50#59#10#32+ + #32#77#111#110#68#105#114#32#105#115#32#34#100#105#114#101#99#116#105#111+ + #110#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116+ + #32#49#54#32#101#110#117#109#32#68#105#114#84#121#112#101#59#10#32#32#77#111+ + #110#65#99#116#105#118#101#32#105#115#32#34#97#99#116#105#118#101#34#32#116+ + #121#112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#49#55#59#10#32+ + #32#77#111#110#67#111#117#110#116#32#105#115#32#34#99#111#117#110#116#34#32+ + #116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#50#48#59#10#32+ + #32#77#111#110#69#102#102#101#99#116#32#105#115#32#34#101#102#102#101#99#116+ + #34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116#32+ + #50#52#59#10#32#32#77#111#110#77#97#120#32#105#115#32#34#109#97#120#34#32+ + #116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#50+ + #54#59#10#32#32#77#111#110#68#101#108#97#121#32#105#115#32#34#100#101#108#97+ + #121#34#32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101+ + #116#32#50#56#59#10#32#32#77#111#110#66#101#104#97#118#32#105#115#32#34#98+ + #101#104#97#118#105#111#117#114#34#32#116#121#112#101#32#117#98#121#116#101+ + #32#111#102#102#115#101#116#32#51#48#59#10#125#10#10#84#114#105#103#103#101+ + #114#68#97#116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#83#80#65#87#78+ + #73#84#69#77#32#123#10#32#32#73#116#101#109#80#111#115#32#105#115#32#34#112+ + #111#115#105#116#105#111#110#34#32#116#121#112#101#32#112#111#105#110#116#32+ + #111#102#102#115#101#116#32#48#59#10#32#32#73#116#101#109#84#121#112#101#32+ + #105#115#32#34#116#121#112#101#34#32#116#121#112#101#32#117#98#121#116#101+ + #32#111#102#102#115#101#116#32#56#59#10#32#32#73#116#101#109#70#97#108#108+ + #115#32#105#115#32#34#103#114#97#118#105#116#121#34#32#116#121#112#101#32#98+ + #111#111#108#32#111#102#102#115#101#116#32#57#59#10#32#32#73#116#101#109#79+ + #110#108#121#68#77#32#105#115#32#34#100#109#111#110#108#121#34#32#116#121+ + #112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#49#48#59#10#32#32+ + #73#116#101#109#67#111#117#110#116#32#105#115#32#34#99#111#117#110#116#34#32+ + #116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#49#50#59#10#32+ + #32#73#116#101#109#69#102#102#101#99#116#32#105#115#32#34#101#102#102#101#99+ + #116#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116+ + #32#49#54#59#10#32#32#73#116#101#109#77#97#120#32#105#115#32#34#109#97#120+ + #34#32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116+ + #32#49#56#59#10#32#32#73#116#101#109#68#101#108#97#121#32#105#115#32#34#100+ + #101#108#97#121#34#32#116#121#112#101#32#117#115#104#111#114#116#32#111#102+ + #102#115#101#116#32#50#48#59#10#125#10#10#84#114#105#103#103#101#114#68#97+ + #116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#77#85#83#73#67#32#123#10+ + #32#32#77#117#115#105#99#78#97#109#101#32#105#115#32#34#110#97#109#101#34#32+ + #116#121#112#101#32#99#104#97#114#91#54#52#93#32#111#102#102#115#101#116#32+ + #48#59#10#32#32#77#117#115#105#99#65#99#116#105#111#110#32#105#115#32#34#97+ + #99#116#105#111#110#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102+ + #102#115#101#116#32#54#52#59#10#125#10#10#84#114#105#103#103#101#114#68#97+ + #116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#80#85#83#72#32#123#10#32+ + #32#80#117#115#104#65#110#103#108#101#32#105#115#32#34#97#110#103#108#101#34+ + #32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32+ + #48#59#10#32#32#80#117#115#104#70#111#114#99#101#32#105#115#32#34#102#111+ + #114#99#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115+ + #101#116#32#50#59#10#32#32#82#101#115#101#116#86#101#108#32#105#115#32#34+ + #114#101#115#101#116#118#101#108#111#99#105#116#121#34#32#116#121#112#101#32+ + #98#111#111#108#32#111#102#102#115#101#116#32#51#59#10#125#10#10#84#114#105+ + #103#103#101#114#68#97#116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#83+ + #67#79#82#69#32#123#10#32#32#83#99#111#114#101#65#99#116#105#111#110#32#105+ + #115#32#34#97#99#116#105#111#110#34#32#116#121#112#101#32#117#98#121#116#101+ + #32#111#102#102#115#101#116#32#48#59#10#32#32#83#99#111#114#101#67#111#117+ + #110#116#32#105#115#32#34#99#111#117#110#116#34#32#116#121#112#101#32#117#98+ + #121#116#101#32#111#102#102#115#101#116#32#49#59#10#32#32#83#99#111#114#101+ + #84#101#97#109#32#105#115#32#34#116#101#97#109#34#32#116#121#112#101#32#117+ + #98#121#116#101#32#111#102#102#115#101#116#32#50#59#10#32#32#83#99#111#114+ + #101#67#111#110#32#105#115#32#34#99#111#110#115#111#108#101#34#32#116#121+ + #112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#51#59#10#32#32#83+ + #99#111#114#101#77#115#103#32#105#115#32#34#109#101#115#115#97#103#101#34#32+ + #116#121#112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#52#59#10+ + #125#10#10#84#114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#84#82+ + #73#71#71#69#82#95#77#69#83#83#65#71#69#32#123#10#32#32#77#101#115#115#97+ + #103#101#75#105#110#100#32#105#115#32#34#107#105#110#100#34#32#116#121#112+ + #101#32#117#98#121#116#101#32#111#102#102#115#101#116#32#48#59#10#32#32#77+ + #101#115#115#97#103#101#83#101#110#100#84#111#32#105#115#32#34#115#101#110+ + #100#116#111#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115+ + #101#116#32#49#59#10#32#32#77#101#115#115#97#103#101#84#101#120#116#32#105+ + #115#32#34#116#101#120#116#34#32#116#121#112#101#32#99#104#97#114#91#49#48+ + #48#93#32#111#102#102#115#101#116#32#50#59#10#32#32#77#101#115#115#97#103+ + #101#84#105#109#101#32#105#115#32#34#116#105#109#101#34#32#116#121#112#101+ + #32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#49#48#50#59#10#125+ + #10#10#84#114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#84#82#73#71+ + #71#69#82#95#68#65#77#65#71#69#32#123#10#32#32#68#97#109#97#103#101#86#97+ + #108#117#101#32#105#115#32#34#97#109#111#117#110#116#34#32#116#121#112#101+ + #32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#48#59#10#32#32#68+ + #97#109#97#103#101#73#110#116#101#114#118#97#108#32#105#115#32#34#105#110+ + #116#101#114#118#97#108#34#32#116#121#112#101#32#117#115#104#111#114#116#32+ + #111#102#102#115#101#116#32#50#59#10#125#10#10#84#114#105#103#103#101#114#68+ + #97#116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#72#69#65#76#84#72#32+ + #123#10#32#32#72#101#97#108#86#97#108#117#101#32#105#115#32#34#97#109#111+ + #117#110#116#34#32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102+ + #115#101#116#32#48#59#10#32#32#72#101#97#108#73#110#116#101#114#118#97#108+ + #32#105#115#32#34#105#110#116#101#114#118#97#108#34#32#116#121#112#101#32+ + #117#115#104#111#114#116#32#111#102#102#115#101#116#32#50#59#10#32#32#72#101+ + #97#108#77#97#120#32#105#115#32#34#109#97#120#34#32#116#121#112#101#32#98+ + #111#111#108#32#111#102#102#115#101#116#32#52#59#10#32#32#72#101#97#108#83+ + #105#108#101#110#116#32#105#115#32#34#115#105#108#101#110#116#34#32#116#121+ + #112#101#32#98#111#111#108#32#111#102#102#115#101#116#32#53#59#10#125#10#10+ + #84#114#105#103#103#101#114#68#97#116#97#32#102#111#114#32#84#82#73#71#71#69+ + #82#95#83#72#79#84#32#123#10#32#32#83#104#111#116#80#111#115#32#105#115#32+ + #34#112#111#115#105#116#105#111#110#34#32#116#121#112#101#32#112#111#105#110+ + #116#32#111#102#102#115#101#116#32#48#59#10#32#32#83#104#111#116#84#121#112+ + #101#32#105#115#32#34#116#121#112#101#34#32#116#121#112#101#32#117#98#121+ + #116#101#32#111#102#102#115#101#116#32#56#32#101#110#117#109#32#84#114#105+ + #103#103#101#114#83#104#111#116#59#10#32#32#83#104#111#116#84#97#114#103#101+ + #116#32#105#115#32#34#116#97#114#103#101#116#34#32#116#121#112#101#32#117#98+ + #121#116#101#32#111#102#102#115#101#116#32#57#32#101#110#117#109#32#84#114+ + #105#103#103#101#114#83#104#111#116#84#97#114#103#101#116#59#10#32#32#83#104+ + #111#116#83#111#117#110#100#32#105#115#32#34#115#105#108#101#110#116#34#32+ + #116#121#112#101#32#110#101#103#98#111#111#108#32#111#102#102#115#101#116#32+ + #49#48#59#32#47#47#32#110#101#103#98#111#111#108#33#10#32#32#83#104#111#116+ + #65#105#109#32#105#115#32#34#97#105#109#34#32#116#121#112#101#32#98#121#116+ + #101#32#111#102#102#115#101#116#32#49#49#59#10#32#32#83#104#111#116#80#97+ + #110#101#108#73#68#32#105#115#32#34#112#97#110#101#108#105#100#34#32#116#121+ + #112#101#32#105#110#116#32#111#102#102#115#101#116#32#49#50#59#10#32#32#83+ + #104#111#116#73#110#116#83#105#103#104#116#32#105#115#32#34#115#105#103#104+ + #116#34#32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101+ + #116#32#49#54#59#10#32#32#83#104#111#116#65#110#103#108#101#32#105#115#32#34+ + #97#110#103#108#101#34#32#116#121#112#101#32#117#115#104#111#114#116#32#111+ + #102#102#115#101#116#32#49#56#59#10#32#32#83#104#111#116#87#97#105#116#32+ + #105#115#32#34#119#97#105#116#34#32#116#121#112#101#32#117#115#104#111#114+ + #116#32#111#102#102#115#101#116#32#50#48#59#10#32#32#83#104#111#116#65#99#99+ + #117#114#97#99#121#32#105#115#32#34#97#99#99#117#114#97#99#121#34#32#116#121+ + #112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32#50#50#59+ + #10#32#32#83#104#111#116#65#109#109#111#32#105#115#32#34#97#109#109#111#34+ + #32#116#121#112#101#32#117#115#104#111#114#116#32#111#102#102#115#101#116#32+ + #50#52#59#10#32#32#83#104#111#116#73#110#116#82#101#108#111#97#100#32#105+ + #115#32#34#114#101#108#111#97#100#34#32#116#121#112#101#32#117#115#104#111+ + #114#116#32#111#102#102#115#101#116#32#50#54#59#10#125#10#10#84#114#105#103+ + #103#101#114#68#97#116#97#32#102#111#114#32#84#82#73#71#71#69#82#95#69#70#70+ + #69#67#84#32#123#10#32#32#70#88#67#111#117#110#116#32#105#115#32#34#99#111+ + #117#110#116#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115+ + #101#116#32#48#59#10#32#32#70#88#84#121#112#101#32#105#115#32#34#116#121#112+ + #101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116+ + #32#49#59#10#32#32#70#88#83#117#98#84#121#112#101#32#105#115#32#34#115#117+ + #98#116#121#112#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102+ + #102#115#101#116#32#50#59#10#32#32#70#88#67#111#108#111#114#82#32#105#115#32+ + #34#99#111#108#111#114#114#34#32#116#121#112#101#32#117#98#121#116#101#32+ + #111#102#102#115#101#116#32#51#59#10#32#32#70#88#67#111#108#111#114#71#32+ + #105#115#32#34#99#111#108#111#114#103#34#32#116#121#112#101#32#117#98#121+ + #116#101#32#111#102#102#115#101#116#32#52#59#10#32#32#70#88#67#111#108#111+ + #114#66#32#105#115#32#34#99#111#108#111#114#98#34#32#116#121#112#101#32#117+ + #98#121#116#101#32#111#102#102#115#101#116#32#53#59#10#32#32#70#88#80#111+ + #115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116#121#112#101+ + #32#117#98#121#116#101#32#111#102#102#115#101#116#32#54#59#10#32#32#70#88#87+ + #97#105#116#32#105#115#32#34#119#97#105#116#34#32#116#121#112#101#32#117#115+ + #104#111#114#116#32#111#102#102#115#101#116#32#56#59#10#32#32#70#88#86#101+ + #108#88#32#105#115#32#34#118#101#108#120#34#32#116#121#112#101#32#98#121#116+ + #101#32#111#102#102#115#101#116#32#49#48#59#10#32#32#70#88#86#101#108#89#32+ + #105#115#32#34#118#101#108#121#34#32#116#121#112#101#32#98#121#116#101#32+ + #111#102#102#115#101#116#32#49#49#59#10#32#32#70#88#83#112#114#101#97#100#76+ + #32#105#115#32#34#115#112#114#101#97#100#108#34#32#116#121#112#101#32#117#98+ + #121#116#101#32#111#102#102#115#101#116#32#49#50#59#10#32#32#70#88#83#112+ + #114#101#97#100#82#32#105#115#32#34#115#112#114#101#97#100#114#34#32#116#121+ + #112#101#32#117#98#121#116#101#32#111#102#102#115#101#116#32#49#51#59#10#32+ + #32#70#88#83#112#114#101#97#100#85#32#105#115#32#34#115#112#114#101#97#100+ + #117#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102#115#101#116+ + #32#49#52#59#10#32#32#70#88#83#112#114#101#97#100#68#32#105#115#32#34#115+ + #112#114#101#97#100#100#34#32#116#121#112#101#32#117#98#121#116#101#32#111+ + #102#102#115#101#116#32#49#53#59#10#125#10 +; \ No newline at end of file diff --git a/src/shared/mapdef.txt b/src/shared/mapdef.txt index d93b48d..db3a64f 100644 --- a/src/shared/mapdef.txt +++ b/src/shared/mapdef.txt @@ -486,7 +486,7 @@ TriggerData for TRIGGER_SHOT { ShotType is "type" type ubyte offset 8 enum TriggerShot; ShotTarget is "target" type ubyte offset 9 enum TriggerShotTarget; ShotSound is "silent" type negbool offset 10; // negbool! - ShotAllMap is "allmap" type bool offset 11; + ShotAim is "aim" type byte offset 11; ShotPanelID is "panelid" type int offset 12; ShotIntSight is "sight" type ushort offset 16; ShotAngle is "angle" type ushort offset 18; diff --git a/src/shared/mapstructio.inc b/src/shared/mapstructio.inc deleted file mode 100644 index 68b46ac..0000000 --- a/src/shared/mapstructio.inc +++ /dev/null @@ -1,685 +0,0 @@ -procedure getBytesAt (var dest; const buf; ofs, len: Integer); -begin - Move((PChar(@buf)+ofs)^, dest, len); -end; - -procedure getWordAt (var dest; const buf; ofs: Integer); -type PWord = ^Word; PByte = ^Byte; -var - p: PByte; - d: PWord; -begin - p := PByte(@buf); Inc(p, ofs); - d := PWord(@dest); - d^ := p^; - Inc(p); - d^ := (d^) or ((p^) shl 8); -end; - -procedure getIntAt (var dest; const buf; ofs: Integer); -type PInt = ^LongWord; PByte = ^Byte; -var - p: PByte; - d: PInt; -begin - p := PByte(@buf); Inc(p, ofs); - d := PInt(@dest); - d^ := p^; - Inc(p); - d^ := (d^) or ((p^) shl 8); - Inc(p); - d^ := (d^) or ((p^) shl 16); - Inc(p); - d^ := (d^) or ((p^) shl 24); -end; - -procedure putBytesAt (var buf; ofs: Integer; const src; len: Integer); -begin - Move(src, (PChar(@buf)+ofs)^, len); -end; - -procedure putWordAt (var buf; ofs: Integer; const src); -type PWord = ^Word; PByte = ^Byte; -var - p: PByte; - d: PWord; -begin - p := PByte(PChar(@buf)+ofs); - d := PWord(@src); - p^ := (d^) and $ff; - Inc(p); - p^ := ((d^) shr 8) and $ff; -end; - -procedure putIntAt (var buf; ofs: Integer; const src); -type PInt = ^LongWord; PByte = ^Byte; -var - p: PByte; - d: PInt; -begin - p := PByte(PChar(@buf)+ofs); - d := PInt(@src); - p^ := (d^) and $ff; - Inc(p); - p^ := ((d^) shr 8) and $ff; - Inc(p); - p^ := ((d^) shr 16) and $ff; - Inc(p); - p^ := ((d^) shr 24) and $ff; -end; - -procedure mb_Read_TriggerData (var tr: TTriggerData; ttype: Integer; const buf; bufsize: Integer); - procedure xreadExit (); - begin - getBytesAt(tr.MapName, buf, 0, 16); - end; - - procedure xreadTeleport (); - begin - getIntAt(tr.TargetPoint.x, buf, 0); - getIntAt(tr.TargetPoint.y, buf, 4); - getBytesAt(tr.d2d_teleport, buf, 8, 1); - getBytesAt(tr.silent_teleport, buf, 9, 1); - getBytesAt(tr.TlpDir, buf, 10, 1); - end; - - procedure xreadOpendoor (); - begin - getIntAt(tr.PanelID, buf, 0); - getBytesAt(tr.NoSound, buf, 4, 1); - getBytesAt(tr.d2d_doors, buf, 5, 1); - end; - - procedure xreadPress (); - begin - getIntAt(tr.tX, buf, 0); - getIntAt(tr.tY, buf, 4); - getWordAt(tr.tWidth, buf, 8); - getWordAt(tr.tHeight, buf, 10); - getWordAt(tr.Wait, buf, 12); - getWordAt(tr.Count, buf, 14); - getIntAt(tr.MonsterID, buf, 16); - getBytesAt(tr.ExtRandom, buf, 20, 1); - end; - - procedure xreadSecret (); - begin - end; - - procedure xreadTexture (); - begin - getBytesAt(tr.ActivateOnce, buf, 0, 1); - getBytesAt(tr.AnimOnce, buf, 1, 1); - end; - - procedure xreadSound (); - begin - getBytesAt(tr.SoundName, buf, 0, 64); - getBytesAt(tr.Volume, buf, 64, 1); - getBytesAt(tr.Pan, buf, 65, 1); - getBytesAt(tr.Local, buf, 66, 1); - getBytesAt(tr.PlayCount, buf, 67, 1); - getBytesAt(tr.SoundSwitch, buf, 68, 1); - end; - - procedure xreadSpawnmonster (); - begin - getIntAt(tr.MonPos.x, buf, 0); - getIntAt(tr.MonPos.y, buf, 4); - getBytesAt(tr.MonType, buf, 8, 1); - getIntAt(tr.MonHealth, buf, 12); - getBytesAt(tr.MonDir, buf, 16, 1); - getBytesAt(tr.MonActive, buf, 17, 1); - getIntAt(tr.MonCount, buf, 20); - getBytesAt(tr.MonEffect, buf, 24, 1); - getWordAt(tr.MonMax, buf, 26); - getWordAt(tr.MonDelay, buf, 28); - getBytesAt(tr.MonBehav, buf, 30, 1); - end; - - procedure xreadSpawnitem (); - begin - getIntAt(tr.ItemPos.x, buf, 0); - getIntAt(tr.ItemPos.y, buf, 4); - getBytesAt(tr.ItemType, buf, 8, 1); - getBytesAt(tr.ItemFalls, buf, 9, 1); - getBytesAt(tr.ItemOnlyDM, buf, 10, 1); - getIntAt(tr.ItemCount, buf, 12); - getBytesAt(tr.ItemEffect, buf, 16, 1); - getWordAt(tr.ItemMax, buf, 18); - getWordAt(tr.ItemDelay, buf, 20); - end; - - procedure xreadMusic (); - begin - getBytesAt(tr.MusicName, buf, 0, 64); - getBytesAt(tr.MusicAction, buf, 64, 1); - end; - - procedure xreadPush (); - begin - getWordAt(tr.PushAngle, buf, 0); - getBytesAt(tr.PushForce, buf, 2, 1); - getBytesAt(tr.ResetVel, buf, 3, 1); - end; - - procedure xreadScore (); - begin - getBytesAt(tr.ScoreAction, buf, 0, 1); - getBytesAt(tr.ScoreCount, buf, 1, 1); - getBytesAt(tr.ScoreTeam, buf, 2, 1); - getBytesAt(tr.ScoreCon, buf, 3, 1); - getBytesAt(tr.ScoreMsg, buf, 4, 1); - end; - - procedure xreadMessage (); - begin - getBytesAt(tr.MessageKind, buf, 0, 1); - getBytesAt(tr.MessageSendTo, buf, 1, 1); - getBytesAt(tr.MessageText, buf, 2, 100); - getWordAt(tr.MessageTime, buf, 102); - end; - - procedure xreadDamage (); - begin - getWordAt(tr.DamageValue, buf, 0); - getWordAt(tr.DamageInterval, buf, 2); - end; - - procedure xreadHealth (); - begin - getWordAt(tr.HealValue, buf, 0); - getWordAt(tr.HealInterval, buf, 2); - getBytesAt(tr.HealMax, buf, 4, 1); - getBytesAt(tr.HealSilent, buf, 5, 1); - end; - - procedure xreadShot (); - begin - getIntAt(tr.ShotPos.x, buf, 0); - getIntAt(tr.ShotPos.y, buf, 4); - getBytesAt(tr.ShotType, buf, 8, 1); - getBytesAt(tr.ShotTarget, buf, 9, 1); - getBytesAt(tr.ShotSound, buf, 10, 1); - getBytesAt(tr.ShotAim, buf, 11, 1); - getIntAt(tr.ShotPanelID, buf, 12); - getWordAt(tr.ShotIntSight, buf, 16); - getWordAt(tr.ShotAngle, buf, 18); - getWordAt(tr.ShotWait, buf, 20); - getWordAt(tr.ShotAccuracy, buf, 22); - getWordAt(tr.ShotAmmo, buf, 24); - getWordAt(tr.ShotIntReload, buf, 26); - end; - - procedure xreadEffect (); - begin - getBytesAt(tr.FXCount, buf, 0, 1); - getBytesAt(tr.FXType, buf, 1, 1); - getBytesAt(tr.FXSubType, buf, 2, 1); - getBytesAt(tr.FXColorR, buf, 3, 1); - getBytesAt(tr.FXColorG, buf, 4, 1); - getBytesAt(tr.FXColorB, buf, 5, 1); - getBytesAt(tr.FXPos, buf, 6, 1); - getWordAt(tr.FXWait, buf, 8); - getBytesAt(tr.FXVelX, buf, 10, 1); - getBytesAt(tr.FXVelY, buf, 11, 1); - getBytesAt(tr.FXSpreadL, buf, 12, 1); - getBytesAt(tr.FXSpreadR, buf, 13, 1); - getBytesAt(tr.FXSpreadU, buf, 14, 1); - getBytesAt(tr.FXSpreadD, buf, 15, 1); - end; - - procedure xreadScript (); - begin - getBytesAt(tr.SCRProc, buf, 0, 64); - getIntAt(tr.SCRArg, buf, 64); - end; - -begin - if (bufsize < 104) then raise Exception.Create('invalid buffer size in mb_Read_TriggerData'); - if (ttype = TRIGGER_EXIT) then begin xreadExit(); exit; end; - if (ttype = TRIGGER_TELEPORT) then begin xreadTeleport(); exit; end; - if (ttype = TRIGGER_OPENDOOR) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_CLOSEDOOR) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_DOOR) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_DOOR5) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_CLOSETRAP) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_TRAP) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_LIFTUP) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_LIFTDOWN) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_LIFT) then begin xreadOpendoor(); exit; end; - if (ttype = TRIGGER_PRESS) then begin xreadPress(); exit; end; - if (ttype = TRIGGER_ON) then begin xreadPress(); exit; end; - if (ttype = TRIGGER_OFF) then begin xreadPress(); exit; end; - if (ttype = TRIGGER_ONOFF) then begin xreadPress(); exit; end; - if (ttype = TRIGGER_SECRET) then begin xreadSecret(); exit; end; - if (ttype = TRIGGER_TEXTURE) then begin xreadTexture(); exit; end; - if (ttype = TRIGGER_SOUND) then begin xreadSound(); exit; end; - if (ttype = TRIGGER_SPAWNMONSTER) then begin xreadSpawnmonster(); exit; end; - if (ttype = TRIGGER_SPAWNITEM) then begin xreadSpawnitem(); exit; end; - if (ttype = TRIGGER_MUSIC) then begin xreadMusic(); exit; end; - if (ttype = TRIGGER_PUSH) then begin xreadPush(); exit; end; - if (ttype = TRIGGER_SCORE) then begin xreadScore(); exit; end; - if (ttype = TRIGGER_MESSAGE) then begin xreadMessage(); exit; end; - if (ttype = TRIGGER_DAMAGE) then begin xreadDamage(); exit; end; - if (ttype = TRIGGER_HEALTH) then begin xreadHealth(); exit; end; - if (ttype = TRIGGER_SHOT) then begin xreadShot(); exit; end; - if (ttype = TRIGGER_EFFECT) then begin xreadEffect(); exit; end; - if (ttype = TRIGGER_SCRIPT) then begin xreadScript(); exit; end; - raise Exception.Create('invalid trigger type in mb_Read_TriggerData'); -end; - - -procedure mb_Read_TMapHeaderRec_1 (var tr: TMapHeaderRec_1; const buf; bufsize: Integer); - procedure xreadTmapheaderrec_1 (); - begin - getBytesAt(tr.MapName, buf, 0, 32); - getBytesAt(tr.MapAuthor, buf, 32, 32); - getBytesAt(tr.MapDescription, buf, 64, 256); - getBytesAt(tr.MusicName, buf, 320, 64); - getBytesAt(tr.SkyName, buf, 384, 64); - getWordAt(tr.Width, buf, 448); - getWordAt(tr.Height, buf, 450); - end; - -begin - if (bufsize < 452) then raise Exception.Create('invalid buffer size in readTMapHeaderRec_1'); - xreadTmapheaderrec_1(); -end; - -procedure mb_Read_TTextureRec_1 (var tr: TTextureRec_1; const buf; bufsize: Integer); - procedure xreadTtexturerec_1 (); - begin - getBytesAt(tr.Resource, buf, 0, 64); - getBytesAt(tr.Anim, buf, 64, 1); - end; - -begin - if (bufsize < 65) then raise Exception.Create('invalid buffer size in readTTextureRec_1'); - xreadTtexturerec_1(); -end; - -procedure mb_Read_TPanelRec_1 (var tr: TPanelRec_1; const buf; bufsize: Integer); - procedure xreadTpanelrec_1 (); - begin - getIntAt(tr.X, buf, 0); - getIntAt(tr.Y, buf, 4); - getWordAt(tr.Width, buf, 8); - getWordAt(tr.Height, buf, 10); - getWordAt(tr.TextureNum, buf, 12); - getWordAt(tr.PanelType, buf, 14); - getBytesAt(tr.Alpha, buf, 16, 1); - getBytesAt(tr.Flags, buf, 17, 1); - end; - -begin - if (bufsize < 18) then raise Exception.Create('invalid buffer size in readTPanelRec_1'); - xreadTpanelrec_1(); -end; - -procedure mb_Read_TItemRec_1 (var tr: TItemRec_1; const buf; bufsize: Integer); - procedure xreadTitemrec_1 (); - begin - getIntAt(tr.X, buf, 0); - getIntAt(tr.Y, buf, 4); - getBytesAt(tr.ItemType, buf, 8, 1); - getBytesAt(tr.Options, buf, 9, 1); - end; - -begin - if (bufsize < 10) then raise Exception.Create('invalid buffer size in readTItemRec_1'); - xreadTitemrec_1(); -end; - -procedure mb_Read_TMonsterRec_1 (var tr: TMonsterRec_1; const buf; bufsize: Integer); - procedure xreadTmonsterrec_1 (); - begin - getIntAt(tr.X, buf, 0); - getIntAt(tr.Y, buf, 4); - getBytesAt(tr.MonsterType, buf, 8, 1); - getBytesAt(tr.Direction, buf, 9, 1); - end; - -begin - if (bufsize < 10) then raise Exception.Create('invalid buffer size in readTMonsterRec_1'); - xreadTmonsterrec_1(); -end; - -procedure mb_Read_TAreaRec_1 (var tr: TAreaRec_1; const buf; bufsize: Integer); - procedure xreadTarearec_1 (); - begin - getIntAt(tr.X, buf, 0); - getIntAt(tr.Y, buf, 4); - getBytesAt(tr.AreaType, buf, 8, 1); - getBytesAt(tr.Direction, buf, 9, 1); - end; - -begin - if (bufsize < 10) then raise Exception.Create('invalid buffer size in readTAreaRec_1'); - xreadTarearec_1(); -end; - -procedure mb_Read_TTriggerRec_1 (var tr: TTriggerRec_1; const buf; bufsize: Integer); - procedure xreadTtriggerrec_1 (); - begin - getIntAt(tr.X, buf, 0); - getIntAt(tr.Y, buf, 4); - getWordAt(tr.Width, buf, 8); - getWordAt(tr.Height, buf, 10); - getBytesAt(tr.Enabled, buf, 12, 1); - getIntAt(tr.TexturePanel, buf, 13); - getBytesAt(tr.TriggerType, buf, 17, 1); - getBytesAt(tr.ActivateType, buf, 18, 1); - getBytesAt(tr.Keys, buf, 19, 1); - getBytesAt(tr.DATA, buf, 20, 128); - end; - -begin - if (bufsize < 148) then raise Exception.Create('invalid buffer size in readTTriggerRec_1'); - xreadTtriggerrec_1(); -end; - -procedure mb_Write_TriggerData (var buf; bufsize: Integer; ttype: Integer; var tr: TTriggerData); - procedure xwriteExit (); - begin - putBytesAt(buf, 0, tr.MapName, 16); - end; - - procedure xwriteTeleport (); - begin - putIntAt(buf, 0, tr.TargetPoint.x); - putIntAt(buf, 4, tr.TargetPoint.y); - putBytesAt(buf, 8, tr.d2d_teleport, 1); - putBytesAt(buf, 9, tr.silent_teleport, 1); - putBytesAt(buf, 10, tr.TlpDir, 1); - end; - - procedure xwriteOpendoor (); - begin - putIntAt(buf, 0, tr.PanelID); - putBytesAt(buf, 4, tr.NoSound, 1); - putBytesAt(buf, 5, tr.d2d_doors, 1); - end; - - procedure xwritePress (); - begin - putIntAt(buf, 0, tr.tX); - putIntAt(buf, 4, tr.tY); - putWordAt(buf, 8, tr.tWidth); - putWordAt(buf, 10, tr.tHeight); - putWordAt(buf, 12, tr.Wait); - putWordAt(buf, 14, tr.Count); - putIntAt(buf, 16, tr.MonsterID); - putBytesAt(buf, 20, tr.ExtRandom, 1); - end; - - procedure xwriteSecret (); - begin - end; - - procedure xwriteTexture (); - begin - putBytesAt(buf, 0, tr.ActivateOnce, 1); - putBytesAt(buf, 1, tr.AnimOnce, 1); - end; - - procedure xwriteSound (); - begin - putBytesAt(buf, 0, tr.SoundName, 64); - putBytesAt(buf, 64, tr.Volume, 1); - putBytesAt(buf, 65, tr.Pan, 1); - putBytesAt(buf, 66, tr.Local, 1); - putBytesAt(buf, 67, tr.PlayCount, 1); - putBytesAt(buf, 68, tr.SoundSwitch, 1); - end; - - procedure xwriteSpawnmonster (); - begin - putIntAt(buf, 0, tr.MonPos.x); - putIntAt(buf, 4, tr.MonPos.y); - putBytesAt(buf, 8, tr.MonType, 1); - putIntAt(buf, 12, tr.MonHealth); - putBytesAt(buf, 16, tr.MonDir, 1); - putBytesAt(buf, 17, tr.MonActive, 1); - putIntAt(buf, 20, tr.MonCount); - putBytesAt(buf, 24, tr.MonEffect, 1); - putWordAt(buf, 26, tr.MonMax); - putWordAt(buf, 28, tr.MonDelay); - putBytesAt(buf, 30, tr.MonBehav, 1); - end; - - procedure xwriteSpawnitem (); - begin - putIntAt(buf, 0, tr.ItemPos.x); - putIntAt(buf, 4, tr.ItemPos.y); - putBytesAt(buf, 8, tr.ItemType, 1); - putBytesAt(buf, 9, tr.ItemFalls, 1); - putBytesAt(buf, 10, tr.ItemOnlyDM, 1); - putIntAt(buf, 12, tr.ItemCount); - putBytesAt(buf, 16, tr.ItemEffect, 1); - putWordAt(buf, 18, tr.ItemMax); - putWordAt(buf, 20, tr.ItemDelay); - end; - - procedure xwriteMusic (); - begin - putBytesAt(buf, 0, tr.MusicName, 64); - putBytesAt(buf, 64, tr.MusicAction, 1); - end; - - procedure xwritePush (); - begin - putWordAt(buf, 0, tr.PushAngle); - putBytesAt(buf, 2, tr.PushForce, 1); - putBytesAt(buf, 3, tr.ResetVel, 1); - end; - - procedure xwriteScore (); - begin - putBytesAt(buf, 0, tr.ScoreAction, 1); - putBytesAt(buf, 1, tr.ScoreCount, 1); - putBytesAt(buf, 2, tr.ScoreTeam, 1); - putBytesAt(buf, 3, tr.ScoreCon, 1); - putBytesAt(buf, 4, tr.ScoreMsg, 1); - end; - - procedure xwriteMessage (); - begin - putBytesAt(buf, 0, tr.MessageKind, 1); - putBytesAt(buf, 1, tr.MessageSendTo, 1); - putBytesAt(buf, 2, tr.MessageText, 100); - putWordAt(buf, 102, tr.MessageTime); - end; - - procedure xwriteDamage (); - begin - putWordAt(buf, 0, tr.DamageValue); - putWordAt(buf, 2, tr.DamageInterval); - end; - - procedure xwriteHealth (); - begin - putWordAt(buf, 0, tr.HealValue); - putWordAt(buf, 2, tr.HealInterval); - putBytesAt(buf, 4, tr.HealMax, 1); - putBytesAt(buf, 5, tr.HealSilent, 1); - end; - - procedure xwriteShot (); - begin - putIntAt(buf, 0, tr.ShotPos.x); - putIntAt(buf, 4, tr.ShotPos.y); - putBytesAt(buf, 8, tr.ShotType, 1); - putBytesAt(buf, 9, tr.ShotTarget, 1); - putBytesAt(buf, 10, tr.ShotSound, 1); - putBytesAt(buf, 11, tr.ShotAim, 1); - putIntAt(buf, 12, tr.ShotPanelID); - putWordAt(buf, 16, tr.ShotIntSight); - putWordAt(buf, 18, tr.ShotAngle); - putWordAt(buf, 20, tr.ShotWait); - putWordAt(buf, 22, tr.ShotAccuracy); - putWordAt(buf, 24, tr.ShotAmmo); - putWordAt(buf, 26, tr.ShotIntReload); - end; - - procedure xwriteEffect (); - begin - putBytesAt(buf, 0, tr.FXCount, 1); - putBytesAt(buf, 1, tr.FXType, 1); - putBytesAt(buf, 2, tr.FXSubType, 1); - putBytesAt(buf, 3, tr.FXColorR, 1); - putBytesAt(buf, 4, tr.FXColorG, 1); - putBytesAt(buf, 5, tr.FXColorB, 1); - putBytesAt(buf, 6, tr.FXPos, 1); - putWordAt(buf, 8, tr.FXWait); - putBytesAt(buf, 10, tr.FXVelX, 1); - putBytesAt(buf, 11, tr.FXVelY, 1); - putBytesAt(buf, 12, tr.FXSpreadL, 1); - putBytesAt(buf, 13, tr.FXSpreadR, 1); - putBytesAt(buf, 14, tr.FXSpreadU, 1); - putBytesAt(buf, 15, tr.FXSpreadD, 1); - end; - -begin - if (bufsize < 104) then raise Exception.Create('invalid buffer size in mb_Write_TriggerData'); - if (ttype = TRIGGER_EXIT) then begin xwriteExit(); exit; end; - if (ttype = TRIGGER_TELEPORT) then begin xwriteTeleport(); exit; end; - if (ttype = TRIGGER_OPENDOOR) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_CLOSEDOOR) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_DOOR) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_DOOR5) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_CLOSETRAP) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_TRAP) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_LIFTUP) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_LIFTDOWN) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_LIFT) then begin xwriteOpendoor(); exit; end; - if (ttype = TRIGGER_PRESS) then begin xwritePress(); exit; end; - if (ttype = TRIGGER_ON) then begin xwritePress(); exit; end; - if (ttype = TRIGGER_OFF) then begin xwritePress(); exit; end; - if (ttype = TRIGGER_ONOFF) then begin xwritePress(); exit; end; - if (ttype = TRIGGER_SECRET) then begin xwriteSecret(); exit; end; - if (ttype = TRIGGER_TEXTURE) then begin xwriteTexture(); exit; end; - if (ttype = TRIGGER_SOUND) then begin xwriteSound(); exit; end; - if (ttype = TRIGGER_SPAWNMONSTER) then begin xwriteSpawnmonster(); exit; end; - if (ttype = TRIGGER_SPAWNITEM) then begin xwriteSpawnitem(); exit; end; - if (ttype = TRIGGER_MUSIC) then begin xwriteMusic(); exit; end; - if (ttype = TRIGGER_PUSH) then begin xwritePush(); exit; end; - if (ttype = TRIGGER_SCORE) then begin xwriteScore(); exit; end; - if (ttype = TRIGGER_MESSAGE) then begin xwriteMessage(); exit; end; - if (ttype = TRIGGER_DAMAGE) then begin xwriteDamage(); exit; end; - if (ttype = TRIGGER_HEALTH) then begin xwriteHealth(); exit; end; - if (ttype = TRIGGER_SHOT) then begin xwriteShot(); exit; end; - if (ttype = TRIGGER_EFFECT) then begin xwriteEffect(); exit; end; - raise Exception.Create('invalid trigger type in mb_Write_TriggerData'); -end; - - -procedure mb_Write_TMapHeaderRec_1 (var buf; bufsize: Integer; var tr: TMapHeaderRec_1); - procedure xwriteTmapheaderrec_1 (); - begin - putBytesAt(buf, 0, tr.MapName, 32); - putBytesAt(buf, 32, tr.MapAuthor, 32); - putBytesAt(buf, 64, tr.MapDescription, 256); - putBytesAt(buf, 320, tr.MusicName, 64); - putBytesAt(buf, 384, tr.SkyName, 64); - putWordAt(buf, 448, tr.Width); - putWordAt(buf, 450, tr.Height); - end; - -begin - if (bufsize < 452) then raise Exception.Create('invalid buffer size in writeTMapHeaderRec_1'); - xwriteTmapheaderrec_1(); -end; - -procedure mb_Write_TTextureRec_1 (var buf; bufsize: Integer; var tr: TTextureRec_1); - procedure xwriteTtexturerec_1 (); - begin - putBytesAt(buf, 0, tr.Resource, 64); - putBytesAt(buf, 64, tr.Anim, 1); - end; - -begin - if (bufsize < 65) then raise Exception.Create('invalid buffer size in writeTTextureRec_1'); - xwriteTtexturerec_1(); -end; - -procedure mb_Write_TPanelRec_1 (var buf; bufsize: Integer; var tr: TPanelRec_1); - procedure xwriteTpanelrec_1 (); - begin - putIntAt(buf, 0, tr.X); - putIntAt(buf, 4, tr.Y); - putWordAt(buf, 8, tr.Width); - putWordAt(buf, 10, tr.Height); - putWordAt(buf, 12, tr.TextureNum); - putWordAt(buf, 14, tr.PanelType); - putBytesAt(buf, 16, tr.Alpha, 1); - putBytesAt(buf, 17, tr.Flags, 1); - end; - -begin - if (bufsize < 18) then raise Exception.Create('invalid buffer size in writeTPanelRec_1'); - xwriteTpanelrec_1(); -end; - -procedure mb_Write_TItemRec_1 (var buf; bufsize: Integer; var tr: TItemRec_1); - procedure xwriteTitemrec_1 (); - begin - putIntAt(buf, 0, tr.X); - putIntAt(buf, 4, tr.Y); - putBytesAt(buf, 8, tr.ItemType, 1); - putBytesAt(buf, 9, tr.Options, 1); - end; - -begin - if (bufsize < 10) then raise Exception.Create('invalid buffer size in writeTItemRec_1'); - xwriteTitemrec_1(); -end; - -procedure mb_Write_TMonsterRec_1 (var buf; bufsize: Integer; var tr: TMonsterRec_1); - procedure xwriteTmonsterrec_1 (); - begin - putIntAt(buf, 0, tr.X); - putIntAt(buf, 4, tr.Y); - putBytesAt(buf, 8, tr.MonsterType, 1); - putBytesAt(buf, 9, tr.Direction, 1); - end; - -begin - if (bufsize < 10) then raise Exception.Create('invalid buffer size in writeTMonsterRec_1'); - xwriteTmonsterrec_1(); -end; - -procedure mb_Write_TAreaRec_1 (var buf; bufsize: Integer; var tr: TAreaRec_1); - procedure xwriteTarearec_1 (); - begin - putIntAt(buf, 0, tr.X); - putIntAt(buf, 4, tr.Y); - putBytesAt(buf, 8, tr.AreaType, 1); - putBytesAt(buf, 9, tr.Direction, 1); - end; - -begin - if (bufsize < 10) then raise Exception.Create('invalid buffer size in writeTAreaRec_1'); - xwriteTarearec_1(); -end; - -procedure mb_Write_TTriggerRec_1 (var buf; bufsize: Integer; var tr: TTriggerRec_1); - procedure xwriteTtriggerrec_1 (); - begin - putIntAt(buf, 0, tr.X); - putIntAt(buf, 4, tr.Y); - putWordAt(buf, 8, tr.Width); - putWordAt(buf, 10, tr.Height); - putBytesAt(buf, 12, tr.Enabled, 1); - putIntAt(buf, 13, tr.TexturePanel); - putBytesAt(buf, 17, tr.TriggerType, 1); - putBytesAt(buf, 18, tr.ActivateType, 1); - putBytesAt(buf, 19, tr.Keys, 1); - putBytesAt(buf, 20, tr.DATA, 128); - end; - -begin - if (bufsize < 148) then raise Exception.Create('invalid buffer size in writeTTriggerRec_1'); - xwriteTtriggerrec_1(); -end; - diff --git a/src/shared/mapstructsizes.inc b/src/shared/mapstructsizes.inc deleted file mode 100644 index e793c06..0000000 --- a/src/shared/mapstructsizes.inc +++ /dev/null @@ -1,25 +0,0 @@ -const - SizeOf_TMapHeaderRec_1 = 452; - SizeOf_TTextureRec_1 = 65; - SizeOf_TPanelRec_1 = 18; - SizeOf_TItemRec_1 = 10; - SizeOf_TMonsterRec_1 = 10; - SizeOf_TAreaRec_1 = 10; - SizeOf_TTriggerRec_1 = 148; - -procedure mb_Read_TriggerData (var tr: TTriggerData; ttype: Integer; const buf; bufsize: Integer); -procedure mb_Write_TriggerData (var buf; bufsize: Integer; ttype: Integer; var tr: TTriggerData); -procedure mb_Read_TMapHeaderRec_1 (var tr: TMapHeaderRec_1; const buf; bufsize: Integer); -procedure mb_Write_TMapHeaderRec_1 (var buf; bufsize: Integer; var tr: TMapHeaderRec_1); -procedure mb_Read_TTextureRec_1 (var tr: TTextureRec_1; const buf; bufsize: Integer); -procedure mb_Write_TTextureRec_1 (var buf; bufsize: Integer; var tr: TTextureRec_1); -procedure mb_Read_TPanelRec_1 (var tr: TPanelRec_1; const buf; bufsize: Integer); -procedure mb_Write_TPanelRec_1 (var buf; bufsize: Integer; var tr: TPanelRec_1); -procedure mb_Read_TItemRec_1 (var tr: TItemRec_1; const buf; bufsize: Integer); -procedure mb_Write_TItemRec_1 (var buf; bufsize: Integer; var tr: TItemRec_1); -procedure mb_Read_TMonsterRec_1 (var tr: TMonsterRec_1; const buf; bufsize: Integer); -procedure mb_Write_TMonsterRec_1 (var buf; bufsize: Integer; var tr: TMonsterRec_1); -procedure mb_Read_TAreaRec_1 (var tr: TAreaRec_1; const buf; bufsize: Integer); -procedure mb_Write_TAreaRec_1 (var buf; bufsize: Integer; var tr: TAreaRec_1); -procedure mb_Read_TTriggerRec_1 (var tr: TTriggerRec_1; const buf; bufsize: Integer); -procedure mb_Write_TTriggerRec_1 (var buf; bufsize: Integer; var tr: TTriggerRec_1); diff --git a/src/shared/wadreader.pas b/src/shared/wadreader.pas index 3830af2..8207f60 100644 --- a/src/shared/wadreader.pas +++ b/src/shared/wadreader.pas @@ -76,7 +76,7 @@ var implementation uses - SysUtils, e_log, utils, MAPSTRUCT; + SysUtils, e_log, utils, MAPDEF; function findDiskWad (fname: AnsiString): AnsiString; diff --git a/src/shared/xdynrec.pas b/src/shared/xdynrec.pas index 3a31a96..f129dd0 100644 --- a/src/shared/xdynrec.pas +++ b/src/shared/xdynrec.pas @@ -45,9 +45,6 @@ type // TTrigData: array of mMaxDim bytes, but internally a record (mRecRef) // arrays of chars are pascal shortstrings (with counter in the first byte) - TDynFieldArray = array of TDynField; - TDynRecordArray = array of TDynRecord; - private type TEBS = (TNone, TRec, TEnum, TBitSet); @@ -102,6 +99,7 @@ type class function getTypeName (t: TType): AnsiString; function definition (): AnsiString; + function pasdef (): AnsiString; function clone (newOwner: TDynRecord=nil): TDynField; @@ -129,6 +127,7 @@ type property ebs: TEBS read mEBS; property ebstype: TObject read mEBSType; property ebstypename: AnsiString read mEBSTypeName; // enum/bitset name + property list: TDynRecList read mRVal; // for list property x: Integer read mIVal; property w: Integer read mIVal; @@ -172,6 +171,7 @@ type destructor Destroy (); override; function definition (): AnsiString; + function pasdef (): AnsiString; function clone (): TDynRecord; @@ -181,11 +181,14 @@ type procedure parseBinValue (st: TStream; forceData: Boolean=false); procedure writeTo (wr: TTextWriter; putHeader: Boolean=true); - procedure writeBinTo (st: TStream; trigbufsz: Integer=-1); + procedure writeBinTo (st: TStream; trigbufsz: Integer=-1; onlyFields: Boolean=false); // find field with `TriggerType` type function trigTypeField (): TDynField; + // number of records of the given instance + function instanceCount (const typename: AnsiString): Integer; + public property id: AnsiString read mId; // for map parser property pasname: AnsiString read mPasName; @@ -196,9 +199,10 @@ type property field[const aname: AnsiString]: TDynField read getFieldByName; property isTrigData: Boolean read getIsTrigData; property isForTrig[const aname: AnsiString]: Boolean read getIsForTrig; + property headerType: TDynRecord read mHeaderRec; + property isHeader: Boolean read mHeader; end; - TDynEBS = class private mOwner: TDynMapDef; @@ -223,6 +227,7 @@ type destructor Destroy (); override; function definition (): AnsiString; + function pasdef (): AnsiString; // return empty string if not found function nameByValue (v: Integer): AnsiString; @@ -254,6 +259,8 @@ type function findTrigFor (const aname: AnsiString): TDynRecord; function findEBSType (const aname: AnsiString): TDynEBS; + function pasdef (): AnsiString; + // creates new header record function parseMap (pr: TTextParser): TDynRecord; @@ -271,6 +278,10 @@ uses SysUtils; +// ////////////////////////////////////////////////////////////////////////// // +function StrEqu (const a, b: AnsiString): Boolean; inline; begin result := (a = b); end; + + // ////////////////////////////////////////////////////////////////////////// // constructor TDynField.Create (const aname: AnsiString; atype: TType); begin @@ -535,6 +546,34 @@ begin end; +function TDynField.pasdef (): AnsiString; +begin + result := mPasName+': '; + case mType of + TType.TBool: result += 'Boolean;'; + TType.TChar: if (mMaxDim > 0) then result += formatstrf('Char%d;', [mMaxDim]) else result += 'Char;'; + TType.TByte: result += 'ShortInt;'; + TType.TUByte: result += 'Byte;'; + TType.TShort: result += 'SmallInt;'; + TType.TUShort: result += 'Word;'; + TType.TInt: result += 'LongInt;'; + TType.TUInt: result += 'LongWord;'; + TType.TString: result += 'AnsiString;'; + TType.TPoint: + if mAsT then result := 'tX, tY: Integer;' + else if mSepPosSize then result := 'X, Y: Integer;' + else result += 'TDFPoint;'; + TType.TSize: + if mAsT then result := 'tWidth, tHeight: Word;' + else if mSepPosSize then result := 'Width, Height: Word;' + else result += 'TSize;'; + TType.TList: assert(false); + TType.TTrigData: result += formatstrf('Byte%d;', [mMaxDim]); + else raise Exception.Create('ketmar forgot to handle some field type'); + end; +end; + + procedure TDynField.parseDef (pr: TTextParser); var fldname: AnsiString; @@ -753,17 +792,6 @@ begin exit; end; // record reference - if (mRecRef = nil) then - begin - // no ref, write -1 - case mType of - TType.TByte, TType.TUByte: writeInt(st, Byte(-1)); - TType.TShort, TType.TUShort: writeInt(st, SmallInt(-1)); - TType.TInt, TType.TUInt: writeInt(st, Integer(-1)); - else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName])); - end; - exit; - end; case mType of TType.TByte: maxv := 127; TType.TUByte: maxv := 254; @@ -774,13 +802,20 @@ begin else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName])); end; // find record number - f := mOwner.findRecordNumByType(mEBSTypeName, mRecRef); - if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName])); - if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName])); + if (mRecRef <> nil) then + begin + f := mOwner.findRecordNumByType(mEBSTypeName, mRecRef); + if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName])); + if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName])); + end + else + begin + f := -1; + end; case mType of TType.TByte, TType.TUByte: writeInt(st, Byte(f)); TType.TShort, TType.TUShort: writeInt(st, SmallInt(f)); - TType.TInt, TType.TUInt: writeInt(st, Integer(f)); + TType.TInt, TType.TUInt: writeInt(st, LongWord(f)); else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName])); end; exit; @@ -1484,7 +1519,7 @@ begin result := 0; while (result < mFields.count) do begin - if (CompareText(aname, mFields[result].mName) = 0) then exit; + if StrEqu(aname, mFields[result].mName) then exit; Inc(result); end; result := -1; @@ -1517,7 +1552,7 @@ var f: Integer; begin result := true; - for f := 0 to High(mTrigTypes) do if (CompareText(mTrigTypes[f], aname) = 0) then exit; + for f := 0 to High(mTrigTypes) do if StrEqu(mTrigTypes[f], aname) then exit; result := false; end; @@ -1562,7 +1597,7 @@ begin begin for rec in fld.mRVal do begin - if (CompareText(rec.mId, aid) = 0) then begin result := rec; exit; end; + if StrEqu(rec.mId, aid) then begin result := rec; exit; end; end; end; // alas @@ -1638,12 +1673,23 @@ begin if not (fld.mEBSType is TDynEBS) then continue; es := (fld.mEBSType as TDynEBS); assert(es <> nil); - if (CompareText(es.mName, 'TriggerType') = 0) then begin result := fld; exit; end; + if StrEqu(es.mName, 'TriggerType') then begin result := fld; exit; end; end; result := nil; end; +// number of records of the given instance +function TDynRecord.instanceCount (const typename: AnsiString): Integer; +var + fld: TDynField; +begin + result := 0; + fld := field[typename]; + if (fld <> nil) and (fld.mType = fld.TType.TList) then result := fld.mRVal.count; +end; + + procedure TDynRecord.parseDef (pr: TTextParser); var fld: TDynField; @@ -1713,6 +1759,30 @@ begin end; +function TDynRecord.pasdef (): AnsiString; +var + fld: TDynField; +begin + if isTrigData then + begin + assert(false); + result := ''; + end + else + begin + // record + result := ' '+mPasName+' = packed record'#10; + end; + for fld in mFields do + begin + if fld.mInternal then continue; + if (fld.mBinOfs < 0) then continue; + result += ' '+fld.pasdef+#10; + end; + result += ' end;'#10; +end; + + function TDynRecord.definition (): AnsiString; var f: Integer; @@ -1812,7 +1882,7 @@ begin if (btype = 0) then break; // no more blocks readLongWord(st); // reserved bsize := readLongInt(st); - writeln('btype=', btype, '; bsize=', bsize); + //writeln('btype=', btype, '; bsize=', bsize); if (bsize < 0) or (bsize > $1fffffff) then raise Exception.Create(Format('block of type %d has invalid size %d', [btype, bsize])); if loaded[btype] then raise Exception.Create(Format('block of type %d already loaded', [btype])); loaded[btype] := true; @@ -1820,7 +1890,7 @@ begin rect := nil; for rec in mOwner.recTypes do if (rec.mBinBlock = btype) then begin rect := rec; break; end; if (rect = nil) then raise Exception.Create(Format('block of type %d has no corresponding record', [btype])); - writeln('found type ''', rec.mName, ''' for block type ', btype); + //writeln('found type ''', rec.mName, ''' for block type ', btype); if (rec.mSize = 0) or ((bsize mod rec.mSize) <> 0) then raise Exception.Create(Format('block of type %d has invalid number of records', [btype])); // header? if (rect.mHeader) then @@ -1867,7 +1937,7 @@ begin end; // read fields - if (CompareText(mName, 'TriggerData') = 0) then mSize := Integer(st.size-st.position); + if StrEqu(mName, 'TriggerData') then mSize := Integer(st.size-st.position); if (mSize < 1) then raise Exception.Create(Format('cannot read record of type ''%s'' with unknown size', [mName])); GetMem(buf, mSize); st.ReadBuffer(buf^, mSize); @@ -1887,7 +1957,7 @@ begin end; -procedure TDynRecord.writeBinTo (st: TStream; trigbufsz: Integer=-1); +procedure TDynRecord.writeBinTo (st: TStream; trigbufsz: Integer=-1; onlyFields: Boolean=false); var fld: TDynField; rec, rv: TDynRecord; @@ -1927,7 +1997,7 @@ begin end; // write block with normal fields - if mHeader then + if mHeader and not onlyFields then begin //writeln('writing header...'); // signature and version @@ -1942,7 +2012,7 @@ begin FreeMem(buf); buf := nil; // write other blocks, if any - if mHeader then + if mHeader and not onlyFields then begin // calculate blkmax blkmax := 0; @@ -2089,7 +2159,7 @@ begin begin for rv in fld.mRVal do begin - if (Length(rv.mId) > 0) and (CompareText(rv.mId, rec.mId) = 0) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName])); + if (Length(rv.mId) > 0) and StrEqu(rv.mId, rec.mId) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName])); end; end; end; @@ -2154,7 +2224,7 @@ begin result := 0; while (result < Length(mIds)) do begin - if (CompareText(aname, mIds[result]) = 0) then exit; + if StrEqu(aname, mIds[result]) then exit; Inc(result); end; result := -1; @@ -2207,6 +2277,19 @@ begin end; +function TDynEBS.pasdef (): AnsiString; +var + f: Integer; +begin + result := '// '+mName+#10'const'#10; + // fields + for f := 0 to High(mIds) do + begin + result += formatstrf(' %s = %d;'#10, [mIds[f], mVals[f]]); + end; +end; + + function TDynEBS.nameByValue (v: Integer): AnsiString; var f: Integer; @@ -2239,9 +2322,9 @@ begin idname := pr.expectId(); for f := 0 to High(mIds) do begin - if (CompareText(mIds[f], idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName])); + if StrEqu(mIds[f], idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName])); end; - if (CompareText(mMaxName, idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName])); + if StrEqu(mMaxName, idname) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName])); skipAdd := false; hasV := false; v := cv; @@ -2336,7 +2419,7 @@ var begin for rec in recTypes do begin - if (CompareText(rec.name, aname) = 0) then begin result := rec; exit; end; + if StrEqu(rec.name, aname) then begin result := rec; exit; end; end; result := nil; end; @@ -2360,7 +2443,7 @@ var begin for ebs in ebsTypes do begin - if (CompareText(ebs.name, aname) = 0) then begin result := ebs; exit; end; + if StrEqu(ebs.name, aname) then begin result := ebs; exit; end; end; result := nil; end; @@ -2448,7 +2531,7 @@ begin rec := TDynRecord.Create(pr); //writeln(dr.definition); writeln; if (findRecType(rec.name) <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end; - if (hdr <> nil) and (CompareText(rec.name, hdr.name) = 0) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end; + if (hdr <> nil) and StrEqu(rec.name, hdr.name) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end; rec.mOwner := self; if rec.mHeader then begin @@ -2519,4 +2602,51 @@ begin end; +function TDynMapDef.pasdef (): AnsiString; +var + ebs: TDynEBS; + rec: TDynRecord; + fld: TDynField; + needComma: Boolean; + tn: AnsiString; +begin + result := ''; + result += '// ////////////////////////////////////////////////////////////////////////// //'#10; + result += '// enums and bitsets'#10; + for ebs in ebsTypes do result += #10+ebs.pasdef(); + result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10; + result += '// records'#10'type'#10; + for rec in recTypes do + begin + if (rec.mSize < 1) then continue; + result += rec.pasdef(); + result += #10; + end; + result += #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10; + result += '// triggerdata'#10'type'#10; + result += ' TTriggerData = record'#10; + result += ' case Byte of'#10; + result += ' 0: (Default: Byte128);'#10; + for rec in trigTypes do + begin + result += ' '; + needComma := false; + for tn in rec.mTrigTypes do + begin + if needComma then result += ', ' else needComma := true; + result += tn; + end; + result += ': ('#10; + for fld in rec.mFields do + begin + if fld.mInternal then continue; + if (fld.mBinOfs < 0) then continue; + result += ' '+fld.pasdef+#10; + end; + result += ' );'#10; + end; + result += ' end;'#10; +end; + + end. diff --git a/src/shared/xparser.pas b/src/shared/xparser.pas index d0f0d3a..7263b7d 100644 --- a/src/shared/xparser.pas +++ b/src/shared/xparser.pas @@ -177,6 +177,11 @@ uses SysUtils, utils; +// ////////////////////////////////////////////////////////////////////////// // +function StrEqu (const a, b: AnsiString): Boolean; inline; begin result := (a = b); end; + + +// ////////////////////////////////////////////////////////////////////////// // var wc2shitmap: array[0..65535] of AnsiChar; wc2shitmapInited: Boolean = false; @@ -528,7 +533,7 @@ end; procedure TTextParser.expectId (const aid: AnsiString); begin - if (mTokType <> TTId) or (CompareText(mTokStr, aid) <> 0) then raise Exception.Create('identifier '''+aid+''' expected'); + if (mTokType <> TTId) or (not StrEqu(mTokStr, aid)) then raise Exception.Create('identifier '''+aid+''' expected'); skipToken(); end; @@ -536,7 +541,7 @@ end; function TTextParser.eatId (const aid: AnsiString): Boolean; begin result := false; - if (mTokType <> TTId) or (CompareText(mTokStr, aid) <> 0) then exit; + if (mTokType <> TTId) or (not StrEqu(mTokStr, aid)) then exit; result := true; skipToken(); end; diff --git a/src/shared/zmapgen.dpr b/src/shared/zmapgen.dpr new file mode 100644 index 0000000..e983e43 --- /dev/null +++ b/src/shared/zmapgen.dpr @@ -0,0 +1,53 @@ +{$INCLUDE a_modes.inc} +{$M+} + +uses + SysUtils, Classes, + xparser in 'xparser.pas', + xdynrec in 'xdynrec.pas', + utils in 'utils.pas'; + + +// ////////////////////////////////////////////////////////////////////////// // +var + pr: TTextParser; + dfmapdef: TDynMapDef; + fo: TextFile; + st: TStream; + ch: AnsiChar; + wdt: Integer; + s: AnsiString; +begin + writeln('parsing "mapdef.txt"...'); + pr := TFileTextParser.Create('mapdef.txt'); + try + dfmapdef := TDynMapDef.Create(pr); + except on e: Exception do + begin + writeln('ERROR at (', pr.line, ',', pr.col, '): ', e.message); + Halt(1); + end; + end; + + writeln('writing "mapdef.inc"...'); + AssignFile(fo, 'mapdef.inc'); + Rewrite(fo); + write(fo, '// *** WARNING! ***'#10); + write(fo, '// regenerate this part directly from "mapdef.txt" with ''zmapgen'', NEVER manually change anything here!'#10#10#10); + write(fo, dfmapdef.pasdef); + + st := openDiskFileRO('mapdef.txt'); + write(fo, #10#10'const defaultMapDef: AnsiString = ''''+'#10' '); + wdt := 2; + while true do + begin + if (st.Read(ch, 1) <> 1) then break; + s := formatstrf('#%d', [Byte(ch)]); + if (wdt+Length(s) > 78) then begin wdt := 2; write(fo, '+'#10' '); end; + write(fo, s); + Inc(wdt, Length(s)); + end; + write(fo, #10';'); + + CloseFile(fo); +end. -- 2.29.2