DEADSOFTWARE

network code for mplats: looks like it works; see commit comments for some more info
[d2df-sdl.git] / src / game / g_panel.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 {$M+}
18 unit g_panel;
20 interface
22 uses
23 MAPDEF, BinEditor, g_textures, xdynrec;
25 type
26 TAddTextureArray = Array of
27 record
28 Texture: Cardinal;
29 Anim: Boolean;
30 end;
32 TPanel = Class (TObject)
33 private
34 const
35 private
36 mGUID: Integer; // will be assigned in "g_map.pas"
37 FTextureWidth: Word;
38 FTextureHeight: Word;
39 FAlpha: Byte;
40 FBlending: Boolean;
41 FTextureIDs: Array of
42 record
43 case Anim: Boolean of
44 False: (Tex: Cardinal);
45 True: (AnTex: TAnimation);
46 end;
48 mMovingSpeed: TDFPoint;
49 mMovingStart: TDFPoint;
50 mMovingEnd: TDFPoint;
51 mMovingActive: Boolean;
52 mMoveOnce: Boolean;
54 mOldMovingActive: Boolean;
56 mSizeSpeed: TDFSize;
57 mSizeEnd: TDFSize;
59 mEndPosTrig: Integer;
60 mEndSizeTrig: Integer;
62 mNeedSend: Boolean; // for network
64 private
65 function getx1 (): Integer; inline;
66 function gety1 (): Integer; inline;
67 function getvisvalid (): Boolean; inline;
69 function getMovingSpeedX (): Integer; inline;
70 procedure setMovingSpeedX (v: Integer); inline;
71 function getMovingSpeedY (): Integer; inline;
72 procedure setMovingSpeedY (v: Integer); inline;
74 function getMovingStartX (): Integer; inline;
75 procedure setMovingStartX (v: Integer); inline;
76 function getMovingStartY (): Integer; inline;
77 procedure setMovingStartY (v: Integer); inline;
79 function getMovingEndX (): Integer; inline;
80 procedure setMovingEndX (v: Integer); inline;
81 function getMovingEndY (): Integer; inline;
82 procedure setMovingEndY (v: Integer); inline;
84 function getSizeSpeedX (): Integer; inline;
85 procedure setSizeSpeedX (v: Integer); inline;
86 function getSizeSpeedY (): Integer; inline;
87 procedure setSizeSpeedY (v: Integer); inline;
89 function getSizeEndX (): Integer; inline;
90 procedure setSizeEndX (v: Integer); inline;
91 function getSizeEndY (): Integer; inline;
92 procedure setSizeEndY (v: Integer); inline;
94 public
95 FCurTexture: Integer; // Íîìåð òåêóùåé òåêñòóðû
96 FCurFrame: Integer;
97 FCurFrameCount: Byte;
98 FX, FY: Integer;
99 FWidth, FHeight: Word;
100 FPanelType: Word;
101 FSaveIt: Boolean; // Ñîõðàíÿòü ïðè SaveState?
102 FEnabled: Boolean;
103 FDoor: Boolean;
104 FMoved: Boolean;
105 FLiftType: Byte;
106 FLastAnimLoop: Byte;
107 // sorry, there fields are public to allow setting 'em in g_map; this should be fixed later
108 // for now, PLEASE, don't modify 'em, or all hell will break loose
109 arrIdx: Integer; // index in one of internal arrays; sorry
110 tag: Integer; // used in coldets and such; sorry; see g_map.GridTagXXX
111 proxyId: Integer; // proxy id in map grid (DO NOT USE!)
112 mapId: AnsiString; // taken directly from map file; dunno why it is here
114 constructor Create(PanelRec: TDynRecord;
115 AddTextures: TAddTextureArray;
116 CurTex: Integer;
117 var Textures: TLevelTextureArray; aguid: Integer);
118 destructor Destroy(); override;
120 procedure Draw();
121 procedure DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Integer);
122 procedure Update();
123 procedure SetFrame(Frame: Integer; Count: Byte);
124 procedure NextTexture(AnimLoop: Byte = 0);
125 procedure SetTexture(ID: Integer; AnimLoop: Byte = 0);
126 function GetTextureID(): Cardinal;
127 function GetTextureCount(): Integer;
129 procedure SaveState(var Mem: TBinMemoryWriter);
130 procedure LoadState(var Mem: TBinMemoryReader);
132 procedure positionChanged (); inline;
134 function getIsGBack (): Boolean; inline; // gRenderBackgrounds
135 function getIsGStep (): Boolean; inline; // gSteps
136 function getIsGWall (): Boolean; inline; // gWalls
137 function getIsGAcid1 (): Boolean; inline; // gAcid1
138 function getIsGAcid2 (): Boolean; inline; // gAcid2
139 function getIsGWater (): Boolean; inline; // gWater
140 function getIsGFore (): Boolean; inline; // gRenderForegrounds
141 function getIsGLift (): Boolean; inline; // gLifts
142 function getIsGBlockMon (): Boolean; inline; // gBlockMon
144 // get-and-clear
145 function gncNeedSend (): Boolean; inline;
146 procedure setDirty (); inline; // why `dirty`? 'cause i may introduce property `needSend` later
148 public
149 property visvalid: Boolean read getvisvalid; // panel is "visvalid" when it's width and height are positive
151 published
152 property guid: Integer read mGUID; // will be assigned in "g_map.pas"
153 property x0: Integer read FX;
154 property y0: Integer read FY;
155 property x1: Integer read getx1; // inclusive!
156 property y1: Integer read gety1; // inclusive!
157 property x: Integer read FX write FX;
158 property y: Integer read FY write FY;
159 property width: Word read FWidth write FWidth;
160 property height: Word read FHeight write FHeight;
161 property panelType: Word read FPanelType write FPanelType;
162 property saveIt: Boolean read FSaveIt write FSaveIt; // Ñîõðàíÿòü ïðè SaveState?
163 property enabled: Boolean read FEnabled write FEnabled; // Ñîõðàíÿòü ïðè SaveState?
164 property door: Boolean read FDoor write FDoor; // Ñîõðàíÿòü ïðè SaveState?
165 property moved: Boolean read FMoved write FMoved; // Ñîõðàíÿòü ïðè SaveState?
166 property liftType: Byte read FLiftType write FLiftType; // Ñîõðàíÿòü ïðè SaveState?
167 property lastAnimLoop: Byte read FLastAnimLoop write FLastAnimLoop; // Ñîõðàíÿòü ïðè SaveState?
169 property movingSpeedX: Integer read getMovingSpeedX write setMovingSpeedX;
170 property movingSpeedY: Integer read getMovingSpeedY write setMovingSpeedY;
171 property movingStartX: Integer read getMovingStartX write setMovingStartX;
172 property movingStartY: Integer read getMovingStartY write setMovingStartY;
173 property movingEndX: Integer read getMovingEndX write setMovingEndX;
174 property movingEndY: Integer read getMovingEndY write setMovingEndY;
175 property movingActive: Boolean read mMovingActive write mMovingActive;
176 property moveOnce: Boolean read mMoveOnce write mMoveOnce;
178 property sizeSpeedX: Integer read getSizeSpeedX write setSizeSpeedX;
179 property sizeSpeedY: Integer read getSizeSpeedY write setSizeSpeedY;
180 property sizeEndX: Integer read getSizeEndX write setSizeEndX;
181 property sizeEndY: Integer read getSizeEndY write setSizeEndY;
183 property isGBack: Boolean read getIsGBack;
184 property isGStep: Boolean read getIsGStep;
185 property isGWall: Boolean read getIsGWall;
186 property isGAcid1: Boolean read getIsGAcid1;
187 property isGAcid2: Boolean read getIsGAcid2;
188 property isGWater: Boolean read getIsGWater;
189 property isGFore: Boolean read getIsGFore;
190 property isGLift: Boolean read getIsGLift;
191 property isGBlockMon: Boolean read getIsGBlockMon;
193 public
194 property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed;
195 property movingStart: TDFPoint read mMovingStart write mMovingStart;
196 property movingEnd: TDFPoint read mMovingEnd write mMovingEnd;
198 property sizeSpeed: TDFSize read mSizeSpeed write mSizeSpeed;
199 property sizeEnd: TDFSize read mSizeEnd write mSizeEnd;
201 property endPosTrigId: Integer read mEndPosTrig write mEndPosTrig;
202 property endSizeTrigId: Integer read mEndSizeTrig write mEndSizeTrig;
203 end;
205 TPanelArray = Array of TPanel;
207 var
208 g_dbgpan_mplat_active: Boolean = {$IF DEFINED(D2F_DEBUG)}true{$ELSE}true{$ENDIF};
209 g_dbgpan_mplat_step: Boolean = false; // one step, and stop
212 implementation
214 uses
215 SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, g_triggers,
216 g_console, g_language, g_monsters, g_player, g_grid, e_log, GL, utils;
218 const
219 PANEL_SIGNATURE = $4C4E4150; // 'PANL'
221 { T P a n e l : }
223 constructor TPanel.Create(PanelRec: TDynRecord;
224 AddTextures: TAddTextureArray;
225 CurTex: Integer;
226 var Textures: TLevelTextureArray; aguid: Integer);
227 var
228 i: Integer;
229 begin
230 X := PanelRec.X;
231 Y := PanelRec.Y;
232 Width := PanelRec.Width;
233 Height := PanelRec.Height;
234 FAlpha := 0;
235 FBlending := False;
236 FCurFrame := 0;
237 FCurFrameCount := 0;
238 LastAnimLoop := 0;
239 Moved := False;
241 mapId := PanelRec.id;
242 mGUID := aguid;
244 mMovingSpeed := PanelRec.moveSpeed;
245 mMovingStart := PanelRec.moveStart;
246 mMovingEnd := PanelRec.moveEnd;
247 mMovingActive := PanelRec['move_active'].varvalue;
248 mOldMovingActive := mMovingActive;
249 mMoveOnce := PanelRec.moveOnce;
251 mSizeSpeed := PanelRec.sizeSpeed;
252 mSizeEnd := PanelRec.sizeEnd;
254 mEndPosTrig := PanelRec.endPosTrig;
255 mEndSizeTrig := PanelRec.endSizeTrig;
257 mNeedSend := false;
259 // Òèï ïàíåëè:
260 PanelType := PanelRec.PanelType;
261 Enabled := True;
262 Door := False;
263 LiftType := 0;
264 SaveIt := False;
266 case PanelType of
267 PANEL_OPENDOOR:
268 begin
269 Enabled := False;
270 Door := True;
271 SaveIt := True;
272 end;
273 PANEL_CLOSEDOOR:
274 begin
275 Door := True;
276 SaveIt := True;
277 end;
278 PANEL_LIFTUP:
279 SaveIt := True;
280 PANEL_LIFTDOWN:
281 begin
282 LiftType := 1;
283 SaveIt := True;
284 end;
285 PANEL_LIFTLEFT:
286 begin
287 LiftType := 2;
288 SaveIt := True;
289 end;
290 PANEL_LIFTRIGHT:
291 begin
292 LiftType := 3;
293 SaveIt := True;
294 end;
295 end;
297 // Íåâèäèìàÿ:
298 if ByteBool(PanelRec.Flags and PANEL_FLAG_HIDE) then
299 begin
300 SetLength(FTextureIDs, 0);
301 FCurTexture := -1;
302 Exit;
303 end;
304 // Ïàíåëè, íå èñïîëüçóþùèå òåêñòóðû:
305 if ByteBool(PanelType and
306 (PANEL_LIFTUP or
307 PANEL_LIFTDOWN or
308 PANEL_LIFTLEFT or
309 PANEL_LIFTRIGHT or
310 PANEL_BLOCKMON)) then
311 begin
312 SetLength(FTextureIDs, 0);
313 FCurTexture := -1;
314 Exit;
315 end;
317 // Åñëè ýòî æèäêîñòü áåç òåêñòóðû - ñïåöòåêñòóðó:
318 if WordBool(PanelType and (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2)) and
319 (not ByteBool(PanelRec.Flags and PANEL_FLAG_WATERTEXTURES)) then
320 begin
321 SetLength(FTextureIDs, 1);
322 FTextureIDs[0].Anim := False;
324 case PanelRec.PanelType of
325 PANEL_WATER:
326 FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_WATER);
327 PANEL_ACID1:
328 FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID1);
329 PANEL_ACID2:
330 FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID2);
331 end;
333 FCurTexture := 0;
334 Exit;
335 end;
337 SetLength(FTextureIDs, Length(AddTextures));
339 if CurTex < 0 then
340 FCurTexture := -1
341 else
342 if CurTex >= Length(FTextureIDs) then
343 FCurTexture := Length(FTextureIDs) - 1
344 else
345 FCurTexture := CurTex;
347 for i := 0 to Length(FTextureIDs)-1 do
348 begin
349 FTextureIDs[i].Anim := AddTextures[i].Anim;
350 if FTextureIDs[i].Anim then
351 begin // Àíèìèðîâàííàÿ òåêñòóðà
352 FTextureIDs[i].AnTex :=
353 TAnimation.Create(Textures[AddTextures[i].Texture].FramesID,
354 True, Textures[AddTextures[i].Texture].Speed);
355 FTextureIDs[i].AnTex.Blending := ByteBool(PanelRec.Flags and PANEL_FLAG_BLENDING);
356 FTextureIDs[i].AnTex.Alpha := PanelRec.Alpha;
357 SaveIt := True;
358 end
359 else
360 begin // Îáû÷íàÿ òåêñòóðà
361 FTextureIDs[i].Tex := Textures[AddTextures[i].Texture].TextureID;
362 end;
363 end;
365 // Òåêñòóð íåñêîëüêî - íóæíî ñîõðàíÿòü òåêóùóþ:
366 if Length(FTextureIDs) > 1 then
367 SaveIt := True;
369 // Åñëè íå ñïåöòåêñòóðà, òî çàäàåì ðàçìåðû:
370 if PanelRec.TextureNum > High(Textures) then
371 begin
372 e_WriteLog(Format('WTF?! PanelRec.TextureNum is out of limits! (%d : %d)', [PanelRec.TextureNum, High(Textures)]), MSG_FATALERROR);
373 FTextureWidth := 2;
374 FTextureHeight := 2;
375 FAlpha := 0;
376 FBlending := ByteBool(0);
377 end
378 else if not g_Map_IsSpecialTexture(Textures[PanelRec.TextureNum].TextureName) then
379 begin
380 FTextureWidth := Textures[PanelRec.TextureNum].Width;
381 FTextureHeight := Textures[PanelRec.TextureNum].Height;
382 FAlpha := PanelRec.Alpha;
383 FBlending := ByteBool(PanelRec.Flags and PANEL_FLAG_BLENDING);
384 end;
385 end;
387 destructor TPanel.Destroy();
388 var
389 i: Integer;
390 begin
391 for i := 0 to High(FTextureIDs) do
392 if FTextureIDs[i].Anim then
393 FTextureIDs[i].AnTex.Free();
394 SetLength(FTextureIDs, 0);
396 Inherited;
397 end;
399 function TPanel.getx1 (): Integer; inline; begin result := X+Width-1; end;
400 function TPanel.gety1 (): Integer; inline; begin result := Y+Height-1; end;
401 function TPanel.getvisvalid (): Boolean; inline; begin result := (Width > 0) and (Height > 0); end;
403 function TPanel.getMovingSpeedX (): Integer; inline; begin result := mMovingSpeed.X; end;
404 procedure TPanel.setMovingSpeedX (v: Integer); inline; begin mMovingSpeed.X := v; end;
405 function TPanel.getMovingSpeedY (): Integer; inline; begin result := mMovingSpeed.Y; end;
406 procedure TPanel.setMovingSpeedY (v: Integer); inline; begin mMovingSpeed.Y := v; end;
408 function TPanel.getMovingStartX (): Integer; inline; begin result := mMovingStart.X; end;
409 procedure TPanel.setMovingStartX (v: Integer); inline; begin mMovingStart.X := v; end;
410 function TPanel.getMovingStartY (): Integer; inline; begin result := mMovingStart.Y; end;
411 procedure TPanel.setMovingStartY (v: Integer); inline; begin mMovingStart.Y := v; end;
413 function TPanel.getMovingEndX (): Integer; inline; begin result := mMovingEnd.X; end;
414 procedure TPanel.setMovingEndX (v: Integer); inline; begin mMovingEnd.X := v; end;
415 function TPanel.getMovingEndY (): Integer; inline; begin result := mMovingEnd.Y; end;
416 procedure TPanel.setMovingEndY (v: Integer); inline; begin mMovingEnd.Y := v; end;
418 function TPanel.getSizeSpeedX (): Integer; inline; begin result := mSizeSpeed.w; end;
419 procedure TPanel.setSizeSpeedX (v: Integer); inline; begin mSizeSpeed.w := v; end;
420 function TPanel.getSizeSpeedY (): Integer; inline; begin result := mSizeSpeed.h; end;
421 procedure TPanel.setSizeSpeedY (v: Integer); inline; begin mSizeSpeed.h := v; end;
423 function TPanel.getSizeEndX (): Integer; inline; begin result := mSizeEnd.w; end;
424 procedure TPanel.setSizeEndX (v: Integer); inline; begin mSizeEnd.w := v; end;
425 function TPanel.getSizeEndY (): Integer; inline; begin result := mSizeEnd.h; end;
426 procedure TPanel.setSizeEndY (v: Integer); inline; begin mSizeEnd.h := v; end;
428 function TPanel.getIsGBack (): Boolean; inline; begin result := ((tag and GridTagBack) <> 0); end;
429 function TPanel.getIsGStep (): Boolean; inline; begin result := ((tag and GridTagStep) <> 0); end;
430 function TPanel.getIsGWall (): Boolean; inline; begin result := ((tag and (GridTagWall or GridTagDoor)) <> 0); end;
431 function TPanel.getIsGAcid1 (): Boolean; inline; begin result := ((tag and GridTagAcid1) <> 0); end;
432 function TPanel.getIsGAcid2 (): Boolean; inline; begin result := ((tag and GridTagAcid2) <> 0); end;
433 function TPanel.getIsGWater (): Boolean; inline; begin result := ((tag and GridTagWater) <> 0); end;
434 function TPanel.getIsGFore (): Boolean; inline; begin result := ((tag and GridTagFore) <> 0); end;
435 function TPanel.getIsGLift (): Boolean; inline; begin result := ((tag and GridTagLift) <> 0); end;
436 function TPanel.getIsGBlockMon (): Boolean; inline; begin result := ((tag and GridTagBlockMon) <> 0); end;
438 function TPanel.gncNeedSend (): Boolean; inline; begin result := mNeedSend; mNeedSend := false; end;
439 procedure TPanel.setDirty (); inline; begin mNeedSend := true; end;
442 procedure TPanel.Draw ();
443 var
444 xx, yy: Integer;
445 NoTextureID: DWORD;
446 NW, NH: Word;
447 begin
448 if {Enabled and} (FCurTexture >= 0) and
449 (Width > 0) and (Height > 0) and (FAlpha < 255) and
450 ((g_dbg_scale <> 1.0) or g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)) then
451 begin
452 if FTextureIDs[FCurTexture].Anim then
453 begin // Àíèìèðîâàííàÿ òåêñòóðà
454 if FTextureIDs[FCurTexture].AnTex = nil then
455 Exit;
457 for xx := 0 to (Width div FTextureWidth)-1 do
458 for yy := 0 to (Height div FTextureHeight)-1 do
459 FTextureIDs[FCurTexture].AnTex.Draw(
460 X + xx*FTextureWidth,
461 Y + yy*FTextureHeight, M_NONE);
462 end
463 else
464 begin // Îáû÷íàÿ òåêñòóðà
465 case FTextureIDs[FCurTexture].Tex of
466 LongWord(TEXTURE_SPECIAL_WATER):
467 e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1,
468 0, 0, 255, 0, B_FILTER);
469 LongWord(TEXTURE_SPECIAL_ACID1):
470 e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1,
471 0, 128, 0, 0, B_FILTER);
472 LongWord(TEXTURE_SPECIAL_ACID2):
473 e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1,
474 128, 0, 0, 0, B_FILTER);
475 LongWord(TEXTURE_NONE):
476 if g_Texture_Get('NOTEXTURE', NoTextureID) then
477 begin
478 e_GetTextureSize(NoTextureID, @NW, @NH);
479 e_DrawFill(NoTextureID, X, Y, Width div NW, Height div NH,
480 0, False, False);
481 end else
482 begin
483 xx := X + (Width div 2);
484 yy := Y + (Height div 2);
485 e_DrawFillQuad(X, Y, xx, yy,
486 255, 0, 255, 0);
487 e_DrawFillQuad(xx, Y, X+Width-1, yy,
488 255, 255, 0, 0);
489 e_DrawFillQuad(X, yy, xx, Y+Height-1,
490 255, 255, 0, 0);
491 e_DrawFillQuad(xx, yy, X+Width-1, Y+Height-1,
492 255, 0, 255, 0);
493 end;
495 else
496 if not mMovingActive then
497 e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, Width div FTextureWidth, Height div FTextureHeight, FAlpha, True, FBlending)
498 else
499 e_DrawFillX(FTextureIDs[FCurTexture].Tex, X, Y, Width, Height, FAlpha, True, FBlending, g_dbg_scale);
500 end;
501 end;
502 end;
503 end;
505 procedure TPanel.DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Integer);
506 procedure extrude (x: Integer; y: Integer);
507 begin
508 glVertex2i(x+(x-lightX)*500, y+(y-lightY)*500);
509 //e_WriteLog(Format(' : (%d,%d)', [x+(x-lightX)*300, y+(y-lightY)*300]), MSG_WARNING);
510 end;
512 procedure drawLine (x0: Integer; y0: Integer; x1: Integer; y1: Integer);
513 begin
514 // does this side facing the light?
515 if ((x1-x0)*(lightY-y0)-(lightX-x0)*(y1-y0) >= 0) then exit;
516 //e_WriteLog(Format('lightpan: (%d,%d)-(%d,%d)', [x0, y0, x1, y1]), MSG_WARNING);
517 // this edge is facing the light, extrude and draw it
518 glVertex2i(x0, y0);
519 glVertex2i(x1, y1);
520 extrude(x1, y1);
521 extrude(x0, y0);
522 end;
524 begin
525 if radius < 4 then exit;
526 if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) and
527 ((g_dbg_scale <> 1.0) or g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)) then
528 begin
529 if not FTextureIDs[FCurTexture].Anim then
530 begin
531 case FTextureIDs[FCurTexture].Tex of
532 LongWord(TEXTURE_SPECIAL_WATER): exit;
533 LongWord(TEXTURE_SPECIAL_ACID1): exit;
534 LongWord(TEXTURE_SPECIAL_ACID2): exit;
535 LongWord(TEXTURE_NONE): exit;
536 end;
537 end;
538 if (X+Width < lightX-radius) then exit;
539 if (Y+Height < lightY-radius) then exit;
540 if (X > lightX+radius) then exit;
541 if (Y > lightY+radius) then exit;
542 //e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, Width div FTextureWidth, Height div FTextureHeight, FAlpha, True, FBlending);
544 glBegin(GL_QUADS);
545 drawLine(x, y, x+width, y); // top
546 drawLine(x+width, y, x+width, y+height); // right
547 drawLine(x+width, y+height, x, y+height); // bottom
548 drawLine(x, y+height, x, y); // left
549 glEnd();
550 end;
551 end;
554 procedure TPanel.positionChanged (); inline;
555 var
556 px, py, pw, ph: Integer;
557 begin
558 if (proxyId >= 0) then
559 begin
560 mapGrid.getBodyDims(proxyId, px, py, pw, ph);
561 if (px <> x) or (py <> y) or (pw <> Width) or (ph <> Height) then
562 begin
564 e_LogWritefln('panel moved: arridx=%s; guid=%s; proxyid=%s; old:(%s,%s)-(%sx%s); new:(%s,%s)-(%sx%s)',
565 [arrIdx, mGUID, proxyId, px, py, pw, ph, x, y, width, height]);
567 g_Mark(px, py, pw, ph, MARK_WALL, false);
568 if (Width < 1) or (Height < 1) then
569 begin
570 mapGrid.proxyEnabled[proxyId] := false;
571 end
572 else
573 begin
574 mapGrid.proxyEnabled[proxyId] := Enabled;
575 if (pw <> Width) or (ph <> Height) then
576 begin
577 //writeln('panel resize!');
578 mapGrid.moveResizeBody(proxyId, X, Y, Width, Height)
579 end
580 else
581 begin
582 mapGrid.moveBody(proxyId, X, Y);
583 end;
584 g_Mark(X, Y, Width, Height, MARK_WALL);
585 end;
586 end;
587 end;
588 end;
591 var
592 monCheckList: array of TMonster = nil;
593 monCheckListUsed: Integer = 0;
595 procedure TPanel.Update();
596 var
597 ox, oy: Integer;
598 nx, ny, nw, nh: Integer;
599 ex, ey, nex, ney: Integer;
600 mpw, mph: Integer;
602 // return `true` if we should move by dx,dy
603 function tryMPlatMove (px, py, pw, ph: Integer; out dx, dy: Integer; out squash: Boolean; ontop: PBoolean=nil): Boolean;
604 var
605 u0: Single;
606 tex, tey: Integer;
607 pdx, pdy: Integer;
608 trtag: Integer;
609 szdx, szdy: Integer;
610 begin
611 squash := false;
612 tex := px;
613 tey := py;
614 pdx := mMovingSpeed.X;
615 pdy := mMovingSpeed.Y;
616 // standing on the platform?
617 if (py+ph = oy) then
618 begin
619 if (ontop <> nil) then ontop^ := true;
620 // yes, move with it; but skip steps (no need to process size change here, 'cause platform top cannot be changed with it)
621 mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, (GridTagWall or GridTagDoor));
622 end
623 else
624 begin
625 if (ontop <> nil) then ontop^ := false;
626 // not standing on the platform: trace platform to see if it hits the entity
627 // first, process size change (as we cannot sweeptest both move and size change)
628 // but we don't have to check for pushing if the panel is shrinking
629 szdx := nw-mpw;
630 szdy := nh-mph;
631 if (szdx > 0) or (szdy > 0) then
632 begin
633 // ignore shrinking dimension
634 if (szdx < 0) then szdx := 0;
635 if (szdy < 0) then szdy := 0;
636 // move platform by szd* back, and check for szd* movement
637 if sweepAABB(ox-szdx, oy-szdy, nw, nh, szdx, szdy, px, py, pw, ph, @u0) then
638 begin
639 // yes, platform hits the entity, push the entity in the resizing direction
640 u0 := 1.0-u0; // how much path left?
641 szdx := trunc(szdx*u0);
642 szdy := trunc(szdy*u0);
643 if (szdx <> 0) or (szdy <> 0) then
644 begin
645 // has some path to go, trace the entity
646 trtag := (GridTagWall or GridTagDoor);
647 // if we're moving down, consider steps too
648 if (szdy > 0) then trtag := trtag or GridTagStep;
649 mapGrid.traceBox(tex, tey, px, py, pw, ph, szdx, szdy, nil, trtag);
650 end;
651 end;
652 end;
653 // second, process platform movement, using te* as entity starting point
654 if sweepAABB(ox, oy, nw, nh, pdx, pdy, tex, tey, pw, ph, @u0) then
655 begin
656 //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]);
657 // yes, platform hits the entity, push the entity in the direction of the platform
658 u0 := 1.0-u0; // how much path left?
659 pdx := trunc(pdx*u0);
660 pdy := trunc(pdy*u0);
661 //e_LogWritefln(' platsweep; uleft=%s; pd=(%s,%s)', [u0, pdx, pdy]);
662 if (pdx <> 0) or (pdy <> 0) then
663 begin
664 // has some path to go, trace the entity
665 trtag := (GridTagWall or GridTagDoor);
666 // if we're moving down, consider steps too
667 if (pdy > 0) then trtag := trtag or GridTagStep;
668 mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, trtag);
669 end;
670 end;
671 end;
672 // done with entity movement, new coords are in te*
673 dx := tex-px;
674 dy := tey-py;
675 result := (dx <> 0) or (dy <> 0);
676 if ((tag and (GridTagWall or GridTagDoor)) <> 0) then
677 begin
678 // check for squashing; as entity cannot be pushed into a wall, check only collision with the platform itself
679 squash := g_Collide(tex, tey, pw, ph, nx, ny, nw, nh); // squash, if still in platform
680 end;
681 end;
683 function monCollect (mon: TMonster): Boolean;
684 begin
685 result := false; // don't stop
686 if (monCheckListUsed >= Length(monCheckList)) then SetLength(monCheckList, monCheckListUsed+128);
687 monCheckList[monCheckListUsed] := mon;
688 Inc(monCheckListUsed);
689 end;
691 var
692 cx0, cy0, cx1, cy1, cw, ch: Integer;
693 f: Integer;
694 px, py, pw, ph, pdx, pdy: Integer;
695 squash: Boolean;
696 plr: TPlayer;
697 gib: PGib;
698 cor: TCorpse;
699 mon: TMonster;
700 mpfrid: LongWord;
701 ontop: Boolean;
702 actMoveTrig: Boolean;
703 actSizeTrig: Boolean;
704 begin
705 if (not Enabled) or (Width < 1) or (Height < 1) then exit;
707 if (FCurTexture >= 0) and
708 (FTextureIDs[FCurTexture].Anim) and
709 (FTextureIDs[FCurTexture].AnTex <> nil) and
710 (FAlpha < 255) then
711 begin
712 FTextureIDs[FCurTexture].AnTex.Update();
713 FCurFrame := FTextureIDs[FCurTexture].AnTex.CurrentFrame;
714 FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter;
715 end;
717 if not g_dbgpan_mplat_active then exit;
719 if (mOldMovingActive <> mMovingActive) then mNeedSend := true;
720 mOldMovingActive := mMovingActive;
722 if not mMovingActive then exit;
723 if mMovingSpeed.isZero and mSizeSpeed.isZero then exit;
725 //TODO: write wall size change processing
727 // moving platform?
728 begin
729 (*
730 * collect all monsters and players (aka entities) along the possible platform path
731 * if entity is standing on a platform:
732 * try to move it along the platform path, checking wall collisions
733 * if entity is NOT standing on a platform, but hit with sweeped platform aabb:
734 * try to push entity
735 * if we can't push entity all the way, squash it
736 *)
737 ox := X;
738 oy := Y;
739 mpw := Width;
740 mph := Height;
742 nw := mpw+mSizeSpeed.w;
743 nh := mph+mSizeSpeed.h;
744 nx := ox+mMovingSpeed.X;
745 ny := oy+mMovingSpeed.Y;
747 // force network updates only if some sudden change happened
748 // set the flag here, so we can sync affected monsters
749 if not mSizeSpeed.isZero and (nw = mSizeEnd.w) and (nh = mSizeEnd.h) then
750 begin
751 mNeedSend := true;
752 end
753 else if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then
754 begin
755 mNeedSend := true;
756 end
757 else if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then
758 begin
759 mNeedSend := true;
760 end;
762 // if pannel disappeared, we don't have to do anything
763 if (nw > 0) and (nh > 0) then
764 begin
765 // old rect
766 ex := ox+mpw-1;
767 ey := ox+mph-1;
768 // new rect
769 nex := nx+nw-1;
770 ney := ny+nh-1;
771 // full rect
772 cx0 := nmin(ox, nx);
773 cy0 := nmin(oy, ny);
774 cx1 := nmax(ex, nex);
775 cy1 := nmax(ey, ney);
776 // extrude
777 cx0 -= 1;
778 cy0 -= 1;
779 cx1 += 1;
780 cy1 += 1;
781 cw := cx1-cx0+1;
782 ch := cy1-cy0+1;
784 // process "obstacle" panels
785 if ((tag and GridTagObstacle) <> 0) then
786 begin
787 // temporarily turn off this panel, so it won't interfere with collision checks
788 mapGrid.proxyEnabled[proxyId] := false;
790 // process players
791 for f := 0 to High(gPlayers) do
792 begin
793 plr := gPlayers[f];
794 if (plr = nil) or (not plr.alive) then continue;
795 plr.getMapBox(px, py, pw, ph);
796 if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
797 if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then
798 begin
799 // set new position
800 plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us
801 end;
802 // squash player, if necessary
803 if not g_Game_IsClient and squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP);
804 end;
806 // process gibs
807 for f := 0 to High(gGibs) do
808 begin
809 gib := @gGibs[f];
810 if not gib.alive then continue;
811 gib.getMapBox(px, py, pw, ph);
812 if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
813 if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
814 begin
815 // set new position
816 gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us
817 end;
818 end;
820 // move and push corpses
821 for f := 0 to High(gCorpses) do
822 begin
823 cor := gCorpses[f];
824 if (cor = nil) then continue;
825 cor.getMapBox(px, py, pw, ph);
826 if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
827 if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
828 begin
829 // set new position
830 cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
831 end;
832 end;
834 // collect monsters
835 monCheckListUsed := 0;
836 g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect);
838 // process collected monsters
839 if (monCheckListUsed > 0) then
840 begin
841 mpfrid := g_Mons_getNewMPlatFrameId();
842 for f := 0 to monCheckListUsed do
843 begin
844 mon := monCheckList[f];
845 if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue;
846 mon.mplatCheckFrameId := mpfrid;
847 mon.getMapBox(px, py, pw, ph);
848 //if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
849 if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then
850 begin
851 // set new position
852 mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us
853 //???FIXME: do we really need to send monsters over the net?
854 // i don't think so, as dead reckoning should take care of 'em
855 // ok, send new monster position only if platform is going to change it's direction
856 if mNeedSend then mon.setDirty();
857 end;
858 // squash monster, if necessary
859 if not g_Game_IsClient and squash then mon.Damage(15000, 0, 0, 0, HIT_TRAP);
860 end;
861 end;
863 // restore panel state
864 mapGrid.proxyEnabled[proxyId] := true;
865 end;
866 end;
868 // move panel
869 X := nx;
870 Y := ny;
871 FWidth := nw;
872 FHeight := nh;
873 positionChanged();
875 actMoveTrig := false;
876 actSizeTrig := false;
878 // `mNeedSend` was set above
880 // check "size stop"
881 if not mSizeSpeed.isZero and (nw = mSizeEnd.w) and (nh = mSizeEnd.h) then
882 begin
883 mSizeSpeed.w := 0;
884 mSizeSpeed.h := 0;
885 actSizeTrig := true;
886 if (nw < 1) or (nh < 1) then mMovingActive := false; //HACK!
887 end;
889 // reverse moving direction, if necessary
890 if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then
891 begin
892 if mMoveOnce then mMovingActive := false else mMovingSpeed.X := -mMovingSpeed.X;
893 actMoveTrig := true;
894 end;
896 if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then
897 begin
898 if mMoveOnce then mMovingActive := false else mMovingSpeed.Y := -mMovingSpeed.Y;
899 actMoveTrig := true;
900 end;
902 if (mOldMovingActive <> mMovingActive) then mNeedSend := true;
903 mOldMovingActive := mMovingActive;
905 if g_Game_IsServer and g_Game_IsNet then
906 begin
907 if actMoveTrig then g_Triggers_Press(mEndPosTrig, ACTIVATE_CUSTOM);
908 if actSizeTrig then g_Triggers_Press(mEndSizeTrig, ACTIVATE_CUSTOM);
909 end;
911 // some triggers may activate this, don't delay sending
912 //TODO: when triggers will be able to control speed and size, check that here too
913 if (mOldMovingActive <> mMovingActive) then mNeedSend := true;
914 mOldMovingActive := mMovingActive;
915 end;
916 end;
919 procedure TPanel.SetFrame(Frame: Integer; Count: Byte);
921 function ClampInt(X, A, B: Integer): Integer;
922 begin
923 Result := X;
924 if X < A then Result := A else if X > B then Result := B;
925 end;
927 begin
928 if Enabled and (FCurTexture >= 0) and
929 (FTextureIDs[FCurTexture].Anim) and
930 (FTextureIDs[FCurTexture].AnTex <> nil) and
931 (Width > 0) and (Height > 0) and (FAlpha < 255) then
932 begin
933 FCurFrame := ClampInt(Frame, 0, FTextureIDs[FCurTexture].AnTex.TotalFrames);
934 FCurFrameCount := Count;
935 FTextureIDs[FCurTexture].AnTex.CurrentFrame := FCurFrame;
936 FTextureIDs[FCurTexture].AnTex.CurrentCounter := FCurFrameCount;
937 end;
938 end;
940 procedure TPanel.NextTexture(AnimLoop: Byte = 0);
941 begin
942 Assert(FCurTexture >= -1, 'FCurTexture < -1');
944 // Íåò òåêñòóð:
945 if Length(FTextureIDs) = 0 then
946 FCurTexture := -1
947 else
948 // Òîëüêî îäíà òåêñòóðà:
949 if Length(FTextureIDs) = 1 then
950 begin
951 if FCurTexture = 0 then
952 FCurTexture := -1
953 else
954 FCurTexture := 0;
955 end
956 else
957 // Áîëüøå îäíîé òåêñòóðû:
958 begin
959 // Ñëåäóþùàÿ:
960 Inc(FCurTexture);
961 // Ñëåäóþùåé íåò - âîçâðàò ê íà÷àëó:
962 if FCurTexture >= Length(FTextureIDs) then
963 FCurTexture := 0;
964 end;
966 // Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó:
967 if (FCurTexture >= 0) and FTextureIDs[FCurTexture].Anim then
968 begin
969 if (FTextureIDs[FCurTexture].AnTex = nil) then
970 begin
971 g_FatalError(_lc[I_GAME_ERROR_SWITCH_TEXTURE]);
972 Exit;
973 end;
975 if AnimLoop = 1 then
976 FTextureIDs[FCurTexture].AnTex.Loop := True
977 else
978 if AnimLoop = 2 then
979 FTextureIDs[FCurTexture].AnTex.Loop := False;
981 FTextureIDs[FCurTexture].AnTex.Reset();
982 end;
984 LastAnimLoop := AnimLoop;
985 end;
987 procedure TPanel.SetTexture(ID: Integer; AnimLoop: Byte = 0);
988 begin
989 // Íåò òåêñòóð:
990 if Length(FTextureIDs) = 0 then
991 FCurTexture := -1
992 else
993 // Òîëüêî îäíà òåêñòóðà:
994 if Length(FTextureIDs) = 1 then
995 begin
996 if (ID = 0) or (ID = -1) then
997 FCurTexture := ID;
998 end
999 else
1000 // Áîëüøå îäíîé òåêñòóðû:
1001 begin
1002 if (ID >= -1) and (ID <= High(FTextureIDs)) then
1003 FCurTexture := ID;
1004 end;
1006 // Ïåðåêëþ÷èëèñü íà âèäèìóþ àíèì. òåêñòóðó:
1007 if (FCurTexture >= 0) and FTextureIDs[FCurTexture].Anim then
1008 begin
1009 if (FTextureIDs[FCurTexture].AnTex = nil) then
1010 begin
1011 g_FatalError(_lc[I_GAME_ERROR_SWITCH_TEXTURE]);
1012 Exit;
1013 end;
1015 if AnimLoop = 1 then
1016 FTextureIDs[FCurTexture].AnTex.Loop := True
1017 else
1018 if AnimLoop = 2 then
1019 FTextureIDs[FCurTexture].AnTex.Loop := False;
1021 FTextureIDs[FCurTexture].AnTex.Reset();
1022 end;
1024 LastAnimLoop := AnimLoop;
1025 end;
1027 function TPanel.GetTextureID(): DWORD;
1028 begin
1029 Result := LongWord(TEXTURE_NONE);
1031 if (FCurTexture >= 0) then
1032 begin
1033 if FTextureIDs[FCurTexture].Anim then
1034 Result := FTextureIDs[FCurTexture].AnTex.FramesID
1035 else
1036 Result := FTextureIDs[FCurTexture].Tex;
1037 end;
1038 end;
1040 function TPanel.GetTextureCount(): Integer;
1041 begin
1042 Result := Length(FTextureIDs);
1043 if Enabled and (FCurTexture >= 0) then
1044 if (FTextureIDs[FCurTexture].Anim) and
1045 (FTextureIDs[FCurTexture].AnTex <> nil) and
1046 (Width > 0) and (Height > 0) and (FAlpha < 255) then
1047 Result := Result + 100;
1048 end;
1050 const
1051 PAN_SAVE_VERSION = 1;
1053 procedure TPanel.SaveState(Var Mem: TBinMemoryWriter);
1054 var
1055 sig: DWORD;
1056 anim: Boolean;
1057 ver: Byte;
1058 begin
1059 if (Mem = nil) then exit;
1060 //if not SaveIt then exit;
1062 // Ñèãíàòóðà ïàíåëè:
1063 sig := PANEL_SIGNATURE; // 'PANL'
1064 Mem.WriteDWORD(sig);
1065 ver := PAN_SAVE_VERSION;
1066 Mem.WriteByte(ver);
1067 // Îòêðûòà/çàêðûòà, åñëè äâåðü:
1068 Mem.WriteBoolean(FEnabled);
1069 // Íàïðàâëåíèå ëèôòà, åñëè ëèôò:
1070 Mem.WriteByte(FLiftType);
1071 // Íîìåð òåêóùåé òåêñòóðû:
1072 Mem.WriteInt(FCurTexture);
1073 // Êîîðäû
1074 Mem.WriteInt(FX);
1075 Mem.WriteInt(FY);
1076 Mem.WriteWord(FWidth);
1077 Mem.WriteWord(FHeight);
1078 // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà:
1079 if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) then
1080 begin
1081 Assert(FTextureIDs[FCurTexture].AnTex <> nil,
1082 'TPanel.SaveState: No animation object');
1083 anim := True;
1084 end
1085 else
1086 anim := False;
1087 Mem.WriteBoolean(anim);
1088 // Åñëè äà - ñîõðàíÿåì àíèìàöèþ:
1089 if anim then
1090 FTextureIDs[FCurTexture].AnTex.SaveState(Mem);
1092 // moving platform state
1093 Mem.WriteInt(mMovingSpeed.X);
1094 Mem.WriteInt(mMovingSpeed.Y);
1095 Mem.WriteInt(mMovingStart.X);
1096 Mem.WriteInt(mMovingStart.Y);
1097 Mem.WriteInt(mMovingEnd.X);
1098 Mem.WriteInt(mMovingEnd.Y);
1100 Mem.WriteInt(mSizeSpeed.w);
1101 Mem.WriteInt(mSizeSpeed.h);
1102 Mem.WriteInt(mSizeEnd.w);
1103 Mem.WriteInt(mSizeEnd.h);
1104 Mem.WriteBoolean(mMovingActive);
1105 Mem.WriteBoolean(mMoveOnce);
1107 Mem.WriteInt(mEndPosTrig);
1108 Mem.WriteInt(mEndSizeTrig);
1109 end;
1111 procedure TPanel.LoadState(var Mem: TBinMemoryReader);
1112 var
1113 sig: DWORD;
1114 anim: Boolean;
1115 ver: Byte;
1116 //ox, oy: Integer;
1117 begin
1118 if (Mem = nil) then exit;
1119 //if not SaveIt then exit;
1121 // Ñèãíàòóðà ïàíåëè:
1122 Mem.ReadDWORD(sig);
1123 if (sig <> PANEL_SIGNATURE) then raise EBinSizeError.Create('TPanel.LoadState: wrong panel signature'); // 'PANL'
1124 Mem.ReadByte(ver);
1125 if (ver <> PAN_SAVE_VERSION) then raise EBinSizeError.Create('TPanel.LoadState: invalid panel version');
1126 // Îòêðûòà/çàêðûòà, åñëè äâåðü:
1127 Mem.ReadBoolean(FEnabled);
1128 // Íàïðàâëåíèå ëèôòà, åñëè ëèôò:
1129 Mem.ReadByte(FLiftType);
1130 // Íîìåð òåêóùåé òåêñòóðû:
1131 Mem.ReadInt(FCurTexture);
1132 // Êîîðäû
1133 //ox := FX;
1134 //oy := FY;
1135 Mem.ReadInt(FX);
1136 Mem.ReadInt(FY);
1137 Mem.ReadWord(FWidth);
1138 Mem.ReadWord(FHeight);
1139 //e_LogWritefln('panel %s(%s): old=(%s,%s); new=(%s,%s); delta=(%s,%s)', [arrIdx, proxyId, ox, oy, FX, FY, FX-ox, FY-oy]);
1140 // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà:
1141 Mem.ReadBoolean(anim);
1142 // Åñëè äà - çàãðóæàåì àíèìàöèþ:
1143 if anim then
1144 begin
1145 Assert((FCurTexture >= 0) and
1146 (FTextureIDs[FCurTexture].Anim) and
1147 (FTextureIDs[FCurTexture].AnTex <> nil),
1148 'TPanel.LoadState: No animation object');
1149 FTextureIDs[FCurTexture].AnTex.LoadState(Mem);
1150 end;
1152 // moving platform state
1153 Mem.ReadInt(mMovingSpeed.X);
1154 Mem.ReadInt(mMovingSpeed.Y);
1155 Mem.ReadInt(mMovingStart.X);
1156 Mem.ReadInt(mMovingStart.Y);
1157 Mem.ReadInt(mMovingEnd.X);
1158 Mem.ReadInt(mMovingEnd.Y);
1159 Mem.ReadInt(mSizeSpeed.w);
1160 Mem.ReadInt(mSizeSpeed.h);
1161 Mem.ReadInt(mSizeEnd.w);
1162 Mem.ReadInt(mSizeEnd.h);
1163 Mem.ReadBoolean(mMovingActive);
1164 Mem.ReadBoolean(mMoveOnce);
1166 Mem.ReadInt(mEndPosTrig);
1167 Mem.ReadInt(mEndSizeTrig);
1169 positionChanged();
1170 //mapGrid.proxyEnabled[proxyId] := FEnabled; // done in g_map.pas
1171 end;
1173 end.