X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_map.pas;h=0e31b25d28acb6a33847bb606cf8367bafaceb8a;hb=abda6900c041e39944de6a49aa088a60c170715e;hp=1ddbffdd052253d446f2163e1f4597294dd445ff;hpb=52046a296d5acd6588c2dde5918cdb6cbd26fc52;p=d2df-sdl.git diff --git a/src/game/g_map.pas b/src/game/g_map.pas index 1ddbffd..0e31b25 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -2,8 +2,7 @@ * * 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. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -21,7 +20,7 @@ interface uses SysUtils, Classes, mempool, - e_graphics, g_basic, MAPDEF, g_textures, + g_base, g_basic, MAPDEF, g_textures, g_phys, utils, g_panel, g_grid, md5, binheap, xprofiler, xparser, xdynrec; type @@ -32,6 +31,7 @@ type Author: String; MusicName: String; SkyName: String; + SkyFullName: String; // used by render Height: Word; Width: Word; end; @@ -53,7 +53,6 @@ type State: Byte; Count: Integer; CaptureTime: LongWord; - Animation: TAnimation; Direction: TDirection; end; @@ -66,10 +65,6 @@ procedure g_Map_Update(); function g_Map_PanelByGUID (aguid: Integer): TPanel; inline; -procedure g_Map_DrawPanels (PanelType: Word; hasAmbient: Boolean; constref ambColor: TDFColor); // unaccelerated -procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); - -procedure g_Map_DrawBack(dx, dy: Integer); function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean=false): Boolean; function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD; @@ -90,17 +85,15 @@ function g_Map_IsSpecialTexture(Texture: String): Boolean; function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean; function g_Map_GetPointCount(PointType: Byte): Word; +function g_Map_GetRandomPointType(): Byte; function g_Map_HaveFlagPoints(): Boolean; procedure g_Map_ResetFlag(Flag: Byte); -procedure g_Map_DrawFlags(); procedure g_Map_SaveState (st: TStream); procedure g_Map_LoadState (st: TStream); -procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); - // returns panel or nil // sets `ex` and `ey` to `x1` and `y1` when no hit was detected function g_Map_traceToNearestWall (x0, y0, x1, y1: Integer; hitx: PInteger=nil; hity: PInteger=nil): TPanel; @@ -196,6 +189,7 @@ const GridTagLift = 1 shl 8; // gLifts GridTagBlockMon = 1 shl 9; // gBlockMon + GridTagSolid = (GridTagWall or GridTagDoor); GridTagObstacle = (GridTagStep or GridTagWall or GridTagDoor); GridTagLiquid = (GridTagAcid1 or GridTagAcid2 or GridTagWater); @@ -221,12 +215,10 @@ var gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag; //gDOMFlags: array of TFlag; gMapInfo: TMapInfo; - gBackSize: TDFPoint; gDoorMap: array of array of DWORD; gLiftMap: array of array of DWORD; gWADHash: TMD5Digest; - BackID: DWORD = DWORD(-1); - gExternalResources: TStringList; + gExternalResources: array of TDiskFileInfo = nil; gMovingWallIds: array of Integer = nil; gdbg_map_use_accel_render: Boolean = true; @@ -248,17 +240,18 @@ type var mapGrid: TPanelGrid = nil; // DO NOT USE! public for debugging only! +var (* private state *) + Textures: TLevelTextureArray = nil; implementation uses - e_input, g_main, e_log, e_texture, g_items, g_gfx, g_console, - GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG, + e_input, e_log, e_res, g_items, g_gfx, g_console, + g_weapons, g_game, g_sound, e_sound, CONFIG, g_options, g_triggers, g_player, Math, g_monsters, g_saveload, g_language, g_netmsg, sfs, xstreams, hashtable, wadreader, - ImagingTypes, Imaging, ImagingUtility, - ImagingGif, ImagingNetworkGraphics; + g_res_downloader; const FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52); @@ -343,8 +336,8 @@ begin try e_LogWritefln('parsing "mapdef.txt"...', []); - st := openDiskFileRO(DataDir+'mapdef.txt'); - e_LogWritefln('found local "%smapdef.txt"', [DataDir]); + st := e_OpenResourceRO(DataDirs, 'mapdef.txt'); + e_LogWritefln('found local "mapdef.txt"', []); except st := nil; end; @@ -434,17 +427,19 @@ end; // ////////////////////////////////////////////////////////////////////////// // var NNF_PureName: String; // Èìÿ òåêñòóðû áåç öèôð â êîíöå + NNF_PureExt: String; // extension postfix NNF_FirstNum: Integer; // ×èñëî ó íà÷àëüíîé òåêñòóðû NNF_CurrentNum: Integer; // Ñëåäóþùåå ÷èñëî ó òåêñòóðû function g_Texture_NumNameFindStart(name: String): Boolean; var - i: Integer; + i, j: Integer; begin Result := False; NNF_PureName := ''; + NNF_PureExt := ''; NNF_FirstNum := -1; NNF_CurrentNum := -1; @@ -457,8 +452,11 @@ begin end else begin + j := i + 1; + while (j <= Length(name)) and (name[j] <> '.') do inc(j); NNF_PureName := Copy(name, 1, i); - Delete(name, 1, i); + NNF_PureExt := Copy(name, j); + name := Copy(name, i + 1, j - i - 1); Break; end; end; @@ -482,7 +480,7 @@ begin Exit; end; - newName := NNF_PureName + IntToStr(NNF_CurrentNum); + newName := NNF_PureName + IntToStr(NNF_CurrentNum) + NNF_PureExt; if NNF_CurrentNum < NNF_FirstNum then Result := NNF_NAME_BEFORE @@ -522,14 +520,7 @@ begin result := (a.arrIdx < b.arrIdx); end; -procedure dplClear (); -begin - if (gDrawPanelList = nil) then gDrawPanelList := TBinHeapPanelDraw.Create() else gDrawPanelList.clear(); -end; - - var - Textures: TLevelTextureArray = nil; TextNameHash: THashStrInt = nil; // key: texture name; value: index in `Textures` BadTextNameHash: THashStrInt = nil; // set; so we won't spam with non-existing texture messages RespawnPoints: array of TRespawnPoint; @@ -540,9 +531,9 @@ var procedure g_Map_ProfilersBegin (); begin if (profMapCollision = nil) then profMapCollision := TProfiler.Create('COLSOLID', g_profile_history_size); - profMapCollision.mainBegin(g_profile_collision); + if (profMapCollision <> nil) then profMapCollision.mainBegin(g_profile_collision); // create sections - if g_profile_collision then + if g_profile_collision and (profMapCollision <> nil) then begin profMapCollision.sectionBegin('*solids'); profMapCollision.sectionEnd(); @@ -600,10 +591,10 @@ begin begin // stop if the lift of the right type result := - ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = 0)) or - (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = 1)) or - (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = 2)) or - (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))); + ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = LIFTTYPE_UP)) or + (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = LIFTTYPE_DOWN)) or + (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = LIFTTYPE_LEFT)) or + (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = LIFTTYPE_RIGHT))); exit; end; result := true; // otherwise, stop anyway, 'cause `forEachAtPoint()` is guaranteed to call this only for correct panels @@ -877,381 +868,198 @@ begin if (TextNameHash = nil) then TextNameHash := THashStrInt.Create(); if TextNameHash.get(RecName, result) then exit; // i found her! - SetLength(Textures, Length(Textures)+1); - result := High(Textures); - - with Textures[High(Textures)] do - begin - TextureName := RecName; - Width := 1; - Height := 1; - Anim := False; - TextureID := LongWord(TEXTURE_NONE); - end; - + SetLength(Textures, Length(Textures) + 1); + Textures[High(Textures)].TextureName := RecName; + Textures[High(Textures)].FullName := ''; + Result := High(Textures); TextNameHash.put(RecName, result); end; -function CreateTexture(RecName: AnsiString; Map: string; log: Boolean): Integer; +function extractWadName (resourceName: string): string; var - WAD: TWADFile; - TextureData: Pointer; - WADName: String; - a, ResLength: Integer; + posN: Integer; begin - RecName := toLowerCase1251(RecName); - if (TextNameHash = nil) then TextNameHash := THashStrInt.Create(); - if TextNameHash.get(RecName, result) then - begin - // i found her! - //e_LogWritefln('texture ''%s'' already loaded (%s)', [RecName, result]); - exit; - end; - - Result := -1; - - if (BadTextNameHash <> nil) and BadTextNameHash.has(RecName) then exit; // don't do it again and again - - { - if Textures <> nil then - begin - for a := 0 to High(Textures) do - begin - if (Textures[a].TextureName = RecName) then - begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü - e_LogWritefln('texture ''%s'' already loaded', [RecName]); - Result := a; - Exit; - end; - end; - end; - } - - // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà): - if (RecName = TEXTURE_NAME_WATER) or - (RecName = TEXTURE_NAME_ACID1) or - (RecName = TEXTURE_NAME_ACID2) then - begin - SetLength(Textures, Length(Textures)+1); - - with Textures[High(Textures)] do - begin - TextureName := RecName; - if (TextureName = TEXTURE_NAME_WATER) then TextureID := LongWord(TEXTURE_SPECIAL_WATER) - else if (TextureName = TEXTURE_NAME_ACID1) then TextureID := LongWord(TEXTURE_SPECIAL_ACID1) - else if (TextureName = TEXTURE_NAME_ACID2) then TextureID := LongWord(TEXTURE_SPECIAL_ACID2); - - Anim := False; - end; - - result := High(Textures); - TextNameHash.put(RecName, result); - Exit; - end; - - // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à: - WADName := g_ExtractWadName(RecName); - - WAD := TWADFile.Create(); - - if WADName <> '' then WADName := GameDir+'/wads/'+WADName else WADName := Map; - - WAD.ReadFile(WADName); - - //txname := RecName; - { - if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then - begin - FreeMem(TextureData); - RecName := 'COMMON\ALIEN'; - end; - } + posN := Pos(':', resourceName); + if posN > 0 then + Result:= Copy(resourceName, 0, posN-1) + else + Result := ''; +end; - if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength, log) then - begin - SetLength(Textures, Length(Textures)+1); - if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then - begin - e_WriteLog(Format('Error loading texture %s', [RecName]), TMsgType.Warning); - SetLength(Textures, Length(Textures)-1); - result := -1; - Exit; - end; - e_GetTextureSize(Textures[High(Textures)].TextureID, @Textures[High(Textures)].Width, @Textures[High(Textures)].Height); - FreeMem(TextureData); - Textures[High(Textures)].TextureName := RecName; - Textures[High(Textures)].Anim := False; - result := High(Textures); - TextNameHash.put(RecName, result); +procedure addResToExternalResList (res: AnsiString); +var + uname: AnsiString; + f: Integer; + fi: TDiskFileInfo; +begin + if g_Game_IsClient or not g_Game_IsNet then exit; + if (length(res) = 0) then exit; // map wad + //res := extractWadName(res); + //if (length(res) = 0) then exit; // map wad + uname := toLowerCase1251(res); + // do not add duplicates + for f := 0 to High(gExternalResources) do + begin + if (gExternalResources[f].userName = uname) then exit; + end; + //writeln('***(000) addResToExternalResList: res=[', res, ']'); + // add new resource + fi.userName := uname; + if not findFileCI(res) then exit; + //writeln('***(001) addResToExternalResList: res=[', res, ']'); + fi.diskName := res; + if (not GetDiskFileInfo(res, fi)) then + begin + fi.tag := -1; end - else // Íåò òàêîãî ðåóñðñà â WAD'å + else begin - //e_WriteLog(Format('SHIT! Error loading texture %s : %s', [RecName, g_ExtractFilePathName(RecName)]), MSG_WARNING); - if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create(); - if log and (not BadTextNameHash.get(RecName, a)) then - begin - e_WriteLog(Format('Error loading texture %s', [RecName]), TMsgType.Warning); - //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING); + //writeln('***(002) addResToExternalResList: res=[', res, ']'); + fi.tag := 0; // non-zero means "cannot caclucate hash" + try + fi.hash := MD5File(fi.diskName); + except + fi.tag := -1; end; - BadTextNameHash.put(RecName, -1); end; - - WAD.Free(); + //e_LogWritefln('addext: res=[%s]; uname=[%s]; diskName=[%s]', [res, fi.userName, fi.diskName]); + SetLength(gExternalResources, length(gExternalResources)+1); + gExternalResources[High(gExternalResources)] := fi; end; -function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer; +procedure compactExtResList (); var - WAD: TWADFile; - TextureWAD: PChar = nil; - TextData: Pointer = nil; - TextureData: Pointer = nil; - cfg: TConfig = nil; - WADName: String; - ResLength: Integer; - TextureResource: String; - _width, _height, _framecount, _speed: Integer; - _backanimation: Boolean; - //imgfmt: string; - ia: TDynImageDataArray = nil; - f, c, frdelay, frloop: Integer; + src, dest: Integer; begin - RecName := toLowerCase1251(RecName); - if (TextNameHash = nil) then TextNameHash := THashStrInt.Create(); - if TextNameHash.get(RecName, result) then + src := 0; + dest := 0; + for src := 0 to High(gExternalResources) do begin - // i found her! - //e_LogWritefln('animated texture ''%s'' already loaded (%s)', [RecName, result]); - exit; + if (gExternalResources[src].tag = 0) then + begin + // copy it + if (dest <> src) then gExternalResources[dest] := gExternalResources[src]; + Inc(dest); + end; end; + if (dest <> length(gExternalResources)) then SetLength(gExternalResources, dest); +end; - result := -1; - - //e_LogWritefln('*** Loading animated texture "%s"', [RecName]); - if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create(); - if BadTextNameHash.get(RecName, f) then +function GetReplacementWad (WadName: AnsiString): AnsiString; +begin + result := ''; + if WadName <> '' then begin - //e_WriteLog(Format('no animation texture %s (don''t worry)', [RecName]), MSG_NOTIFY); - exit; + result := WadName; + if g_Game_IsClient then result := g_Res_FindReplacementWad(WadName); + if (result = WadName) then result := e_FindWad(WadDirs, result) end; +end; - // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü: - WADName := g_ExtractWadName(RecName); - - WAD := TWADFile.Create(); - try - if WADName <> '' then WADName := GameDir+'/wads/'+WADName else WADName := Map; - - WAD.ReadFile(WADName); - - if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength, log) then - begin - if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create(); - if log and (not BadTextNameHash.get(RecName, f)) then - begin - e_WriteLog(Format('Error loading animation texture %s', [RecName]), TMsgType.Warning); - //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING); - end; - BadTextNameHash.put(RecName, -1); - exit; - end; - - {TEST - if WADName = Map then - begin - //FreeMem(TextureWAD); - if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1); - end; - } - - WAD.FreeWAD(); - if ResLength < 6 then - begin - e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; +procedure generateExternalResourcesList (map: TDynRecord); +begin + SetLength(gExternalResources, 0); + addResToExternalResList(GetReplacementWad(g_ExtractWadName(map.MusicName))); + addResToExternalResList(GetReplacementWad(g_ExtractWadName(map.SkyName))); +end; - // ýòî ïòèöà? ýòî ñàìîë¸ò? - if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and - (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then + function CreateTexture (RecName: AnsiString; Map: String; log: Boolean): Integer; + var + HName: AnsiString; + WAD, WADz: TWADFile; + WADName, ResName: String; + ResData, ReszData: Pointer; + ResLen, ReszLen: Integer; + cfg: TConfig; + id: Integer; + begin + Result := -1; + HName := toLowerCase1251(RecName); + if (TextNameHash = nil) then + TextNameHash := THashStrInt.Create(); + if TextNameHash.get(HName, Result) then + begin + // e_LogWritefln('CreateTexture: found loaded %s', [Result]); + end + else begin - // íåò, ýòî ñóïåðìåí! - if not WAD.ReadMemory(TextureWAD, ResLength) then - begin - e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; - - // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè: - if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then - begin - e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; - - cfg := TConfig.CreateMem(TextData, ResLength); - - TextureResource := cfg.ReadStr('', 'resource', ''); - if TextureResource = '' then - begin - e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; - - _width := cfg.ReadInt('', 'framewidth', 0); - _height := cfg.ReadInt('', 'frameheight', 0); - _framecount := cfg.ReadInt('', 'framecount', 0); - _speed := cfg.ReadInt('', 'waitcount', 0); - _backanimation := cfg.ReadBool('', 'backanimation', False); - - cfg.Free(); - cfg := nil; - - // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü: - if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then - begin - e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; - - WAD.Free(); - WAD := nil; - - SetLength(Textures, Length(Textures)+1); - with Textures[High(Textures)] do + Result := -1; + if (BadTextNameHash = nil) or not BadTextNameHash.has(HName) then begin - // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè: - if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then - begin - TextureName := RecName; - Width := _width; - Height := _height; - Anim := True; - FramesCount := _framecount; - Speed := _speed; - result := High(Textures); - TextNameHash.put(RecName, result); - end + case RecName of + TEXTURE_NAME_WATER, TEXTURE_NAME_ACID1, TEXTURE_NAME_ACID2: + begin + SetLength(Textures, Length(Textures) + 1); + Textures[High(Textures)].FullName := RecName; + Textures[High(Textures)].TextureName := RecName; + Result := High(Textures); + TextNameHash.put(RecName, result); + end else - begin - if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create(); - if log and (not BadTextNameHash.get(RecName, f)) then + WADName := GetReplacementWad(g_ExtractWadName(RecName)); + if (WADName <> '') then + addResToExternalResList(WADName); + if WADName = '' then + WADName := Map; + ResName := g_ExtractFilePathName(RecName); + WAD := TWADFile.Create(); + if WAD.ReadFile(WadName) then begin - e_WriteLog(Format('Error loading animation texture %s', [RecName]), TMsgType.Warning); + if WAD.GetResource(ResName, ResData, ResLen, log) then + begin + if IsWadData(ResData, ResLen) then + begin + WADz := TWADFile.Create(); + if WADz.ReadMemory(ResData, ResLen) then + begin + if WADz.GetResource('TEXT/ANIM', ReszData, ReszLen) then + begin + cfg := TConfig.CreateMem(ReszData, ReszLen); + if cfg <> nil then + begin + SetLength(Textures, Length(Textures) + 1); + Textures[High(Textures)].TextureName := RecName; + Textures[High(Textures)].FullName := WadName + ':' + ResName; + Textures[High(Textures)].FramesCount := cfg.ReadInt('', 'framecount', 0); + Textures[High(Textures)].Speed := cfg.ReadInt('', 'waitcount', 0); + Result := High(Textures); + TextNameHash.put(HName, result); + cfg.Free; + end; + FreeMem(ReszData); + end + end; + WADz.Free; + end + else + begin + SetLength(Textures, Length(Textures) + 1); + Textures[High(Textures)].FullName := WADName + ':' + ResName; + Textures[High(Textures)].TextureName := RecName; + Result := High(Textures); + TextNameHash.put(HName, result); + end; + FreeMem(ResData); + end end; - BadTextNameHash.put(RecName, -1); - end; - end; - end - else - begin - // try animated image - { - imgfmt := DetermineMemoryFormat(TextureWAD, ResLength); - if length(imgfmt) = 0 then - begin - e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING); - exit; - end; - } - GlobalMetadata.ClearMetaItems(); - GlobalMetadata.ClearMetaItemsForSaving(); - if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then - begin - e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; - if length(ia) = 0 then - begin - e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), TMsgType.Warning); - BadTextNameHash.put(RecName, -1); - exit; - end; - - WAD.Free(); - WAD := nil; - - _width := ia[0].width; - _height := ia[0].height; - _framecount := length(ia); - _speed := 1; - _backanimation := false; - frdelay := -1; - frloop := -666; - if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then - begin - //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]); - try - f := GlobalMetadata.MetaItems[SMetaFrameDelay]; - frdelay := f; - if f < 0 then f := 0; - // rounding ;-) - c := f mod 28; - if c < 13 then c := 0 else c := 1; - f := (f div 28)+c; - if f < 1 then f := 1 else if f > 255 then f := 255; - _speed := f; - except - end; - end; - if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then - begin - //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]); - try - f := GlobalMetadata.MetaItems[SMetaAnimationLoops]; - frloop := f; - if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back - except - end; - end; - //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...'); - //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height); - f := ord(_backanimation); - e_WriteLog(Format('Animated texture file "%s": %d frames (delay:%d; back:%d; frdelay:%d; frloop:%d), %dx%d', [RecName, length(ia), _speed, f, frdelay, frloop, _width, _height]), TMsgType.Notify); - - SetLength(Textures, Length(Textures)+1); - // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê - if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then - begin - Textures[High(Textures)].TextureName := RecName; - Textures[High(Textures)].Width := _width; - Textures[High(Textures)].Height := _height; - Textures[High(Textures)].Anim := True; - Textures[High(Textures)].FramesCount := length(ia); - Textures[High(Textures)].Speed := _speed; - result := High(Textures); - TextNameHash.put(RecName, result); - //writeln(' CREATED!'); - end - else - begin - if (BadTextNameHash = nil) then BadTextNameHash := THashStrInt.Create(); - if log and (not BadTextNameHash.get(RecName, f)) then - begin - e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), TMsgType.Warning); - end; - BadTextNameHash.put(RecName, -1); + WAD.Free; + end end; end; - finally - for f := 0 to High(ia) do FreeImage(ia[f]); - WAD.Free(); - cfg.Free(); - if (TextureWAD <> nil) then FreeMem(TextureWAD); - if (TextData <> nil) then FreeMem(TextData); - if (TextureData <> nil) then FreeMem(TextureData); + if Result < 0 then + begin + if (BadTextNameHash = nil) then + BadTextNameHash := THashStrInt.Create(); + if log and (not BadTextNameHash.get(HName, id)) then + e_WriteLog(Format('Error loading texture %s', [RecName]), TMsgType.Warning); + BadTextNameHash.put(HName, -1); + end end; -end; procedure CreateItem(Item: TDynRecord); begin @@ -1268,7 +1076,6 @@ end; procedure CreateArea(Area: TDynRecord); var a: Integer; - id: DWORD = 0; begin case Area.AreaType of AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2, @@ -1308,14 +1115,7 @@ begin with gFlags[a] do begin - case a of - FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED'); - FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE'); - end; - - Animation := TAnimation.Create(id, True, 8); Obj.Rect := FLAGRECT; - g_Map_ResetFlag(a); end; end; @@ -1338,6 +1138,7 @@ end; function CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer): Integer; var _trigger: TTrigger; + tp: TPanel; begin result := -1; if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit; @@ -1356,6 +1157,12 @@ begin ActivateType := Trigger.ActivateType; Keys := Trigger.Keys; trigPanelGUID := atrigpanid; + // HACK: used in TPanel.CanChangeTexture. maybe there's a better way? + if TexturePanelGUID <> -1 then + begin + tp := g_Map_PanelByGUID(TexturePanelGUID); + if (tp <> nil) then tp.hasTexTrigger := True; + end; end; result := Integer(g_Triggers_Create(_trigger, Trigger)); @@ -1423,66 +1230,6 @@ begin g_Mons_ForEach(monsDieTrig); end; -function extractWadName(resourceName: string): string; -var - posN: Integer; -begin - posN := Pos(':', resourceName); - if posN > 0 then - Result:= Copy(resourceName, 0, posN-1) - else - Result := ''; -end; - -procedure addResToExternalResList(res: string); -begin - res := extractWadName(res); - if (res <> '') and (gExternalResources.IndexOf(res) = -1) then - gExternalResources.Add(res); -end; - -procedure generateExternalResourcesList({mapReader: TMapReader_1}map: TDynRecord); -//var - //textures: TTexturesRec1Array; - //textures: TDynField; - //trec: TDynRecord; - //mapHeader: TMapHeaderRec_1; - //i: integer; - //resFile: String = ''; -begin - if gExternalResources = nil then - gExternalResources := TStringList.Create; - - gExternalResources.Clear; - - (* - { - textures := GetTextures(map); - for i := 0 to High(textures) do - begin - addResToExternalResList(resFile); - end; - } - - textures := map['texture']; - if (textures <> nil) then - begin - for trec in textures do - begin - addResToExternalResList(resFile); - end; - end; - - textures := nil; - *) - - //mapHeader := GetMapHeader(map); - - addResToExternalResList(map.MusicName); - addResToExternalResList(map.SkyName); -end; - - procedure mapCreateGrid (); var mapX0: Integer = $3fffffff; @@ -1629,7 +1376,7 @@ var FileName, mapResName, TexName, s: AnsiString; Data: Pointer; Len: Integer; - ok, isAnim: Boolean; + ok: Boolean; CurTex, ntn: Integer; rec, texrec: TDynRecord; pttit: PTRec; @@ -1662,7 +1409,7 @@ begin if (gCurrentMap = nil) then begin FileName := g_ExtractWadName(Res); - e_WriteLog('Loading map WAD: '+FileName, TMsgType.Notify); + e_LogWritefln('Loading map WAD [%s] (res=[%s])', [FileName, Res], TMsgType.Notify); g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False); WAD := TWADFile.Create(); @@ -1807,23 +1554,17 @@ begin else begin {$IF DEFINED(D2F_DEBUG_TXLOAD)} - e_LogWritefln(' Loading texture #%d: %s', [cnt, rec.Resource]); + e_LogWritefln(' Loading texture #%d: %s', [cnt, rec.Resource]); {$ENDIF} - //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY); - if rec.Anim then - begin - // Àíèìèðîâàííàÿ òåêñòóðà - ntn := CreateAnimTexture(rec.Resource, FileName, True); - if (ntn < 0) then g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [rec.Resource])); - end - else + ntn := CreateTexture(rec.Resource, FileName, True); + if ntn < 0 then begin - // Îáû÷íàÿ òåêñòóðà - ntn := CreateTexture(rec.Resource, FileName, True); - if (ntn < 0) then g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [rec.Resource])); + if rec.Anim then + g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [rec.Resource])) + else + g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [rec.Resource])); + ntn := CreateNullTexture(rec.Resource) end; - if (ntn < 0) then ntn := CreateNullTexture(rec.Resource); - rec.tagInt := ntn; // remember texture number end; g_Game_StepLoading(); @@ -1963,39 +1704,7 @@ begin if (k = NNF_NAME_BEFORE) or (k = NNF_NAME_AFTER) then begin - // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó - if texrec.Anim then - begin - // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ - isAnim := True; - //e_LogWritefln('000: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - ok := CreateAnimTexture(TexName, FileName, False) >= 0; - //e_LogWritefln('001: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - if not ok then - begin - // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ - isAnim := False; - //e_LogWritefln('002: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - ok := CreateTexture(TexName, FileName, False) >= 0; - //e_LogWritefln('003: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - end; - end - else - begin - // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ - isAnim := False; - //e_LogWritefln('004: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - ok := CreateTexture(TexName, FileName, False) >= 0; - //e_LogWritefln('005: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - if not ok then - begin - // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ - isAnim := True; - //e_LogWritefln('006: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - ok := CreateAnimTexture(TexName, FileName, False) >= 0; - //e_LogWritefln('007: pannum=%s; TexName=[%s]; FileName=[%s]', [pannum, TexName, FileName]); - end; - end; + ok := CreateTexture(TexName, FileName, False) >= 0; // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè if ok then @@ -2007,7 +1716,6 @@ begin begin SetLength(AddTextures, Length(AddTextures)+1); AddTextures[High(AddTextures)].Texture := c; - AddTextures[High(AddTextures)].Anim := isAnim; break; end; end; @@ -2016,7 +1724,6 @@ begin begin SetLength(AddTextures, Length(AddTextures)+1); AddTextures[High(AddTextures)].Texture := c; - AddTextures[High(AddTextures)].Anim := isAnim; end; end; end @@ -2027,7 +1734,6 @@ begin // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî SetLength(AddTextures, Length(AddTextures)+1); AddTextures[High(AddTextures)].Texture := rec.tagInt; // internal texture number, not map index - AddTextures[High(AddTextures)].Anim := texrec.Anim; CurTex := High(AddTextures); ok := true; end @@ -2047,8 +1753,6 @@ begin // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó SetLength(AddTextures, 1); AddTextures[0].Texture := rec.tagInt; // internal texture number, not map index - AddTextures[0].Anim := false; - if (texrec <> nil) then AddTextures[0].Anim := texrec.Anim; CurTex := 0; end; @@ -2164,28 +1868,12 @@ begin //mapReader := nil; // Çàãðóçêà íåáà + gMapInfo.SkyFullName := ''; if (gMapInfo.SkyName <> '') then begin e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, TMsgType.Notify); g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False); - FileName := g_ExtractWadName(gMapInfo.SkyName); - - if (FileName <> '') then FileName := GameDir+'/wads/'+FileName else FileName := g_ExtractWadName(Res); - - if gTextureFilter then TEXTUREFILTER := GL_LINEAR else TEXTUREFILTER := GL_NEAREST; - try - s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName); - if g_Texture_CreateWAD(BackID, s) then - begin - g_Game_SetupScreenSize(); - end - else - begin - g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s])); - end; - finally - TEXTUREFILTER := GL_NEAREST; - end; + gMapInfo.SkyFullName := e_GetResourcePath(WadDirs, gMapInfo.SkyName, g_ExtractWadName(Res)); end; // Çàãðóçêà ìóçûêè @@ -2194,16 +1882,8 @@ begin begin e_WriteLog(' Loading music: ' + gMapInfo.MusicName, TMsgType.Notify); g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False); - FileName := g_ExtractWadName(gMapInfo.MusicName); - if FileName <> '' then - FileName := GameDir+'/wads/'+FileName - else - begin - FileName := g_ExtractWadName(Res); - end; - - s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName); + s := e_GetResourcePath(WadDirs, gMapInfo.MusicName, g_ExtractWadName(Res)); if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then ok := True else @@ -2247,7 +1927,7 @@ begin finally sfsGCEnable(); // enable releasing unused volumes //mapReader.Free(); - e_ClearInputBuffer(); // why not? + e_UnpressAllKeys; // why not? if not mapOk then begin gCurrentMap.Free(); @@ -2256,6 +1936,7 @@ begin end; end; + compactExtResList(); e_WriteLog('Done loading map.', TMsgType.Notify); Result := True; end; @@ -2381,8 +2062,6 @@ begin end; procedure g_Map_Free(freeTextures: Boolean=true); -var - a: Integer; procedure FreePanelArray(var panels: TPanelArray); var @@ -2431,27 +2110,7 @@ begin if freeTextures then begin e_LogWritefln('g_Map_Free: clearing textures...', []); - if (Textures <> nil) then - begin - for a := 0 to High(Textures) do - begin - if not g_Map_IsSpecialTexture(Textures[a].TextureName) then - begin - if Textures[a].Anim then - begin - g_Frames_DeleteByID(Textures[a].FramesID) - end - else - begin - if (Textures[a].TextureID <> LongWord(TEXTURE_NONE)) then - begin - e_DeleteTexture(Textures[a].TextureID); - end; - end; - end; - end; - Textures := nil; - end; + Textures := nil; TextNameHash.Free(); TextNameHash := nil; BadTextNameHash.Free(); @@ -2474,14 +2133,6 @@ begin FreePanelArray(gBlockMon); gMovingWallIds := nil; - if BackID <> DWORD(-1) then - begin - gBackSize.X := 0; - gBackSize.Y := 0; - e_DeleteTexture(BackID); - BackID := DWORD(-1); - end; - g_Game_StopAllSounds(False); gMusic.FreeSound(); g_Sound_Delete(gMapInfo.MusicName); @@ -2501,6 +2152,7 @@ var a, d, j: Integer; m: Word; s: String; + b: Byte; procedure UpdatePanelArray(var panels: TPanelArray); var @@ -2531,8 +2183,6 @@ begin begin with gFlags[a] do begin - if gFlags[a].Animation <> nil then gFlags[a].Animation.Update(); - m := g_Obj_Move(@Obj, True, True); if gTime mod (GAME_TICK*2) <> 0 then Continue; @@ -2551,6 +2201,15 @@ begin s := _lc[I_PLAYER_FLAG_BLUE]; g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144); + if (((gPlayer1 <> nil) and (((gPlayer1.Team = TEAM_RED) and (a = FLAG_RED)) or ((gPlayer1.Team = TEAM_BLUE) and (a = FLAG_BLUE)))) + or ((gPlayer2 <> nil) and (((gPlayer2.Team = TEAM_RED) and (a = FLAG_RED)) or ((gPlayer2.Team = TEAM_BLUE) and (a = FLAG_BLUE))))) then + b := 0 + else + b := 1; + + if not sound_ret_flag[b].IsPlaying() then + sound_ret_flag[b].Play(); + if g_Game_IsNet then MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0); Continue; @@ -2581,71 +2240,6 @@ begin end; end; - -// old algo -procedure g_Map_DrawPanels (PanelType: Word; hasAmbient: Boolean; constref ambColor: TDFColor); - - procedure DrawPanels (constref panels: TPanelArray; drawDoors: Boolean=False); - var - idx: Integer; - begin - if (panels <> nil) then - begin - // alas, no visible set - for idx := 0 to High(panels) do - begin - if not (drawDoors xor panels[idx].Door) then panels[idx].Draw(hasAmbient, ambColor); - end; - end; - end; - -begin - case PanelType of - PANEL_WALL: DrawPanels(gWalls); - PANEL_CLOSEDOOR: DrawPanels(gWalls, True); - PANEL_BACK: DrawPanels(gRenderBackgrounds); - PANEL_FORE: DrawPanels(gRenderForegrounds); - PANEL_WATER: DrawPanels(gWater); - PANEL_ACID1: DrawPanels(gAcid1); - PANEL_ACID2: DrawPanels(gAcid2); - PANEL_STEP: DrawPanels(gSteps); - end; -end; - - -// new algo -procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); -var - mwit: PPanel; - it: TPanelGrid.Iter; -begin - dplClear(); - it := mapGrid.forEachInAABB(x0, y0, wdt, hgt, GridDrawableMask); - for mwit in it do if (((mwit^.tag and GridTagDoor) <> 0) = mwit^.Door) then gDrawPanelList.insert(mwit^); - it.release(); - // list will be rendered in `g_game.DrawPlayer()` -end; - - -procedure g_Map_DrawPanelShadowVolumes (lightX: Integer; lightY: Integer; radius: Integer); -var - mwit: PPanel; - it: TPanelGrid.Iter; -begin - it := mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, (GridTagWall or GridTagDoor)); - for mwit in it do mwit^.DrawShadowVolume(lightX, lightY, radius); - it.release(); -end; - - -procedure g_Map_DrawBack(dx, dy: Integer); -begin - if gDrawBackGround and (BackID <> DWORD(-1)) then - e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y) - else - e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0); -end; - function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean=false): Boolean; var @@ -2735,10 +2329,10 @@ begin h := High(gLifts); for a := 0 to h do - if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or - (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or - (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or - (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and + if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = LIFTTYPE_UP)) or + (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = LIFTTYPE_DOWN)) or + (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = LIFTTYPE_LEFT)) or + (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = LIFTTYPE_RIGHT))) and g_Collide(X, Y, Width, Height, gLifts[a].X, gLifts[a].Y, gLifts[a].Width, gLifts[a].Height) then @@ -2814,10 +2408,10 @@ const if ((tag and GridTagLift) <> 0) then begin result := - ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = 0)) or - (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = 1)) or - (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = 2)) or - (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))) {and + ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = LIFTTYPE_UP)) or + (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = LIFTTYPE_DOWN)) or + (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = LIFTTYPE_LEFT)) or + (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = LIFTTYPE_RIGHT))) {and g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height)}; exit; end; @@ -2863,10 +2457,10 @@ begin if ((pan.tag and GridTagLift) <> 0) then begin result := - ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = 0)) or - (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = 1)) or - (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = 2)) or - (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = 3))) {and + ((WordBool(PanelType and PANEL_LIFTUP) and (pan.LiftType = LIFTTYPE_UP)) or + (WordBool(PanelType and PANEL_LIFTDOWN) and (pan.LiftType = LIFTTYPE_DOWN)) or + (WordBool(PanelType and PANEL_LIFTLEFT) and (pan.LiftType = LIFTTYPE_LEFT)) or + (WordBool(PanelType and PANEL_LIFTRIGHT) and (pan.LiftType = LIFTTYPE_RIGHT))) {and g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height)}; end else if ((pan.tag and GridTagBlockMon) <> 0) then @@ -3028,10 +2622,10 @@ begin //TODO: make separate lift tags, and change tag here case LiftType of - 0: g_Mark(X, Y, Width, Height, MARK_LIFTUP); - 1: g_Mark(X, Y, Width, Height, MARK_LIFTDOWN); - 2: g_Mark(X, Y, Width, Height, MARK_LIFTLEFT); - 3: g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT); + LIFTTYPE_UP: g_Mark(X, Y, Width, Height, MARK_LIFTUP); + LIFTTYPE_DOWN: g_Mark(X, Y, Width, Height, MARK_LIFTDOWN); + LIFTTYPE_LEFT: g_Mark(X, Y, Width, Height, MARK_LIFTLEFT); + LIFTTYPE_RIGHT: g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT); end; //if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(pguid); @@ -3080,6 +2674,14 @@ begin Result := Result + 1; end; +function g_Map_GetRandomPointType(): Byte; +begin + if RespawnPoints = nil then + Result := 255 + else + Result := RespawnPoints[Random(Length(RespawnPoints))].PointType; +end; + function g_Map_HaveFlagPoints(): Boolean; begin Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil); @@ -3106,46 +2708,6 @@ begin end; end; -procedure g_Map_DrawFlags(); -var - i, dx: Integer; - Mirror: TMirrorType; -begin - if gGameSettings.GameMode <> GM_CTF then - Exit; - - for i := FLAG_RED to FLAG_BLUE do - with gFlags[i] do - if State <> FLAG_STATE_CAPTURED then - begin - if State = FLAG_STATE_NONE then - continue; - - if Direction = TDirection.D_LEFT then - begin - Mirror := TMirrorType.Horizontal; - dx := -1; - end - else - begin - Mirror := TMirrorType.None; - dx := 1; - end; - - Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror); - - if g_debug_Frames then - begin - e_DrawQuad(Obj.X+Obj.Rect.X, - Obj.Y+Obj.Rect.Y, - Obj.X+Obj.Rect.X+Obj.Rect.Width-1, - Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1, - 0, 255, 0); - end; - end; -end; - - procedure g_Map_SaveState (st: TStream); var str: String;