X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_panel.pas;h=55190ae2b7dd52d5847d2599501dd457f2b4796b;hb=db9e913bebcfba6251351e97118db8ee01c76cc0;hp=5197654726df8a94a0f2d905f5e9a4cffaa493d3;hpb=f98d08606610e3f3d05b159cfefbaf8bb4874a05;p=d2df-sdl.git diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index 5197654..55190ae 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -49,6 +49,17 @@ type mMovingStart: TDFPoint; mMovingEnd: TDFPoint; mMovingActive: Boolean; + mMoveOnce: Boolean; + + mOldMovingActive: Boolean; + + mSizeSpeed: TDFSize; + mSizeEnd: TDFSize; + + mEndPosTrig: Integer; + mEndSizeTrig: Integer; + + mNeedSend: Boolean; // for network private function getx1 (): Integer; inline; @@ -70,6 +81,16 @@ type function getMovingEndY (): Integer; inline; procedure setMovingEndY (v: Integer); inline; + function getSizeSpeedX (): Integer; inline; + procedure setSizeSpeedX (v: Integer); inline; + function getSizeSpeedY (): Integer; inline; + procedure setSizeSpeedY (v: Integer); inline; + + function getSizeEndX (): Integer; inline; + procedure setSizeEndX (v: Integer); inline; + function getSizeEndY (): Integer; inline; + procedure setSizeEndY (v: Integer); inline; + public FCurTexture: Integer; // Íîìåð òåêóùåé òåêñòóðû FCurFrame: Integer; @@ -77,10 +98,8 @@ type FX, FY: Integer; FWidth, FHeight: Word; FPanelType: Word; - FSaveIt: Boolean; // Ñîõðàíÿòü ïðè SaveState? FEnabled: Boolean; FDoor: Boolean; - FMoved: Boolean; FLiftType: Byte; FLastAnimLoop: Byte; // sorry, there fields are public to allow setting 'em in g_map; this should be fixed later @@ -120,6 +139,10 @@ type function getIsGLift (): Boolean; inline; // gLifts function getIsGBlockMon (): Boolean; inline; // gBlockMon + // get-and-clear + function gncNeedSend (): Boolean; inline; + procedure setDirty (); inline; // why `dirty`? 'cause i may introduce property `needSend` later + public property visvalid: Boolean read getvisvalid; // panel is "visvalid" when it's width and height are positive @@ -134,10 +157,8 @@ type property width: Word read FWidth write FWidth; property height: Word read FHeight write FHeight; property panelType: Word read FPanelType write FPanelType; - property saveIt: Boolean read FSaveIt write FSaveIt; // Ñîõðàíÿòü ïðè SaveState? property enabled: Boolean read FEnabled write FEnabled; // Ñîõðàíÿòü ïðè SaveState? property door: Boolean read FDoor write FDoor; // Ñîõðàíÿòü ïðè SaveState? - property moved: Boolean read FMoved write FMoved; // Ñîõðàíÿòü ïðè SaveState? property liftType: Byte read FLiftType write FLiftType; // Ñîõðàíÿòü ïðè SaveState? property lastAnimLoop: Byte read FLastAnimLoop write FLastAnimLoop; // Ñîõðàíÿòü ïðè SaveState? @@ -148,6 +169,12 @@ type property movingEndX: Integer read getMovingEndX write setMovingEndX; property movingEndY: Integer read getMovingEndY write setMovingEndY; property movingActive: Boolean read mMovingActive write mMovingActive; + property moveOnce: Boolean read mMoveOnce write mMoveOnce; + + property sizeSpeedX: Integer read getSizeSpeedX write setSizeSpeedX; + property sizeSpeedY: Integer read getSizeSpeedY write setSizeSpeedY; + property sizeEndX: Integer read getSizeEndX write setSizeEndX; + property sizeEndY: Integer read getSizeEndY write setSizeEndY; property isGBack: Boolean read getIsGBack; property isGStep: Boolean read getIsGStep; @@ -163,19 +190,25 @@ type property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed; property movingStart: TDFPoint read mMovingStart write mMovingStart; property movingEnd: TDFPoint read mMovingEnd write mMovingEnd; + + property sizeSpeed: TDFSize read mSizeSpeed write mSizeSpeed; + property sizeEnd: TDFSize read mSizeEnd write mSizeEnd; + + property endPosTrigId: Integer read mEndPosTrig write mEndPosTrig; + property endSizeTrigId: Integer read mEndSizeTrig write mEndSizeTrig; end; TPanelArray = Array of TPanel; var - g_dbgpan_mplat_active: Boolean = {$IF DEFINED(D2F_DEBUG)}false{$ELSE}true{$ENDIF}; + g_dbgpan_mplat_active: Boolean = {$IF DEFINED(D2F_DEBUG)}true{$ELSE}true{$ENDIF}; g_dbgpan_mplat_step: Boolean = false; // one step, and stop implementation uses - SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, + SysUtils, 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; const @@ -199,7 +232,6 @@ begin FCurFrame := 0; FCurFrameCount := 0; LastAnimLoop := 0; - Moved := False; mapId := PanelRec.id; mGUID := aguid; @@ -208,43 +240,30 @@ begin mMovingStart := PanelRec.moveStart; mMovingEnd := PanelRec.moveEnd; mMovingActive := PanelRec['move_active'].varvalue; + mOldMovingActive := mMovingActive; + mMoveOnce := PanelRec.moveOnce; + + mSizeSpeed := PanelRec.sizeSpeed; + mSizeEnd := PanelRec.sizeEnd; + + mEndPosTrig := PanelRec.endPosTrig; + mEndSizeTrig := PanelRec.endSizeTrig; + + mNeedSend := false; // Òèï ïàíåëè: PanelType := PanelRec.PanelType; Enabled := True; Door := False; LiftType := 0; - SaveIt := False; case PanelType of - PANEL_OPENDOOR: - begin - Enabled := False; - Door := True; - SaveIt := True; - end; - PANEL_CLOSEDOOR: - begin - Door := True; - SaveIt := True; - end; - PANEL_LIFTUP: - SaveIt := True; - PANEL_LIFTDOWN: - begin - LiftType := 1; - SaveIt := True; - end; - PANEL_LIFTLEFT: - begin - LiftType := 2; - SaveIt := True; - end; - PANEL_LIFTRIGHT: - begin - LiftType := 3; - SaveIt := True; - end; + 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; end; // Íåâèäèìàÿ: @@ -307,7 +326,6 @@ begin True, Textures[AddTextures[i].Texture].Speed); FTextureIDs[i].AnTex.Blending := ByteBool(PanelRec.Flags and PANEL_FLAG_BLENDING); FTextureIDs[i].AnTex.Alpha := PanelRec.Alpha; - SaveIt := True; end else begin // Îáû÷íàÿ òåêñòóðà @@ -316,8 +334,7 @@ begin end; // Òåêñòóð íåñêîëüêî - íóæíî ñîõðàíÿòü òåêóùóþ: - if Length(FTextureIDs) > 1 then - SaveIt := True; + //if Length(FTextureIDs) > 1 then SaveIt := True; // Åñëè íå ñïåöòåêñòóðà, òî çàäàåì ðàçìåðû: if PanelRec.TextureNum > High(Textures) then @@ -368,6 +385,16 @@ procedure TPanel.setMovingEndX (v: Integer); inline; begin mMovingEnd.X := v; en function TPanel.getMovingEndY (): Integer; inline; begin result := mMovingEnd.Y; end; procedure TPanel.setMovingEndY (v: Integer); inline; begin mMovingEnd.Y := v; end; +function TPanel.getSizeSpeedX (): Integer; inline; begin result := mSizeSpeed.w; end; +procedure TPanel.setSizeSpeedX (v: Integer); inline; begin mSizeSpeed.w := v; end; +function TPanel.getSizeSpeedY (): Integer; inline; begin result := mSizeSpeed.h; end; +procedure TPanel.setSizeSpeedY (v: Integer); inline; begin mSizeSpeed.h := v; end; + +function TPanel.getSizeEndX (): Integer; inline; begin result := mSizeEnd.w; end; +procedure TPanel.setSizeEndX (v: Integer); inline; begin mSizeEnd.w := v; end; +function TPanel.getSizeEndY (): Integer; inline; begin result := mSizeEnd.h; end; +procedure TPanel.setSizeEndY (v: Integer); inline; begin mSizeEnd.h := v; end; + function TPanel.getIsGBack (): Boolean; inline; begin result := ((tag and GridTagBack) <> 0); end; function TPanel.getIsGStep (): Boolean; inline; begin result := ((tag and GridTagStep) <> 0); end; function TPanel.getIsGWall (): Boolean; inline; begin result := ((tag and (GridTagWall or GridTagDoor)) <> 0); end; @@ -378,7 +405,11 @@ function TPanel.getIsGFore (): Boolean; inline; begin result := ((tag and GridTa function TPanel.getIsGLift (): Boolean; inline; begin result := ((tag and GridTagLift) <> 0); end; function TPanel.getIsGBlockMon (): Boolean; inline; begin result := ((tag and GridTagBlockMon) <> 0); end; -procedure TPanel.Draw(); +function TPanel.gncNeedSend (): Boolean; inline; begin result := mNeedSend; mNeedSend := false; end; +procedure TPanel.setDirty (); inline; begin mNeedSend := true; end; + + +procedure TPanel.Draw (); var xx, yy: Integer; NoTextureID: DWORD; @@ -432,10 +463,10 @@ begin end; else - e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, - Width div FTextureWidth, - Height div FTextureHeight, - FAlpha, True, FBlending); + if not mMovingActive then + e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, Width div FTextureWidth, Height div FTextureHeight, FAlpha, True, FBlending) + else + e_DrawFillX(FTextureIDs[FCurTexture].Tex, X, Y, Width, Height, FAlpha, True, FBlending, g_dbg_scale); end; end; end; @@ -462,7 +493,8 @@ procedure TPanel.DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Inte 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 + if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) and + ((g_dbg_scale <> 1.0) or g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)) then begin if not FTextureIDs[FCurTexture].Anim then begin @@ -503,9 +535,24 @@ begin [arrIdx, mGUID, proxyId, px, py, pw, ph, x, y, width, height]); } g_Mark(px, py, pw, ph, MARK_WALL, false); - if (pw <> Width) or (ph <> Height) then mapGrid.moveResizeBody(proxyId, X, Y, Width, Height) - else mapGrid.moveBody(proxyId, X, Y); - g_Mark(X, Y, Width, Height, MARK_WALL); + if (Width < 1) or (Height < 1) then + begin + mapGrid.proxyEnabled[proxyId] := false; + end + else + begin + mapGrid.proxyEnabled[proxyId] := Enabled; + if (pw <> Width) or (ph <> Height) then + begin + //writeln('panel resize!'); + mapGrid.moveResizeBody(proxyId, X, Y, Width, Height) + end + else + begin + mapGrid.moveBody(proxyId, X, Y); + end; + g_Mark(X, Y, Width, Height, MARK_WALL); + end; end; end; end; @@ -518,46 +565,63 @@ var procedure TPanel.Update(); var ox, oy: Integer; - nx, ny: Integer; + nx, ny, nw, nh: Integer; ex, ey, nex, ney: Integer; mpw, mph: Integer; // 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; var - u0, u1: Single; + u0: Single; tex, tey: Integer; pdx, pdy: Integer; + trtag: Integer; + szdx, szdy: Integer; begin squash := false; - dx := 0; - dy := 0; + tex := px; + tey := py; pdx := mMovingSpeed.X; pdy := mMovingSpeed.Y; // standing on the platform? if (py+ph = oy) then begin if (ontop <> nil) then ontop^ := true; - // yes, move with it - mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, GridTagObstacle); - //e_LogWritefln('entity on the platform; tracing=(%s,%s); endpoint=(%s,%s); mustbe=(%s,%s)', [px, py, tex, tey, px+pdx, py+pdy]); - // still in platform? - squash := g_Collide(tex, tey, pw, ph, nx, ny, mpw, mph); - dx := tex-px; - dy := tey-py; + // 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)); end else begin if (ontop <> nil) then ontop^ := false; // not standing on the platform: trace platform to see if it hits the entity - // hitedge (for `it`): 0: top; 1: right; 2: bottom; 3: left - { - if g_Collide(px, py, pw, ph, ox, oy, mpw, mph) then + // first, process size change (as we cannot sweeptest both move and size change) + // but we don't have to check for pushing if the panel is shrinking + szdx := nw-mpw; + szdy := nh-mph; + if (szdx > 0) or (szdy > 0) then begin - e_LogWritefln('entity is embedded: plr=(%s,%s)-(%s,%s); mpl=(%s,%s)-(%s,%s)', [px, py, px+pw-1, py+ph-1, ox, oy, ox+mpw-1, oy+mph-1]); + // ignore shrinking dimension + if (szdx < 0) then szdx := 0; + if (szdy < 0) then szdy := 0; + // move platform by szd* back, and check for szd* movement + if sweepAABB(ox-szdx, oy-szdy, nw, nh, szdx, szdy, px, py, pw, ph, @u0) then + begin + // yes, platform hits the entity, push the entity in the resizing direction + u0 := 1.0-u0; // how much path left? + szdx := trunc(szdx*u0); + szdy := trunc(szdy*u0); + if (szdx <> 0) or (szdy <> 0) then + begin + // has some path to go, trace the entity + 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); + end; + end; end; - } - if sweepAABB(ox, oy, mpw, mph, pdx, pdy, px, py, pw, ph, @u0, nil, @u1) then + // second, process platform movement, using te* as entity starting point + if sweepAABB(ox, oy, nw, nh, pdx, pdy, tex, tey, pw, ph, @u0) then begin //e_LogWritefln('T: platsweep; u0=%s; u1=%s; hedge=%s; sweepAABB(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', [u0, u1, hedge, ox, oy, mpw, mph, pdx, pdy, px-1, py-1, pw+2, ph+2]); // yes, platform hits the entity, push the entity in the direction of the platform @@ -568,29 +632,22 @@ var if (pdx <> 0) or (pdy <> 0) then begin // has some path to go, trace the entity - mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, GridTagObstacle); - //e_LogWritefln(' tracebox: te=(%s,%s)', [tex, tey]); - end - else - begin - // no movement - tex := px; - tey := py; + 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); end; - // free to push along the whole path, or path was corrected - // still in platform? - squash := g_Collide(tex, tey, pw, ph, nx, ny, mpw, mph); - dx := tex-px; - dy := tey-py; - end - else - begin - // no collistion, but may be embedded - //e_LogWritefln('F: platsweep; u0=%s; u1=%s; sweepAABB(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', [u0, u1, ox, oy, mpw, mph, pdx, pdy, px-1, py-1, pw+2, ph+2]); - squash := (u1 >= 0.0); end; end; + // done with entity movement, new coords are in te* + dx := tex-px; + dy := tey-py; result := (dx <> 0) or (dy <> 0); + if ((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 + end; end; function monCollect (mon: TMonster): Boolean; @@ -612,6 +669,8 @@ var mon: TMonster; mpfrid: LongWord; ontop: Boolean; + actMoveTrig: Boolean; + actSizeTrig: Boolean; begin if (not Enabled) or (Width < 1) or (Height < 1) then exit; @@ -625,8 +684,17 @@ begin FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter; end; + if not g_dbgpan_mplat_active then exit; + + if (mOldMovingActive <> mMovingActive) then mNeedSend := true; + mOldMovingActive := mMovingActive; + + if not mMovingActive then exit; + if mMovingSpeed.isZero and mSizeSpeed.isZero then exit; + + //TODO: write wall size change processing + // moving platform? - if mMovingActive and (not mMovingSpeed.isZero) and g_dbgpan_mplat_active then begin (* * collect all monsters and players (aka entities) along the possible platform path @@ -636,133 +704,188 @@ begin * try to push entity * if we can't push entity all the way, squash it *) + ox := X; + oy := Y; mpw := Width; mph := Height; - // old rect - ox := X; - oy := Y; - ex := ox+mpw-1; - ey := ox+mph-1; - // new rect + nw := mpw+mSizeSpeed.w; + nh := mph+mSizeSpeed.h; nx := ox+mMovingSpeed.X; ny := oy+mMovingSpeed.Y; - nex := nx+mpw-1; - ney := ny+mph-1; - // full rect - cx0 := nmin(ox, nx); - cy0 := nmin(oy, ny); - cx1 := nmax(ex, nex); - cy1 := nmax(ey, ney); - // extrude - cx0 -= 1; - cy0 -= 1; - cx1 += 1; - cy1 += 1; - cw := cx1-cx0+1; - ch := cy1-cy0+1; - - // temporarily turn off this panel, so it won't interfere with collision checks - mapGrid.proxyEnabled[proxyId] := false; - - // process players - for f := 0 to High(gPlayers) do + + // force network updates only if some sudden change happened + // set the flag here, so we can sync affected monsters + if not mSizeSpeed.isZero and (nw = mSizeEnd.w) and (nh = mSizeEnd.h) then begin - plr := gPlayers[f]; - if (plr = nil) or (not plr.alive) then continue; - plr.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) then - begin - // set new position - plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us - // squash player, if necessary - if squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP); - end; + mNeedSend := true; + end + else if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then + begin + mNeedSend := true; + end + else if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then + begin + mNeedSend := true; end; - // process gibs - for f := 0 to High(gGibs) do + // if pannel disappeared, we don't have to do anything + if (nw > 0) and (nh > 0) then 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 + // old rect + ex := ox+mpw-1; + ey := ox+mph-1; + // new rect + nex := nx+nw-1; + ney := ny+nh-1; + // full rect + cx0 := nmin(ox, nx); + cy0 := nmin(oy, ny); + cx1 := nmax(ex, nex); + cy1 := nmax(ey, ney); + // extrude + cx0 -= 1; + cy0 -= 1; + cx1 += 1; + cy1 += 1; + cw := cx1-cx0+1; + ch := cy1-cy0+1; + + // process "obstacle" panels + if ((tag and GridTagObstacle) <> 0) then begin - // set new position - gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us - { - if ontop then + // temporarily turn off this panel, so it won't interfere with collision checks + mapGrid.proxyEnabled[proxyId] := false; + + // process players + for f := 0 to High(gPlayers) do begin - gib.Obj.Vel.X += pdx; - gib.Obj.Vel.Y += pdy; + plr := gPlayers[f]; + if (plr = nil) or (not plr.alive) then continue; + plr.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) then + begin + // set new position + plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us + end; + // squash player, if necessary + if not g_Game_IsClient and squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP); end; - } - end; - end; - // 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 - { - if ontop then + // process gibs + for f := 0 to High(gGibs) do begin - cor.ObjPtr.Vel.X += pdx; - cor.ObjPtr.Vel.Y += pdy; + 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; - } - end; - end; - // collect monsters - monCheckListUsed := 0; - g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect); + // 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; - // process collected monsters - if (monCheckListUsed > 0) then - begin - mpfrid := g_Mons_getNewMPlatFrameId(); - for f := 0 to monCheckListUsed do - begin - mon := monCheckList[f]; - if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue; - mon.mplatCheckFrameId := mpfrid; - mon.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) then + // collect monsters + monCheckListUsed := 0; + g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect); + + // process collected monsters + if (monCheckListUsed > 0) then begin - // set new position - mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us - // squash player, if necessary - if squash then mon.Damage(15000, 0, 0, 0, HIT_TRAP); + mpfrid := g_Mons_getNewMPlatFrameId(); + for f := 0 to monCheckListUsed do + begin + mon := monCheckList[f]; + if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue; + mon.mplatCheckFrameId := mpfrid; + mon.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) then + begin + // set new position + mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us + //???FIXME: do we really need to send monsters over the net? + // i don't think so, as dead reckoning should take care of 'em + // ok, send new monster position only if platform is going to change it's direction + if mNeedSend then mon.setDirty(); + end; + // squash monster, if necessary + if not g_Game_IsClient and squash then mon.Damage(15000, 0, 0, 0, HIT_TRAP); + end; end; + + // restore panel state + mapGrid.proxyEnabled[proxyId] := true; end; end; - // restore panel state - mapGrid.proxyEnabled[proxyId] := true; - // and really move it + // move panel X := nx; Y := ny; + FWidth := nw; + FHeight := nh; positionChanged(); + actMoveTrig := false; + actSizeTrig := false; + + // `mNeedSend` was set above + + // check "size stop" + if not mSizeSpeed.isZero and (nw = mSizeEnd.w) and (nh = mSizeEnd.h) then + begin + mSizeSpeed.w := 0; + mSizeSpeed.h := 0; + actSizeTrig := true; + if (nw < 1) or (nh < 1) then mMovingActive := false; //HACK! + end; + // reverse moving direction, if necessary - if (mMovingSpeed.X < 0) and (nx <= mMovingStart.X) then mMovingSpeed.X := -mMovingSpeed.X - else if (mMovingSpeed.X > 0) and (nx >= mMovingEnd.X) then mMovingSpeed.X := -mMovingSpeed.X; - if (mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y) then mMovingSpeed.Y := -mMovingSpeed.Y - else if (mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y) then mMovingSpeed.Y := -mMovingSpeed.Y; + 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 (mOldMovingActive <> mMovingActive) then mNeedSend := true; + mOldMovingActive := mMovingActive; + + if not g_Game_IsClient then + begin + if actMoveTrig then g_Triggers_Press(mEndPosTrig, ACTIVATE_CUSTOM); + if actSizeTrig then g_Triggers_Press(mEndSizeTrig, ACTIVATE_CUSTOM); + end; + + // some triggers may activate this, don't delay sending + //TODO: when triggers will be able to control speed and size, check that here too + if (mOldMovingActive <> mMovingActive) then mNeedSend := true; + mOldMovingActive := mMovingActive; end; end; + procedure TPanel.SetFrame(Frame: Integer; Count: Byte); function ClampInt(X, A, B: Integer): Integer; @@ -894,17 +1017,22 @@ begin Result := Result + 100; end; +const + PAN_SAVE_VERSION = 1; + procedure TPanel.SaveState(Var Mem: TBinMemoryWriter); var sig: DWORD; anim: Boolean; + ver: Byte; begin if (Mem = nil) then exit; - //if not SaveIt then exit; // Ñèãíàòóðà ïàíåëè: sig := PANEL_SIGNATURE; // 'PANL' Mem.WriteDWORD(sig); + ver := PAN_SAVE_VERSION; + Mem.WriteByte(ver); // Îòêðûòà/çàêðûòà, åñëè äâåðü: Mem.WriteBoolean(FEnabled); // Íàïðàâëåíèå ëèôòà, åñëè ëèôò: @@ -914,6 +1042,8 @@ begin // Êîîðäû Mem.WriteInt(FX); Mem.WriteInt(FY); + Mem.WriteWord(FWidth); + Mem.WriteWord(FHeight); // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà: if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) then begin @@ -927,6 +1057,7 @@ begin // Åñëè äà - ñîõðàíÿåì àíèìàöèþ: if anim then FTextureIDs[FCurTexture].AnTex.SaveState(Mem); + // moving platform state Mem.WriteInt(mMovingSpeed.X); Mem.WriteInt(mMovingSpeed.Y); @@ -934,24 +1065,32 @@ begin Mem.WriteInt(mMovingStart.Y); Mem.WriteInt(mMovingEnd.X); Mem.WriteInt(mMovingEnd.Y); + + Mem.WriteInt(mSizeSpeed.w); + Mem.WriteInt(mSizeSpeed.h); + Mem.WriteInt(mSizeEnd.w); + Mem.WriteInt(mSizeEnd.h); Mem.WriteBoolean(mMovingActive); + Mem.WriteBoolean(mMoveOnce); + + Mem.WriteInt(mEndPosTrig); + Mem.WriteInt(mEndSizeTrig); end; procedure TPanel.LoadState(var Mem: TBinMemoryReader); var sig: DWORD; anim: Boolean; + ver: Byte; //ox, oy: Integer; begin if (Mem = nil) then exit; - //if not SaveIt then exit; // Ñèãíàòóðà ïàíåëè: Mem.ReadDWORD(sig); - if sig <> PANEL_SIGNATURE then // 'PANL' - begin - raise EBinSizeError.Create('TPanel.LoadState: Wrong Panel Signature'); - end; + if (sig <> PANEL_SIGNATURE) then raise EBinSizeError.Create('TPanel.LoadState: wrong panel signature'); // 'PANL' + Mem.ReadByte(ver); + if (ver <> PAN_SAVE_VERSION) then raise EBinSizeError.Create('TPanel.LoadState: invalid panel version'); // Îòêðûòà/çàêðûòà, åñëè äâåðü: Mem.ReadBoolean(FEnabled); // Íàïðàâëåíèå ëèôòà, åñëè ëèôò: @@ -963,6 +1102,8 @@ begin //oy := FY; Mem.ReadInt(FX); Mem.ReadInt(FY); + Mem.ReadWord(FWidth); + Mem.ReadWord(FHeight); //e_LogWritefln('panel %s(%s): old=(%s,%s); new=(%s,%s); delta=(%s,%s)', [arrIdx, proxyId, ox, oy, FX, FY, FX-ox, FY-oy]); // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà: Mem.ReadBoolean(anim); @@ -975,6 +1116,7 @@ begin 'TPanel.LoadState: No animation object'); FTextureIDs[FCurTexture].AnTex.LoadState(Mem); end; + // moving platform state Mem.ReadInt(mMovingSpeed.X); Mem.ReadInt(mMovingSpeed.Y); @@ -982,7 +1124,15 @@ begin Mem.ReadInt(mMovingStart.Y); Mem.ReadInt(mMovingEnd.X); Mem.ReadInt(mMovingEnd.Y); + Mem.ReadInt(mSizeSpeed.w); + Mem.ReadInt(mSizeSpeed.h); + Mem.ReadInt(mSizeEnd.w); + Mem.ReadInt(mSizeEnd.h); Mem.ReadBoolean(mMovingActive); + Mem.ReadBoolean(mMoveOnce); + + Mem.ReadInt(mEndPosTrig); + Mem.ReadInt(mEndSizeTrig); positionChanged(); //mapGrid.proxyEnabled[proxyId] := FEnabled; // done in g_map.pas