X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_panel.pas;h=70d2cc15fd4ff5c1deaa801dae3e2d98aaab9e28;hb=ce03f86070c096a59f6774317655485f98f5da70;hp=c5eec299a67f3b75dbffbdae292e14c19ca3870a;hpb=94a927ca673a2d8af4b8449d434f3c70f38b11c1;p=d2df-sdl.git diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index c5eec29..70d2cc1 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -1,9 +1,8 @@ -(* Copyright (C) DooM 2D:Forever Developers +(* 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. + * 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,31 +20,35 @@ interface uses SysUtils, Classes, - MAPDEF, g_textures, xdynrec; + MAPDEF, g_animations, xdynrec; type - TAddTextureArray = Array of - record - Texture: Cardinal; - Anim: Boolean; - end; + TLevelTexture = record + TextureName: AnsiString; // as stored in wad + FullName: AnsiString; // full path to texture // !!! merge it with TextureName + end; + + TLevelTextureArray = array of TLevelTexture; + + TAddTextureArray = array of record + Texture: Cardinal; // Textures[Texture] + end; + ATextureID = array of record + Texture: Cardinal; // Textures[Texture] + end; + + PPanel = ^TPanel; TPanel = Class (TObject) private const private mGUID: Integer; // will be assigned in "g_map.pas" - FTextureWidth: Word; - FTextureHeight: Word; FAlpha: Byte; FBlending: Boolean; - FTextureIDs: Array of - record - case Anim: Boolean of - False: (Tex: Cardinal); - True: (AnTex: TAnimation); - end; - + FTextureIDs: ATextureID; + FAnimTime: LongWord; + FAnimLoop: Boolean; mMovingSpeed: TDFPoint; mMovingStart: TDFPoint; mMovingEnd: TDFPoint; @@ -93,11 +96,11 @@ type procedure setSizeEndY (v: Integer); inline; public - FCurTexture: Integer; // Íîìåð òåêóùåé òåêñòóðû - FCurFrame: Integer; - FCurFrameCount: Byte; + FCurTexture: Integer; // Номер текущей текстуры FX, FY: Integer; + FOldX, FOldY: Integer; FWidth, FHeight: Word; + FOldW, FOldH: Word; FPanelType: Word; FEnabled: Boolean; FDoor: Boolean; @@ -109,6 +112,7 @@ type tag: Integer; // used in coldets and such; sorry; see g_map.GridTagXXX proxyId: Integer; // proxy id in map grid (DO NOT USE!) mapId: AnsiString; // taken directly from map file; dunno why it is here + hasTexTrigger: Boolean; // HACK: true when there's a trigger than can change my texture constructor Create(PanelRec: TDynRecord; AddTextures: TAddTextureArray; @@ -116,14 +120,13 @@ type var Textures: TLevelTextureArray; aguid: Integer); destructor Destroy(); override; - procedure Draw (hasAmbient: Boolean; constref ambColor: TDFColor); - procedure DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Integer); procedure Update(); - procedure SetFrame(Frame: Integer; Count: Byte); + procedure SetFrame(StartTime: LongWord); procedure NextTexture(AnimLoop: Byte = 0); procedure SetTexture(ID: Integer; AnimLoop: Byte = 0); function GetTextureID(): Cardinal; function GetTextureCount(): Integer; + function CanChangeTexture(): Boolean; procedure SaveState (st: TStream); procedure LoadState (st: TStream); @@ -157,6 +160,10 @@ type property y: Integer read FY write FY; property width: Word read FWidth write FWidth; property height: Word read FHeight write FHeight; + property oldX: Integer read FOldX; + property oldY: Integer read FOldY; + property oldWidth: Word read FOldW; + property oldHeight: Word read FOldH; property panelType: Word read FPanelType write FPanelType; property enabled: Boolean read FEnabled write FEnabled; property door: Boolean read FDoor write FDoor; @@ -187,6 +194,12 @@ type property isGLift: Boolean read getIsGLift; property isGBlockMon: Boolean read getIsGBlockMon; + property Alpha: Byte read FAlpha; + property Blending: Boolean read FBlending; + property TextureIDs: ATextureID read FTextureIDs; + property AnimTime: LongWord read FAnimTime; + property AnimLoop: Boolean read FAnimLoop; + public property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed; property movingStart: TDFPoint read mMovingStart write mMovingStart; @@ -201,6 +214,12 @@ type TPanelArray = Array of TPanel; +const + LIFTTYPE_UP = 0; + LIFTTYPE_DOWN = 1; + LIFTTYPE_LEFT = 2; + LIFTTYPE_RIGHT = 3; + var g_dbgpan_mplat_active: Boolean = {$IF DEFINED(D2F_DEBUG)}true{$ELSE}true{$ENDIF}; g_dbgpan_mplat_step: Boolean = false; // one step, and stop @@ -208,30 +227,60 @@ var implementation -uses - e_texture, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, g_triggers, - g_console, g_language, g_monsters, g_player, g_grid, e_log, GL, utils, xstreams; + uses + {$IFDEF ENABLE_GFX} + g_gfx, + {$ENDIF} + {$IFDEF ENABLE_GIBS} + g_gibs, + {$ENDIF} + {$IFDEF ENABLE_CORPSES} + g_corpses, + {$ENDIF} + g_basic, g_map, g_game, g_weapons, g_triggers, g_items, + g_console, g_language, g_monsters, g_player, g_grid, e_log, geom, utils, xstreams + ; const PANEL_SIGNATURE = $4C4E4150; // 'PANL' { T P a n e l : } + function FindTextureByName (const name: String): Integer; + var i: Integer; + begin + Result := -1; + if Textures <> nil then + begin + for i := 0 to High(Textures) do + begin + if Textures[i].TextureName = name then + begin + Result := i; + break; + end + end + end + end; + constructor TPanel.Create(PanelRec: TDynRecord; AddTextures: TAddTextureArray; CurTex: Integer; var Textures: TLevelTextureArray; aguid: Integer); var i: Integer; + tnum: Integer; begin X := PanelRec.X; Y := PanelRec.Y; + FOldX := X; + FOldY := Y; Width := PanelRec.Width; Height := PanelRec.Height; + FOldW := Width; + FOldH := Height; FAlpha := 0; FBlending := False; - FCurFrame := 0; - FCurFrameCount := 0; LastAnimLoop := 0; mapId := PanelRec.id; @@ -252,29 +301,30 @@ begin mNeedSend := false; -// Òèï ïàíåëè: +// Тип панели: PanelType := PanelRec.PanelType; Enabled := True; Door := False; - LiftType := 0; + LiftType := LIFTTYPE_UP; + hasTexTrigger := False; case PanelType of PANEL_OPENDOOR: begin Enabled := False; Door := True; end; PANEL_CLOSEDOOR: Door := True; - PANEL_LIFTUP: LiftType := 0; //??? - PANEL_LIFTDOWN: LiftType := 1; - PANEL_LIFTLEFT: LiftType := 2; - PANEL_LIFTRIGHT: LiftType := 3; + PANEL_LIFTUP: LiftType := LIFTTYPE_UP; //??? + PANEL_LIFTDOWN: LiftType := LIFTTYPE_DOWN; + PANEL_LIFTLEFT: LiftType := LIFTTYPE_LEFT; + PANEL_LIFTRIGHT: LiftType := LIFTTYPE_RIGHT; end; -// Íåâèäèìàÿ: +// Невидимая: if ByteBool(PanelRec.Flags and PANEL_FLAG_HIDE) then begin SetLength(FTextureIDs, 0); FCurTexture := -1; Exit; end; -// Ïàíåëè, íå èñïîëüçóþùèå òåêñòóðû: +// Панели, не использующие текстуры: if ByteBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or @@ -287,22 +337,16 @@ begin Exit; end; -// Åñëè ýòî æèäêîñòü áåç òåêñòóðû - ñïåöòåêñòóðó: +// Если это жидкость без текстуры - спецтекстуру: if WordBool(PanelType and (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2)) and (not ByteBool(PanelRec.Flags and PANEL_FLAG_WATERTEXTURES)) then begin SetLength(FTextureIDs, 1); - FTextureIDs[0].Anim := False; - case PanelRec.PanelType of - PANEL_WATER: - FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_WATER); - PANEL_ACID1: - FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID1); - PANEL_ACID2: - FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID2); + PANEL_WATER: FTextureIDs[0].Texture := FindTextureByName(TEXTURE_NAME_WATER); + PANEL_ACID1: FTextureIDs[0].Texture := FindTextureByName(TEXTURE_NAME_ACID1); + PANEL_ACID2: FTextureIDs[0].Texture := FindTextureByName(TEXTURE_NAME_ACID2); end; - FCurTexture := 0; Exit; end; @@ -317,53 +361,35 @@ begin else FCurTexture := CurTex; - for i := 0 to Length(FTextureIDs)-1 do - begin - FTextureIDs[i].Anim := AddTextures[i].Anim; - if FTextureIDs[i].Anim then - begin // Àíèìèðîâàííàÿ òåêñòóðà - FTextureIDs[i].AnTex := - TAnimation.Create(Textures[AddTextures[i].Texture].FramesID, - True, Textures[AddTextures[i].Texture].Speed); - FTextureIDs[i].AnTex.Blending := ByteBool(PanelRec.Flags and PANEL_FLAG_BLENDING); - FTextureIDs[i].AnTex.Alpha := PanelRec.Alpha; - end - else - begin // Îáû÷íàÿ òåêñòóðà - FTextureIDs[i].Tex := Textures[AddTextures[i].Texture].TextureID; - end; - end; + for i := 0 to Length(FTextureIDs) - 1 do + FTextureIDs[i].Texture := AddTextures[i].Texture; + + FAnimTime := gTime; + FAnimLoop := true; -// Òåêñòóð íåñêîëüêî - íóæíî ñîõðàíÿòü òåêóùóþ: +// Текстур несколько - нужно сохранять текущую: //if Length(FTextureIDs) > 1 then SaveIt := True; -// Åñëè íå ñïåöòåêñòóðà, òî çàäàåì ðàçìåðû: - if PanelRec.TextureNum > High(Textures) then + if (PanelRec.TextureRec = nil) then tnum := -1 else tnum := PanelRec.tagInt; + if (tnum < 0) then tnum := Length(Textures); + +// Если не спецтекстура, то задаем размеры: + if ({PanelRec.TextureNum}tnum > High(Textures)) then begin - e_WriteLog(Format('WTF?! PanelRec.TextureNum is out of limits! (%d : %d)', [PanelRec.TextureNum, High(Textures)]), MSG_FATALERROR); - FTextureWidth := 2; - FTextureHeight := 2; + e_WriteLog(Format('WTF?! tnum is out of limits! (%d : %d)', [tnum, High(Textures)]), TMsgType.Warning); FAlpha := 0; FBlending := ByteBool(0); end - else if not g_Map_IsSpecialTexture(Textures[PanelRec.TextureNum].TextureName) then + else if not g_Map_IsSpecialTexture(Textures[{PanelRec.TextureNum}tnum].TextureName) then begin - FTextureWidth := Textures[PanelRec.TextureNum].Width; - FTextureHeight := Textures[PanelRec.TextureNum].Height; FAlpha := PanelRec.Alpha; FBlending := ByteBool(PanelRec.Flags and PANEL_FLAG_BLENDING); end; end; destructor TPanel.Destroy(); -var - i: Integer; begin - for i := 0 to High(FTextureIDs) do - if FTextureIDs[i].Anim then - FTextureIDs[i].AnTex.Free(); SetLength(FTextureIDs, 0); - Inherited; end; @@ -409,111 +435,6 @@ function TPanel.getIsGBlockMon (): Boolean; inline; begin result := ((tag and Gr function TPanel.gncNeedSend (): Boolean; inline; begin result := mNeedSend; mNeedSend := false; end; procedure TPanel.setDirty (); inline; begin mNeedSend := true; end; - -procedure TPanel.Draw (hasAmbient: Boolean; constref ambColor: TDFColor); -var - xx, yy: Integer; - NoTextureID: DWORD; - NW, NH: Word; -begin - if {Enabled and} (FCurTexture >= 0) and - (Width > 0) and (Height > 0) and (FAlpha < 255) {and - g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)} then - begin - if FTextureIDs[FCurTexture].Anim then - begin // Àíèìèðîâàííàÿ òåêñòóðà - if FTextureIDs[FCurTexture].AnTex = nil then - Exit; - - for xx := 0 to (Width div FTextureWidth)-1 do - for yy := 0 to (Height div FTextureHeight)-1 do - FTextureIDs[FCurTexture].AnTex.Draw( - X + xx*FTextureWidth, - Y + yy*FTextureHeight, M_NONE); - end - else - begin // Îáû÷íàÿ òåêñòóðà - case FTextureIDs[FCurTexture].Tex of - LongWord(TEXTURE_SPECIAL_WATER): e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1, 0, 0, 255, 0, B_FILTER); - LongWord(TEXTURE_SPECIAL_ACID1): e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1, 0, 128, 0, 0, B_FILTER); - LongWord(TEXTURE_SPECIAL_ACID2): e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1, 128, 0, 0, 0, B_FILTER); - LongWord(TEXTURE_NONE): - if g_Texture_Get('NOTEXTURE', NoTextureID) then - begin - e_GetTextureSize(NoTextureID, @NW, @NH); - e_DrawFill(NoTextureID, X, Y, Width div NW, Height div NH, 0, False, False); - end - else - begin - xx := X + (Width div 2); - yy := Y + (Height div 2); - e_DrawFillQuad(X, Y, xx, yy, 255, 0, 255, 0); - e_DrawFillQuad(xx, Y, X+Width-1, yy, 255, 255, 0, 0); - e_DrawFillQuad(X, yy, xx, Y+Height-1, 255, 255, 0, 0); - e_DrawFillQuad(xx, yy, X+Width-1, Y+Height-1, 255, 0, 255, 0); - end; - else - begin - if not mMovingActive then - e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, Width div FTextureWidth, Height div FTextureHeight, FAlpha, True, FBlending, hasAmbient) - else - e_DrawFillX(FTextureIDs[FCurTexture].Tex, X, Y, Width, Height, FAlpha, True, FBlending, g_dbg_scale, hasAmbient); - if hasAmbient then e_AmbientQuad(X, Y, Width, Height, ambColor.r, ambColor.g, ambColor.b, ambColor.a); - end; - end; - end; - end; -end; - -procedure TPanel.DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Integer); - procedure extrude (x: Integer; y: Integer); - begin - glVertex2i(x+(x-lightX)*500, y+(y-lightY)*500); - //e_WriteLog(Format(' : (%d,%d)', [x+(x-lightX)*300, y+(y-lightY)*300]), MSG_WARNING); - end; - - procedure drawLine (x0: Integer; y0: Integer; x1: Integer; y1: Integer); - begin - // does this side facing the light? - if ((x1-x0)*(lightY-y0)-(lightX-x0)*(y1-y0) >= 0) then exit; - //e_WriteLog(Format('lightpan: (%d,%d)-(%d,%d)', [x0, y0, x1, y1]), MSG_WARNING); - // this edge is facing the light, extrude and draw it - glVertex2i(x0, y0); - glVertex2i(x1, y1); - extrude(x1, y1); - extrude(x0, y0); - end; - -begin - if radius < 4 then exit; - if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) {and - g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)} then - begin - if not FTextureIDs[FCurTexture].Anim then - begin - case FTextureIDs[FCurTexture].Tex of - 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; - if (Y+Height < lightY-radius) then exit; - if (X > lightX+radius) then exit; - if (Y > lightY+radius) then exit; - //e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, Width div FTextureWidth, Height div FTextureHeight, FAlpha, True, FBlending); - - glBegin(GL_QUADS); - drawLine(x, y, x+width, y); // top - drawLine(x+width, y, x+width, y+height); // right - drawLine(x+width, y+height, x, y+height); // bottom - drawLine(x, y+height, x, y); // left - glEnd(); - end; -end; - - procedure TPanel.positionChanged (); inline; var px, py, pw, ph: Integer; @@ -527,7 +448,9 @@ begin e_LogWritefln('panel moved: arridx=%s; guid=%s; proxyid=%s; old:(%s,%s)-(%sx%s); new:(%s,%s)-(%sx%s)', [arrIdx, mGUID, proxyId, px, py, pw, ph, x, y, width, height]); } - g_Mark(px, py, pw, ph, MARK_WALL, false); + {$IFDEF ENABLE_GFX} + g_Mark(px, py, pw, ph, MARK_WALL, false); + {$ENDIF} if (Width < 1) or (Height < 1) then begin mapGrid.proxyEnabled[proxyId] := false; @@ -544,7 +467,9 @@ begin begin mapGrid.moveBody(proxyId, X, Y); end; - g_Mark(X, Y, Width, Height, MARK_WALL); + {$IFDEF ENABLE_GFX} + g_Mark(X, Y, Width, Height, MARK_WALL); + {$ENDIF} end; end; end; @@ -561,6 +486,7 @@ var nx, ny, nw, nh: Integer; ex, ey, nex, ney: Integer; mpw, mph: Integer; + conveyor: Boolean; // return `true` if we should move by dx,dy function tryMPlatMove (px, py, pw, ph: Integer; out dx, dy: Integer; out squash: Boolean; ontop: PBoolean=nil): Boolean; @@ -581,7 +507,7 @@ var begin if (ontop <> nil) then ontop^ := true; // yes, move with it; but skip steps (no need to process size change here, 'cause platform top cannot be changed with it) - mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, (GridTagWall or GridTagDoor)); + mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, (GridTagWall or GridTagDoor)); end else begin @@ -609,7 +535,7 @@ var trtag := (GridTagWall or GridTagDoor); // if we're moving down, consider steps too if (szdy > 0) then trtag := trtag or GridTagStep; - mapGrid.traceBox(tex, tey, px, py, pw, ph, szdx, szdy, nil, trtag); + mapGrid.traceBox(tex, tey, px, py, pw, ph, szdx, szdy, trtag); end; end; end; @@ -628,7 +554,7 @@ var trtag := (GridTagWall or GridTagDoor); // if we're moving down, consider steps too if (pdy > 0) then trtag := trtag or GridTagStep; - mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, trtag); + mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, trtag); end; end; end; @@ -636,7 +562,7 @@ var dx := tex-px; dy := tey-py; result := (dx <> 0) or (dy <> 0); - if ((tag and (GridTagWall or GridTagDoor)) <> 0) then + if not conveyor and ((tag and (GridTagWall or GridTagDoor)) <> 0) then begin // check for squashing; as entity cannot be pushed into a wall, check only collision with the platform itself squash := g_Collide(tex, tey, pw, ph, nx, ny, nw, nh); // squash, if still in platform @@ -657,26 +583,22 @@ var px, py, pw, ph, pdx, pdy: Integer; squash: Boolean; plr: TPlayer; - gib: PGib; - cor: TCorpse; + {$IFDEF ENABLE_GIBS} + gib: PGib; + {$ENDIF} + {$IFDEF ENABLE_CORPSES} + cor: TCorpse; + {$ENDIF} + ontop: Boolean; mon: TMonster; + flg: PFlag; + itm: PItem; mpfrid: LongWord; - ontop: Boolean; actMoveTrig: Boolean; actSizeTrig: Boolean; begin if (not Enabled) or (Width < 1) or (Height < 1) then exit; - if (FCurTexture >= 0) and - (FTextureIDs[FCurTexture].Anim) and - (FTextureIDs[FCurTexture].AnTex <> nil) and - (FAlpha < 255) then - begin - FTextureIDs[FCurTexture].AnTex.Update(); - FCurFrame := FTextureIDs[FCurTexture].AnTex.CurrentFrame; - FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter; - end; - if not g_dbgpan_mplat_active then exit; if (mOldMovingActive <> mMovingActive) then mNeedSend := true; @@ -702,10 +624,19 @@ begin mpw := Width; mph := Height; + // the mplat acts as a stationary conveyor belt when it's locked within a movement rect of zero area + conveyor := (mMovingEnd.X = mMovingStart.X) and (mMovingEnd.Y = mMovingStart.Y) + and (mMovingEnd.X = X) and (mMovingEnd.Y = Y); + nw := mpw+mSizeSpeed.w; nh := mph+mSizeSpeed.h; - nx := ox+mMovingSpeed.X; - ny := oy+mMovingSpeed.Y; + nx := ox; + ny := oy; + if not conveyor then + begin + nx += mMovingSpeed.X; + ny += mMovingSpeed.Y; + end; // force network updates only if some sudden change happened // set the flag here, so we can sync affected monsters @@ -766,32 +697,70 @@ begin if not g_Game_IsClient and squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP); end; - // process gibs - for f := 0 to High(gGibs) do - begin - gib := @gGibs[f]; - if not gib.alive then continue; - gib.getMapBox(px, py, pw, ph); - if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; - if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + {$IFDEF ENABLE_GIBS} + // process gibs + for f := 0 to High(gGibs) do begin - // set new position - gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us + gib := @gGibs[f]; + if not gib.alive then continue; + gib.getMapBox(px, py, pw, ph); + if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + begin + // set new position + gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us + end; + end; + {$ENDIF} + + {$IFDEF ENABLE_CORPSES} + // move and push corpses + for f := 0 to High(gCorpses) do + begin + cor := gCorpses[f]; + if (cor = nil) then continue; + cor.getMapBox(px, py, pw, ph); + if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + begin + // set new position + cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us + end; + end; + {$ENDIF} + + // move and push flags + if gGameSettings.GameMode = GM_CTF then + for f := FLAG_RED to FLAG_BLUE do + begin + flg := @gFlags[f]; + if (flg.State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then continue; + px := flg.Obj.X+flg.Obj.Rect.X; + py := flg.Obj.Y+flg.Obj.Rect.Y; + pw := flg.Obj.Rect.Width; + ph := flg.Obj.Rect.Height; + if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + if (pdx <> 0) or (pdy <> 0) then + begin + flg.Obj.X := flg.Obj.X + pdx; + flg.Obj.Y := flg.Obj.Y + pdy; + flg.NeedSend := true; + end; end; - end; - // move and push corpses - for f := 0 to High(gCorpses) do + // move and push items + itm := g_Items_NextAlive(-1); + while itm <> nil do begin - cor := gCorpses[f]; - if (cor = nil) then continue; - cor.getMapBox(px, py, pw, ph); - if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue; - if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + if itm.Fall then begin - // set new position - cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us + itm.getMapBox(px, py, pw, ph); + if g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then + if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then + itm.moveBy(pdx, pdy); // this will call `positionChanged()` for us end; + itm := g_Items_NextAlive(itm.myId); end; // collect monsters @@ -829,8 +798,12 @@ begin end; // move panel + FOldX := X; + FOldY := Y; X := nx; Y := ny; + FOldW := FWidth; + FOldH := FHeight; FWidth := nw; FHeight := nh; positionChanged(); @@ -849,21 +822,24 @@ begin if (nw < 1) or (nh < 1) then mMovingActive := false; //HACK! end; - // reverse moving direction, if necessary - if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then + if not conveyor then begin - if mMoveOnce then mMovingActive := false else mMovingSpeed.X := -mMovingSpeed.X; - actMoveTrig := true; - end; + // reverse moving direction, if necessary + if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then + begin + if mMoveOnce then mMovingActive := false else mMovingSpeed.X := -mMovingSpeed.X; + actMoveTrig := true; + end; - if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then - begin - if mMoveOnce then mMovingActive := false else mMovingSpeed.Y := -mMovingSpeed.Y; - actMoveTrig := true; - end; + if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then + begin + if mMoveOnce then mMovingActive := false else mMovingSpeed.Y := -mMovingSpeed.Y; + actMoveTrig := true; + end; - if (mOldMovingActive <> mMovingActive) then mNeedSend := true; - mOldMovingActive := mMovingActive; + if (mOldMovingActive <> mMovingActive) then mNeedSend := true; + mOldMovingActive := mMovingActive; + end; if not g_Game_IsClient then begin @@ -878,37 +854,21 @@ begin end; end; - -procedure TPanel.SetFrame(Frame: Integer; Count: Byte); - - function ClampInt(X, A, B: Integer): Integer; + procedure TPanel.SetFrame (StartTime: LongWord); begin - Result := X; - if X < A then Result := A else if X > B then Result := B; + if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) then + FAnimTime := StartTime; end; -begin - if Enabled and (FCurTexture >= 0) and - (FTextureIDs[FCurTexture].Anim) and - (FTextureIDs[FCurTexture].AnTex <> nil) and - (Width > 0) and (Height > 0) and (FAlpha < 255) then - begin - FCurFrame := ClampInt(Frame, 0, FTextureIDs[FCurTexture].AnTex.TotalFrames); - FCurFrameCount := Count; - FTextureIDs[FCurTexture].AnTex.CurrentFrame := FCurFrame; - FTextureIDs[FCurTexture].AnTex.CurrentCounter := FCurFrameCount; - end; -end; - procedure TPanel.NextTexture(AnimLoop: Byte = 0); begin Assert(FCurTexture >= -1, 'FCurTexture < -1'); -// Íåò òåêñòóð: +// Нет текстур: if Length(FTextureIDs) = 0 then FCurTexture := -1 else - // Òîëüêî îäíà òåêñòóðà: + // Только одна текстура: if Length(FTextureIDs) = 1 then begin if FCurTexture = 0 then @@ -917,31 +877,22 @@ begin FCurTexture := 0; end else - // Áîëüøå îäíîé òåêñòóðû: + // Больше одной текстуры: begin - // Ñëåäóþùàÿ: + // Следующая: Inc(FCurTexture); - // Ñëåäóþùåé íåò - âîçâðàò ê íà÷àëó: + // Следующей нет - возврат к началу: if FCurTexture >= Length(FTextureIDs) then FCurTexture := 0; end; -// Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó: - if (FCurTexture >= 0) and FTextureIDs[FCurTexture].Anim then + if FCurTexture >= 0 then begin - if (FTextureIDs[FCurTexture].AnTex = nil) then - begin - g_FatalError(_lc[I_GAME_ERROR_SWITCH_TEXTURE]); - Exit; + case AnimLoop of + 1: FAnimLoop := true; + 2: FAnimLoop := false; end; - - if AnimLoop = 1 then - FTextureIDs[FCurTexture].AnTex.Loop := True - else - if AnimLoop = 2 then - FTextureIDs[FCurTexture].AnTex.Loop := False; - - FTextureIDs[FCurTexture].AnTex.Reset(); + FAnimTime := gTime; end; LastAnimLoop := AnimLoop; @@ -949,104 +900,80 @@ end; procedure TPanel.SetTexture(ID: Integer; AnimLoop: Byte = 0); begin -// Íåò òåêñòóð: - if Length(FTextureIDs) = 0 then - FCurTexture := -1 - else - // Òîëüêî îäíà òåêñòóðà: - if Length(FTextureIDs) = 1 then - begin - if (ID = 0) or (ID = -1) then - FCurTexture := ID; - end - else - // Áîëüøå îäíîé òåêñòóðû: - begin - if (ID >= -1) and (ID <= High(FTextureIDs)) then - FCurTexture := ID; - end; + if (ID >= -1) and (ID < Length(FTextureIDs)) then + FCurTexture := ID; -// Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó: - if (FCurTexture >= 0) and FTextureIDs[FCurTexture].Anim then + if FCurTexture >= 0 then begin - if (FTextureIDs[FCurTexture].AnTex = nil) then - begin - g_FatalError(_lc[I_GAME_ERROR_SWITCH_TEXTURE]); - Exit; + case AnimLoop of + 1: FAnimLoop := true; + 2: FAnimLoop := false; end; - - if AnimLoop = 1 then - FTextureIDs[FCurTexture].AnTex.Loop := True - else - if AnimLoop = 2 then - FTextureIDs[FCurTexture].AnTex.Loop := False; - - FTextureIDs[FCurTexture].AnTex.Reset(); + FAnimTime := gTime; end; LastAnimLoop := AnimLoop; end; -function TPanel.GetTextureID(): DWORD; -begin - Result := LongWord(TEXTURE_NONE); - - if (FCurTexture >= 0) then + function TPanel.GetTextureID(): DWORD; + var Texture: Integer; begin - if FTextureIDs[FCurTexture].Anim then - Result := FTextureIDs[FCurTexture].AnTex.FramesID - else - Result := FTextureIDs[FCurTexture].Tex; + Result := LongWord(TEXTURE_NONE); + if (FCurTexture >= 0) then + begin + Texture := FTextureIDs[FCurTexture].Texture; + case Textures[Texture].TextureName of + TEXTURE_NAME_WATER: Result := DWORD(TEXTURE_SPECIAL_WATER); + TEXTURE_NAME_ACID1: Result := DWORD(TEXTURE_SPECIAL_ACID1); + TEXTURE_NAME_ACID2: Result := DWORD(TEXTURE_SPECIAL_ACID2); + end + end end; -end; function TPanel.GetTextureCount(): Integer; begin Result := Length(FTextureIDs); - if Enabled and (FCurTexture >= 0) then - if (FTextureIDs[FCurTexture].Anim) and - (FTextureIDs[FCurTexture].AnTex <> nil) and - (Width > 0) and (Height > 0) and (FAlpha < 255) then - Result := Result + 100; + if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) then + Result := Result + 100; // ??? end; +function TPanel.CanChangeTexture(): Boolean; +begin + Result := (GetTextureCount() > 1) or hasTexTrigger; +end; const PAN_SAVE_VERSION = 1; procedure TPanel.SaveState (st: TStream); -var - anim: Boolean; + var anim: Boolean; stub: TAnimState; begin if (st = nil) then exit; - // Ñèãíàòóðà ïàíåëè + // Сигнатура панели utils.writeSign(st, 'PANL'); utils.writeInt(st, Byte(PAN_SAVE_VERSION)); - // Îòêðûòà/çàêðûòà, åñëè äâåðü + // Открыта/закрыта, если дверь utils.writeBool(st, FEnabled); - // Íàïðàâëåíèå ëèôòà, åñëè ëèôò + // Направление лифта, если лифт utils.writeInt(st, Byte(FLiftType)); - // Íîìåð òåêóùåé òåêñòóðû + // Номер текущей текстуры utils.writeInt(st, Integer(FCurTexture)); - // Êîîðäèíàòû è ðàçìåð + // Координаты и размер utils.writeInt(st, Integer(FX)); utils.writeInt(st, Integer(FY)); utils.writeInt(st, Word(FWidth)); utils.writeInt(st, Word(FHeight)); - // Àíèìèðîâàíà ëè òåêóùàÿ òåêñòóðà - if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) then - begin - assert(FTextureIDs[FCurTexture].AnTex <> nil, 'TPanel.SaveState: No animation object'); - anim := true; - end - else + // Анимирована ли текущая текстура + anim := FCurTexture >= 0; + utils.writeBool(st, anim); + // Если да - сохраняем анимацию + if anim then begin - anim := false; + stub := TAnimState.Create(FAnimLoop, 1, 1); + stub.SaveState(st, FAlpha, FBlending); + stub.Invalidate; end; - utils.writeBool(st, anim); - // Åñëè äà - ñîõðàíÿåì àíèìàöèþ - if anim then FTextureIDs[FCurTexture].AnTex.SaveState(st); // moving platform state utils.writeInt(st, Integer(mMovingSpeed.X)); @@ -1070,32 +997,36 @@ end; procedure TPanel.LoadState (st: TStream); + var stub: TAnimState; begin if (st = nil) then exit; - // Ñèãíàòóðà ïàíåëè + // Сигнатура панели if not utils.checkSign(st, 'PANL') then raise XStreamError.create('wrong panel signature'); if (utils.readByte(st) <> PAN_SAVE_VERSION) then raise XStreamError.create('wrong panel version'); - // Îòêðûòà/çàêðûòà, åñëè äâåðü + // Открыта/закрыта, если дверь FEnabled := utils.readBool(st); - // Íàïðàâëåíèå ëèôòà, åñëè ëèôò + // Направление лифта, если лифт FLiftType := utils.readByte(st); - // Íîìåð òåêóùåé òåêñòóðû + // Номер текущей текстуры FCurTexture := utils.readLongInt(st); - // Êîîðäèíàòû è ðàçìåð + // Координаты и размер FX := utils.readLongInt(st); FY := utils.readLongInt(st); + FOldX := FX; + FOldY := FY; FWidth := utils.readWord(st); FHeight := utils.readWord(st); - // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà + FOldW := FWidth; + FOldH := FHeight; + // Анимированная ли текущая текстура if utils.readBool(st) then begin - // Åñëè äà - çàãðóæàåì àíèìàöèþ - Assert((FCurTexture >= 0) and - (FTextureIDs[FCurTexture].Anim) and - (FTextureIDs[FCurTexture].AnTex <> nil), - 'TPanel.LoadState: No animation object'); - FTextureIDs[FCurTexture].AnTex.LoadState(st); + // Если да - загружаем анимацию + Assert(FCurTexture >= 0, 'TPanel.LoadState: No animation object'); + stub := TAnimState.Create(FAnimLoop, 1, 1); + stub.LoadState(st, FAlpha, FBlending); + stub.Invalidate; end; // moving platform state