DEADSOFTWARE

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