DEADSOFTWARE

55f1e4aae46348be6ac6d66fdb93f255f39bbb22
[d2df-sdl.git] / src / game / g_map.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 unit g_map;
19 interface
21 uses
22 e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
23 g_phys, wadreader, BinEditor, g_panel, g_grid, g_sap, md5, xprofiler;
25 type
26 TMapInfo = record
27 Map: String;
28 Name: String;
29 Description: String;
30 Author: String;
31 MusicName: String;
32 SkyName: String;
33 Height: Word;
34 Width: Word;
35 end;
37 PRespawnPoint = ^TRespawnPoint;
38 TRespawnPoint = record
39 X, Y: Integer;
40 Direction: TDirection;
41 PointType: Byte;
42 end;
44 PFlagPoint = ^TFlagPoint;
45 TFlagPoint = TRespawnPoint;
47 PFlag = ^TFlag;
48 TFlag = record
49 Obj: TObj;
50 RespawnType: Byte;
51 State: Byte;
52 Count: Integer;
53 CaptureTime: LongWord;
54 Animation: TAnimation;
55 Direction: TDirection;
56 end;
58 function g_Map_Load(Res: String): Boolean;
59 function g_Map_GetMapInfo(Res: String): TMapInfo;
60 function g_Map_GetMapsList(WADName: String): SArray;
61 function g_Map_Exist(Res: String): Boolean;
62 procedure g_Map_Free();
63 procedure g_Map_Update();
65 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
67 procedure g_Map_DrawBack(dx, dy: Integer);
68 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
69 PanelType: Word; b1x3: Boolean): Boolean;
70 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
71 procedure g_Map_EnableWall(ID: DWORD);
72 procedure g_Map_DisableWall(ID: DWORD);
73 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
74 procedure g_Map_SetLift(ID: DWORD; t: Integer);
75 procedure g_Map_ReAdd_DieTriggers();
76 function g_Map_IsSpecialTexture(Texture: String): Boolean;
78 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
79 function g_Map_GetPointCount(PointType: Byte): Word;
81 function g_Map_HaveFlagPoints(): Boolean;
83 procedure g_Map_ResetFlag(Flag: Byte);
84 procedure g_Map_DrawFlags();
86 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
88 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
89 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
91 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
93 procedure g_Map_ProfilersBegin ();
94 procedure g_Map_ProfilersEnd ();
96 const
97 RESPAWNPOINT_PLAYER1 = 1;
98 RESPAWNPOINT_PLAYER2 = 2;
99 RESPAWNPOINT_DM = 3;
100 RESPAWNPOINT_RED = 4;
101 RESPAWNPOINT_BLUE = 5;
103 FLAG_NONE = 0;
104 FLAG_RED = 1;
105 FLAG_BLUE = 2;
106 FLAG_DOM = 3;
108 FLAG_STATE_NONE = 0;
109 FLAG_STATE_NORMAL = 1;
110 FLAG_STATE_DROPPED = 2;
111 FLAG_STATE_CAPTURED = 3;
112 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
113 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
115 FLAG_TIME = 720; // 20 seconds
117 SKY_STRETCH: Single = 1.5;
119 var
120 gWalls: TPanelArray;
121 gRenderBackgrounds: TPanelArray;
122 gRenderForegrounds: TPanelArray;
123 gWater, gAcid1, gAcid2: TPanelArray;
124 gSteps: TPanelArray;
125 gLifts: TPanelArray;
126 gBlockMon: TPanelArray;
127 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
128 //gDOMFlags: array of TFlag;
129 gMapInfo: TMapInfo;
130 gBackSize: TPoint;
131 gDoorMap: array of array of DWORD;
132 gLiftMap: array of array of DWORD;
133 gWADHash: TMD5Digest;
134 BackID: DWORD = DWORD(-1);
135 gExternalResources: TStringList;
137 gdbg_map_use_grid_render: Boolean = true;
138 gdbg_map_use_grid_coldet: Boolean = true;
139 gdbg_map_use_sap_draw: Boolean = true;
140 gdbg_map_use_sap_coldet: Boolean = false;
141 profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY!
143 implementation
145 uses
146 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
147 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
148 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
149 Math, g_monsters, g_saveload, g_language, g_netmsg,
150 utils, sfs, binheap,
151 ImagingTypes, Imaging, ImagingUtility,
152 ImagingGif, ImagingNetworkGraphics;
154 const
155 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
156 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
157 FLAG_SIGNATURE = $47414C46; // 'FLAG'
159 GridTagInvalid = -1;
160 GridTagWallDoor = 0;
161 GridTagBack = 1;
162 GridTagFore = 2;
163 GridTagWater = 3;
164 GridTagAcid1 = 4;
165 GridTagAcid2 = 5;
166 GridTagStep = 6;
167 GridTagLift = 7;
168 GridTagBlockMon = 8;
171 function panelTypeToTag (panelType: Word): Integer;
172 begin
173 case panelType of
174 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR: result := GridTagWallDoor; // gWalls
175 PANEL_BACK: result := GridTagBack; // gRenderBackgrounds
176 PANEL_FORE: result := GridTagFore; // gRenderForegrounds
177 PANEL_WATER: result := GridTagWater; // gWater
178 PANEL_ACID1: result := GridTagAcid1; // gAcid1
179 PANEL_ACID2: result := GridTagAcid2; // gAcid2
180 PANEL_STEP: result := GridTagStep; // gSteps
181 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT: result := GridTagLift; // gLifts -- this is for all lifts
182 PANEL_BLOCKMON: result := GridTagBlockMon; // gBlockMon -- this is for all blockmons
183 else result := GridTagInvalid;
184 end;
185 end;
188 type
189 TPanelID = record
190 PWhere: ^TPanelArray;
191 PArrID: Integer;
192 end;
194 var
195 PanelById: array of TPanelID;
196 Textures: TLevelTextureArray;
197 RespawnPoints: Array of TRespawnPoint;
198 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
199 //DOMFlagPoints: Array of TFlagPoint;
200 gMapGrid: TBodyGrid = nil;
201 gMapSAP: TSweepAndPrune = nil;
204 procedure g_Map_ProfilersBegin ();
205 begin
206 if (profMapCollision = nil) then profMapCollision := TProfiler.Create('MAP COLLISION', g_profile_history_size);
207 profMapCollision.mainBegin(g_profile_collision);
208 // create sections
209 if g_profile_collision then
210 begin
211 profMapCollision.sectionBegin('wall coldet');
212 profMapCollision.sectionEnd();
213 profMapCollision.sectionBegin('liquid coldet');
214 profMapCollision.sectionEnd();
215 end;
216 end;
218 procedure g_Map_ProfilersEnd ();
219 begin
220 if (profMapCollision <> nil) then profMapCollision.mainEnd();
221 end;
224 function g_Map_IsSpecialTexture(Texture: String): Boolean;
225 begin
226 Result := (Texture = TEXTURE_NAME_WATER) or
227 (Texture = TEXTURE_NAME_ACID1) or
228 (Texture = TEXTURE_NAME_ACID2);
229 end;
231 procedure CreateDoorMap();
232 var
233 PanelArray: Array of record
234 X, Y: Integer;
235 Width, Height: Word;
236 Active: Boolean;
237 PanelID: DWORD;
238 end;
239 a, b, c, m, i, len: Integer;
240 ok: Boolean;
241 begin
242 if gWalls = nil then
243 Exit;
245 i := 0;
246 len := 128;
247 SetLength(PanelArray, len);
249 for a := 0 to High(gWalls) do
250 if gWalls[a].Door then
251 begin
252 PanelArray[i].X := gWalls[a].X;
253 PanelArray[i].Y := gWalls[a].Y;
254 PanelArray[i].Width := gWalls[a].Width;
255 PanelArray[i].Height := gWalls[a].Height;
256 PanelArray[i].Active := True;
257 PanelArray[i].PanelID := a;
259 i := i + 1;
260 if i = len then
261 begin
262 len := len + 128;
263 SetLength(PanelArray, len);
264 end;
265 end;
267 // Íåò äâåðåé:
268 if i = 0 then
269 begin
270 PanelArray := nil;
271 Exit;
272 end;
274 SetLength(gDoorMap, 0);
276 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
278 for a := 0 to i-1 do
279 if PanelArray[a].Active then
280 begin
281 PanelArray[a].Active := False;
282 m := Length(gDoorMap);
283 SetLength(gDoorMap, m+1);
284 SetLength(gDoorMap[m], 1);
285 gDoorMap[m, 0] := PanelArray[a].PanelID;
286 ok := True;
288 while ok do
289 begin
290 ok := False;
292 for b := 0 to i-1 do
293 if PanelArray[b].Active then
294 for c := 0 to High(gDoorMap[m]) do
295 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
296 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
297 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
298 PanelArray[b].Width, PanelArray[b].Height,
299 gWalls[gDoorMap[m, c]].X,
300 gWalls[gDoorMap[m, c]].Y,
301 gWalls[gDoorMap[m, c]].Width,
302 gWalls[gDoorMap[m, c]].Height) then
303 begin
304 PanelArray[b].Active := False;
305 SetLength(gDoorMap[m],
306 Length(gDoorMap[m])+1);
307 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
308 ok := True;
309 Break;
310 end;
311 end;
313 g_Game_StepLoading();
314 end;
316 PanelArray := nil;
317 end;
319 procedure CreateLiftMap();
320 var
321 PanelArray: Array of record
322 X, Y: Integer;
323 Width, Height: Word;
324 Active: Boolean;
325 end;
326 a, b, c, len, i, j: Integer;
327 ok: Boolean;
328 begin
329 if gLifts = nil then
330 Exit;
332 len := Length(gLifts);
333 SetLength(PanelArray, len);
335 for a := 0 to len-1 do
336 begin
337 PanelArray[a].X := gLifts[a].X;
338 PanelArray[a].Y := gLifts[a].Y;
339 PanelArray[a].Width := gLifts[a].Width;
340 PanelArray[a].Height := gLifts[a].Height;
341 PanelArray[a].Active := True;
342 end;
344 SetLength(gLiftMap, len);
345 i := 0;
347 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
349 for a := 0 to len-1 do
350 if PanelArray[a].Active then
351 begin
352 PanelArray[a].Active := False;
353 SetLength(gLiftMap[i], 32);
354 j := 0;
355 gLiftMap[i, j] := a;
356 ok := True;
358 while ok do
359 begin
360 ok := False;
361 for b := 0 to len-1 do
362 if PanelArray[b].Active then
363 for c := 0 to j do
364 if g_CollideAround(PanelArray[b].X,
365 PanelArray[b].Y,
366 PanelArray[b].Width,
367 PanelArray[b].Height,
368 PanelArray[gLiftMap[i, c]].X,
369 PanelArray[gLiftMap[i, c]].Y,
370 PanelArray[gLiftMap[i, c]].Width,
371 PanelArray[gLiftMap[i, c]].Height) then
372 begin
373 PanelArray[b].Active := False;
374 j := j+1;
375 if j > High(gLiftMap[i]) then
376 SetLength(gLiftMap[i],
377 Length(gLiftMap[i])+32);
379 gLiftMap[i, j] := b;
380 ok := True;
382 Break;
383 end;
384 end;
386 SetLength(gLiftMap[i], j+1);
387 i := i+1;
389 g_Game_StepLoading();
390 end;
392 SetLength(gLiftMap, i);
394 PanelArray := nil;
395 end;
397 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
398 CurTex: Integer; sav: Boolean): Integer;
399 var
400 len: Integer;
401 panels: ^TPanelArray;
402 begin
403 Result := -1;
405 case PanelRec.PanelType of
406 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
407 panels := @gWalls;
408 PANEL_BACK:
409 panels := @gRenderBackgrounds;
410 PANEL_FORE:
411 panels := @gRenderForegrounds;
412 PANEL_WATER:
413 panels := @gWater;
414 PANEL_ACID1:
415 panels := @gAcid1;
416 PANEL_ACID2:
417 panels := @gAcid2;
418 PANEL_STEP:
419 panels := @gSteps;
420 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
421 panels := @gLifts;
422 PANEL_BLOCKMON:
423 panels := @gBlockMon;
424 else
425 Exit;
426 end;
428 len := Length(panels^);
429 SetLength(panels^, len + 1);
431 panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures);
432 panels^[len].ArrIdx := len;
433 if sav then
434 panels^[len].SaveIt := True;
436 Result := len;
438 len := Length(PanelByID);
439 SetLength(PanelByID, len + 1);
440 PanelByID[len].PWhere := panels;
441 PanelByID[len].PArrID := Result;
442 end;
444 function CreateNullTexture(RecName: String): Integer;
445 begin
446 SetLength(Textures, Length(Textures)+1);
447 result := High(Textures);
449 with Textures[High(Textures)] do
450 begin
451 TextureName := RecName;
452 Width := 1;
453 Height := 1;
454 Anim := False;
455 TextureID := TEXTURE_NONE;
456 end;
457 end;
459 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
460 var
461 WAD: TWADFile;
462 TextureData: Pointer;
463 WADName, txname: String;
464 a, ResLength: Integer;
465 begin
466 Result := -1;
468 if Textures <> nil then
469 for a := 0 to High(Textures) do
470 if Textures[a].TextureName = RecName then
471 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
472 Result := a;
473 Exit;
474 end;
476 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
477 if (RecName = TEXTURE_NAME_WATER) or
478 (RecName = TEXTURE_NAME_ACID1) or
479 (RecName = TEXTURE_NAME_ACID2) then
480 begin
481 SetLength(Textures, Length(Textures)+1);
483 with Textures[High(Textures)] do
484 begin
485 TextureName := RecName;
487 if TextureName = TEXTURE_NAME_WATER then
488 TextureID := TEXTURE_SPECIAL_WATER
489 else
490 if TextureName = TEXTURE_NAME_ACID1 then
491 TextureID := TEXTURE_SPECIAL_ACID1
492 else
493 if TextureName = TEXTURE_NAME_ACID2 then
494 TextureID := TEXTURE_SPECIAL_ACID2;
496 Anim := False;
497 end;
499 result := High(Textures);
500 Exit;
501 end;
503 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
504 WADName := g_ExtractWadName(RecName);
506 WAD := TWADFile.Create();
508 if WADName <> '' then
509 WADName := GameDir+'/wads/'+WADName
510 else
511 WADName := Map;
513 WAD.ReadFile(WADName);
515 txname := RecName;
517 if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
518 begin
519 FreeMem(TextureData);
520 RecName := 'COMMON\ALIEN';
521 end;
524 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
525 begin
526 SetLength(Textures, Length(Textures)+1);
527 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
528 Exit;
529 e_GetTextureSize(Textures[High(Textures)].TextureID,
530 @Textures[High(Textures)].Width,
531 @Textures[High(Textures)].Height);
532 FreeMem(TextureData);
533 Textures[High(Textures)].TextureName := {RecName}txname;
534 Textures[High(Textures)].Anim := False;
536 result := High(Textures);
537 end
538 else // Íåò òàêîãî ðåóñðñà â WAD'å
539 begin
540 //e_WriteLog(Format('SHIT! Error loading texture %s : %s : %s', [RecName, txname, g_ExtractFilePathName(RecName)]), MSG_WARNING);
541 if log then
542 begin
543 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
544 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
545 end;
546 end;
548 WAD.Free();
549 end;
551 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
552 var
553 WAD: TWADFile;
554 TextureWAD: PChar = nil;
555 TextData: Pointer = nil;
556 TextureData: Pointer = nil;
557 cfg: TConfig = nil;
558 WADName: String;
559 ResLength: Integer;
560 TextureResource: String;
561 _width, _height, _framecount, _speed: Integer;
562 _backanimation: Boolean;
563 //imgfmt: string;
564 ia: TDynImageDataArray = nil;
565 f, c, frdelay, frloop: Integer;
566 begin
567 result := -1;
569 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
571 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
572 WADName := g_ExtractWadName(RecName);
574 WAD := TWADFile.Create();
575 try
576 if WADName <> '' then
577 WADName := GameDir+'/wads/'+WADName
578 else
579 WADName := Map;
581 WAD.ReadFile(WADName);
583 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
584 begin
585 if log then
586 begin
587 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
588 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
589 end;
590 exit;
591 end;
593 {TEST
594 if WADName = Map then
595 begin
596 //FreeMem(TextureWAD);
597 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
598 end;
601 WAD.FreeWAD();
603 if ResLength < 6 then
604 begin
605 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
606 exit;
607 end;
609 // ýòî ïòèöà? ýòî ñàìîë¸ò?
610 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
611 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
612 begin
613 // íåò, ýòî ñóïåðìåí!
614 if not WAD.ReadMemory(TextureWAD, ResLength) then
615 begin
616 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
617 exit;
618 end;
620 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
621 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
622 begin
623 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
624 exit;
625 end;
627 cfg := TConfig.CreateMem(TextData, ResLength);
629 TextureResource := cfg.ReadStr('', 'resource', '');
630 if TextureResource = '' then
631 begin
632 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
633 exit;
634 end;
636 _width := cfg.ReadInt('', 'framewidth', 0);
637 _height := cfg.ReadInt('', 'frameheight', 0);
638 _framecount := cfg.ReadInt('', 'framecount', 0);
639 _speed := cfg.ReadInt('', 'waitcount', 0);
640 _backanimation := cfg.ReadBool('', 'backanimation', False);
642 cfg.Free();
643 cfg := nil;
645 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
646 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
647 begin
648 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
649 exit;
650 end;
652 WAD.Free();
653 WAD := nil;
655 SetLength(Textures, Length(Textures)+1);
656 with Textures[High(Textures)] do
657 begin
658 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
659 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
660 begin
661 TextureName := RecName;
662 Width := _width;
663 Height := _height;
664 Anim := True;
665 FramesCount := _framecount;
666 Speed := _speed;
667 result := High(Textures);
668 end
669 else
670 begin
671 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
672 end;
673 end;
674 end
675 else
676 begin
677 // try animated image
679 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
680 if length(imgfmt) = 0 then
681 begin
682 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
683 exit;
684 end;
686 GlobalMetadata.ClearMetaItems();
687 GlobalMetadata.ClearMetaItemsForSaving();
688 if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
689 begin
690 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
691 exit;
692 end;
693 if length(ia) = 0 then
694 begin
695 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
696 exit;
697 end;
699 WAD.Free();
700 WAD := nil;
702 _width := ia[0].width;
703 _height := ia[0].height;
704 _framecount := length(ia);
705 _speed := 1;
706 _backanimation := false;
707 frdelay := -1;
708 frloop := -666;
709 if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then
710 begin
711 //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]);
712 try
713 f := GlobalMetadata.MetaItems[SMetaFrameDelay];
714 frdelay := f;
715 if f < 0 then f := 0;
716 // rounding ;-)
717 c := f mod 28;
718 if c < 13 then c := 0 else c := 1;
719 f := (f div 28)+c;
720 if f < 1 then f := 1 else if f > 255 then f := 255;
721 _speed := f;
722 except
723 end;
724 end;
725 if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then
726 begin
727 //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]);
728 try
729 f := GlobalMetadata.MetaItems[SMetaAnimationLoops];
730 frloop := f;
731 if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back
732 except
733 end;
734 end;
735 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
736 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
737 f := ord(_backanimation);
738 e_WriteLog(Format('Animated texture file "%s": %d frames (delay:%d; back:%d; frdelay:%d; frloop:%d), %dx%d', [RecName, length(ia), _speed, f, frdelay, frloop, _width, _height]), MSG_NOTIFY);
740 SetLength(Textures, Length(Textures)+1);
741 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
742 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
743 begin
744 Textures[High(Textures)].TextureName := RecName;
745 Textures[High(Textures)].Width := _width;
746 Textures[High(Textures)].Height := _height;
747 Textures[High(Textures)].Anim := True;
748 Textures[High(Textures)].FramesCount := length(ia);
749 Textures[High(Textures)].Speed := _speed;
750 result := High(Textures);
751 //writeln(' CREATED!');
752 end
753 else
754 begin
755 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
756 end;
757 end;
758 finally
759 for f := 0 to High(ia) do FreeImage(ia[f]);
760 WAD.Free();
761 cfg.Free();
762 if TextureWAD <> nil then FreeMem(TextureWAD);
763 if TextData <> nil then FreeMem(TextData);
764 if TextureData <> nil then FreeMem(TextureData);
765 end;
766 end;
768 procedure CreateItem(Item: TItemRec_1);
769 begin
770 if g_Game_IsClient then Exit;
772 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
773 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
774 Exit;
776 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
777 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
778 end;
780 procedure CreateArea(Area: TAreaRec_1);
781 var
782 a: Integer;
783 id: DWORD;
784 begin
785 case Area.AreaType of
786 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
787 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
788 begin
789 SetLength(RespawnPoints, Length(RespawnPoints)+1);
790 with RespawnPoints[High(RespawnPoints)] do
791 begin
792 X := Area.X;
793 Y := Area.Y;
794 Direction := TDirection(Area.Direction);
796 case Area.AreaType of
797 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
798 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
799 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
800 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
801 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
802 end;
803 end;
804 end;
806 AREA_REDFLAG, AREA_BLUEFLAG:
807 begin
808 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
810 if FlagPoints[a] <> nil then Exit;
812 New(FlagPoints[a]);
814 with FlagPoints[a]^ do
815 begin
816 X := Area.X-FLAGRECT.X;
817 Y := Area.Y-FLAGRECT.Y;
818 Direction := TDirection(Area.Direction);
819 end;
821 with gFlags[a] do
822 begin
823 case a of
824 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
825 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
826 end;
828 Animation := TAnimation.Create(id, True, 8);
829 Obj.Rect := FLAGRECT;
831 g_Map_ResetFlag(a);
832 end;
833 end;
835 AREA_DOMFLAG:
836 begin
837 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
838 with DOMFlagPoints[High(DOMFlagPoints)] do
839 begin
840 X := Area.X;
841 Y := Area.Y;
842 Direction := TDirection(Area.Direction);
843 end;
845 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
846 end;
847 end;
848 end;
850 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
851 var
852 _trigger: TTrigger;
853 begin
854 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
856 with _trigger do
857 begin
858 X := Trigger.X;
859 Y := Trigger.Y;
860 Width := Trigger.Width;
861 Height := Trigger.Height;
862 Enabled := ByteBool(Trigger.Enabled);
863 TexturePanel := Trigger.TexturePanel;
864 TexturePanelType := fTexturePanel1Type;
865 ShotPanelType := fTexturePanel2Type;
866 TriggerType := Trigger.TriggerType;
867 ActivateType := Trigger.ActivateType;
868 Keys := Trigger.Keys;
869 Data.Default := Trigger.DATA;
870 end;
872 g_Triggers_Create(_trigger);
873 end;
875 procedure CreateMonster(monster: TMonsterRec_1);
876 var
877 a, i: Integer;
878 begin
879 if g_Game_IsClient then Exit;
881 if (gGameSettings.GameType = GT_SINGLE)
882 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
883 begin
884 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
885 TDirection(monster.Direction));
887 if gTriggers <> nil then
888 for a := 0 to High(gTriggers) do
889 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
890 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
891 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
892 gMonsters[i].AddTrigger(a);
894 if monster.MonsterType <> MONSTER_BARREL then
895 Inc(gTotalMonsters);
896 end;
897 end;
899 procedure g_Map_ReAdd_DieTriggers();
900 var
901 i, a: Integer;
902 begin
903 if g_Game_IsClient then Exit;
905 for i := 0 to High(gMonsters) do
906 if gMonsters[i] <> nil then
907 begin
908 gMonsters[i].ClearTriggers();
910 for a := 0 to High(gTriggers) do
911 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
912 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
913 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
914 gMonsters[i].AddTrigger(a);
915 end;
916 end;
918 function extractWadName(resourceName: string): string;
919 var
920 posN: Integer;
921 begin
922 posN := Pos(':', resourceName);
923 if posN > 0 then
924 Result:= Copy(resourceName, 0, posN-1)
925 else
926 Result := '';
927 end;
929 procedure addResToExternalResList(res: string);
930 begin
931 res := extractWadName(res);
932 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
933 gExternalResources.Add(res);
934 end;
936 procedure generateExternalResourcesList(mapReader: TMapReader_1);
937 var
938 textures: TTexturesRec1Array;
939 mapHeader: TMapHeaderRec_1;
940 i: integer;
941 resFile: String = '';
942 begin
943 if gExternalResources = nil then
944 gExternalResources := TStringList.Create;
946 gExternalResources.Clear;
947 textures := mapReader.GetTextures();
948 for i := 0 to High(textures) do
949 begin
950 addResToExternalResList(resFile);
951 end;
953 textures := nil;
955 mapHeader := mapReader.GetMapHeader;
957 addResToExternalResList(mapHeader.MusicName);
958 addResToExternalResList(mapHeader.SkyName);
959 end;
961 procedure mapCreateGrid ();
962 var
963 mapX0: Integer = $3fffffff;
964 mapY0: Integer = $3fffffff;
965 mapX1: Integer = -$3fffffff;
966 mapY1: Integer = -$3fffffff;
968 procedure fixMinMax (var panels: TPanelArray);
969 var
970 idx: Integer;
971 begin
972 for idx := 0 to High(panels) do
973 begin
974 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
975 if mapX0 > panels[idx].X then mapX0 := panels[idx].X;
976 if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y;
977 if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1;
978 if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1;
979 end;
980 end;
982 procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer);
983 var
984 idx: Integer;
985 begin
986 tag := panelTypeToTag(tag);
987 for idx := High(panels) downto 0 do
988 begin
989 gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
990 gMapSAP.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
991 end;
992 end;
994 begin
995 gMapGrid.Free();
996 gMapGrid := nil;
997 gMapSAP.Free();
998 gMapSAP := nil;
1000 fixMinMax(gWalls);
1001 fixMinMax(gRenderBackgrounds);
1002 fixMinMax(gRenderForegrounds);
1003 fixMinMax(gWater);
1004 fixMinMax(gAcid1);
1005 fixMinMax(gAcid2);
1006 fixMinMax(gSteps);
1007 fixMinMax(gLifts);
1008 fixMinMax(gBlockMon);
1010 if (mapX0 < 0) or (mapY0 < 0) then
1011 begin
1012 e_WriteLog(Format('funny map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING);
1013 //raise Exception.Create('we are fucked');
1014 end;
1016 gMapGrid := TBodyGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1);
1017 gMapSAP := TSweepAndPrune.Create();
1019 gMapSAP.batchUpdateBegin();
1021 addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR
1022 addPanelsToGrid(gRenderBackgrounds, PANEL_BACK);
1023 addPanelsToGrid(gRenderForegrounds, PANEL_FORE);
1024 addPanelsToGrid(gWater, PANEL_WATER);
1025 addPanelsToGrid(gAcid1, PANEL_ACID1);
1026 addPanelsToGrid(gAcid2, PANEL_ACID2);
1027 addPanelsToGrid(gSteps, PANEL_STEP);
1028 addPanelsToGrid(gLifts, PANEL_LIFTUP); // it doesn't matter which LIFT type is used here
1029 addPanelsToGrid(gBlockMon, PANEL_BLOCKMON);
1031 gMapSAP.batchUpdateEnd();
1033 gMapGrid.dumpStats();
1034 gMapSAP.dumpStats();
1035 end;
1037 function g_Map_Load(Res: String): Boolean;
1038 const
1039 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
1040 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
1041 var
1042 WAD: TWADFile;
1043 MapReader: TMapReader_1;
1044 Header: TMapHeaderRec_1;
1045 _textures: TTexturesRec1Array;
1046 _texnummap: array of Integer; // `_textures` -> `Textures`
1047 panels: TPanelsRec1Array;
1048 items: TItemsRec1Array;
1049 monsters: TMonsterRec1Array;
1050 areas: TAreasRec1Array;
1051 triggers: TTriggersRec1Array;
1052 a, b, c, k: Integer;
1053 PanelID: DWORD;
1054 AddTextures: TAddTextureArray;
1055 texture: TTextureRec_1;
1056 TriggersTable: Array of record
1057 TexturePanel: Integer;
1058 LiftPanel: Integer;
1059 DoorPanel: Integer;
1060 ShotPanel: Integer;
1061 end;
1062 FileName, mapResName, s, TexName: String;
1063 Data: Pointer;
1064 Len: Integer;
1065 ok, isAnim, trigRef: Boolean;
1066 CurTex, ntn: Integer;
1068 begin
1069 gMapGrid.Free();
1070 gMapGrid := nil;
1071 gMapSAP.Free();
1072 gMapSAP := nil;
1074 Result := False;
1075 gMapInfo.Map := Res;
1076 TriggersTable := nil;
1077 FillChar(texture, SizeOf(texture), 0);
1079 sfsGCDisable(); // temporary disable removing of temporary volumes
1080 try
1081 // Çàãðóçêà WAD:
1082 FileName := g_ExtractWadName(Res);
1083 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
1084 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
1086 WAD := TWADFile.Create();
1087 if not WAD.ReadFile(FileName) then
1088 begin
1089 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
1090 WAD.Free();
1091 Exit;
1092 end;
1093 //k8: why loader ignores path here?
1094 mapResName := g_ExtractFileName(Res);
1095 if not WAD.GetMapResource(mapResName, Data, Len) then
1096 begin
1097 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
1098 WAD.Free();
1099 Exit;
1100 end;
1102 WAD.Free();
1104 // Çàãðóçêà êàðòû:
1105 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
1106 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
1107 MapReader := TMapReader_1.Create();
1109 if not MapReader.LoadMap(Data) then
1110 begin
1111 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
1112 FreeMem(Data);
1113 MapReader.Free();
1114 Exit;
1115 end;
1117 FreeMem(Data);
1118 generateExternalResourcesList(MapReader);
1119 // Çàãðóçêà òåêñòóð:
1120 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
1121 _textures := MapReader.GetTextures();
1122 _texnummap := nil;
1124 // Äîáàâëåíèå òåêñòóð â Textures[]:
1125 if _textures <> nil then
1126 begin
1127 e_WriteLog(' Loading textures:', MSG_NOTIFY);
1128 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
1129 SetLength(_texnummap, length(_textures));
1131 for a := 0 to High(_textures) do
1132 begin
1133 SetLength(s, 64);
1134 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
1135 for b := 1 to Length(s) do
1136 if s[b] = #0 then
1137 begin
1138 SetLength(s, b-1);
1139 Break;
1140 end;
1141 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
1142 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
1143 // Àíèìèðîâàííàÿ òåêñòóðà:
1144 if ByteBool(_textures[a].Anim) then
1145 begin
1146 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1147 if ntn < 0 then
1148 begin
1149 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1150 ntn := CreateNullTexture(_textures[a].Resource);
1151 end;
1152 end
1153 else // Îáû÷íàÿ òåêñòóðà:
1154 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1155 if ntn < 0 then
1156 begin
1157 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1158 ntn := CreateNullTexture(_textures[a].Resource);
1159 end;
1161 _texnummap[a] := ntn; // fix texture number
1162 g_Game_StepLoading();
1163 end;
1164 end;
1166 // Çàãðóçêà òðèããåðîâ:
1167 gTriggerClientID := 0;
1168 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1169 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1170 triggers := MapReader.GetTriggers();
1172 // Çàãðóçêà ïàíåëåé:
1173 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1174 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1175 panels := MapReader.GetPanels();
1177 // check texture numbers for panels
1178 for a := 0 to High(panels) do
1179 begin
1180 if panels[a].TextureNum > High(_textures) then
1181 begin
1182 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1183 result := false;
1184 exit;
1185 end;
1186 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1187 end;
1189 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1190 if triggers <> nil then
1191 begin
1192 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1193 SetLength(TriggersTable, Length(triggers));
1194 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1196 for a := 0 to High(TriggersTable) do
1197 begin
1198 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1199 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1200 // Ëèôòû:
1201 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1202 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1203 else
1204 TriggersTable[a].LiftPanel := -1;
1205 // Äâåðè:
1206 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1207 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1208 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1209 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1210 else
1211 TriggersTable[a].DoorPanel := -1;
1212 // Òóðåëü:
1213 if triggers[a].TriggerType = TRIGGER_SHOT then
1214 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1215 else
1216 TriggersTable[a].ShotPanel := -1;
1218 g_Game_StepLoading();
1219 end;
1220 end;
1222 // Ñîçäàåì ïàíåëè:
1223 if panels <> nil then
1224 begin
1225 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1226 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1228 for a := 0 to High(panels) do
1229 begin
1230 SetLength(AddTextures, 0);
1231 trigRef := False;
1232 CurTex := -1;
1233 if _textures <> nil then
1234 begin
1235 texture := _textures[panels[a].TextureNum];
1236 ok := True;
1237 end
1238 else
1239 ok := False;
1241 if ok then
1242 begin
1243 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1244 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1245 ok := False;
1246 if (TriggersTable <> nil) and (_textures <> nil) then
1247 for b := 0 to High(TriggersTable) do
1248 if (TriggersTable[b].TexturePanel = a)
1249 or (TriggersTable[b].ShotPanel = a) then
1250 begin
1251 trigRef := True;
1252 ok := True;
1253 Break;
1254 end;
1255 end;
1257 if ok then
1258 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1259 SetLength(s, 64);
1260 CopyMemory(@s[1], @texture.Resource[0], 64);
1261 // Èçìåðÿåì äëèíó:
1262 Len := Length(s);
1263 for c := Len downto 1 do
1264 if s[c] <> #0 then
1265 begin
1266 Len := c;
1267 Break;
1268 end;
1269 SetLength(s, Len);
1271 // Ñïåö-òåêñòóðû çàïðåùåíû:
1272 if g_Map_IsSpecialTexture(s) then
1273 ok := False
1274 else
1275 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1276 ok := g_Texture_NumNameFindStart(s);
1278 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1279 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1280 if ok then
1281 begin
1282 k := NNF_NAME_BEFORE;
1283 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1284 while ok or (k = NNF_NAME_BEFORE) or
1285 (k = NNF_NAME_EQUALS) do
1286 begin
1287 k := g_Texture_NumNameFindNext(TexName);
1289 if (k = NNF_NAME_BEFORE) or
1290 (k = NNF_NAME_AFTER) then
1291 begin
1292 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1293 if ByteBool(texture.Anim) then
1294 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1295 isAnim := True;
1296 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1297 if not ok then
1298 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1299 isAnim := False;
1300 ok := CreateTexture(TexName, FileName, False) >= 0;
1301 end;
1302 end
1303 else
1304 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1305 isAnim := False;
1306 ok := CreateTexture(TexName, FileName, False) >= 0;
1307 if not ok then
1308 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1309 isAnim := True;
1310 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1311 end;
1312 end;
1314 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1315 if ok then
1316 begin
1317 for c := 0 to High(Textures) do
1318 if Textures[c].TextureName = TexName then
1319 begin
1320 SetLength(AddTextures, Length(AddTextures)+1);
1321 AddTextures[High(AddTextures)].Texture := c;
1322 AddTextures[High(AddTextures)].Anim := isAnim;
1323 Break;
1324 end;
1325 end;
1326 end
1327 else
1328 if k = NNF_NAME_EQUALS then
1329 begin
1330 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1331 SetLength(AddTextures, Length(AddTextures)+1);
1332 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1333 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1334 CurTex := High(AddTextures);
1335 ok := True;
1336 end
1337 else // NNF_NO_NAME
1338 ok := False;
1339 end; // while ok...
1341 ok := True;
1342 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1343 end; // if ok - ññûëàþòñÿ òðèããåðû
1345 if not ok then
1346 begin
1347 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1348 SetLength(AddTextures, 1);
1349 AddTextures[0].Texture := panels[a].TextureNum;
1350 AddTextures[0].Anim := ByteBool(texture.Anim);
1351 CurTex := 0;
1352 end;
1354 //e_WriteLog(Format('panel #%d: TextureNum=%d; ht=%d; ht1=%d; atl=%d', [a, panels[a].TextureNum, High(_textures), High(Textures), High(AddTextures)]), MSG_NOTIFY);
1356 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1357 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1359 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1360 if TriggersTable <> nil then
1361 for b := 0 to High(TriggersTable) do
1362 begin
1363 // Òðèããåð äâåðè/ëèôòà:
1364 if (TriggersTable[b].LiftPanel = a) or
1365 (TriggersTable[b].DoorPanel = a) then
1366 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1367 // Òðèããåð ñìåíû òåêñòóðû:
1368 if TriggersTable[b].TexturePanel = a then
1369 triggers[b].TexturePanel := PanelID;
1370 // Òðèããåð "Òóðåëü":
1371 if TriggersTable[b].ShotPanel = a then
1372 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1373 end;
1375 g_Game_StepLoading();
1376 end;
1377 end;
1379 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1380 if (triggers <> nil) and not gLoadGameMode then
1381 begin
1382 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1383 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1384 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1385 for a := 0 to High(triggers) do
1386 begin
1387 if triggers[a].TexturePanel <> -1 then
1388 b := panels[TriggersTable[a].TexturePanel].PanelType
1389 else
1390 b := 0;
1391 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1392 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1393 c := panels[TriggersTable[a].ShotPanel].PanelType
1394 else
1395 c := 0;
1396 CreateTrigger(triggers[a], b, c);
1397 end;
1398 end;
1400 // Çàãðóçêà ïðåäìåòîâ:
1401 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1402 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1403 items := MapReader.GetItems();
1405 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1406 if (items <> nil) and not gLoadGameMode then
1407 begin
1408 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1409 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1410 for a := 0 to High(items) do
1411 CreateItem(Items[a]);
1412 end;
1414 // Çàãðóçêà îáëàñòåé:
1415 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1416 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1417 areas := MapReader.GetAreas();
1419 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1420 if areas <> nil then
1421 begin
1422 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1423 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1424 for a := 0 to High(areas) do
1425 CreateArea(areas[a]);
1426 end;
1428 // Çàãðóçêà ìîíñòðîâ:
1429 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1430 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1431 monsters := MapReader.GetMonsters();
1433 gTotalMonsters := 0;
1435 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1436 if (monsters <> nil) and not gLoadGameMode then
1437 begin
1438 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1439 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1440 for a := 0 to High(monsters) do
1441 CreateMonster(monsters[a]);
1442 end;
1444 // Çàãðóçêà îïèñàíèÿ êàðòû:
1445 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1446 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1447 Header := MapReader.GetMapHeader();
1449 MapReader.Free();
1451 with gMapInfo do
1452 begin
1453 Name := Header.MapName;
1454 Description := Header.MapDescription;
1455 Author := Header.MapAuthor;
1456 MusicName := Header.MusicName;
1457 SkyName := Header.SkyName;
1458 Height := Header.Height;
1459 Width := Header.Width;
1460 end;
1462 // Çàãðóçêà íåáà:
1463 if gMapInfo.SkyName <> '' then
1464 begin
1465 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1466 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1467 FileName := g_ExtractWadName(gMapInfo.SkyName);
1469 if FileName <> '' then
1470 FileName := GameDir+'/wads/'+FileName
1471 else
1472 begin
1473 FileName := g_ExtractWadName(Res);
1474 end;
1476 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1477 if g_Texture_CreateWAD(BackID, s) then
1478 begin
1479 g_Game_SetupScreenSize();
1480 end
1481 else
1482 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1483 end;
1485 // Çàãðóçêà ìóçûêè:
1486 ok := False;
1487 if gMapInfo.MusicName <> '' then
1488 begin
1489 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1490 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1491 FileName := g_ExtractWadName(gMapInfo.MusicName);
1493 if FileName <> '' then
1494 FileName := GameDir+'/wads/'+FileName
1495 else
1496 begin
1497 FileName := g_ExtractWadName(Res);
1498 end;
1500 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1501 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1502 ok := True
1503 else
1504 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1505 end;
1507 // Îñòàëüíûå óñòàíâêè:
1508 CreateDoorMap();
1509 CreateLiftMap();
1511 g_Items_Init();
1512 g_Weapon_Init();
1513 g_Monsters_Init();
1515 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1516 if not gLoadGameMode then
1517 g_GFX_Init();
1519 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1520 _textures := nil;
1521 panels := nil;
1522 items := nil;
1523 areas := nil;
1524 triggers := nil;
1525 TriggersTable := nil;
1526 AddTextures := nil;
1528 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1529 if ok and (not gLoadGameMode) then
1530 begin
1531 gMusic.SetByName(gMapInfo.MusicName);
1532 gMusic.Play();
1533 end
1534 else
1535 gMusic.SetByName('');
1536 finally
1537 sfsGCEnable(); // enable releasing unused volumes
1538 end;
1540 e_WriteLog('Creating map grid', MSG_NOTIFY);
1541 mapCreateGrid();
1543 e_WriteLog('Done loading map.', MSG_NOTIFY);
1544 Result := True;
1545 end;
1547 function g_Map_GetMapInfo(Res: String): TMapInfo;
1548 var
1549 WAD: TWADFile;
1550 MapReader: TMapReader_1;
1551 Header: TMapHeaderRec_1;
1552 FileName: String;
1553 Data: Pointer;
1554 Len: Integer;
1555 begin
1556 FillChar(Result, SizeOf(Result), 0);
1557 FileName := g_ExtractWadName(Res);
1559 WAD := TWADFile.Create();
1560 if not WAD.ReadFile(FileName) then
1561 begin
1562 WAD.Free();
1563 Exit;
1564 end;
1566 //k8: it ignores path again
1567 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1568 begin
1569 WAD.Free();
1570 Exit;
1571 end;
1573 WAD.Free();
1575 MapReader := TMapReader_1.Create();
1577 if not MapReader.LoadMap(Data) then
1578 begin
1579 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1580 ZeroMemory(@Header, SizeOf(Header));
1581 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1582 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1583 end
1584 else
1585 begin
1586 Header := MapReader.GetMapHeader();
1587 Result.Name := Header.MapName;
1588 Result.Description := Header.MapDescription;
1589 end;
1591 FreeMem(Data);
1592 MapReader.Free();
1594 Result.Map := Res;
1595 Result.Author := Header.MapAuthor;
1596 Result.Height := Header.Height;
1597 Result.Width := Header.Width;
1598 end;
1600 function g_Map_GetMapsList(WADName: string): SArray;
1601 var
1602 WAD: TWADFile;
1603 a: Integer;
1604 ResList: SArray;
1605 begin
1606 Result := nil;
1607 WAD := TWADFile.Create();
1608 if not WAD.ReadFile(WADName) then
1609 begin
1610 WAD.Free();
1611 Exit;
1612 end;
1613 ResList := WAD.GetMapResources();
1614 if ResList <> nil then
1615 begin
1616 for a := 0 to High(ResList) do
1617 begin
1618 SetLength(Result, Length(Result)+1);
1619 Result[High(Result)] := ResList[a];
1620 end;
1621 end;
1622 WAD.Free();
1623 end;
1625 function g_Map_Exist(Res: string): Boolean;
1626 var
1627 WAD: TWADFile;
1628 FileName, mnn: string;
1629 ResList: SArray;
1630 a: Integer;
1631 begin
1632 Result := False;
1634 FileName := addWadExtension(g_ExtractWadName(Res));
1636 WAD := TWADFile.Create;
1637 if not WAD.ReadFile(FileName) then
1638 begin
1639 WAD.Free();
1640 Exit;
1641 end;
1643 ResList := WAD.GetMapResources();
1644 WAD.Free();
1646 mnn := g_ExtractFileName(Res);
1647 if ResList <> nil then
1648 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1649 begin
1650 Result := True;
1651 Exit;
1652 end;
1653 end;
1655 procedure g_Map_Free();
1656 var
1657 a: Integer;
1659 procedure FreePanelArray(var panels: TPanelArray);
1660 var
1661 i: Integer;
1663 begin
1664 if panels <> nil then
1665 begin
1666 for i := 0 to High(panels) do
1667 panels[i].Free();
1668 panels := nil;
1669 end;
1670 end;
1672 begin
1673 g_GFX_Free();
1674 g_Weapon_Free();
1675 g_Items_Free();
1676 g_Triggers_Free();
1677 g_Monsters_Free();
1679 RespawnPoints := nil;
1680 if FlagPoints[FLAG_RED] <> nil then
1681 begin
1682 Dispose(FlagPoints[FLAG_RED]);
1683 FlagPoints[FLAG_RED] := nil;
1684 end;
1685 if FlagPoints[FLAG_BLUE] <> nil then
1686 begin
1687 Dispose(FlagPoints[FLAG_BLUE]);
1688 FlagPoints[FLAG_BLUE] := nil;
1689 end;
1690 //DOMFlagPoints := nil;
1692 //gDOMFlags := nil;
1694 if Textures <> nil then
1695 begin
1696 for a := 0 to High(Textures) do
1697 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1698 if Textures[a].Anim then
1699 g_Frames_DeleteByID(Textures[a].FramesID)
1700 else
1701 if Textures[a].TextureID <> TEXTURE_NONE then
1702 e_DeleteTexture(Textures[a].TextureID);
1704 Textures := nil;
1705 end;
1707 FreePanelArray(gWalls);
1708 FreePanelArray(gRenderBackgrounds);
1709 FreePanelArray(gRenderForegrounds);
1710 FreePanelArray(gWater);
1711 FreePanelArray(gAcid1);
1712 FreePanelArray(gAcid2);
1713 FreePanelArray(gSteps);
1714 FreePanelArray(gLifts);
1715 FreePanelArray(gBlockMon);
1717 if BackID <> DWORD(-1) then
1718 begin
1719 gBackSize.X := 0;
1720 gBackSize.Y := 0;
1721 e_DeleteTexture(BackID);
1722 BackID := DWORD(-1);
1723 end;
1725 g_Game_StopAllSounds(False);
1726 gMusic.FreeSound();
1727 g_Sound_Delete(gMapInfo.MusicName);
1729 gMapInfo.Name := '';
1730 gMapInfo.Description := '';
1731 gMapInfo.MusicName := '';
1732 gMapInfo.Height := 0;
1733 gMapInfo.Width := 0;
1735 gDoorMap := nil;
1736 gLiftMap := nil;
1738 PanelByID := nil;
1739 end;
1741 procedure g_Map_Update();
1742 var
1743 a, d, j: Integer;
1744 m: Word;
1745 s: String;
1747 procedure UpdatePanelArray(var panels: TPanelArray);
1748 var
1749 i: Integer;
1751 begin
1752 if panels <> nil then
1753 for i := 0 to High(panels) do
1754 panels[i].Update();
1755 end;
1757 begin
1758 UpdatePanelArray(gWalls);
1759 UpdatePanelArray(gRenderBackgrounds);
1760 UpdatePanelArray(gRenderForegrounds);
1761 UpdatePanelArray(gWater);
1762 UpdatePanelArray(gAcid1);
1763 UpdatePanelArray(gAcid2);
1764 UpdatePanelArray(gSteps);
1766 if gGameSettings.GameMode = GM_CTF then
1767 begin
1768 for a := FLAG_RED to FLAG_BLUE do
1769 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1770 with gFlags[a] do
1771 begin
1772 if gFlags[a].Animation <> nil then
1773 gFlags[a].Animation.Update();
1775 m := g_Obj_Move(@Obj, True, True);
1777 if gTime mod (GAME_TICK*2) <> 0 then
1778 Continue;
1780 // Ñîïðîòèâëåíèå âîçäóõà:
1781 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1783 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1784 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1785 begin
1786 g_Map_ResetFlag(a);
1787 gFlags[a].CaptureTime := 0;
1788 if a = FLAG_RED then
1789 s := _lc[I_PLAYER_FLAG_RED]
1790 else
1791 s := _lc[I_PLAYER_FLAG_BLUE];
1792 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1794 if g_Game_IsNet then
1795 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1796 Continue;
1797 end;
1799 if Count > 0 then
1800 Count := Count - 1;
1802 // Èãðîê áåðåò ôëàã:
1803 if gPlayers <> nil then
1804 begin
1805 j := Random(Length(gPlayers)) - 1;
1807 for d := 0 to High(gPlayers) do
1808 begin
1809 Inc(j);
1810 if j > High(gPlayers) then
1811 j := 0;
1813 if gPlayers[j] <> nil then
1814 if gPlayers[j].Live and
1815 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1816 begin
1817 if gPlayers[j].GetFlag(a) then
1818 Break;
1819 end;
1820 end;
1821 end;
1822 end;
1823 end;
1824 end;
1827 procedure g_Map_DrawPanelsOld(PanelType: Word);
1829 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1830 var
1831 idx: Integer;
1832 begin
1833 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1834 begin
1835 // alas, no visible set
1836 for idx := 0 to High(panels) do
1837 begin
1838 if not (drawDoors xor panels[idx].Door) then panels[idx].Draw();
1839 end;
1840 end;
1841 end;
1843 begin
1844 case PanelType of
1845 PANEL_WALL: DrawPanels(0, gWalls);
1846 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1847 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1848 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1849 PANEL_WATER: DrawPanels(3, gWater);
1850 PANEL_ACID1: DrawPanels(4, gAcid1);
1851 PANEL_ACID2: DrawPanels(5, gAcid2);
1852 PANEL_STEP: DrawPanels(6, gSteps);
1853 end;
1854 end;
1857 var
1858 gDrawPanelList: TBinaryHeapObj = nil;
1860 function dplLess (a, b: TObject): Boolean;
1861 begin
1862 result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx);
1863 end;
1865 procedure dplClear ();
1866 begin
1867 if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear();
1868 end;
1870 procedure dplAddPanel (pan: TPanel);
1871 begin
1872 if pan = nil then exit;
1873 gDrawPanelList.insert(pan);
1874 end;
1877 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
1878 var
1879 ptag: Integer;
1881 function checker (obj: TObject; tag: Integer): Boolean;
1882 var
1883 pan: TPanel;
1884 begin
1885 result := false; // don't stop, ever
1886 if (tag <> ptag) then exit;
1887 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1889 if obj = nil then begin e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
1890 if not (obj is TPanel) then begin e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
1891 //pan := (obj as TPanel);
1892 //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1894 pan := (obj as TPanel);
1895 if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end;
1896 //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1897 dplAddPanel(pan);
1898 end;
1900 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1901 var
1902 idx: Integer;
1903 pan: TPanel;
1904 begin
1905 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1906 begin
1907 // alas, no visible set
1908 for idx := 0 to High(panels) do
1909 begin
1910 if not (drawDoors xor panels[idx].Door) then
1911 begin
1912 pan := panels[idx];
1914 if (pan.Width < 1) or (pan.Height < 1) then continue;
1915 if (pan.X+pan.Width <= x0) or (pan.Y+pan.Height <= y0) then continue;
1916 if (pan.X >= x0+wdt) or (pan.Y >= y0+hgt) then continue;
1918 pan.Draw();
1919 //e_WriteLog(Format(' *body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, PanelType, PanelType]), MSG_NOTIFY);
1920 end;
1921 end;
1922 end;
1923 end;
1925 begin
1926 //g_Map_DrawPanelsOld(PanelType); exit;
1927 //e_WriteLog('==================', MSG_NOTIFY);
1928 //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1929 dplClear();
1930 ptag := panelTypeToTag(PanelType);
1932 if gdbg_map_use_grid_render then
1933 begin
1934 if gdbg_map_use_sap_draw then
1935 begin
1936 gMapSAP.forEachInAABB(x0, y0, wdt, hgt, checker);
1937 end
1938 else
1939 begin
1940 gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker);
1941 end;
1942 // sort and draw the list (we need to sort it, or rendering is fucked)
1943 while gDrawPanelList.count > 0 do
1944 begin
1945 (gDrawPanelList.front() as TPanel).Draw();
1946 gDrawPanelList.popFront();
1947 end;
1948 end
1949 else
1950 begin
1951 //e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1952 case PanelType of
1953 PANEL_WALL: DrawPanels(0, gWalls);
1954 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1955 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1956 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1957 PANEL_WATER: DrawPanels(3, gWater);
1958 PANEL_ACID1: DrawPanels(4, gAcid1);
1959 PANEL_ACID2: DrawPanels(5, gAcid2);
1960 PANEL_STEP: DrawPanels(6, gSteps);
1961 end;
1962 end;
1964 //e_WriteLog('==================', MSG_NOTIFY);
1965 end;
1968 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
1969 function checker (obj: TObject; tag: Integer): Boolean;
1970 var
1971 pan: TPanel;
1972 begin
1973 result := false; // don't stop, ever
1974 if (tag <> GridTagWallDoor) then exit; // only walls
1975 pan := (obj as TPanel);
1976 pan.DrawShadowVolume(lightX, lightY, radius);
1977 end;
1979 begin
1980 if gdbg_map_use_sap_draw then
1981 begin
1982 gMapSAP.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker);
1983 end
1984 else
1985 begin
1986 gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker);
1987 end;
1988 end;
1991 procedure g_Map_DrawBack(dx, dy: Integer);
1992 begin
1993 if gDrawBackGround and (BackID <> DWORD(-1)) then
1994 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1995 else
1996 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1997 end;
1999 function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word;
2000 PanelType: Word; b1x3: Boolean): Boolean;
2001 var
2002 a, h: Integer;
2003 begin
2004 Result := False;
2006 if WordBool(PanelType and PANEL_WALL) then
2007 if gWalls <> nil then
2008 begin
2009 h := High(gWalls);
2011 for a := 0 to h do
2012 if gWalls[a].Enabled and
2013 g_Collide(X, Y, Width, Height,
2014 gWalls[a].X, gWalls[a].Y,
2015 gWalls[a].Width, gWalls[a].Height) then
2016 begin
2017 Result := True;
2018 Exit;
2019 end;
2020 end;
2022 if WordBool(PanelType and PANEL_WATER) then
2023 if gWater <> nil then
2024 begin
2025 h := High(gWater);
2027 for a := 0 to h do
2028 if g_Collide(X, Y, Width, Height,
2029 gWater[a].X, gWater[a].Y,
2030 gWater[a].Width, gWater[a].Height) then
2031 begin
2032 Result := True;
2033 Exit;
2034 end;
2035 end;
2037 if WordBool(PanelType and PANEL_ACID1) then
2038 if gAcid1 <> nil then
2039 begin
2040 h := High(gAcid1);
2042 for a := 0 to h do
2043 if g_Collide(X, Y, Width, Height,
2044 gAcid1[a].X, gAcid1[a].Y,
2045 gAcid1[a].Width, gAcid1[a].Height) then
2046 begin
2047 Result := True;
2048 Exit;
2049 end;
2050 end;
2052 if WordBool(PanelType and PANEL_ACID2) then
2053 if gAcid2 <> nil then
2054 begin
2055 h := High(gAcid2);
2057 for a := 0 to h do
2058 if g_Collide(X, Y, Width, Height,
2059 gAcid2[a].X, gAcid2[a].Y,
2060 gAcid2[a].Width, gAcid2[a].Height) then
2061 begin
2062 Result := True;
2063 Exit;
2064 end;
2065 end;
2067 if WordBool(PanelType and PANEL_STEP) then
2068 if gSteps <> nil then
2069 begin
2070 h := High(gSteps);
2072 for a := 0 to h do
2073 if g_Collide(X, Y, Width, Height,
2074 gSteps[a].X, gSteps[a].Y,
2075 gSteps[a].Width, gSteps[a].Height) then
2076 begin
2077 Result := True;
2078 Exit;
2079 end;
2080 end;
2082 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
2083 if gLifts <> nil then
2084 begin
2085 h := High(gLifts);
2087 for a := 0 to h do
2088 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2089 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2090 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2091 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2092 g_Collide(X, Y, Width, Height,
2093 gLifts[a].X, gLifts[a].Y,
2094 gLifts[a].Width, gLifts[a].Height) then
2095 begin
2096 Result := True;
2097 Exit;
2098 end;
2099 end;
2101 if WordBool(PanelType and PANEL_BLOCKMON) then
2102 if gBlockMon <> nil then
2103 begin
2104 h := High(gBlockMon);
2106 for a := 0 to h do
2107 if ( (not b1x3) or
2108 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2109 g_Collide(X, Y, Width, Height,
2110 gBlockMon[a].X, gBlockMon[a].Y,
2111 gBlockMon[a].Width, gBlockMon[a].Height) then
2112 begin
2113 Result := True;
2114 Exit;
2115 end;
2116 end;
2117 end;
2119 function g_Map_CollideLiquid_TextureOld(X, Y: Integer; Width, Height: Word): DWORD;
2120 var
2121 texid: DWORD;
2123 function checkPanels (var panels: TPanelArray): Boolean;
2124 var
2125 a: Integer;
2126 begin
2127 result := false;
2128 if panels = nil then exit;
2129 for a := 0 to High(panels) do
2130 begin
2131 if g_Collide(X, Y, Width, Height, panels[a].X, panels[a].Y, panels[a].Width, panels[a].Height) then
2132 begin
2133 result := true;
2134 texid := panels[a].GetTextureID();
2135 exit;
2136 end;
2137 end;
2138 end;
2140 begin
2141 texid := TEXTURE_NONE;
2142 result := texid;
2143 if not checkPanels(gWater) then
2144 if not checkPanels(gAcid1) then
2145 if not checkPanels(gAcid2) then exit;
2146 result := texid;
2147 end;
2150 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean;
2152 function checker (obj: TObject; tag: Integer): Boolean;
2153 var
2154 pan: TPanel;
2155 a: Integer;
2156 begin
2157 result := false; // don't stop, ever
2159 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2161 if obj = nil then
2162 begin
2163 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2164 end;
2165 if not (obj is TPanel) then
2166 begin
2167 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2168 exit;
2169 end;
2171 pan := (obj as TPanel);
2172 a := pan.ArrIdx;
2174 if WordBool(PanelType and PANEL_WALL) and (tag = GridTagWallDoor) then
2175 begin
2176 if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then
2177 begin
2178 result := true;
2179 exit;
2180 end;
2181 end;
2183 if WordBool(PanelType and PANEL_WATER) and (tag = GridTagWater) then
2184 begin
2185 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2186 begin
2187 result := True;
2188 exit;
2189 end;
2190 end;
2192 if WordBool(PanelType and PANEL_ACID1) and (tag = GridTagAcid1) then
2193 begin
2194 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2195 begin
2196 result := True;
2197 exit;
2198 end;
2199 end;
2201 if WordBool(PanelType and PANEL_ACID2) and (tag = GridTagAcid2) then
2202 begin
2203 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2204 begin
2205 result := True;
2206 exit;
2207 end;
2208 end;
2210 if WordBool(PanelType and PANEL_STEP) and (tag = GridTagStep) then
2211 begin
2212 if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then
2213 begin
2214 result := True;
2215 exit;
2216 end;
2217 end;
2219 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (tag = GridTagLift) then
2220 begin
2221 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2222 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2223 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2224 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2225 g_Collide(X, Y, Width, Height, gLifts[a].X, gLifts[a].Y, gLifts[a].Width, gLifts[a].Height) then
2226 begin
2227 result := true;
2228 exit;
2229 end;
2230 end;
2232 if WordBool(PanelType and PANEL_BLOCKMON) and (tag = GridTagBlockMon) then
2233 begin
2234 if ((not b1x3) or ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64)) and
2235 g_Collide(X, Y, Width, Height, gBlockMon[a].X, gBlockMon[a].Y, gBlockMon[a].Width, gBlockMon[a].Height) then
2236 begin
2237 result := True;
2238 exit;
2239 end;
2240 end;
2241 end;
2243 begin
2244 //TODO: detailed profile
2245 if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('wall coldet');
2246 try
2247 if gdbg_map_use_grid_coldet then
2248 begin
2249 if gdbg_map_use_sap_coldet then
2250 begin
2251 gMapSAP.forEachInAABB(X, Y, Width, Height, checker);
2252 end
2253 else
2254 begin
2255 result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
2256 end;
2257 end
2258 else
2259 begin
2260 result := g_Map_CollidePanelOld(X, Y, Width, Height, PanelType, b1x3);
2261 end;
2262 finally
2263 if (profMapCollision <> nil) then profMapCollision.sectionEnd();
2264 end;
2265 end;
2268 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
2269 var
2270 cctype: Integer = 3; // priority: 0: water, 1: acid1, 2: acid2; 3: others (nothing)
2271 texid: DWORD;
2273 // slightly different from the old code, but meh...
2274 function checker (obj: TObject; tag: Integer): Boolean;
2275 var
2276 pan: TPanel;
2277 a: Integer;
2278 begin
2279 result := false; // don't stop, ever
2280 pan := (obj as TPanel);
2281 a := pan.ArrIdx;
2282 // water
2283 if (tag = GridTagWater) then
2284 begin
2285 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2286 begin
2287 result := true; // water has highest priority, so stop right here
2288 texid := gWater[a].GetTextureID();
2289 exit;
2290 end;
2291 end;
2292 // acid1
2293 if (cctype > 1) and (tag = GridTagAcid1) then
2294 begin
2295 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2296 begin
2297 cctype := 1;
2298 texid := gAcid1[a].GetTextureID();
2299 exit;
2300 end;
2301 end;
2302 // acid2
2303 if (cctype > 2) and (tag = GridTagAcid2) then
2304 begin
2305 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2306 begin
2307 cctype := 2;
2308 texid := gAcid2[a].GetTextureID();
2309 exit;
2310 end;
2311 end;
2312 end;
2314 begin
2315 //TODO: detailed profile?
2316 if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('liquid coldet');
2317 try
2318 if gdbg_map_use_grid_coldet then
2319 begin
2320 texid := TEXTURE_NONE;
2321 if gdbg_map_use_sap_coldet then
2322 begin
2323 gMapSAP.forEachInAABB(X, Y, Width, Height, checker);
2324 end
2325 else
2326 begin
2327 gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
2328 end;
2329 result := texid;
2330 end
2331 else
2332 begin
2333 result := g_Map_CollideLiquid_TextureOld(X, Y, Width, Height);
2334 end;
2335 finally
2336 if (profMapCollision <> nil) then profMapCollision.sectionEnd();
2337 end;
2338 end;
2340 procedure g_Map_EnableWall(ID: DWORD);
2341 begin
2342 with gWalls[ID] do
2343 begin
2344 Enabled := True;
2345 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
2347 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2348 end;
2349 end;
2351 procedure g_Map_DisableWall(ID: DWORD);
2352 begin
2353 with gWalls[ID] do
2354 begin
2355 Enabled := False;
2356 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
2358 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2359 end;
2360 end;
2362 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
2363 var
2364 tp: TPanel;
2365 begin
2366 case PanelType of
2367 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2368 tp := gWalls[ID];
2369 PANEL_FORE:
2370 tp := gRenderForegrounds[ID];
2371 PANEL_BACK:
2372 tp := gRenderBackgrounds[ID];
2373 PANEL_WATER:
2374 tp := gWater[ID];
2375 PANEL_ACID1:
2376 tp := gAcid1[ID];
2377 PANEL_ACID2:
2378 tp := gAcid2[ID];
2379 PANEL_STEP:
2380 tp := gSteps[ID];
2381 else
2382 Exit;
2383 end;
2385 tp.NextTexture(AnimLoop);
2386 if g_Game_IsServer and g_Game_IsNet then
2387 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
2388 end;
2390 procedure g_Map_SetLift(ID: DWORD; t: Integer);
2391 begin
2392 if gLifts[ID].LiftType = t then
2393 Exit;
2395 with gLifts[ID] do
2396 begin
2397 LiftType := t;
2399 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
2401 if LiftType = 0 then
2402 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
2403 else if LiftType = 1 then
2404 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
2405 else if LiftType = 2 then
2406 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
2407 else if LiftType = 3 then
2408 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
2410 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2411 end;
2412 end;
2414 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
2415 var
2416 a: Integer;
2417 PointsArray: Array of TRespawnPoint;
2418 begin
2419 Result := False;
2420 SetLength(PointsArray, 0);
2422 if RespawnPoints = nil then
2423 Exit;
2425 for a := 0 to High(RespawnPoints) do
2426 if RespawnPoints[a].PointType = PointType then
2427 begin
2428 SetLength(PointsArray, Length(PointsArray)+1);
2429 PointsArray[High(PointsArray)] := RespawnPoints[a];
2430 end;
2432 if PointsArray = nil then
2433 Exit;
2435 RespawnPoint := PointsArray[Random(Length(PointsArray))];
2436 Result := True;
2437 end;
2439 function g_Map_GetPointCount(PointType: Byte): Word;
2440 var
2441 a: Integer;
2442 begin
2443 Result := 0;
2445 if RespawnPoints = nil then
2446 Exit;
2448 for a := 0 to High(RespawnPoints) do
2449 if RespawnPoints[a].PointType = PointType then
2450 Result := Result + 1;
2451 end;
2453 function g_Map_HaveFlagPoints(): Boolean;
2454 begin
2455 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
2456 end;
2458 procedure g_Map_ResetFlag(Flag: Byte);
2459 begin
2460 with gFlags[Flag] do
2461 begin
2462 Obj.X := -1000;
2463 Obj.Y := -1000;
2464 Obj.Vel.X := 0;
2465 Obj.Vel.Y := 0;
2466 Direction := D_LEFT;
2467 State := FLAG_STATE_NONE;
2468 if FlagPoints[Flag] <> nil then
2469 begin
2470 Obj.X := FlagPoints[Flag]^.X;
2471 Obj.Y := FlagPoints[Flag]^.Y;
2472 Direction := FlagPoints[Flag]^.Direction;
2473 State := FLAG_STATE_NORMAL;
2474 end;
2475 Count := -1;
2476 end;
2477 end;
2479 procedure g_Map_DrawFlags();
2480 var
2481 i, dx: Integer;
2482 Mirror: TMirrorType;
2483 begin
2484 if gGameSettings.GameMode <> GM_CTF then
2485 Exit;
2487 for i := FLAG_RED to FLAG_BLUE do
2488 with gFlags[i] do
2489 if State <> FLAG_STATE_CAPTURED then
2490 begin
2491 if State = FLAG_STATE_NONE then
2492 continue;
2494 if Direction = D_LEFT then
2495 begin
2496 Mirror := M_HORIZONTAL;
2497 dx := -1;
2498 end
2499 else
2500 begin
2501 Mirror := M_NONE;
2502 dx := 1;
2503 end;
2505 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2507 if g_debug_Frames then
2508 begin
2509 e_DrawQuad(Obj.X+Obj.Rect.X,
2510 Obj.Y+Obj.Rect.Y,
2511 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2512 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2513 0, 255, 0);
2514 end;
2515 end;
2516 end;
2518 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2519 var
2520 dw: DWORD;
2521 b: Byte;
2522 str: String;
2523 boo: Boolean;
2525 procedure SavePanelArray(var panels: TPanelArray);
2526 var
2527 PAMem: TBinMemoryWriter;
2528 i: Integer;
2529 begin
2530 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2531 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2533 i := 0;
2534 while i < Length(panels) do
2535 begin
2536 if panels[i].SaveIt then
2537 begin
2538 // ID ïàíåëè:
2539 PAMem.WriteInt(i);
2540 // Ñîõðàíÿåì ïàíåëü:
2541 panels[i].SaveState(PAMem);
2542 end;
2543 Inc(i);
2544 end;
2546 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2547 PAMem.SaveToMemory(Mem);
2548 PAMem.Free();
2549 end;
2551 procedure SaveFlag(flag: PFlag);
2552 begin
2553 // Ñèãíàòóðà ôëàãà:
2554 dw := FLAG_SIGNATURE; // 'FLAG'
2555 Mem.WriteDWORD(dw);
2556 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2557 Mem.WriteByte(flag^.RespawnType);
2558 // Ñîñòîÿíèå ôëàãà:
2559 Mem.WriteByte(flag^.State);
2560 // Íàïðàâëåíèå ôëàãà:
2561 if flag^.Direction = D_LEFT then
2562 b := 1
2563 else // D_RIGHT
2564 b := 2;
2565 Mem.WriteByte(b);
2566 // Îáúåêò ôëàãà:
2567 Obj_SaveState(@flag^.Obj, Mem);
2568 end;
2570 begin
2571 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2573 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2574 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2575 SavePanelArray(gWalls);
2576 // Ñîõðàíÿåì ïàíåëè ôîíà:
2577 SavePanelArray(gRenderBackgrounds);
2578 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2579 SavePanelArray(gRenderForegrounds);
2580 // Ñîõðàíÿåì ïàíåëè âîäû:
2581 SavePanelArray(gWater);
2582 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2583 SavePanelArray(gAcid1);
2584 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2585 SavePanelArray(gAcid2);
2586 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2587 SavePanelArray(gSteps);
2588 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2589 SavePanelArray(gLifts);
2590 ///// /////
2592 ///// Ñîõðàíÿåì ìóçûêó: /////
2593 // Ñèãíàòóðà ìóçûêè:
2594 dw := MUSIC_SIGNATURE; // 'MUSI'
2595 Mem.WriteDWORD(dw);
2596 // Íàçâàíèå ìóçûêè:
2597 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2598 if gMusic.NoMusic then
2599 str := ''
2600 else
2601 str := gMusic.Name;
2602 Mem.WriteString(str, 64);
2603 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2604 dw := gMusic.GetPosition();
2605 Mem.WriteDWORD(dw);
2606 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2607 boo := gMusic.SpecPause;
2608 Mem.WriteBoolean(boo);
2609 ///// /////
2611 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2612 Mem.WriteInt(gTotalMonsters);
2613 ///// /////
2615 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2616 if gGameSettings.GameMode = GM_CTF then
2617 begin
2618 // Ôëàã Êðàñíîé êîìàíäû:
2619 SaveFlag(@gFlags[FLAG_RED]);
2620 // Ôëàã Ñèíåé êîìàíäû:
2621 SaveFlag(@gFlags[FLAG_BLUE]);
2622 end;
2623 ///// /////
2625 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2626 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2627 begin
2628 // Î÷êè Êðàñíîé êîìàíäû:
2629 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2630 // Î÷êè Ñèíåé êîìàíäû:
2631 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2632 end;
2633 ///// /////
2634 end;
2636 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2637 var
2638 dw: DWORD;
2639 b: Byte;
2640 str: String;
2641 boo: Boolean;
2643 procedure LoadPanelArray(var panels: TPanelArray);
2644 var
2645 PAMem: TBinMemoryReader;
2646 i, id: Integer;
2647 begin
2648 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2649 PAMem := TBinMemoryReader.Create();
2650 PAMem.LoadFromMemory(Mem);
2652 for i := 0 to Length(panels)-1 do
2653 if panels[i].SaveIt then
2654 begin
2655 // ID ïàíåëè:
2656 PAMem.ReadInt(id);
2657 if id <> i then
2658 begin
2659 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2660 end;
2661 // Çàãðóæàåì ïàíåëü:
2662 panels[i].LoadState(PAMem);
2663 end;
2665 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2666 PAMem.Free();
2667 end;
2669 procedure LoadFlag(flag: PFlag);
2670 begin
2671 // Ñèãíàòóðà ôëàãà:
2672 Mem.ReadDWORD(dw);
2673 if dw <> FLAG_SIGNATURE then // 'FLAG'
2674 begin
2675 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2676 end;
2677 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2678 Mem.ReadByte(flag^.RespawnType);
2679 // Ñîñòîÿíèå ôëàãà:
2680 Mem.ReadByte(flag^.State);
2681 // Íàïðàâëåíèå ôëàãà:
2682 Mem.ReadByte(b);
2683 if b = 1 then
2684 flag^.Direction := D_LEFT
2685 else // b = 2
2686 flag^.Direction := D_RIGHT;
2687 // Îáúåêò ôëàãà:
2688 Obj_LoadState(@flag^.Obj, Mem);
2689 end;
2691 begin
2692 if Mem = nil then
2693 Exit;
2695 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2696 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2697 LoadPanelArray(gWalls);
2698 // Çàãðóæàåì ïàíåëè ôîíà:
2699 LoadPanelArray(gRenderBackgrounds);
2700 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2701 LoadPanelArray(gRenderForegrounds);
2702 // Çàãðóæàåì ïàíåëè âîäû:
2703 LoadPanelArray(gWater);
2704 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2705 LoadPanelArray(gAcid1);
2706 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2707 LoadPanelArray(gAcid2);
2708 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2709 LoadPanelArray(gSteps);
2710 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2711 LoadPanelArray(gLifts);
2712 ///// /////
2714 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé è ñåòêó:
2715 g_GFX_Init();
2716 mapCreateGrid();
2718 ///// Çàãðóæàåì ìóçûêó: /////
2719 // Ñèãíàòóðà ìóçûêè:
2720 Mem.ReadDWORD(dw);
2721 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2722 begin
2723 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2724 end;
2725 // Íàçâàíèå ìóçûêè:
2726 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2727 Mem.ReadString(str);
2728 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2729 Mem.ReadDWORD(dw);
2730 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2731 Mem.ReadBoolean(boo);
2732 // Çàïóñêàåì ýòó ìóçûêó:
2733 gMusic.SetByName(str);
2734 gMusic.SpecPause := boo;
2735 gMusic.Play();
2736 gMusic.Pause(True);
2737 gMusic.SetPosition(dw);
2738 ///// /////
2740 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2741 Mem.ReadInt(gTotalMonsters);
2742 ///// /////
2744 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2745 if gGameSettings.GameMode = GM_CTF then
2746 begin
2747 // Ôëàã Êðàñíîé êîìàíäû:
2748 LoadFlag(@gFlags[FLAG_RED]);
2749 // Ôëàã Ñèíåé êîìàíäû:
2750 LoadFlag(@gFlags[FLAG_BLUE]);
2751 end;
2752 ///// /////
2754 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2755 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2756 begin
2757 // Î÷êè Êðàñíîé êîìàíäû:
2758 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2759 // Î÷êè Ñèíåé êîìàíäû:
2760 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2761 end;
2762 ///// /////
2763 end;
2765 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
2766 var
2767 Arr: TPanelArray;
2768 begin
2769 Result := nil;
2770 if (PanelID < 0) or (PanelID > High(PanelByID)) then Exit;
2771 Arr := PanelByID[PanelID].PWhere^;
2772 PanelArrayID := PanelByID[PanelID].PArrID;
2773 Result := Addr(Arr[PanelByID[PanelID].PArrID]);
2774 end;
2776 end.