DEADSOFTWARE

42831447a301bf9409e28a2eb38bd66590b9f4a5
[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, md5;
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 const
94 RESPAWNPOINT_PLAYER1 = 1;
95 RESPAWNPOINT_PLAYER2 = 2;
96 RESPAWNPOINT_DM = 3;
97 RESPAWNPOINT_RED = 4;
98 RESPAWNPOINT_BLUE = 5;
100 FLAG_NONE = 0;
101 FLAG_RED = 1;
102 FLAG_BLUE = 2;
103 FLAG_DOM = 3;
105 FLAG_STATE_NONE = 0;
106 FLAG_STATE_NORMAL = 1;
107 FLAG_STATE_DROPPED = 2;
108 FLAG_STATE_CAPTURED = 3;
109 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
110 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
112 FLAG_TIME = 720; // 20 seconds
114 SKY_STRETCH: Single = 1.5;
116 var
117 gWalls: TPanelArray;
118 gRenderBackgrounds: TPanelArray;
119 gRenderForegrounds: TPanelArray;
120 gWater, gAcid1, gAcid2: TPanelArray;
121 gSteps: TPanelArray;
122 gLifts: TPanelArray;
123 gBlockMon: TPanelArray;
124 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
125 //gDOMFlags: array of TFlag;
126 gMapInfo: TMapInfo;
127 gBackSize: TPoint;
128 gDoorMap: array of array of DWORD;
129 gLiftMap: array of array of DWORD;
130 gWADHash: TMD5Digest;
131 BackID: DWORD = DWORD(-1);
132 gExternalResources: TStringList;
134 gdbg_map_use_grid_render: Boolean = true;
135 gdbg_map_use_grid_coldet: Boolean = true;
137 implementation
139 uses
140 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
141 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
142 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
143 Math, g_monsters, g_saveload, g_language, g_netmsg,
144 utils, sfs,
145 ImagingTypes, Imaging, ImagingUtility,
146 ImagingGif, ImagingNetworkGraphics;
148 const
149 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
150 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
151 FLAG_SIGNATURE = $47414C46; // 'FLAG'
153 GridTagInvalid = -1;
154 GridTagWallDoor = 0;
155 GridTagBack = 1;
156 GridTagFore = 2;
157 GridTagWater = 3;
158 GridTagAcid1 = 4;
159 GridTagAcid2 = 5;
160 GridTagStep = 6;
161 GridTagLift = 7;
162 GridTagBlockMon = 8;
165 function panelTypeToTag (panelType: Word): Integer;
166 begin
167 case panelType of
168 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR: result := GridTagWallDoor; // gWalls
169 PANEL_BACK: result := GridTagBack; // gRenderBackgrounds
170 PANEL_FORE: result := GridTagFore; // gRenderForegrounds
171 PANEL_WATER: result := GridTagWater; // gWater
172 PANEL_ACID1: result := GridTagAcid1; // gAcid1
173 PANEL_ACID2: result := GridTagAcid2; // gAcid2
174 PANEL_STEP: result := GridTagStep; // gSteps
175 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT: result := GridTagLift; // gLifts -- this is for all lifts
176 PANEL_BLOCKMON: result := GridTagBlockMon; // gBlockMon -- this is for all blockmons
177 else result := GridTagInvalid;
178 end;
179 end;
182 type
183 TPanelID = record
184 PWhere: ^TPanelArray;
185 PArrID: Integer;
186 end;
188 var
189 PanelById: array of TPanelID;
190 Textures: TLevelTextureArray;
191 RespawnPoints: Array of TRespawnPoint;
192 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
193 //DOMFlagPoints: Array of TFlagPoint;
194 gMapGrid: TBodyGrid = nil;
197 function g_Map_IsSpecialTexture(Texture: String): Boolean;
198 begin
199 Result := (Texture = TEXTURE_NAME_WATER) or
200 (Texture = TEXTURE_NAME_ACID1) or
201 (Texture = TEXTURE_NAME_ACID2);
202 end;
204 procedure CreateDoorMap();
205 var
206 PanelArray: Array of record
207 X, Y: Integer;
208 Width, Height: Word;
209 Active: Boolean;
210 PanelID: DWORD;
211 end;
212 a, b, c, m, i, len: Integer;
213 ok: Boolean;
214 begin
215 if gWalls = nil then
216 Exit;
218 i := 0;
219 len := 128;
220 SetLength(PanelArray, len);
222 for a := 0 to High(gWalls) do
223 if gWalls[a].Door then
224 begin
225 PanelArray[i].X := gWalls[a].X;
226 PanelArray[i].Y := gWalls[a].Y;
227 PanelArray[i].Width := gWalls[a].Width;
228 PanelArray[i].Height := gWalls[a].Height;
229 PanelArray[i].Active := True;
230 PanelArray[i].PanelID := a;
232 i := i + 1;
233 if i = len then
234 begin
235 len := len + 128;
236 SetLength(PanelArray, len);
237 end;
238 end;
240 // Íåò äâåðåé:
241 if i = 0 then
242 begin
243 PanelArray := nil;
244 Exit;
245 end;
247 SetLength(gDoorMap, 0);
249 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
251 for a := 0 to i-1 do
252 if PanelArray[a].Active then
253 begin
254 PanelArray[a].Active := False;
255 m := Length(gDoorMap);
256 SetLength(gDoorMap, m+1);
257 SetLength(gDoorMap[m], 1);
258 gDoorMap[m, 0] := PanelArray[a].PanelID;
259 ok := True;
261 while ok do
262 begin
263 ok := False;
265 for b := 0 to i-1 do
266 if PanelArray[b].Active then
267 for c := 0 to High(gDoorMap[m]) do
268 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
269 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
270 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
271 PanelArray[b].Width, PanelArray[b].Height,
272 gWalls[gDoorMap[m, c]].X,
273 gWalls[gDoorMap[m, c]].Y,
274 gWalls[gDoorMap[m, c]].Width,
275 gWalls[gDoorMap[m, c]].Height) then
276 begin
277 PanelArray[b].Active := False;
278 SetLength(gDoorMap[m],
279 Length(gDoorMap[m])+1);
280 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
281 ok := True;
282 Break;
283 end;
284 end;
286 g_Game_StepLoading();
287 end;
289 PanelArray := nil;
290 end;
292 procedure CreateLiftMap();
293 var
294 PanelArray: Array of record
295 X, Y: Integer;
296 Width, Height: Word;
297 Active: Boolean;
298 end;
299 a, b, c, len, i, j: Integer;
300 ok: Boolean;
301 begin
302 if gLifts = nil then
303 Exit;
305 len := Length(gLifts);
306 SetLength(PanelArray, len);
308 for a := 0 to len-1 do
309 begin
310 PanelArray[a].X := gLifts[a].X;
311 PanelArray[a].Y := gLifts[a].Y;
312 PanelArray[a].Width := gLifts[a].Width;
313 PanelArray[a].Height := gLifts[a].Height;
314 PanelArray[a].Active := True;
315 end;
317 SetLength(gLiftMap, len);
318 i := 0;
320 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
322 for a := 0 to len-1 do
323 if PanelArray[a].Active then
324 begin
325 PanelArray[a].Active := False;
326 SetLength(gLiftMap[i], 32);
327 j := 0;
328 gLiftMap[i, j] := a;
329 ok := True;
331 while ok do
332 begin
333 ok := False;
334 for b := 0 to len-1 do
335 if PanelArray[b].Active then
336 for c := 0 to j do
337 if g_CollideAround(PanelArray[b].X,
338 PanelArray[b].Y,
339 PanelArray[b].Width,
340 PanelArray[b].Height,
341 PanelArray[gLiftMap[i, c]].X,
342 PanelArray[gLiftMap[i, c]].Y,
343 PanelArray[gLiftMap[i, c]].Width,
344 PanelArray[gLiftMap[i, c]].Height) then
345 begin
346 PanelArray[b].Active := False;
347 j := j+1;
348 if j > High(gLiftMap[i]) then
349 SetLength(gLiftMap[i],
350 Length(gLiftMap[i])+32);
352 gLiftMap[i, j] := b;
353 ok := True;
355 Break;
356 end;
357 end;
359 SetLength(gLiftMap[i], j+1);
360 i := i+1;
362 g_Game_StepLoading();
363 end;
365 SetLength(gLiftMap, i);
367 PanelArray := nil;
368 end;
370 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
371 CurTex: Integer; sav: Boolean): Integer;
372 var
373 len: Integer;
374 panels: ^TPanelArray;
375 begin
376 Result := -1;
378 case PanelRec.PanelType of
379 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
380 panels := @gWalls;
381 PANEL_BACK:
382 panels := @gRenderBackgrounds;
383 PANEL_FORE:
384 panels := @gRenderForegrounds;
385 PANEL_WATER:
386 panels := @gWater;
387 PANEL_ACID1:
388 panels := @gAcid1;
389 PANEL_ACID2:
390 panels := @gAcid2;
391 PANEL_STEP:
392 panels := @gSteps;
393 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
394 panels := @gLifts;
395 PANEL_BLOCKMON:
396 panels := @gBlockMon;
397 else
398 Exit;
399 end;
401 len := Length(panels^);
402 SetLength(panels^, len + 1);
404 panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures);
405 panels^[len].ArrIdx := len;
406 if sav then
407 panels^[len].SaveIt := True;
409 Result := len;
411 len := Length(PanelByID);
412 SetLength(PanelByID, len + 1);
413 PanelByID[len].PWhere := panels;
414 PanelByID[len].PArrID := Result;
415 end;
417 function CreateNullTexture(RecName: String): Integer;
418 begin
419 SetLength(Textures, Length(Textures)+1);
420 result := High(Textures);
422 with Textures[High(Textures)] do
423 begin
424 TextureName := RecName;
425 Width := 1;
426 Height := 1;
427 Anim := False;
428 TextureID := TEXTURE_NONE;
429 end;
430 end;
432 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
433 var
434 WAD: TWADFile;
435 TextureData: Pointer;
436 WADName, txname: String;
437 a, ResLength: Integer;
438 begin
439 Result := -1;
441 if Textures <> nil then
442 for a := 0 to High(Textures) do
443 if Textures[a].TextureName = RecName then
444 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
445 Result := a;
446 Exit;
447 end;
449 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
450 if (RecName = TEXTURE_NAME_WATER) or
451 (RecName = TEXTURE_NAME_ACID1) or
452 (RecName = TEXTURE_NAME_ACID2) then
453 begin
454 SetLength(Textures, Length(Textures)+1);
456 with Textures[High(Textures)] do
457 begin
458 TextureName := RecName;
460 if TextureName = TEXTURE_NAME_WATER then
461 TextureID := TEXTURE_SPECIAL_WATER
462 else
463 if TextureName = TEXTURE_NAME_ACID1 then
464 TextureID := TEXTURE_SPECIAL_ACID1
465 else
466 if TextureName = TEXTURE_NAME_ACID2 then
467 TextureID := TEXTURE_SPECIAL_ACID2;
469 Anim := False;
470 end;
472 result := High(Textures);
473 Exit;
474 end;
476 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
477 WADName := g_ExtractWadName(RecName);
479 WAD := TWADFile.Create();
481 if WADName <> '' then
482 WADName := GameDir+'/wads/'+WADName
483 else
484 WADName := Map;
486 WAD.ReadFile(WADName);
488 txname := RecName;
490 if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
491 begin
492 FreeMem(TextureData);
493 RecName := 'COMMON\ALIEN';
494 end;
497 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
498 begin
499 SetLength(Textures, Length(Textures)+1);
500 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
501 Exit;
502 e_GetTextureSize(Textures[High(Textures)].TextureID,
503 @Textures[High(Textures)].Width,
504 @Textures[High(Textures)].Height);
505 FreeMem(TextureData);
506 Textures[High(Textures)].TextureName := {RecName}txname;
507 Textures[High(Textures)].Anim := False;
509 result := High(Textures);
510 end
511 else // Íåò òàêîãî ðåóñðñà â WAD'å
512 begin
513 //e_WriteLog(Format('SHIT! Error loading texture %s : %s : %s', [RecName, txname, g_ExtractFilePathName(RecName)]), MSG_WARNING);
514 if log then
515 begin
516 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
517 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
518 end;
519 end;
521 WAD.Free();
522 end;
524 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
525 var
526 WAD: TWADFile;
527 TextureWAD: PChar = nil;
528 TextData: Pointer = nil;
529 TextureData: Pointer = nil;
530 cfg: TConfig = nil;
531 WADName: String;
532 ResLength: Integer;
533 TextureResource: String;
534 _width, _height, _framecount, _speed: Integer;
535 _backanimation: Boolean;
536 //imgfmt: string;
537 ia: TDynImageDataArray = nil;
538 f, c, frdelay, frloop: Integer;
539 begin
540 result := -1;
542 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
544 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
545 WADName := g_ExtractWadName(RecName);
547 WAD := TWADFile.Create();
548 try
549 if WADName <> '' then
550 WADName := GameDir+'/wads/'+WADName
551 else
552 WADName := Map;
554 WAD.ReadFile(WADName);
556 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
557 begin
558 if log then
559 begin
560 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
561 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
562 end;
563 exit;
564 end;
566 {TEST
567 if WADName = Map then
568 begin
569 //FreeMem(TextureWAD);
570 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
571 end;
574 WAD.FreeWAD();
576 if ResLength < 6 then
577 begin
578 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
579 exit;
580 end;
582 // ýòî ïòèöà? ýòî ñàìîë¸ò?
583 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
584 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
585 begin
586 // íåò, ýòî ñóïåðìåí!
587 if not WAD.ReadMemory(TextureWAD, ResLength) then
588 begin
589 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
590 exit;
591 end;
593 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
594 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
595 begin
596 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
597 exit;
598 end;
600 cfg := TConfig.CreateMem(TextData, ResLength);
602 TextureResource := cfg.ReadStr('', 'resource', '');
603 if TextureResource = '' then
604 begin
605 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
606 exit;
607 end;
609 _width := cfg.ReadInt('', 'framewidth', 0);
610 _height := cfg.ReadInt('', 'frameheight', 0);
611 _framecount := cfg.ReadInt('', 'framecount', 0);
612 _speed := cfg.ReadInt('', 'waitcount', 0);
613 _backanimation := cfg.ReadBool('', 'backanimation', False);
615 cfg.Free();
616 cfg := nil;
618 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
619 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
620 begin
621 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
622 exit;
623 end;
625 WAD.Free();
626 WAD := nil;
628 SetLength(Textures, Length(Textures)+1);
629 with Textures[High(Textures)] do
630 begin
631 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
632 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
633 begin
634 TextureName := RecName;
635 Width := _width;
636 Height := _height;
637 Anim := True;
638 FramesCount := _framecount;
639 Speed := _speed;
640 result := High(Textures);
641 end
642 else
643 begin
644 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
645 end;
646 end;
647 end
648 else
649 begin
650 // try animated image
652 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
653 if length(imgfmt) = 0 then
654 begin
655 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
656 exit;
657 end;
659 GlobalMetadata.ClearMetaItems();
660 GlobalMetadata.ClearMetaItemsForSaving();
661 if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
662 begin
663 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
664 exit;
665 end;
666 if length(ia) = 0 then
667 begin
668 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
669 exit;
670 end;
672 WAD.Free();
673 WAD := nil;
675 _width := ia[0].width;
676 _height := ia[0].height;
677 _framecount := length(ia);
678 _speed := 1;
679 _backanimation := false;
680 frdelay := -1;
681 frloop := -666;
682 if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then
683 begin
684 //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]);
685 try
686 f := GlobalMetadata.MetaItems[SMetaFrameDelay];
687 frdelay := f;
688 if f < 0 then f := 0;
689 // rounding ;-)
690 c := f mod 28;
691 if c < 13 then c := 0 else c := 1;
692 f := (f div 28)+c;
693 if f < 1 then f := 1 else if f > 255 then f := 255;
694 _speed := f;
695 except
696 end;
697 end;
698 if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then
699 begin
700 //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]);
701 try
702 f := GlobalMetadata.MetaItems[SMetaAnimationLoops];
703 frloop := f;
704 if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back
705 except
706 end;
707 end;
708 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
709 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
710 f := ord(_backanimation);
711 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);
713 SetLength(Textures, Length(Textures)+1);
714 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
715 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
716 begin
717 Textures[High(Textures)].TextureName := RecName;
718 Textures[High(Textures)].Width := _width;
719 Textures[High(Textures)].Height := _height;
720 Textures[High(Textures)].Anim := True;
721 Textures[High(Textures)].FramesCount := length(ia);
722 Textures[High(Textures)].Speed := _speed;
723 result := High(Textures);
724 //writeln(' CREATED!');
725 end
726 else
727 begin
728 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
729 end;
730 end;
731 finally
732 for f := 0 to High(ia) do FreeImage(ia[f]);
733 WAD.Free();
734 cfg.Free();
735 if TextureWAD <> nil then FreeMem(TextureWAD);
736 if TextData <> nil then FreeMem(TextData);
737 if TextureData <> nil then FreeMem(TextureData);
738 end;
739 end;
741 procedure CreateItem(Item: TItemRec_1);
742 begin
743 if g_Game_IsClient then Exit;
745 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
746 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
747 Exit;
749 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
750 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
751 end;
753 procedure CreateArea(Area: TAreaRec_1);
754 var
755 a: Integer;
756 id: DWORD;
757 begin
758 case Area.AreaType of
759 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
760 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
761 begin
762 SetLength(RespawnPoints, Length(RespawnPoints)+1);
763 with RespawnPoints[High(RespawnPoints)] do
764 begin
765 X := Area.X;
766 Y := Area.Y;
767 Direction := TDirection(Area.Direction);
769 case Area.AreaType of
770 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
771 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
772 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
773 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
774 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
775 end;
776 end;
777 end;
779 AREA_REDFLAG, AREA_BLUEFLAG:
780 begin
781 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
783 if FlagPoints[a] <> nil then Exit;
785 New(FlagPoints[a]);
787 with FlagPoints[a]^ do
788 begin
789 X := Area.X-FLAGRECT.X;
790 Y := Area.Y-FLAGRECT.Y;
791 Direction := TDirection(Area.Direction);
792 end;
794 with gFlags[a] do
795 begin
796 case a of
797 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
798 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
799 end;
801 Animation := TAnimation.Create(id, True, 8);
802 Obj.Rect := FLAGRECT;
804 g_Map_ResetFlag(a);
805 end;
806 end;
808 AREA_DOMFLAG:
809 begin
810 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
811 with DOMFlagPoints[High(DOMFlagPoints)] do
812 begin
813 X := Area.X;
814 Y := Area.Y;
815 Direction := TDirection(Area.Direction);
816 end;
818 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
819 end;
820 end;
821 end;
823 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
824 var
825 _trigger: TTrigger;
826 begin
827 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
829 with _trigger do
830 begin
831 X := Trigger.X;
832 Y := Trigger.Y;
833 Width := Trigger.Width;
834 Height := Trigger.Height;
835 Enabled := ByteBool(Trigger.Enabled);
836 TexturePanel := Trigger.TexturePanel;
837 TexturePanelType := fTexturePanel1Type;
838 ShotPanelType := fTexturePanel2Type;
839 TriggerType := Trigger.TriggerType;
840 ActivateType := Trigger.ActivateType;
841 Keys := Trigger.Keys;
842 Data.Default := Trigger.DATA;
843 end;
845 g_Triggers_Create(_trigger);
846 end;
848 procedure CreateMonster(monster: TMonsterRec_1);
849 var
850 a, i: Integer;
851 begin
852 if g_Game_IsClient then Exit;
854 if (gGameSettings.GameType = GT_SINGLE)
855 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
856 begin
857 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
858 TDirection(monster.Direction));
860 if gTriggers <> nil then
861 for a := 0 to High(gTriggers) do
862 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
863 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
864 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
865 gMonsters[i].AddTrigger(a);
867 if monster.MonsterType <> MONSTER_BARREL then
868 Inc(gTotalMonsters);
869 end;
870 end;
872 procedure g_Map_ReAdd_DieTriggers();
873 var
874 i, a: Integer;
875 begin
876 if g_Game_IsClient then Exit;
878 for i := 0 to High(gMonsters) do
879 if gMonsters[i] <> nil then
880 begin
881 gMonsters[i].ClearTriggers();
883 for a := 0 to High(gTriggers) do
884 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
885 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
886 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
887 gMonsters[i].AddTrigger(a);
888 end;
889 end;
891 function extractWadName(resourceName: string): string;
892 var
893 posN: Integer;
894 begin
895 posN := Pos(':', resourceName);
896 if posN > 0 then
897 Result:= Copy(resourceName, 0, posN-1)
898 else
899 Result := '';
900 end;
902 procedure addResToExternalResList(res: string);
903 begin
904 res := extractWadName(res);
905 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
906 gExternalResources.Add(res);
907 end;
909 procedure generateExternalResourcesList(mapReader: TMapReader_1);
910 var
911 textures: TTexturesRec1Array;
912 mapHeader: TMapHeaderRec_1;
913 i: integer;
914 resFile: String = '';
915 begin
916 if gExternalResources = nil then
917 gExternalResources := TStringList.Create;
919 gExternalResources.Clear;
920 textures := mapReader.GetTextures();
921 for i := 0 to High(textures) do
922 begin
923 addResToExternalResList(resFile);
924 end;
926 textures := nil;
928 mapHeader := mapReader.GetMapHeader;
930 addResToExternalResList(mapHeader.MusicName);
931 addResToExternalResList(mapHeader.SkyName);
932 end;
934 procedure mapCreateGrid ();
935 var
936 mapX0: Integer = $3fffffff;
937 mapY0: Integer = $3fffffff;
938 mapX1: Integer = -$3fffffff;
939 mapY1: Integer = -$3fffffff;
941 procedure fixMinMax (var panels: TPanelArray);
942 var
943 idx: Integer;
944 begin
945 for idx := 0 to High(panels) do
946 begin
947 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
948 if mapX0 > panels[idx].X then mapX0 := panels[idx].X;
949 if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y;
950 if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1;
951 if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1;
952 end;
953 end;
955 procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer);
956 var
957 idx: Integer;
958 begin
959 tag := panelTypeToTag(tag);
960 for idx := High(panels) downto 0 do
961 begin
962 gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
963 end;
964 end;
966 begin
967 gMapGrid.Free();
968 gMapGrid := nil;
970 fixMinMax(gWalls);
971 fixMinMax(gRenderBackgrounds);
972 fixMinMax(gRenderForegrounds);
973 fixMinMax(gWater);
974 fixMinMax(gAcid1);
975 fixMinMax(gAcid2);
976 fixMinMax(gSteps);
977 fixMinMax(gLifts);
978 fixMinMax(gBlockMon);
980 if (mapX0 < 0) or (mapY0 < 0) then
981 begin
982 e_WriteLog(Format('funny map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING);
983 //raise Exception.Create('we are fucked');
984 end;
986 gMapGrid := TBodyGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1);
988 addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR
989 addPanelsToGrid(gRenderBackgrounds, PANEL_BACK);
990 addPanelsToGrid(gRenderForegrounds, PANEL_FORE);
991 addPanelsToGrid(gWater, PANEL_WATER);
992 addPanelsToGrid(gAcid1, PANEL_ACID1);
993 addPanelsToGrid(gAcid2, PANEL_ACID2);
994 addPanelsToGrid(gSteps, PANEL_STEP);
995 addPanelsToGrid(gLifts, PANEL_LIFTUP); // it doesn't matter which LIFT type is used here
996 addPanelsToGrid(gBlockMon, PANEL_BLOCKMON);
998 gMapGrid.dumpStats();
999 end;
1001 function g_Map_Load(Res: String): Boolean;
1002 const
1003 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
1004 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
1005 var
1006 WAD: TWADFile;
1007 MapReader: TMapReader_1;
1008 Header: TMapHeaderRec_1;
1009 _textures: TTexturesRec1Array;
1010 _texnummap: array of Integer; // `_textures` -> `Textures`
1011 panels: TPanelsRec1Array;
1012 items: TItemsRec1Array;
1013 monsters: TMonsterRec1Array;
1014 areas: TAreasRec1Array;
1015 triggers: TTriggersRec1Array;
1016 a, b, c, k: Integer;
1017 PanelID: DWORD;
1018 AddTextures: TAddTextureArray;
1019 texture: TTextureRec_1;
1020 TriggersTable: Array of record
1021 TexturePanel: Integer;
1022 LiftPanel: Integer;
1023 DoorPanel: Integer;
1024 ShotPanel: Integer;
1025 end;
1026 FileName, mapResName, s, TexName: String;
1027 Data: Pointer;
1028 Len: Integer;
1029 ok, isAnim, trigRef: Boolean;
1030 CurTex, ntn: Integer;
1032 begin
1033 gMapGrid.Free();
1034 gMapGrid := nil;
1036 Result := False;
1037 gMapInfo.Map := Res;
1038 TriggersTable := nil;
1039 FillChar(texture, SizeOf(texture), 0);
1041 sfsGCDisable(); // temporary disable removing of temporary volumes
1042 try
1043 // Çàãðóçêà WAD:
1044 FileName := g_ExtractWadName(Res);
1045 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
1046 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
1048 WAD := TWADFile.Create();
1049 if not WAD.ReadFile(FileName) then
1050 begin
1051 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
1052 WAD.Free();
1053 Exit;
1054 end;
1055 //k8: why loader ignores path here?
1056 mapResName := g_ExtractFileName(Res);
1057 if not WAD.GetMapResource(mapResName, Data, Len) then
1058 begin
1059 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
1060 WAD.Free();
1061 Exit;
1062 end;
1064 WAD.Free();
1066 // Çàãðóçêà êàðòû:
1067 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
1068 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
1069 MapReader := TMapReader_1.Create();
1071 if not MapReader.LoadMap(Data) then
1072 begin
1073 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
1074 FreeMem(Data);
1075 MapReader.Free();
1076 Exit;
1077 end;
1079 FreeMem(Data);
1080 generateExternalResourcesList(MapReader);
1081 // Çàãðóçêà òåêñòóð:
1082 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
1083 _textures := MapReader.GetTextures();
1084 _texnummap := nil;
1086 // Äîáàâëåíèå òåêñòóð â Textures[]:
1087 if _textures <> nil then
1088 begin
1089 e_WriteLog(' Loading textures:', MSG_NOTIFY);
1090 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
1091 SetLength(_texnummap, length(_textures));
1093 for a := 0 to High(_textures) do
1094 begin
1095 SetLength(s, 64);
1096 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
1097 for b := 1 to Length(s) do
1098 if s[b] = #0 then
1099 begin
1100 SetLength(s, b-1);
1101 Break;
1102 end;
1103 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
1104 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
1105 // Àíèìèðîâàííàÿ òåêñòóðà:
1106 if ByteBool(_textures[a].Anim) then
1107 begin
1108 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1109 if ntn < 0 then
1110 begin
1111 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1112 ntn := CreateNullTexture(_textures[a].Resource);
1113 end;
1114 end
1115 else // Îáû÷íàÿ òåêñòóðà:
1116 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1117 if ntn < 0 then
1118 begin
1119 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1120 ntn := CreateNullTexture(_textures[a].Resource);
1121 end;
1123 _texnummap[a] := ntn; // fix texture number
1124 g_Game_StepLoading();
1125 end;
1126 end;
1128 // Çàãðóçêà òðèããåðîâ:
1129 gTriggerClientID := 0;
1130 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1131 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1132 triggers := MapReader.GetTriggers();
1134 // Çàãðóçêà ïàíåëåé:
1135 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1136 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1137 panels := MapReader.GetPanels();
1139 // check texture numbers for panels
1140 for a := 0 to High(panels) do
1141 begin
1142 if panels[a].TextureNum > High(_textures) then
1143 begin
1144 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1145 result := false;
1146 exit;
1147 end;
1148 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1149 end;
1151 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1152 if triggers <> nil then
1153 begin
1154 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1155 SetLength(TriggersTable, Length(triggers));
1156 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1158 for a := 0 to High(TriggersTable) do
1159 begin
1160 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1161 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1162 // Ëèôòû:
1163 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1164 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1165 else
1166 TriggersTable[a].LiftPanel := -1;
1167 // Äâåðè:
1168 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1169 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1170 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1171 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1172 else
1173 TriggersTable[a].DoorPanel := -1;
1174 // Òóðåëü:
1175 if triggers[a].TriggerType = TRIGGER_SHOT then
1176 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1177 else
1178 TriggersTable[a].ShotPanel := -1;
1180 g_Game_StepLoading();
1181 end;
1182 end;
1184 // Ñîçäàåì ïàíåëè:
1185 if panels <> nil then
1186 begin
1187 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1188 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1190 for a := 0 to High(panels) do
1191 begin
1192 SetLength(AddTextures, 0);
1193 trigRef := False;
1194 CurTex := -1;
1195 if _textures <> nil then
1196 begin
1197 texture := _textures[panels[a].TextureNum];
1198 ok := True;
1199 end
1200 else
1201 ok := False;
1203 if ok then
1204 begin
1205 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1206 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1207 ok := False;
1208 if (TriggersTable <> nil) and (_textures <> nil) then
1209 for b := 0 to High(TriggersTable) do
1210 if (TriggersTable[b].TexturePanel = a)
1211 or (TriggersTable[b].ShotPanel = a) then
1212 begin
1213 trigRef := True;
1214 ok := True;
1215 Break;
1216 end;
1217 end;
1219 if ok then
1220 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1221 SetLength(s, 64);
1222 CopyMemory(@s[1], @texture.Resource[0], 64);
1223 // Èçìåðÿåì äëèíó:
1224 Len := Length(s);
1225 for c := Len downto 1 do
1226 if s[c] <> #0 then
1227 begin
1228 Len := c;
1229 Break;
1230 end;
1231 SetLength(s, Len);
1233 // Ñïåö-òåêñòóðû çàïðåùåíû:
1234 if g_Map_IsSpecialTexture(s) then
1235 ok := False
1236 else
1237 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1238 ok := g_Texture_NumNameFindStart(s);
1240 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1241 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1242 if ok then
1243 begin
1244 k := NNF_NAME_BEFORE;
1245 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1246 while ok or (k = NNF_NAME_BEFORE) or
1247 (k = NNF_NAME_EQUALS) do
1248 begin
1249 k := g_Texture_NumNameFindNext(TexName);
1251 if (k = NNF_NAME_BEFORE) or
1252 (k = NNF_NAME_AFTER) then
1253 begin
1254 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1255 if ByteBool(texture.Anim) then
1256 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1257 isAnim := True;
1258 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1259 if not ok then
1260 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1261 isAnim := False;
1262 ok := CreateTexture(TexName, FileName, False) >= 0;
1263 end;
1264 end
1265 else
1266 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1267 isAnim := False;
1268 ok := CreateTexture(TexName, FileName, False) >= 0;
1269 if not ok then
1270 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1271 isAnim := True;
1272 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1273 end;
1274 end;
1276 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1277 if ok then
1278 begin
1279 for c := 0 to High(Textures) do
1280 if Textures[c].TextureName = TexName then
1281 begin
1282 SetLength(AddTextures, Length(AddTextures)+1);
1283 AddTextures[High(AddTextures)].Texture := c;
1284 AddTextures[High(AddTextures)].Anim := isAnim;
1285 Break;
1286 end;
1287 end;
1288 end
1289 else
1290 if k = NNF_NAME_EQUALS then
1291 begin
1292 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1293 SetLength(AddTextures, Length(AddTextures)+1);
1294 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1295 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1296 CurTex := High(AddTextures);
1297 ok := True;
1298 end
1299 else // NNF_NO_NAME
1300 ok := False;
1301 end; // while ok...
1303 ok := True;
1304 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1305 end; // if ok - ññûëàþòñÿ òðèããåðû
1307 if not ok then
1308 begin
1309 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1310 SetLength(AddTextures, 1);
1311 AddTextures[0].Texture := panels[a].TextureNum;
1312 AddTextures[0].Anim := ByteBool(texture.Anim);
1313 CurTex := 0;
1314 end;
1316 //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);
1318 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1319 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1321 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1322 if TriggersTable <> nil then
1323 for b := 0 to High(TriggersTable) do
1324 begin
1325 // Òðèããåð äâåðè/ëèôòà:
1326 if (TriggersTable[b].LiftPanel = a) or
1327 (TriggersTable[b].DoorPanel = a) then
1328 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1329 // Òðèããåð ñìåíû òåêñòóðû:
1330 if TriggersTable[b].TexturePanel = a then
1331 triggers[b].TexturePanel := PanelID;
1332 // Òðèããåð "Òóðåëü":
1333 if TriggersTable[b].ShotPanel = a then
1334 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1335 end;
1337 g_Game_StepLoading();
1338 end;
1339 end;
1341 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1342 if (triggers <> nil) and not gLoadGameMode then
1343 begin
1344 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1345 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1346 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1347 for a := 0 to High(triggers) do
1348 begin
1349 if triggers[a].TexturePanel <> -1 then
1350 b := panels[TriggersTable[a].TexturePanel].PanelType
1351 else
1352 b := 0;
1353 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1354 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1355 c := panels[TriggersTable[a].ShotPanel].PanelType
1356 else
1357 c := 0;
1358 CreateTrigger(triggers[a], b, c);
1359 end;
1360 end;
1362 // Çàãðóçêà ïðåäìåòîâ:
1363 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1364 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1365 items := MapReader.GetItems();
1367 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1368 if (items <> nil) and not gLoadGameMode then
1369 begin
1370 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1371 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1372 for a := 0 to High(items) do
1373 CreateItem(Items[a]);
1374 end;
1376 // Çàãðóçêà îáëàñòåé:
1377 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1378 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1379 areas := MapReader.GetAreas();
1381 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1382 if areas <> nil then
1383 begin
1384 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1385 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1386 for a := 0 to High(areas) do
1387 CreateArea(areas[a]);
1388 end;
1390 // Çàãðóçêà ìîíñòðîâ:
1391 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1392 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1393 monsters := MapReader.GetMonsters();
1395 gTotalMonsters := 0;
1397 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1398 if (monsters <> nil) and not gLoadGameMode then
1399 begin
1400 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1401 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1402 for a := 0 to High(monsters) do
1403 CreateMonster(monsters[a]);
1404 end;
1406 // Çàãðóçêà îïèñàíèÿ êàðòû:
1407 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1408 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1409 Header := MapReader.GetMapHeader();
1411 MapReader.Free();
1413 with gMapInfo do
1414 begin
1415 Name := Header.MapName;
1416 Description := Header.MapDescription;
1417 Author := Header.MapAuthor;
1418 MusicName := Header.MusicName;
1419 SkyName := Header.SkyName;
1420 Height := Header.Height;
1421 Width := Header.Width;
1422 end;
1424 // Çàãðóçêà íåáà:
1425 if gMapInfo.SkyName <> '' then
1426 begin
1427 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1428 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1429 FileName := g_ExtractWadName(gMapInfo.SkyName);
1431 if FileName <> '' then
1432 FileName := GameDir+'/wads/'+FileName
1433 else
1434 begin
1435 FileName := g_ExtractWadName(Res);
1436 end;
1438 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1439 if g_Texture_CreateWAD(BackID, s) then
1440 begin
1441 g_Game_SetupScreenSize();
1442 end
1443 else
1444 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1445 end;
1447 // Çàãðóçêà ìóçûêè:
1448 ok := False;
1449 if gMapInfo.MusicName <> '' then
1450 begin
1451 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1452 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1453 FileName := g_ExtractWadName(gMapInfo.MusicName);
1455 if FileName <> '' then
1456 FileName := GameDir+'/wads/'+FileName
1457 else
1458 begin
1459 FileName := g_ExtractWadName(Res);
1460 end;
1462 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1463 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1464 ok := True
1465 else
1466 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1467 end;
1469 // Îñòàëüíûå óñòàíâêè:
1470 CreateDoorMap();
1471 CreateLiftMap();
1473 g_Items_Init();
1474 g_Weapon_Init();
1475 g_Monsters_Init();
1477 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1478 if not gLoadGameMode then
1479 g_GFX_Init();
1481 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1482 _textures := nil;
1483 panels := nil;
1484 items := nil;
1485 areas := nil;
1486 triggers := nil;
1487 TriggersTable := nil;
1488 AddTextures := nil;
1490 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1491 if ok and (not gLoadGameMode) then
1492 begin
1493 gMusic.SetByName(gMapInfo.MusicName);
1494 gMusic.Play();
1495 end
1496 else
1497 gMusic.SetByName('');
1498 finally
1499 sfsGCEnable(); // enable releasing unused volumes
1500 end;
1502 e_WriteLog('Creating map grid', MSG_NOTIFY);
1503 mapCreateGrid();
1505 e_WriteLog('Done loading map.', MSG_NOTIFY);
1506 Result := True;
1507 end;
1509 function g_Map_GetMapInfo(Res: String): TMapInfo;
1510 var
1511 WAD: TWADFile;
1512 MapReader: TMapReader_1;
1513 Header: TMapHeaderRec_1;
1514 FileName: String;
1515 Data: Pointer;
1516 Len: Integer;
1517 begin
1518 FillChar(Result, SizeOf(Result), 0);
1519 FileName := g_ExtractWadName(Res);
1521 WAD := TWADFile.Create();
1522 if not WAD.ReadFile(FileName) then
1523 begin
1524 WAD.Free();
1525 Exit;
1526 end;
1528 //k8: it ignores path again
1529 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1530 begin
1531 WAD.Free();
1532 Exit;
1533 end;
1535 WAD.Free();
1537 MapReader := TMapReader_1.Create();
1539 if not MapReader.LoadMap(Data) then
1540 begin
1541 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1542 ZeroMemory(@Header, SizeOf(Header));
1543 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1544 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1545 end
1546 else
1547 begin
1548 Header := MapReader.GetMapHeader();
1549 Result.Name := Header.MapName;
1550 Result.Description := Header.MapDescription;
1551 end;
1553 FreeMem(Data);
1554 MapReader.Free();
1556 Result.Map := Res;
1557 Result.Author := Header.MapAuthor;
1558 Result.Height := Header.Height;
1559 Result.Width := Header.Width;
1560 end;
1562 function g_Map_GetMapsList(WADName: string): SArray;
1563 var
1564 WAD: TWADFile;
1565 a: Integer;
1566 ResList: SArray;
1567 begin
1568 Result := nil;
1569 WAD := TWADFile.Create();
1570 if not WAD.ReadFile(WADName) then
1571 begin
1572 WAD.Free();
1573 Exit;
1574 end;
1575 ResList := WAD.GetMapResources();
1576 if ResList <> nil then
1577 begin
1578 for a := 0 to High(ResList) do
1579 begin
1580 SetLength(Result, Length(Result)+1);
1581 Result[High(Result)] := ResList[a];
1582 end;
1583 end;
1584 WAD.Free();
1585 end;
1587 function g_Map_Exist(Res: string): Boolean;
1588 var
1589 WAD: TWADFile;
1590 FileName, mnn: string;
1591 ResList: SArray;
1592 a: Integer;
1593 begin
1594 Result := False;
1596 FileName := addWadExtension(g_ExtractWadName(Res));
1598 WAD := TWADFile.Create;
1599 if not WAD.ReadFile(FileName) then
1600 begin
1601 WAD.Free();
1602 Exit;
1603 end;
1605 ResList := WAD.GetMapResources();
1606 WAD.Free();
1608 mnn := g_ExtractFileName(Res);
1609 if ResList <> nil then
1610 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1611 begin
1612 Result := True;
1613 Exit;
1614 end;
1615 end;
1617 procedure g_Map_Free();
1618 var
1619 a: Integer;
1621 procedure FreePanelArray(var panels: TPanelArray);
1622 var
1623 i: Integer;
1625 begin
1626 if panels <> nil then
1627 begin
1628 for i := 0 to High(panels) do
1629 panels[i].Free();
1630 panels := nil;
1631 end;
1632 end;
1634 begin
1635 g_GFX_Free();
1636 g_Weapon_Free();
1637 g_Items_Free();
1638 g_Triggers_Free();
1639 g_Monsters_Free();
1641 RespawnPoints := nil;
1642 if FlagPoints[FLAG_RED] <> nil then
1643 begin
1644 Dispose(FlagPoints[FLAG_RED]);
1645 FlagPoints[FLAG_RED] := nil;
1646 end;
1647 if FlagPoints[FLAG_BLUE] <> nil then
1648 begin
1649 Dispose(FlagPoints[FLAG_BLUE]);
1650 FlagPoints[FLAG_BLUE] := nil;
1651 end;
1652 //DOMFlagPoints := nil;
1654 //gDOMFlags := nil;
1656 if Textures <> nil then
1657 begin
1658 for a := 0 to High(Textures) do
1659 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1660 if Textures[a].Anim then
1661 g_Frames_DeleteByID(Textures[a].FramesID)
1662 else
1663 if Textures[a].TextureID <> TEXTURE_NONE then
1664 e_DeleteTexture(Textures[a].TextureID);
1666 Textures := nil;
1667 end;
1669 FreePanelArray(gWalls);
1670 FreePanelArray(gRenderBackgrounds);
1671 FreePanelArray(gRenderForegrounds);
1672 FreePanelArray(gWater);
1673 FreePanelArray(gAcid1);
1674 FreePanelArray(gAcid2);
1675 FreePanelArray(gSteps);
1676 FreePanelArray(gLifts);
1677 FreePanelArray(gBlockMon);
1679 if BackID <> DWORD(-1) then
1680 begin
1681 gBackSize.X := 0;
1682 gBackSize.Y := 0;
1683 e_DeleteTexture(BackID);
1684 BackID := DWORD(-1);
1685 end;
1687 g_Game_StopAllSounds(False);
1688 gMusic.FreeSound();
1689 g_Sound_Delete(gMapInfo.MusicName);
1691 gMapInfo.Name := '';
1692 gMapInfo.Description := '';
1693 gMapInfo.MusicName := '';
1694 gMapInfo.Height := 0;
1695 gMapInfo.Width := 0;
1697 gDoorMap := nil;
1698 gLiftMap := nil;
1700 PanelByID := nil;
1701 end;
1703 procedure g_Map_Update();
1704 var
1705 a, d, j: Integer;
1706 m: Word;
1707 s: String;
1709 procedure UpdatePanelArray(var panels: TPanelArray);
1710 var
1711 i: Integer;
1713 begin
1714 if panels <> nil then
1715 for i := 0 to High(panels) do
1716 panels[i].Update();
1717 end;
1719 begin
1720 UpdatePanelArray(gWalls);
1721 UpdatePanelArray(gRenderBackgrounds);
1722 UpdatePanelArray(gRenderForegrounds);
1723 UpdatePanelArray(gWater);
1724 UpdatePanelArray(gAcid1);
1725 UpdatePanelArray(gAcid2);
1726 UpdatePanelArray(gSteps);
1728 if gGameSettings.GameMode = GM_CTF then
1729 begin
1730 for a := FLAG_RED to FLAG_BLUE do
1731 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1732 with gFlags[a] do
1733 begin
1734 if gFlags[a].Animation <> nil then
1735 gFlags[a].Animation.Update();
1737 m := g_Obj_Move(@Obj, True, True);
1739 if gTime mod (GAME_TICK*2) <> 0 then
1740 Continue;
1742 // Ñîïðîòèâëåíèå âîçäóõà:
1743 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1745 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1746 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1747 begin
1748 g_Map_ResetFlag(a);
1749 gFlags[a].CaptureTime := 0;
1750 if a = FLAG_RED then
1751 s := _lc[I_PLAYER_FLAG_RED]
1752 else
1753 s := _lc[I_PLAYER_FLAG_BLUE];
1754 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1756 if g_Game_IsNet then
1757 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1758 Continue;
1759 end;
1761 if Count > 0 then
1762 Count := Count - 1;
1764 // Èãðîê áåðåò ôëàã:
1765 if gPlayers <> nil then
1766 begin
1767 j := Random(Length(gPlayers)) - 1;
1769 for d := 0 to High(gPlayers) do
1770 begin
1771 Inc(j);
1772 if j > High(gPlayers) then
1773 j := 0;
1775 if gPlayers[j] <> nil then
1776 if gPlayers[j].Live and
1777 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1778 begin
1779 if gPlayers[j].GetFlag(a) then
1780 Break;
1781 end;
1782 end;
1783 end;
1784 end;
1785 end;
1786 end;
1789 procedure g_Map_DrawPanelsOld(PanelType: Word);
1791 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1792 var
1793 idx: Integer;
1794 begin
1795 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1796 begin
1797 // alas, no visible set
1798 for idx := 0 to High(panels) do
1799 begin
1800 if not (drawDoors xor panels[idx].Door) then panels[idx].Draw();
1801 end;
1802 end;
1803 end;
1805 begin
1806 case PanelType of
1807 PANEL_WALL: DrawPanels(0, gWalls);
1808 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1809 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1810 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1811 PANEL_WATER: DrawPanels(3, gWater);
1812 PANEL_ACID1: DrawPanels(4, gAcid1);
1813 PANEL_ACID2: DrawPanels(5, gAcid2);
1814 PANEL_STEP: DrawPanels(6, gSteps);
1815 end;
1816 end;
1819 var
1820 gDrawPanelList: TBinaryHeapObj = nil;
1822 function dplLess (a, b: TObject): Boolean;
1823 begin
1824 result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx);
1825 end;
1827 procedure dplClear ();
1828 begin
1829 if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear();
1830 end;
1832 procedure dplAddPanel (pan: TPanel);
1833 begin
1834 if pan = nil then exit;
1835 gDrawPanelList.insert(pan);
1836 end;
1839 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
1840 var
1841 ptag: Integer;
1843 function checker (obj: TObject; tag: Integer): Boolean;
1844 var
1845 pan: TPanel;
1846 begin
1847 result := false; // don't stop, ever
1848 if (tag <> ptag) then exit;
1849 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1851 if obj = nil then begin e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
1852 if not (obj is TPanel) then begin e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
1853 //pan := (obj as TPanel);
1854 //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1856 pan := (obj as TPanel);
1857 if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end;
1858 //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);
1859 dplAddPanel(pan);
1860 end;
1862 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1863 var
1864 idx: Integer;
1865 pan: TPanel;
1866 begin
1867 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1868 begin
1869 // alas, no visible set
1870 for idx := 0 to High(panels) do
1871 begin
1872 if not (drawDoors xor panels[idx].Door) then
1873 begin
1874 pan := panels[idx];
1876 if (pan.Width < 1) or (pan.Height < 1) then continue;
1877 if (pan.X+pan.Width <= x0) or (pan.Y+pan.Height <= y0) then continue;
1878 if (pan.X >= x0+wdt) or (pan.Y >= y0+hgt) then continue;
1880 pan.Draw();
1881 //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);
1882 end;
1883 end;
1884 end;
1885 end;
1887 begin
1888 //g_Map_DrawPanelsOld(PanelType); exit;
1889 //e_WriteLog('==================', MSG_NOTIFY);
1890 //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1891 dplClear();
1892 ptag := panelTypeToTag(PanelType);
1894 if gdbg_map_use_grid_render then
1895 begin
1896 gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker);
1897 // sort and draw the list (we need to sort it, or rendering is fucked)
1898 while gDrawPanelList.count > 0 do
1899 begin
1900 (gDrawPanelList.front() as TPanel).Draw();
1901 gDrawPanelList.popFront();
1902 end;
1903 end
1904 else
1905 begin
1906 //e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1907 case PanelType of
1908 PANEL_WALL: DrawPanels(0, gWalls);
1909 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1910 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1911 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1912 PANEL_WATER: DrawPanels(3, gWater);
1913 PANEL_ACID1: DrawPanels(4, gAcid1);
1914 PANEL_ACID2: DrawPanels(5, gAcid2);
1915 PANEL_STEP: DrawPanels(6, gSteps);
1916 end;
1917 end;
1919 //e_WriteLog('==================', MSG_NOTIFY);
1920 end;
1923 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
1924 function checker (obj: TObject; tag: Integer): Boolean;
1925 var
1926 pan: TPanel;
1927 begin
1928 result := false; // don't stop, ever
1929 if (tag <> GridTagWallDoor) then exit; // only walls
1930 pan := (obj as TPanel);
1931 pan.DrawShadowVolume(lightX, lightY, radius);
1932 end;
1934 begin
1935 gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker);
1936 end;
1939 procedure g_Map_DrawBack(dx, dy: Integer);
1940 begin
1941 if gDrawBackGround and (BackID <> DWORD(-1)) then
1942 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1943 else
1944 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1945 end;
1947 function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word;
1948 PanelType: Word; b1x3: Boolean): Boolean;
1949 var
1950 a, h: Integer;
1951 begin
1952 Result := False;
1954 if WordBool(PanelType and PANEL_WALL) then
1955 if gWalls <> nil then
1956 begin
1957 h := High(gWalls);
1959 for a := 0 to h do
1960 if gWalls[a].Enabled and
1961 g_Collide(X, Y, Width, Height,
1962 gWalls[a].X, gWalls[a].Y,
1963 gWalls[a].Width, gWalls[a].Height) then
1964 begin
1965 Result := True;
1966 Exit;
1967 end;
1968 end;
1970 if WordBool(PanelType and PANEL_WATER) then
1971 if gWater <> nil then
1972 begin
1973 h := High(gWater);
1975 for a := 0 to h do
1976 if g_Collide(X, Y, Width, Height,
1977 gWater[a].X, gWater[a].Y,
1978 gWater[a].Width, gWater[a].Height) then
1979 begin
1980 Result := True;
1981 Exit;
1982 end;
1983 end;
1985 if WordBool(PanelType and PANEL_ACID1) then
1986 if gAcid1 <> nil then
1987 begin
1988 h := High(gAcid1);
1990 for a := 0 to h do
1991 if g_Collide(X, Y, Width, Height,
1992 gAcid1[a].X, gAcid1[a].Y,
1993 gAcid1[a].Width, gAcid1[a].Height) then
1994 begin
1995 Result := True;
1996 Exit;
1997 end;
1998 end;
2000 if WordBool(PanelType and PANEL_ACID2) then
2001 if gAcid2 <> nil then
2002 begin
2003 h := High(gAcid2);
2005 for a := 0 to h do
2006 if g_Collide(X, Y, Width, Height,
2007 gAcid2[a].X, gAcid2[a].Y,
2008 gAcid2[a].Width, gAcid2[a].Height) then
2009 begin
2010 Result := True;
2011 Exit;
2012 end;
2013 end;
2015 if WordBool(PanelType and PANEL_STEP) then
2016 if gSteps <> nil then
2017 begin
2018 h := High(gSteps);
2020 for a := 0 to h do
2021 if g_Collide(X, Y, Width, Height,
2022 gSteps[a].X, gSteps[a].Y,
2023 gSteps[a].Width, gSteps[a].Height) then
2024 begin
2025 Result := True;
2026 Exit;
2027 end;
2028 end;
2030 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
2031 if gLifts <> nil then
2032 begin
2033 h := High(gLifts);
2035 for a := 0 to h do
2036 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2037 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2038 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2039 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2040 g_Collide(X, Y, Width, Height,
2041 gLifts[a].X, gLifts[a].Y,
2042 gLifts[a].Width, gLifts[a].Height) then
2043 begin
2044 Result := True;
2045 Exit;
2046 end;
2047 end;
2049 if WordBool(PanelType and PANEL_BLOCKMON) then
2050 if gBlockMon <> nil then
2051 begin
2052 h := High(gBlockMon);
2054 for a := 0 to h do
2055 if ( (not b1x3) or
2056 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2057 g_Collide(X, Y, Width, Height,
2058 gBlockMon[a].X, gBlockMon[a].Y,
2059 gBlockMon[a].Width, gBlockMon[a].Height) then
2060 begin
2061 Result := True;
2062 Exit;
2063 end;
2064 end;
2065 end;
2067 function g_Map_CollideLiquid_TextureOld(X, Y: Integer; Width, Height: Word): DWORD;
2068 var
2069 texid: DWORD;
2071 function checkPanels (var panels: TPanelArray): Boolean;
2072 var
2073 a: Integer;
2074 begin
2075 result := false;
2076 if panels = nil then exit;
2077 for a := 0 to High(panels) do
2078 begin
2079 if g_Collide(X, Y, Width, Height, panels[a].X, panels[a].Y, panels[a].Width, panels[a].Height) then
2080 begin
2081 result := true;
2082 texid := panels[a].GetTextureID();
2083 exit;
2084 end;
2085 end;
2086 end;
2088 begin
2089 texid := TEXTURE_NONE;
2090 result := texid;
2091 if not checkPanels(gWater) then
2092 if not checkPanels(gAcid1) then
2093 if not checkPanels(gAcid2) then exit;
2094 result := texid;
2095 end;
2098 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean;
2100 function checker (obj: TObject; tag: Integer): Boolean;
2101 var
2102 pan: TPanel;
2103 a: Integer;
2104 begin
2105 result := false; // don't stop, ever
2107 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2109 if obj = nil then
2110 begin
2111 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2112 end;
2113 if not (obj is TPanel) then
2114 begin
2115 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2116 exit;
2117 end;
2119 pan := (obj as TPanel);
2120 a := pan.ArrIdx;
2122 if WordBool(PanelType and PANEL_WALL) and (tag = GridTagWallDoor) then
2123 begin
2124 if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then
2125 begin
2126 result := true;
2127 exit;
2128 end;
2129 end;
2131 if WordBool(PanelType and PANEL_WATER) and (tag = GridTagWater) then
2132 begin
2133 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2134 begin
2135 result := True;
2136 exit;
2137 end;
2138 end;
2140 if WordBool(PanelType and PANEL_ACID1) and (tag = GridTagAcid1) then
2141 begin
2142 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2143 begin
2144 result := True;
2145 exit;
2146 end;
2147 end;
2149 if WordBool(PanelType and PANEL_ACID2) and (tag = GridTagAcid2) then
2150 begin
2151 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2152 begin
2153 result := True;
2154 exit;
2155 end;
2156 end;
2158 if WordBool(PanelType and PANEL_STEP) and (tag = GridTagStep) then
2159 begin
2160 if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then
2161 begin
2162 result := True;
2163 exit;
2164 end;
2165 end;
2167 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (tag = GridTagLift) then
2168 begin
2169 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2170 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2171 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2172 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2173 g_Collide(X, Y, Width, Height, gLifts[a].X, gLifts[a].Y, gLifts[a].Width, gLifts[a].Height) then
2174 begin
2175 result := true;
2176 exit;
2177 end;
2178 end;
2180 if WordBool(PanelType and PANEL_BLOCKMON) and (tag = GridTagBlockMon) then
2181 begin
2182 if ((not b1x3) or ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64)) and
2183 g_Collide(X, Y, Width, Height, gBlockMon[a].X, gBlockMon[a].Y, gBlockMon[a].Width, gBlockMon[a].Height) then
2184 begin
2185 result := True;
2186 exit;
2187 end;
2188 end;
2189 end;
2191 begin
2192 if gdbg_map_use_grid_coldet then
2193 begin
2194 result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
2195 end
2196 else
2197 begin
2198 result := g_Map_CollidePanelOld(X, Y, Width, Height, PanelType, b1x3);
2199 end;
2200 end;
2203 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
2204 var
2205 cctype: Integer = 3; // priority: 0: water, 1: acid1, 2: acid2; 3: others (nothing)
2206 texid: DWORD;
2208 // slightly different from the old code, but meh...
2209 function checker (obj: TObject; tag: Integer): Boolean;
2210 var
2211 pan: TPanel;
2212 a: Integer;
2213 begin
2214 result := false; // don't stop, ever
2215 pan := (obj as TPanel);
2216 a := pan.ArrIdx;
2217 // water
2218 if (tag = GridTagWater) then
2219 begin
2220 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2221 begin
2222 result := true; // water has highest priority, so stop right here
2223 texid := gWater[a].GetTextureID();
2224 exit;
2225 end;
2226 end;
2227 // acid1
2228 if (cctype > 1) and (tag = GridTagAcid1) then
2229 begin
2230 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2231 begin
2232 cctype := 1;
2233 texid := gAcid1[a].GetTextureID();
2234 exit;
2235 end;
2236 end;
2237 // acid2
2238 if (cctype > 2) and (tag = GridTagAcid2) then
2239 begin
2240 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2241 begin
2242 cctype := 2;
2243 texid := gAcid2[a].GetTextureID();
2244 exit;
2245 end;
2246 end;
2247 end;
2249 begin
2250 if not gdbg_map_use_grid_coldet then
2251 begin
2252 result := g_Map_CollideLiquid_TextureOld(X, Y, Width, Height);
2253 end
2254 else
2255 begin
2256 texid := TEXTURE_NONE;
2257 gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
2258 result := texid;
2259 end;
2260 end;
2262 procedure g_Map_EnableWall(ID: DWORD);
2263 begin
2264 with gWalls[ID] do
2265 begin
2266 Enabled := True;
2267 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
2269 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2270 end;
2271 end;
2273 procedure g_Map_DisableWall(ID: DWORD);
2274 begin
2275 with gWalls[ID] do
2276 begin
2277 Enabled := False;
2278 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
2280 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2281 end;
2282 end;
2284 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
2285 var
2286 tp: TPanel;
2287 begin
2288 case PanelType of
2289 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2290 tp := gWalls[ID];
2291 PANEL_FORE:
2292 tp := gRenderForegrounds[ID];
2293 PANEL_BACK:
2294 tp := gRenderBackgrounds[ID];
2295 PANEL_WATER:
2296 tp := gWater[ID];
2297 PANEL_ACID1:
2298 tp := gAcid1[ID];
2299 PANEL_ACID2:
2300 tp := gAcid2[ID];
2301 PANEL_STEP:
2302 tp := gSteps[ID];
2303 else
2304 Exit;
2305 end;
2307 tp.NextTexture(AnimLoop);
2308 if g_Game_IsServer and g_Game_IsNet then
2309 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
2310 end;
2312 procedure g_Map_SetLift(ID: DWORD; t: Integer);
2313 begin
2314 if gLifts[ID].LiftType = t then
2315 Exit;
2317 with gLifts[ID] do
2318 begin
2319 LiftType := t;
2321 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
2323 if LiftType = 0 then
2324 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
2325 else if LiftType = 1 then
2326 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
2327 else if LiftType = 2 then
2328 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
2329 else if LiftType = 3 then
2330 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
2332 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2333 end;
2334 end;
2336 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
2337 var
2338 a: Integer;
2339 PointsArray: Array of TRespawnPoint;
2340 begin
2341 Result := False;
2342 SetLength(PointsArray, 0);
2344 if RespawnPoints = nil then
2345 Exit;
2347 for a := 0 to High(RespawnPoints) do
2348 if RespawnPoints[a].PointType = PointType then
2349 begin
2350 SetLength(PointsArray, Length(PointsArray)+1);
2351 PointsArray[High(PointsArray)] := RespawnPoints[a];
2352 end;
2354 if PointsArray = nil then
2355 Exit;
2357 RespawnPoint := PointsArray[Random(Length(PointsArray))];
2358 Result := True;
2359 end;
2361 function g_Map_GetPointCount(PointType: Byte): Word;
2362 var
2363 a: Integer;
2364 begin
2365 Result := 0;
2367 if RespawnPoints = nil then
2368 Exit;
2370 for a := 0 to High(RespawnPoints) do
2371 if RespawnPoints[a].PointType = PointType then
2372 Result := Result + 1;
2373 end;
2375 function g_Map_HaveFlagPoints(): Boolean;
2376 begin
2377 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
2378 end;
2380 procedure g_Map_ResetFlag(Flag: Byte);
2381 begin
2382 with gFlags[Flag] do
2383 begin
2384 Obj.X := -1000;
2385 Obj.Y := -1000;
2386 Obj.Vel.X := 0;
2387 Obj.Vel.Y := 0;
2388 Direction := D_LEFT;
2389 State := FLAG_STATE_NONE;
2390 if FlagPoints[Flag] <> nil then
2391 begin
2392 Obj.X := FlagPoints[Flag]^.X;
2393 Obj.Y := FlagPoints[Flag]^.Y;
2394 Direction := FlagPoints[Flag]^.Direction;
2395 State := FLAG_STATE_NORMAL;
2396 end;
2397 Count := -1;
2398 end;
2399 end;
2401 procedure g_Map_DrawFlags();
2402 var
2403 i, dx: Integer;
2404 Mirror: TMirrorType;
2405 begin
2406 if gGameSettings.GameMode <> GM_CTF then
2407 Exit;
2409 for i := FLAG_RED to FLAG_BLUE do
2410 with gFlags[i] do
2411 if State <> FLAG_STATE_CAPTURED then
2412 begin
2413 if State = FLAG_STATE_NONE then
2414 continue;
2416 if Direction = D_LEFT then
2417 begin
2418 Mirror := M_HORIZONTAL;
2419 dx := -1;
2420 end
2421 else
2422 begin
2423 Mirror := M_NONE;
2424 dx := 1;
2425 end;
2427 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2429 if g_debug_Frames then
2430 begin
2431 e_DrawQuad(Obj.X+Obj.Rect.X,
2432 Obj.Y+Obj.Rect.Y,
2433 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2434 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2435 0, 255, 0);
2436 end;
2437 end;
2438 end;
2440 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2441 var
2442 dw: DWORD;
2443 b: Byte;
2444 str: String;
2445 boo: Boolean;
2447 procedure SavePanelArray(var panels: TPanelArray);
2448 var
2449 PAMem: TBinMemoryWriter;
2450 i: Integer;
2451 begin
2452 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2453 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2455 i := 0;
2456 while i < Length(panels) do
2457 begin
2458 if panels[i].SaveIt then
2459 begin
2460 // ID ïàíåëè:
2461 PAMem.WriteInt(i);
2462 // Ñîõðàíÿåì ïàíåëü:
2463 panels[i].SaveState(PAMem);
2464 end;
2465 Inc(i);
2466 end;
2468 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2469 PAMem.SaveToMemory(Mem);
2470 PAMem.Free();
2471 end;
2473 procedure SaveFlag(flag: PFlag);
2474 begin
2475 // Ñèãíàòóðà ôëàãà:
2476 dw := FLAG_SIGNATURE; // 'FLAG'
2477 Mem.WriteDWORD(dw);
2478 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2479 Mem.WriteByte(flag^.RespawnType);
2480 // Ñîñòîÿíèå ôëàãà:
2481 Mem.WriteByte(flag^.State);
2482 // Íàïðàâëåíèå ôëàãà:
2483 if flag^.Direction = D_LEFT then
2484 b := 1
2485 else // D_RIGHT
2486 b := 2;
2487 Mem.WriteByte(b);
2488 // Îáúåêò ôëàãà:
2489 Obj_SaveState(@flag^.Obj, Mem);
2490 end;
2492 begin
2493 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2495 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2496 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2497 SavePanelArray(gWalls);
2498 // Ñîõðàíÿåì ïàíåëè ôîíà:
2499 SavePanelArray(gRenderBackgrounds);
2500 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2501 SavePanelArray(gRenderForegrounds);
2502 // Ñîõðàíÿåì ïàíåëè âîäû:
2503 SavePanelArray(gWater);
2504 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2505 SavePanelArray(gAcid1);
2506 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2507 SavePanelArray(gAcid2);
2508 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2509 SavePanelArray(gSteps);
2510 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2511 SavePanelArray(gLifts);
2512 ///// /////
2514 ///// Ñîõðàíÿåì ìóçûêó: /////
2515 // Ñèãíàòóðà ìóçûêè:
2516 dw := MUSIC_SIGNATURE; // 'MUSI'
2517 Mem.WriteDWORD(dw);
2518 // Íàçâàíèå ìóçûêè:
2519 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2520 if gMusic.NoMusic then
2521 str := ''
2522 else
2523 str := gMusic.Name;
2524 Mem.WriteString(str, 64);
2525 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2526 dw := gMusic.GetPosition();
2527 Mem.WriteDWORD(dw);
2528 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2529 boo := gMusic.SpecPause;
2530 Mem.WriteBoolean(boo);
2531 ///// /////
2533 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2534 Mem.WriteInt(gTotalMonsters);
2535 ///// /////
2537 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2538 if gGameSettings.GameMode = GM_CTF then
2539 begin
2540 // Ôëàã Êðàñíîé êîìàíäû:
2541 SaveFlag(@gFlags[FLAG_RED]);
2542 // Ôëàã Ñèíåé êîìàíäû:
2543 SaveFlag(@gFlags[FLAG_BLUE]);
2544 end;
2545 ///// /////
2547 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2548 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2549 begin
2550 // Î÷êè Êðàñíîé êîìàíäû:
2551 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2552 // Î÷êè Ñèíåé êîìàíäû:
2553 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2554 end;
2555 ///// /////
2556 end;
2558 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2559 var
2560 dw: DWORD;
2561 b: Byte;
2562 str: String;
2563 boo: Boolean;
2565 procedure LoadPanelArray(var panels: TPanelArray);
2566 var
2567 PAMem: TBinMemoryReader;
2568 i, id: Integer;
2569 begin
2570 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2571 PAMem := TBinMemoryReader.Create();
2572 PAMem.LoadFromMemory(Mem);
2574 for i := 0 to Length(panels)-1 do
2575 if panels[i].SaveIt then
2576 begin
2577 // ID ïàíåëè:
2578 PAMem.ReadInt(id);
2579 if id <> i then
2580 begin
2581 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2582 end;
2583 // Çàãðóæàåì ïàíåëü:
2584 panels[i].LoadState(PAMem);
2585 end;
2587 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2588 PAMem.Free();
2589 end;
2591 procedure LoadFlag(flag: PFlag);
2592 begin
2593 // Ñèãíàòóðà ôëàãà:
2594 Mem.ReadDWORD(dw);
2595 if dw <> FLAG_SIGNATURE then // 'FLAG'
2596 begin
2597 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2598 end;
2599 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2600 Mem.ReadByte(flag^.RespawnType);
2601 // Ñîñòîÿíèå ôëàãà:
2602 Mem.ReadByte(flag^.State);
2603 // Íàïðàâëåíèå ôëàãà:
2604 Mem.ReadByte(b);
2605 if b = 1 then
2606 flag^.Direction := D_LEFT
2607 else // b = 2
2608 flag^.Direction := D_RIGHT;
2609 // Îáúåêò ôëàãà:
2610 Obj_LoadState(@flag^.Obj, Mem);
2611 end;
2613 begin
2614 if Mem = nil then
2615 Exit;
2617 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2618 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2619 LoadPanelArray(gWalls);
2620 // Çàãðóæàåì ïàíåëè ôîíà:
2621 LoadPanelArray(gRenderBackgrounds);
2622 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2623 LoadPanelArray(gRenderForegrounds);
2624 // Çàãðóæàåì ïàíåëè âîäû:
2625 LoadPanelArray(gWater);
2626 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2627 LoadPanelArray(gAcid1);
2628 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2629 LoadPanelArray(gAcid2);
2630 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2631 LoadPanelArray(gSteps);
2632 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2633 LoadPanelArray(gLifts);
2634 ///// /////
2636 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé è ñåòêó:
2637 g_GFX_Init();
2638 mapCreateGrid();
2640 ///// Çàãðóæàåì ìóçûêó: /////
2641 // Ñèãíàòóðà ìóçûêè:
2642 Mem.ReadDWORD(dw);
2643 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2644 begin
2645 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2646 end;
2647 // Íàçâàíèå ìóçûêè:
2648 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2649 Mem.ReadString(str);
2650 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2651 Mem.ReadDWORD(dw);
2652 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2653 Mem.ReadBoolean(boo);
2654 // Çàïóñêàåì ýòó ìóçûêó:
2655 gMusic.SetByName(str);
2656 gMusic.SpecPause := boo;
2657 gMusic.Play();
2658 gMusic.Pause(True);
2659 gMusic.SetPosition(dw);
2660 ///// /////
2662 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2663 Mem.ReadInt(gTotalMonsters);
2664 ///// /////
2666 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2667 if gGameSettings.GameMode = GM_CTF then
2668 begin
2669 // Ôëàã Êðàñíîé êîìàíäû:
2670 LoadFlag(@gFlags[FLAG_RED]);
2671 // Ôëàã Ñèíåé êîìàíäû:
2672 LoadFlag(@gFlags[FLAG_BLUE]);
2673 end;
2674 ///// /////
2676 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2677 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2678 begin
2679 // Î÷êè Êðàñíîé êîìàíäû:
2680 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2681 // Î÷êè Ñèíåé êîìàíäû:
2682 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2683 end;
2684 ///// /////
2685 end;
2687 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
2688 var
2689 Arr: TPanelArray;
2690 begin
2691 Result := nil;
2692 if (PanelID < 0) or (PanelID > High(PanelByID)) then Exit;
2693 Arr := PanelByID[PanelID].PWhere^;
2694 PanelArrayID := PanelByID[PanelID].PArrID;
2695 Result := Addr(Arr[PanelByID[PanelID].PArrID]);
2696 end;
2698 end.