DEADSOFTWARE

no more path splitting in wad reading, it's useless
[d2df-sdl.git] / src / game / g_map.pas
1 {$MODE DELPHI}
2 unit g_map;
4 interface
6 uses
7 e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
8 g_phys, wadreader, BinEditor, g_panel, md5;
10 type
11 TMapInfo = record
12 Map: String;
13 Name: String;
14 Description: String;
15 Author: String;
16 MusicName: String;
17 SkyName: String;
18 Height: Word;
19 Width: Word;
20 end;
22 PRespawnPoint = ^TRespawnPoint;
23 TRespawnPoint = record
24 X, Y: Integer;
25 Direction: TDirection;
26 PointType: Byte;
27 end;
29 PFlagPoint = ^TFlagPoint;
30 TFlagPoint = TRespawnPoint;
32 PFlag = ^TFlag;
33 TFlag = record
34 Obj: TObj;
35 RespawnType: Byte;
36 State: Byte;
37 Count: Integer;
38 CaptureTime: LongWord;
39 Animation: TAnimation;
40 Direction: TDirection;
41 end;
44 function g_Map_Load(Res: String): Boolean;
45 function g_Map_GetMapInfo(Res: String): TMapInfo;
46 function g_Map_GetMapsList(WADName: String): SArray;
47 function g_Map_Exist(Res: String): Boolean;
48 procedure g_Map_Free();
49 procedure g_Map_Update();
50 procedure g_Map_DrawPanels(PanelType: Word);
51 procedure g_Map_DrawBack(dx, dy: Integer);
52 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
53 PanelType: Word; b1x3: Boolean): Boolean;
54 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
55 procedure g_Map_EnableWall(ID: DWORD);
56 procedure g_Map_DisableWall(ID: DWORD);
57 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
58 procedure g_Map_SetLift(ID: DWORD; t: Integer);
59 procedure g_Map_ReAdd_DieTriggers();
60 function g_Map_IsSpecialTexture(Texture: String): Boolean;
62 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
63 function g_Map_GetPointCount(PointType: Byte): Word;
65 function g_Map_HaveFlagPoints(): Boolean;
67 procedure g_Map_ResetFlag(Flag: Byte);
68 procedure g_Map_DrawFlags();
70 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
71 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
73 const
74 RESPAWNPOINT_PLAYER1 = 1;
75 RESPAWNPOINT_PLAYER2 = 2;
76 RESPAWNPOINT_DM = 3;
77 RESPAWNPOINT_RED = 4;
78 RESPAWNPOINT_BLUE = 5;
80 FLAG_NONE = 0;
81 FLAG_RED = 1;
82 FLAG_BLUE = 2;
83 FLAG_DOM = 3;
85 FLAG_STATE_NONE = 0;
86 FLAG_STATE_NORMAL = 1;
87 FLAG_STATE_DROPPED = 2;
88 FLAG_STATE_CAPTURED = 3;
89 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
90 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
92 FLAG_TIME = 720; // 20 seconds
94 SKY_STRETCH: Single = 1.5;
96 var
97 gWalls: TPanelArray;
98 gRenderBackgrounds: TPanelArray;
99 gRenderForegrounds: TPanelArray;
100 gWater, gAcid1, gAcid2: TPanelArray;
101 gSteps: TPanelArray;
102 gLifts: TPanelArray;
103 gBlockMon: TPanelArray;
104 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
105 //gDOMFlags: array of TFlag;
106 gMapInfo: TMapInfo;
107 gBackSize: TPoint;
108 gDoorMap: array of array of DWORD;
109 gLiftMap: array of array of DWORD;
110 gWADHash: TMD5Digest;
111 BackID: DWORD = DWORD(-1);
112 gExternalResources: TStringList;
114 implementation
116 uses
117 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
118 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
119 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
120 Math, g_monsters, g_saveload, g_language, g_netmsg,
121 utils, sfs;
123 const
124 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
125 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
126 FLAG_SIGNATURE = $47414C46; // 'FLAG'
128 var
129 Textures: TLevelTextureArray;
130 RespawnPoints: Array of TRespawnPoint;
131 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
132 //DOMFlagPoints: Array of TFlagPoint;
135 function g_Map_IsSpecialTexture(Texture: String): Boolean;
136 begin
137 Result := (Texture = TEXTURE_NAME_WATER) or
138 (Texture = TEXTURE_NAME_ACID1) or
139 (Texture = TEXTURE_NAME_ACID2);
140 end;
142 procedure CreateDoorMap();
143 var
144 PanelArray: Array of record
145 X, Y: Integer;
146 Width, Height: Word;
147 Active: Boolean;
148 PanelID: DWORD;
149 end;
150 a, b, c, m, i, len: Integer;
151 ok: Boolean;
152 begin
153 if gWalls = nil then
154 Exit;
156 i := 0;
157 len := 128;
158 SetLength(PanelArray, len);
160 for a := 0 to High(gWalls) do
161 if gWalls[a].Door then
162 begin
163 PanelArray[i].X := gWalls[a].X;
164 PanelArray[i].Y := gWalls[a].Y;
165 PanelArray[i].Width := gWalls[a].Width;
166 PanelArray[i].Height := gWalls[a].Height;
167 PanelArray[i].Active := True;
168 PanelArray[i].PanelID := a;
170 i := i + 1;
171 if i = len then
172 begin
173 len := len + 128;
174 SetLength(PanelArray, len);
175 end;
176 end;
178 // Íåò äâåðåé:
179 if i = 0 then
180 begin
181 PanelArray := nil;
182 Exit;
183 end;
185 SetLength(gDoorMap, 0);
187 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
189 for a := 0 to i-1 do
190 if PanelArray[a].Active then
191 begin
192 PanelArray[a].Active := False;
193 m := Length(gDoorMap);
194 SetLength(gDoorMap, m+1);
195 SetLength(gDoorMap[m], 1);
196 gDoorMap[m, 0] := PanelArray[a].PanelID;
197 ok := True;
199 while ok do
200 begin
201 ok := False;
203 for b := 0 to i-1 do
204 if PanelArray[b].Active then
205 for c := 0 to High(gDoorMap[m]) do
206 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
207 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
208 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
209 PanelArray[b].Width, PanelArray[b].Height,
210 gWalls[gDoorMap[m, c]].X,
211 gWalls[gDoorMap[m, c]].Y,
212 gWalls[gDoorMap[m, c]].Width,
213 gWalls[gDoorMap[m, c]].Height) then
214 begin
215 PanelArray[b].Active := False;
216 SetLength(gDoorMap[m],
217 Length(gDoorMap[m])+1);
218 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
219 ok := True;
220 Break;
221 end;
222 end;
224 g_Game_StepLoading();
225 end;
227 PanelArray := nil;
228 end;
230 procedure CreateLiftMap();
231 var
232 PanelArray: Array of record
233 X, Y: Integer;
234 Width, Height: Word;
235 Active: Boolean;
236 end;
237 a, b, c, len, i, j: Integer;
238 ok: Boolean;
239 begin
240 if gLifts = nil then
241 Exit;
243 len := Length(gLifts);
244 SetLength(PanelArray, len);
246 for a := 0 to len-1 do
247 begin
248 PanelArray[a].X := gLifts[a].X;
249 PanelArray[a].Y := gLifts[a].Y;
250 PanelArray[a].Width := gLifts[a].Width;
251 PanelArray[a].Height := gLifts[a].Height;
252 PanelArray[a].Active := True;
253 end;
255 SetLength(gLiftMap, len);
256 i := 0;
258 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
260 for a := 0 to len-1 do
261 if PanelArray[a].Active then
262 begin
263 PanelArray[a].Active := False;
264 SetLength(gLiftMap[i], 32);
265 j := 0;
266 gLiftMap[i, j] := a;
267 ok := True;
269 while ok do
270 begin
271 ok := False;
272 for b := 0 to len-1 do
273 if PanelArray[b].Active then
274 for c := 0 to j do
275 if g_CollideAround(PanelArray[b].X,
276 PanelArray[b].Y,
277 PanelArray[b].Width,
278 PanelArray[b].Height,
279 PanelArray[gLiftMap[i, c]].X,
280 PanelArray[gLiftMap[i, c]].Y,
281 PanelArray[gLiftMap[i, c]].Width,
282 PanelArray[gLiftMap[i, c]].Height) then
283 begin
284 PanelArray[b].Active := False;
285 j := j+1;
286 if j > High(gLiftMap[i]) then
287 SetLength(gLiftMap[i],
288 Length(gLiftMap[i])+32);
290 gLiftMap[i, j] := b;
291 ok := True;
293 Break;
294 end;
295 end;
297 SetLength(gLiftMap[i], j+1);
298 i := i+1;
300 g_Game_StepLoading();
301 end;
303 SetLength(gLiftMap, i);
305 PanelArray := nil;
306 end;
308 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
309 CurTex: Integer; sav: Boolean): Integer;
310 var
311 len: Integer;
312 panels: ^TPanelArray;
313 begin
314 Result := -1;
316 case PanelRec.PanelType of
317 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
318 panels := @gWalls;
319 PANEL_BACK:
320 panels := @gRenderBackgrounds;
321 PANEL_FORE:
322 panels := @gRenderForegrounds;
323 PANEL_WATER:
324 panels := @gWater;
325 PANEL_ACID1:
326 panels := @gAcid1;
327 PANEL_ACID2:
328 panels := @gAcid2;
329 PANEL_STEP:
330 panels := @gSteps;
331 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
332 panels := @gLifts;
333 PANEL_BLOCKMON:
334 panels := @gBlockMon;
335 else
336 Exit;
337 end;
339 len := Length(panels^);
340 SetLength(panels^, len + 1);
342 panels^[len] := TPanel.Create(PanelRec, AddTextures,
343 CurTex, Textures);
344 if sav then
345 panels^[len].SaveIt := True;
347 Result := len;
348 end;
350 function CreateNullTexture(RecName: String): Integer;
351 begin
352 SetLength(Textures, Length(Textures)+1);
353 result := High(Textures);
355 with Textures[High(Textures)] do
356 begin
357 TextureName := RecName;
358 Width := 1;
359 Height := 1;
360 Anim := False;
361 TextureID := TEXTURE_NONE;
362 end;
363 end;
365 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
366 var
367 WAD: TWADFile;
368 TextureData: Pointer;
369 WADName: String;
370 a, ResLength: Integer;
371 begin
372 Result := -1;
374 if Textures <> nil then
375 for a := 0 to High(Textures) do
376 if Textures[a].TextureName = RecName then
377 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
378 Result := a;
379 Exit;
380 end;
382 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
383 if (RecName = TEXTURE_NAME_WATER) or
384 (RecName = TEXTURE_NAME_ACID1) or
385 (RecName = TEXTURE_NAME_ACID2) then
386 begin
387 SetLength(Textures, Length(Textures)+1);
389 with Textures[High(Textures)] do
390 begin
391 TextureName := RecName;
393 if TextureName = TEXTURE_NAME_WATER then
394 TextureID := TEXTURE_SPECIAL_WATER
395 else
396 if TextureName = TEXTURE_NAME_ACID1 then
397 TextureID := TEXTURE_SPECIAL_ACID1
398 else
399 if TextureName = TEXTURE_NAME_ACID2 then
400 TextureID := TEXTURE_SPECIAL_ACID2;
402 Anim := False;
403 end;
405 result := High(Textures);
406 Exit;
407 end;
409 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
410 WADName := g_ExtractWadName(RecName);
412 WAD := TWADFile.Create();
414 if WADName <> '' then
415 WADName := GameDir+'/wads/'+WADName
416 else
417 WADName := Map;
419 WAD.ReadFile(WADName);
421 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
422 begin
423 SetLength(Textures, Length(Textures)+1);
424 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
425 Exit;
426 e_GetTextureSize(Textures[High(Textures)].TextureID,
427 @Textures[High(Textures)].Width,
428 @Textures[High(Textures)].Height);
429 FreeMem(TextureData);
430 Textures[High(Textures)].TextureName := RecName;
431 Textures[High(Textures)].Anim := False;
433 result := High(Textures);
434 end
435 else // Íåò òàêîãî ðåóñðñà â WAD'å
436 if log then
437 begin
438 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
439 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
440 end;
442 WAD.Free();
443 end;
445 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
446 var
447 WAD: TWADFile;
448 TextureWAD: Pointer;
449 TextData: Pointer;
450 TextureData: Pointer;
451 cfg: TConfig;
452 WADName: String;
453 ResLength: Integer;
454 TextureResource: String;
455 _width, _height, _framecount, _speed: Integer;
456 _backanimation: Boolean;
457 begin
458 Result := -1;
460 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
461 WADName := g_ExtractWadName(RecName);
463 WAD := TWADFile.Create();
465 if WADName <> '' then
466 WADName := GameDir+'/wads/'+WADName
467 else
468 WADName := Map;
470 WAD.ReadFile(WADName);
472 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
473 begin
474 if log then
475 begin
476 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
477 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
478 end;
479 WAD.Free();
480 Exit;
481 end;
483 WAD.FreeWAD();
485 if not WAD.ReadMemory(TextureWAD, ResLength) then
486 begin
487 FreeMem(TextureWAD);
488 WAD.Free();
489 Exit;
490 end;
492 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
493 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
494 begin
495 FreeMem(TextureWAD);
496 WAD.Free();
497 Exit;
498 end;
500 cfg := TConfig.CreateMem(TextData, ResLength);
502 TextureResource := cfg.ReadStr('', 'resource', '');
504 if TextureResource = '' then
505 begin
506 FreeMem(TextureWAD);
507 FreeMem(TextData);
508 WAD.Free();
509 cfg.Free();
510 Exit;
511 end;
513 _width := cfg.ReadInt('', 'framewidth', 0);
514 _height := cfg.ReadInt('', 'frameheight', 0);
515 _framecount := cfg.ReadInt('', 'framecount', 0);
516 _speed := cfg.ReadInt('', 'waitcount', 0);
517 _backanimation := cfg.ReadBool('', 'backanimation', False);
519 cfg.Free();
521 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
522 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
523 begin
524 FreeMem(TextureWAD);
525 FreeMem(TextData);
526 WAD.Free();
527 Exit;
528 end;
530 WAD.Free();
532 SetLength(Textures, Length(Textures)+1);
533 with Textures[High(Textures)] do
534 begin
535 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
536 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength,
537 _width, _height, _framecount, _backanimation) then
538 begin
539 TextureName := RecName;
540 Width := _width;
541 Height := _height;
542 Anim := True;
543 FramesCount := _framecount;
544 Speed := _speed;
546 result := High(Textures);
547 end
548 else
549 if log then
550 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
551 end;
553 FreeMem(TextureWAD);
554 FreeMem(TextData);
555 end;
557 procedure CreateItem(Item: TItemRec_1);
558 begin
559 if g_Game_IsClient then Exit;
561 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
562 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
563 Exit;
565 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
566 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
567 end;
569 procedure CreateArea(Area: TAreaRec_1);
570 var
571 a: Integer;
572 id: DWORD;
573 begin
574 case Area.AreaType of
575 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
576 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
577 begin
578 SetLength(RespawnPoints, Length(RespawnPoints)+1);
579 with RespawnPoints[High(RespawnPoints)] do
580 begin
581 X := Area.X;
582 Y := Area.Y;
583 Direction := TDirection(Area.Direction);
585 case Area.AreaType of
586 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
587 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
588 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
589 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
590 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
591 end;
592 end;
593 end;
595 AREA_REDFLAG, AREA_BLUEFLAG:
596 begin
597 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
599 if FlagPoints[a] <> nil then Exit;
601 New(FlagPoints[a]);
603 with FlagPoints[a]^ do
604 begin
605 X := Area.X-FLAGRECT.X;
606 Y := Area.Y-FLAGRECT.Y;
607 Direction := TDirection(Area.Direction);
608 end;
610 with gFlags[a] do
611 begin
612 case a of
613 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
614 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
615 end;
617 Animation := TAnimation.Create(id, True, 8);
618 Obj.Rect := FLAGRECT;
620 g_Map_ResetFlag(a);
621 end;
622 end;
624 AREA_DOMFLAG:
625 begin
626 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
627 with DOMFlagPoints[High(DOMFlagPoints)] do
628 begin
629 X := Area.X;
630 Y := Area.Y;
631 Direction := TDirection(Area.Direction);
632 end;
634 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
635 end;
636 end;
637 end;
639 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
640 var
641 _trigger: TTrigger;
642 begin
643 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
645 with _trigger do
646 begin
647 X := Trigger.X;
648 Y := Trigger.Y;
649 Width := Trigger.Width;
650 Height := Trigger.Height;
651 Enabled := ByteBool(Trigger.Enabled);
652 TexturePanel := Trigger.TexturePanel;
653 TexturePanelType := fTexturePanel1Type;
654 ShotPanelType := fTexturePanel2Type;
655 TriggerType := Trigger.TriggerType;
656 ActivateType := Trigger.ActivateType;
657 Keys := Trigger.Keys;
658 Data.Default := Trigger.DATA;
659 end;
661 g_Triggers_Create(_trigger);
662 end;
664 procedure CreateMonster(monster: TMonsterRec_1);
665 var
666 a, i: Integer;
667 begin
668 if g_Game_IsClient then Exit;
670 if (gGameSettings.GameType = GT_SINGLE)
671 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
672 begin
673 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
674 TDirection(monster.Direction));
676 if gTriggers <> nil then
677 for a := 0 to High(gTriggers) do
678 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
679 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
680 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
681 gMonsters[i].AddTrigger(a);
683 if monster.MonsterType <> MONSTER_BARREL then
684 Inc(gTotalMonsters);
685 end;
686 end;
688 procedure g_Map_ReAdd_DieTriggers();
689 var
690 i, a: Integer;
691 begin
692 if g_Game_IsClient then Exit;
694 for i := 0 to High(gMonsters) do
695 if gMonsters[i] <> nil then
696 begin
697 gMonsters[i].ClearTriggers();
699 for a := 0 to High(gTriggers) do
700 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
701 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
702 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
703 gMonsters[i].AddTrigger(a);
704 end;
705 end;
707 function extractWadName(resourceName: string): string;
708 var
709 posN: Integer;
710 begin
711 posN := Pos(':', resourceName);
712 if posN > 0 then
713 Result:= Copy(resourceName, 0, posN-1)
714 else
715 Result := '';
716 end;
718 procedure addResToExternalResList(res: string);
719 begin
720 res := extractWadName(res);
721 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
722 gExternalResources.Add(res);
723 end;
725 procedure generateExternalResourcesList(mapReader: TMapReader_1);
726 var
727 textures: TTexturesRec1Array;
728 mapHeader: TMapHeaderRec_1;
729 i: integer;
730 resFile: String = '';
731 begin
732 if gExternalResources = nil then
733 gExternalResources := TStringList.Create;
735 gExternalResources.Clear;
736 textures := mapReader.GetTextures();
737 for i := 0 to High(textures) do
738 begin
739 addResToExternalResList(resFile);
740 end;
742 textures := nil;
744 mapHeader := mapReader.GetMapHeader;
746 addResToExternalResList(mapHeader.MusicName);
747 addResToExternalResList(mapHeader.SkyName);
748 end;
750 function g_Map_Load(Res: String): Boolean;
751 const
752 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
753 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
754 var
755 WAD: TWADFile;
756 MapReader: TMapReader_1;
757 Header: TMapHeaderRec_1;
758 _textures: TTexturesRec1Array;
759 _texnummap: array of Integer; // `_textures` -> `Textures`
760 panels: TPanelsRec1Array;
761 items: TItemsRec1Array;
762 monsters: TMonsterRec1Array;
763 areas: TAreasRec1Array;
764 triggers: TTriggersRec1Array;
765 a, b, c, k: Integer;
766 PanelID: DWORD;
767 AddTextures: TAddTextureArray;
768 texture: TTextureRec_1;
769 TriggersTable: Array of record
770 TexturePanel: Integer;
771 LiftPanel: Integer;
772 DoorPanel: Integer;
773 ShotPanel: Integer;
774 end;
775 FileName, mapResName, s, TexName: String;
776 Data: Pointer;
777 Len: Integer;
778 ok, isAnim, trigRef: Boolean;
779 CurTex, ntn: Integer;
780 begin
781 Result := False;
782 gMapInfo.Map := Res;
783 TriggersTable := nil;
784 FillChar(texture, SizeOf(texture), 0);
786 sfsGCDisable(); // temporary disable removing of temporary volumes
787 try
788 // Çàãðóçêà WAD:
789 FileName := g_ExtractWadName(Res);
790 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
791 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
793 WAD := TWADFile.Create();
794 if not WAD.ReadFile(FileName) then
795 begin
796 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
797 WAD.Free();
798 Exit;
799 end;
800 //k8: why loader ignores path here?
801 mapResName := g_ExtractFileName(Res);
802 if not WAD.GetResource(mapResName, Data, Len) then
803 begin
804 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
805 WAD.Free();
806 Exit;
807 end;
808 WAD.Free();
810 // Çàãðóçêà êàðòû:
811 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
812 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
813 MapReader := TMapReader_1.Create();
815 if not MapReader.LoadMap(Data) then
816 begin
817 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
818 FreeMem(Data);
819 MapReader.Free();
820 Exit;
821 end;
823 FreeMem(Data);
824 generateExternalResourcesList(MapReader);
825 // Çàãðóçêà òåêñòóð:
826 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
827 _textures := MapReader.GetTextures();
828 _texnummap := nil;
830 // Äîáàâëåíèå òåêñòóð â Textures[]:
831 if _textures <> nil then
832 begin
833 e_WriteLog(' Loading textures:', MSG_NOTIFY);
834 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
835 SetLength(_texnummap, length(_textures));
837 for a := 0 to High(_textures) do
838 begin
839 SetLength(s, 64);
840 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
841 for b := 1 to Length(s) do
842 if s[b] = #0 then
843 begin
844 SetLength(s, b-1);
845 Break;
846 end;
847 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
848 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
849 // Àíèìèðîâàííàÿ òåêñòóðà:
850 if ByteBool(_textures[a].Anim) then
851 begin
852 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
853 if ntn < 0 then
854 begin
855 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
856 ntn := CreateNullTexture(_textures[a].Resource);
857 end;
858 end
859 else // Îáû÷íàÿ òåêñòóðà:
860 ntn := CreateTexture(_textures[a].Resource, FileName, True);
861 if ntn < 0 then
862 begin
863 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
864 ntn := CreateNullTexture(_textures[a].Resource);
865 end;
867 _texnummap[a] := ntn; // fix texture number
868 g_Game_StepLoading();
869 end;
870 end;
872 // Çàãðóçêà òðèããåðîâ:
873 gTriggerClientID := 0;
874 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
875 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
876 triggers := MapReader.GetTriggers();
878 // Çàãðóçêà ïàíåëåé:
879 e_WriteLog(' Loading panels...', MSG_NOTIFY);
880 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
881 panels := MapReader.GetPanels();
883 // check texture numbers for panels
884 for a := 0 to High(panels) do
885 begin
886 if panels[a].TextureNum > High(_textures) then
887 begin
888 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
889 result := false;
890 exit;
891 end;
892 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
893 end;
895 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
896 if triggers <> nil then
897 begin
898 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
899 SetLength(TriggersTable, Length(triggers));
900 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
902 for a := 0 to High(TriggersTable) do
903 begin
904 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
905 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
906 // Ëèôòû:
907 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
908 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
909 else
910 TriggersTable[a].LiftPanel := -1;
911 // Äâåðè:
912 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
913 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
914 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
915 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
916 else
917 TriggersTable[a].DoorPanel := -1;
918 // Òóðåëü:
919 if triggers[a].TriggerType = TRIGGER_SHOT then
920 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
921 else
922 TriggersTable[a].ShotPanel := -1;
924 g_Game_StepLoading();
925 end;
926 end;
928 // Ñîçäàåì ïàíåëè:
929 if panels <> nil then
930 begin
931 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
932 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
934 for a := 0 to High(panels) do
935 begin
936 SetLength(AddTextures, 0);
937 trigRef := False;
938 CurTex := -1;
939 if _textures <> nil then
940 begin
941 texture := _textures[panels[a].TextureNum];
942 ok := True;
943 end
944 else
945 ok := False;
947 if ok then
948 begin
949 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
950 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
951 ok := False;
952 if (TriggersTable <> nil) and (_textures <> nil) then
953 for b := 0 to High(TriggersTable) do
954 if (TriggersTable[b].TexturePanel = a)
955 or (TriggersTable[b].ShotPanel = a) then
956 begin
957 trigRef := True;
958 ok := True;
959 Break;
960 end;
961 end;
963 if ok then
964 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
965 SetLength(s, 64);
966 CopyMemory(@s[1], @texture.Resource[0], 64);
967 // Èçìåðÿåì äëèíó:
968 Len := Length(s);
969 for c := Len downto 1 do
970 if s[c] <> #0 then
971 begin
972 Len := c;
973 Break;
974 end;
975 SetLength(s, Len);
977 // Ñïåö-òåêñòóðû çàïðåùåíû:
978 if g_Map_IsSpecialTexture(s) then
979 ok := False
980 else
981 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
982 ok := g_Texture_NumNameFindStart(s);
984 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
985 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
986 if ok then
987 begin
988 k := NNF_NAME_BEFORE;
989 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
990 while ok or (k = NNF_NAME_BEFORE) or
991 (k = NNF_NAME_EQUALS) do
992 begin
993 k := g_Texture_NumNameFindNext(TexName);
995 if (k = NNF_NAME_BEFORE) or
996 (k = NNF_NAME_AFTER) then
997 begin
998 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
999 if ByteBool(texture.Anim) then
1000 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1001 isAnim := True;
1002 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1003 if not ok then
1004 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1005 isAnim := False;
1006 ok := CreateTexture(TexName, FileName, False) >= 0;
1007 end;
1008 end
1009 else
1010 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1011 isAnim := False;
1012 ok := CreateTexture(TexName, FileName, False) >= 0;
1013 if not ok then
1014 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1015 isAnim := True;
1016 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1017 end;
1018 end;
1020 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1021 if ok then
1022 begin
1023 for c := 0 to High(Textures) do
1024 if Textures[c].TextureName = TexName then
1025 begin
1026 SetLength(AddTextures, Length(AddTextures)+1);
1027 AddTextures[High(AddTextures)].Texture := c;
1028 AddTextures[High(AddTextures)].Anim := isAnim;
1029 Break;
1030 end;
1031 end;
1032 end
1033 else
1034 if k = NNF_NAME_EQUALS then
1035 begin
1036 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1037 SetLength(AddTextures, Length(AddTextures)+1);
1038 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1039 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1040 CurTex := High(AddTextures);
1041 ok := True;
1042 end
1043 else // NNF_NO_NAME
1044 ok := False;
1045 end; // while ok...
1047 ok := True;
1048 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1049 end; // if ok - ññûëàþòñÿ òðèããåðû
1051 if not ok then
1052 begin
1053 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1054 SetLength(AddTextures, 1);
1055 AddTextures[0].Texture := panels[a].TextureNum;
1056 AddTextures[0].Anim := ByteBool(texture.Anim);
1057 CurTex := 0;
1058 end;
1060 //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);
1062 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1063 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1065 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1066 if TriggersTable <> nil then
1067 for b := 0 to High(TriggersTable) do
1068 begin
1069 // Òðèããåð äâåðè/ëèôòà:
1070 if (TriggersTable[b].LiftPanel = a) or
1071 (TriggersTable[b].DoorPanel = a) then
1072 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1073 // Òðèããåð ñìåíû òåêñòóðû:
1074 if TriggersTable[b].TexturePanel = a then
1075 triggers[b].TexturePanel := PanelID;
1076 // Òðèããåð "Òóðåëü":
1077 if TriggersTable[b].ShotPanel = a then
1078 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1079 end;
1081 g_Game_StepLoading();
1082 end;
1083 end;
1085 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1086 if (triggers <> nil) and not gLoadGameMode then
1087 begin
1088 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1089 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1090 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1091 for a := 0 to High(triggers) do
1092 begin
1093 if triggers[a].TexturePanel <> -1 then
1094 b := panels[TriggersTable[a].TexturePanel].PanelType
1095 else
1096 b := 0;
1097 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1098 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1099 c := panels[TriggersTable[a].ShotPanel].PanelType
1100 else
1101 c := 0;
1102 CreateTrigger(triggers[a], b, c);
1103 end;
1104 end;
1106 // Çàãðóçêà ïðåäìåòîâ:
1107 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1108 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1109 items := MapReader.GetItems();
1111 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1112 if (items <> nil) and not gLoadGameMode then
1113 begin
1114 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1115 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1116 for a := 0 to High(items) do
1117 CreateItem(Items[a]);
1118 end;
1120 // Çàãðóçêà îáëàñòåé:
1121 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1122 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1123 areas := MapReader.GetAreas();
1125 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1126 if areas <> nil then
1127 begin
1128 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1129 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1130 for a := 0 to High(areas) do
1131 CreateArea(areas[a]);
1132 end;
1134 // Çàãðóçêà ìîíñòðîâ:
1135 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1136 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1137 monsters := MapReader.GetMonsters();
1139 gTotalMonsters := 0;
1141 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1142 if (monsters <> nil) and not gLoadGameMode then
1143 begin
1144 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1145 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1146 for a := 0 to High(monsters) do
1147 CreateMonster(monsters[a]);
1148 end;
1150 // Çàãðóçêà îïèñàíèÿ êàðòû:
1151 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1152 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1153 Header := MapReader.GetMapHeader();
1155 MapReader.Free();
1157 with gMapInfo do
1158 begin
1159 Name := Header.MapName;
1160 Description := Header.MapDescription;
1161 Author := Header.MapAuthor;
1162 MusicName := Header.MusicName;
1163 SkyName := Header.SkyName;
1164 Height := Header.Height;
1165 Width := Header.Width;
1166 end;
1168 // Çàãðóçêà íåáà:
1169 if gMapInfo.SkyName <> '' then
1170 begin
1171 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1172 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1173 FileName := g_ExtractWadName(gMapInfo.SkyName);
1175 if FileName <> '' then
1176 FileName := GameDir+'/wads/'+FileName
1177 else
1178 begin
1179 FileName := g_ExtractWadName(Res);
1180 end;
1182 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1183 if g_Texture_CreateWAD(BackID, s) then
1184 begin
1185 g_Game_SetupScreenSize();
1186 end
1187 else
1188 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1189 end;
1191 // Çàãðóçêà ìóçûêè:
1192 ok := False;
1193 if gMapInfo.MusicName <> '' then
1194 begin
1195 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1196 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1197 FileName := g_ExtractWadName(gMapInfo.MusicName);
1199 if FileName <> '' then
1200 FileName := GameDir+'/wads/'+FileName
1201 else
1202 begin
1203 FileName := g_ExtractWadName(Res);
1204 end;
1206 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1207 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1208 ok := True
1209 else
1210 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1211 end;
1213 // Îñòàëüíûå óñòàíâêè:
1214 CreateDoorMap();
1215 CreateLiftMap();
1217 g_Items_Init();
1218 g_Weapon_Init();
1219 g_Monsters_Init();
1221 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1222 if not gLoadGameMode then
1223 g_GFX_Init();
1225 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1226 _textures := nil;
1227 panels := nil;
1228 items := nil;
1229 areas := nil;
1230 triggers := nil;
1231 TriggersTable := nil;
1232 AddTextures := nil;
1234 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1235 if ok and (not gLoadGameMode) then
1236 begin
1237 gMusic.SetByName(gMapInfo.MusicName);
1238 gMusic.Play();
1239 end
1240 else
1241 gMusic.SetByName('');
1242 finally
1243 sfsGCEnable(); // enable releasing unused volumes
1244 end;
1246 e_WriteLog('Done loading map.', MSG_NOTIFY);
1247 Result := True;
1248 end;
1250 function g_Map_GetMapInfo(Res: String): TMapInfo;
1251 var
1252 WAD: TWADFile;
1253 MapReader: TMapReader_1;
1254 Header: TMapHeaderRec_1;
1255 FileName: String;
1256 Data: Pointer;
1257 Len: Integer;
1258 begin
1259 FillChar(Result, SizeOf(Result), 0);
1260 FileName := g_ExtractWadName(Res);
1262 WAD := TWADFile.Create();
1263 if not WAD.ReadFile(FileName) then
1264 begin
1265 WAD.Free();
1266 Exit;
1267 end;
1269 //k8: it ignores path again
1270 if not WAD.GetResource(g_ExtractFileName(Res), Data, Len) then
1271 begin
1272 WAD.Free();
1273 Exit;
1274 end;
1276 WAD.Free();
1278 MapReader := TMapReader_1.Create();
1280 if not MapReader.LoadMap(Data) then
1281 begin
1282 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1283 ZeroMemory(@Header, SizeOf(Header));
1284 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1285 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1286 end
1287 else
1288 begin
1289 Header := MapReader.GetMapHeader();
1290 Result.Name := Header.MapName;
1291 Result.Description := Header.MapDescription;
1292 end;
1294 FreeMem(Data);
1295 MapReader.Free();
1297 Result.Map := Res;
1298 Result.Author := Header.MapAuthor;
1299 Result.Height := Header.Height;
1300 Result.Width := Header.Width;
1301 end;
1303 function g_Map_GetMapsList(WADName: string): SArray;
1304 var
1305 WAD: TWADFile;
1306 a: Integer;
1307 ResList: SArray;
1308 Data: Pointer;
1309 Len: Integer;
1310 Sign: Array [0..2] of Char;
1311 begin
1312 Result := nil;
1314 WAD := TWADFile.Create();
1315 if not WAD.ReadFile(WADName) then
1316 begin
1317 WAD.Free();
1318 Exit;
1319 end;
1321 ResList := WAD.GetRootResources();
1323 if ResList <> nil then
1324 for a := 0 to High(ResList) do
1325 begin
1326 if not WAD.GetResource(ResList[a], Data, Len) then Continue;
1327 CopyMemory(@Sign[0], Data, 3);
1328 FreeMem(Data);
1330 if Sign = MAP_SIGNATURE then
1331 begin
1332 SetLength(Result, Length(Result)+1);
1333 Result[High(Result)] := ResList[a];
1334 end;
1336 Sign := '';
1337 end;
1339 WAD.Free();
1340 end;
1342 function g_Map_Exist(Res: string): Boolean;
1343 var
1344 WAD: TWADFile;
1345 FileName, mnn: string;
1346 ResList: SArray;
1347 a: Integer;
1348 begin
1349 Result := False;
1351 FileName := addWadExtension(g_ExtractWadName(Res));
1353 WAD := TWADFile.Create;
1354 if not WAD.ReadFile(FileName) then
1355 begin
1356 WAD.Free();
1357 Exit;
1358 end;
1360 ResList := WAD.GetRootResources();
1361 WAD.Free();
1363 mnn := g_ExtractFileName(Res);
1364 if ResList <> nil then
1365 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1366 begin
1367 Result := True;
1368 Exit;
1369 end;
1370 end;
1372 procedure g_Map_Free();
1373 var
1374 a: Integer;
1376 procedure FreePanelArray(var panels: TPanelArray);
1377 var
1378 i: Integer;
1380 begin
1381 if panels <> nil then
1382 begin
1383 for i := 0 to High(panels) do
1384 panels[i].Free();
1385 panels := nil;
1386 end;
1387 end;
1389 begin
1390 g_GFX_Free();
1391 g_Weapon_Free();
1392 g_Items_Free();
1393 g_Triggers_Free();
1394 g_Monsters_Free();
1396 RespawnPoints := nil;
1397 if FlagPoints[FLAG_RED] <> nil then
1398 begin
1399 Dispose(FlagPoints[FLAG_RED]);
1400 FlagPoints[FLAG_RED] := nil;
1401 end;
1402 if FlagPoints[FLAG_BLUE] <> nil then
1403 begin
1404 Dispose(FlagPoints[FLAG_BLUE]);
1405 FlagPoints[FLAG_BLUE] := nil;
1406 end;
1407 //DOMFlagPoints := nil;
1409 //gDOMFlags := nil;
1411 if Textures <> nil then
1412 begin
1413 for a := 0 to High(Textures) do
1414 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1415 if Textures[a].Anim then
1416 g_Frames_DeleteByID(Textures[a].FramesID)
1417 else
1418 if Textures[a].TextureID <> TEXTURE_NONE then
1419 e_DeleteTexture(Textures[a].TextureID);
1421 Textures := nil;
1422 end;
1424 FreePanelArray(gWalls);
1425 FreePanelArray(gRenderBackgrounds);
1426 FreePanelArray(gRenderForegrounds);
1427 FreePanelArray(gWater);
1428 FreePanelArray(gAcid1);
1429 FreePanelArray(gAcid2);
1430 FreePanelArray(gSteps);
1431 FreePanelArray(gLifts);
1432 FreePanelArray(gBlockMon);
1434 if BackID <> DWORD(-1) then
1435 begin
1436 gBackSize.X := 0;
1437 gBackSize.Y := 0;
1438 e_DeleteTexture(BackID);
1439 BackID := DWORD(-1);
1440 end;
1442 g_Game_StopAllSounds(False);
1443 gMusic.FreeSound();
1444 g_Sound_Delete(gMapInfo.MusicName);
1446 gMapInfo.Name := '';
1447 gMapInfo.Description := '';
1448 gMapInfo.MusicName := '';
1449 gMapInfo.Height := 0;
1450 gMapInfo.Width := 0;
1452 gDoorMap := nil;
1453 gLiftMap := nil;
1454 end;
1456 procedure g_Map_Update();
1457 var
1458 a, d, j: Integer;
1459 m: Word;
1460 s: String;
1462 procedure UpdatePanelArray(var panels: TPanelArray);
1463 var
1464 i: Integer;
1466 begin
1467 if panels <> nil then
1468 for i := 0 to High(panels) do
1469 panels[i].Update();
1470 end;
1472 begin
1473 UpdatePanelArray(gWalls);
1474 UpdatePanelArray(gRenderBackgrounds);
1475 UpdatePanelArray(gRenderForegrounds);
1476 UpdatePanelArray(gWater);
1477 UpdatePanelArray(gAcid1);
1478 UpdatePanelArray(gAcid2);
1479 UpdatePanelArray(gSteps);
1481 if gGameSettings.GameMode = GM_CTF then
1482 begin
1483 for a := FLAG_RED to FLAG_BLUE do
1484 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1485 with gFlags[a] do
1486 begin
1487 if gFlags[a].Animation <> nil then
1488 gFlags[a].Animation.Update();
1490 m := g_Obj_Move(@Obj, True, True);
1492 if gTime mod (GAME_TICK*2) <> 0 then
1493 Continue;
1495 // Ñîïðîòèâëåíèå âîçäóõà:
1496 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1498 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1499 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1500 begin
1501 g_Map_ResetFlag(a);
1502 gFlags[a].CaptureTime := 0;
1503 if a = FLAG_RED then
1504 s := _lc[I_PLAYER_FLAG_RED]
1505 else
1506 s := _lc[I_PLAYER_FLAG_BLUE];
1507 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1509 if g_Game_IsNet then
1510 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1511 Continue;
1512 end;
1514 if Count > 0 then
1515 Count := Count - 1;
1517 // Èãðîê áåðåò ôëàã:
1518 if gPlayers <> nil then
1519 begin
1520 j := Random(Length(gPlayers)) - 1;
1522 for d := 0 to High(gPlayers) do
1523 begin
1524 Inc(j);
1525 if j > High(gPlayers) then
1526 j := 0;
1528 if gPlayers[j] <> nil then
1529 if gPlayers[j].Live and
1530 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1531 begin
1532 if gPlayers[j].GetFlag(a) then
1533 Break;
1534 end;
1535 end;
1536 end;
1537 end;
1538 end;
1539 end;
1541 procedure g_Map_DrawPanels(PanelType: Word);
1543 procedure DrawPanels(var panels: TPanelArray;
1544 drawDoors: Boolean = False);
1545 var
1546 a: Integer;
1548 begin
1549 if panels <> nil then
1550 for a := 0 to High(panels) do
1551 if not (drawDoors xor panels[a].Door) then
1552 panels[a].Draw();
1553 end;
1555 begin
1556 case PanelType of
1557 PANEL_WALL: DrawPanels(gWalls);
1558 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1559 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1560 PANEL_FORE: DrawPanels(gRenderForegrounds);
1561 PANEL_WATER: DrawPanels(gWater);
1562 PANEL_ACID1: DrawPanels(gAcid1);
1563 PANEL_ACID2: DrawPanels(gAcid2);
1564 PANEL_STEP: DrawPanels(gSteps);
1565 end;
1566 end;
1568 procedure g_Map_DrawBack(dx, dy: Integer);
1569 begin
1570 if gDrawBackGround and (BackID <> DWORD(-1)) then
1571 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1572 else
1573 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1574 end;
1576 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1577 PanelType: Word; b1x3: Boolean): Boolean;
1578 var
1579 a, h: Integer;
1580 begin
1581 Result := False;
1583 if WordBool(PanelType and PANEL_WALL) then
1584 if gWalls <> nil then
1585 begin
1586 h := High(gWalls);
1588 for a := 0 to h do
1589 if gWalls[a].Enabled and
1590 g_Collide(X, Y, Width, Height,
1591 gWalls[a].X, gWalls[a].Y,
1592 gWalls[a].Width, gWalls[a].Height) then
1593 begin
1594 Result := True;
1595 Exit;
1596 end;
1597 end;
1599 if WordBool(PanelType and PANEL_WATER) then
1600 if gWater <> nil then
1601 begin
1602 h := High(gWater);
1604 for a := 0 to h do
1605 if g_Collide(X, Y, Width, Height,
1606 gWater[a].X, gWater[a].Y,
1607 gWater[a].Width, gWater[a].Height) then
1608 begin
1609 Result := True;
1610 Exit;
1611 end;
1612 end;
1614 if WordBool(PanelType and PANEL_ACID1) then
1615 if gAcid1 <> nil then
1616 begin
1617 h := High(gAcid1);
1619 for a := 0 to h do
1620 if g_Collide(X, Y, Width, Height,
1621 gAcid1[a].X, gAcid1[a].Y,
1622 gAcid1[a].Width, gAcid1[a].Height) then
1623 begin
1624 Result := True;
1625 Exit;
1626 end;
1627 end;
1629 if WordBool(PanelType and PANEL_ACID2) then
1630 if gAcid2 <> nil then
1631 begin
1632 h := High(gAcid2);
1634 for a := 0 to h do
1635 if g_Collide(X, Y, Width, Height,
1636 gAcid2[a].X, gAcid2[a].Y,
1637 gAcid2[a].Width, gAcid2[a].Height) then
1638 begin
1639 Result := True;
1640 Exit;
1641 end;
1642 end;
1644 if WordBool(PanelType and PANEL_STEP) then
1645 if gSteps <> nil then
1646 begin
1647 h := High(gSteps);
1649 for a := 0 to h do
1650 if g_Collide(X, Y, Width, Height,
1651 gSteps[a].X, gSteps[a].Y,
1652 gSteps[a].Width, gSteps[a].Height) then
1653 begin
1654 Result := True;
1655 Exit;
1656 end;
1657 end;
1659 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1660 if gLifts <> nil then
1661 begin
1662 h := High(gLifts);
1664 for a := 0 to h do
1665 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1666 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1667 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1668 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1669 g_Collide(X, Y, Width, Height,
1670 gLifts[a].X, gLifts[a].Y,
1671 gLifts[a].Width, gLifts[a].Height) then
1672 begin
1673 Result := True;
1674 Exit;
1675 end;
1676 end;
1678 if WordBool(PanelType and PANEL_BLOCKMON) then
1679 if gBlockMon <> nil then
1680 begin
1681 h := High(gBlockMon);
1683 for a := 0 to h do
1684 if ( (not b1x3) or
1685 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1686 g_Collide(X, Y, Width, Height,
1687 gBlockMon[a].X, gBlockMon[a].Y,
1688 gBlockMon[a].Width, gBlockMon[a].Height) then
1689 begin
1690 Result := True;
1691 Exit;
1692 end;
1693 end;
1694 end;
1696 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1697 var
1698 a, h: Integer;
1699 begin
1700 Result := TEXTURE_NONE;
1702 if gWater <> nil then
1703 begin
1704 h := High(gWater);
1706 for a := 0 to h do
1707 if g_Collide(X, Y, Width, Height,
1708 gWater[a].X, gWater[a].Y,
1709 gWater[a].Width, gWater[a].Height) then
1710 begin
1711 Result := gWater[a].GetTextureID();
1712 Exit;
1713 end;
1714 end;
1716 if gAcid1 <> nil then
1717 begin
1718 h := High(gAcid1);
1720 for a := 0 to h do
1721 if g_Collide(X, Y, Width, Height,
1722 gAcid1[a].X, gAcid1[a].Y,
1723 gAcid1[a].Width, gAcid1[a].Height) then
1724 begin
1725 Result := gAcid1[a].GetTextureID();
1726 Exit;
1727 end;
1728 end;
1730 if gAcid2 <> nil then
1731 begin
1732 h := High(gAcid2);
1734 for a := 0 to h do
1735 if g_Collide(X, Y, Width, Height,
1736 gAcid2[a].X, gAcid2[a].Y,
1737 gAcid2[a].Width, gAcid2[a].Height) then
1738 begin
1739 Result := gAcid2[a].GetTextureID();
1740 Exit;
1741 end;
1742 end;
1743 end;
1745 procedure g_Map_EnableWall(ID: DWORD);
1746 begin
1747 with gWalls[ID] do
1748 begin
1749 Enabled := True;
1750 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1752 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1753 end;
1754 end;
1756 procedure g_Map_DisableWall(ID: DWORD);
1757 begin
1758 with gWalls[ID] do
1759 begin
1760 Enabled := False;
1761 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1763 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1764 end;
1765 end;
1767 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1768 var
1769 tp: TPanel;
1770 begin
1771 case PanelType of
1772 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1773 tp := gWalls[ID];
1774 PANEL_FORE:
1775 tp := gRenderForegrounds[ID];
1776 PANEL_BACK:
1777 tp := gRenderBackgrounds[ID];
1778 PANEL_WATER:
1779 tp := gWater[ID];
1780 PANEL_ACID1:
1781 tp := gAcid1[ID];
1782 PANEL_ACID2:
1783 tp := gAcid2[ID];
1784 PANEL_STEP:
1785 tp := gSteps[ID];
1786 else
1787 Exit;
1788 end;
1790 tp.NextTexture(AnimLoop);
1791 if g_Game_IsServer and g_Game_IsNet then
1792 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1793 end;
1795 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1796 begin
1797 if gLifts[ID].LiftType = t then
1798 Exit;
1800 with gLifts[ID] do
1801 begin
1802 LiftType := t;
1804 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1806 if LiftType = 0 then
1807 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1808 else if LiftType = 1 then
1809 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1810 else if LiftType = 2 then
1811 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1812 else if LiftType = 3 then
1813 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1815 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1816 end;
1817 end;
1819 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1820 var
1821 a: Integer;
1822 PointsArray: Array of TRespawnPoint;
1823 begin
1824 Result := False;
1825 SetLength(PointsArray, 0);
1827 if RespawnPoints = nil then
1828 Exit;
1830 for a := 0 to High(RespawnPoints) do
1831 if RespawnPoints[a].PointType = PointType then
1832 begin
1833 SetLength(PointsArray, Length(PointsArray)+1);
1834 PointsArray[High(PointsArray)] := RespawnPoints[a];
1835 end;
1837 if PointsArray = nil then
1838 Exit;
1840 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1841 Result := True;
1842 end;
1844 function g_Map_GetPointCount(PointType: Byte): Word;
1845 var
1846 a: Integer;
1847 begin
1848 Result := 0;
1850 if RespawnPoints = nil then
1851 Exit;
1853 for a := 0 to High(RespawnPoints) do
1854 if RespawnPoints[a].PointType = PointType then
1855 Result := Result + 1;
1856 end;
1858 function g_Map_HaveFlagPoints(): Boolean;
1859 begin
1860 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1861 end;
1863 procedure g_Map_ResetFlag(Flag: Byte);
1864 begin
1865 with gFlags[Flag] do
1866 begin
1867 Obj.X := -1000;
1868 Obj.Y := -1000;
1869 Obj.Vel.X := 0;
1870 Obj.Vel.Y := 0;
1871 Direction := D_LEFT;
1872 State := FLAG_STATE_NONE;
1873 if FlagPoints[Flag] <> nil then
1874 begin
1875 Obj.X := FlagPoints[Flag]^.X;
1876 Obj.Y := FlagPoints[Flag]^.Y;
1877 Direction := FlagPoints[Flag]^.Direction;
1878 State := FLAG_STATE_NORMAL;
1879 end;
1880 Count := -1;
1881 end;
1882 end;
1884 procedure g_Map_DrawFlags();
1885 var
1886 i, dx: Integer;
1887 Mirror: TMirrorType;
1888 begin
1889 if gGameSettings.GameMode <> GM_CTF then
1890 Exit;
1892 for i := FLAG_RED to FLAG_BLUE do
1893 with gFlags[i] do
1894 if State <> FLAG_STATE_CAPTURED then
1895 begin
1896 if State = FLAG_STATE_NONE then
1897 continue;
1899 if Direction = D_LEFT then
1900 begin
1901 Mirror := M_HORIZONTAL;
1902 dx := -1;
1903 end
1904 else
1905 begin
1906 Mirror := M_NONE;
1907 dx := 1;
1908 end;
1910 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
1912 if g_debug_Frames then
1913 begin
1914 e_DrawQuad(Obj.X+Obj.Rect.X,
1915 Obj.Y+Obj.Rect.Y,
1916 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
1917 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
1918 0, 255, 0);
1919 end;
1920 end;
1921 end;
1923 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
1924 var
1925 dw: DWORD;
1926 b: Byte;
1927 str: String;
1928 boo: Boolean;
1930 procedure SavePanelArray(var panels: TPanelArray);
1931 var
1932 PAMem: TBinMemoryWriter;
1933 i: Integer;
1934 begin
1935 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
1936 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
1938 i := 0;
1939 while i < Length(panels) do
1940 begin
1941 if panels[i].SaveIt then
1942 begin
1943 // ID ïàíåëè:
1944 PAMem.WriteInt(i);
1945 // Ñîõðàíÿåì ïàíåëü:
1946 panels[i].SaveState(PAMem);
1947 end;
1948 Inc(i);
1949 end;
1951 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
1952 PAMem.SaveToMemory(Mem);
1953 PAMem.Free();
1954 end;
1956 procedure SaveFlag(flag: PFlag);
1957 begin
1958 // Ñèãíàòóðà ôëàãà:
1959 dw := FLAG_SIGNATURE; // 'FLAG'
1960 Mem.WriteDWORD(dw);
1961 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
1962 Mem.WriteByte(flag^.RespawnType);
1963 // Ñîñòîÿíèå ôëàãà:
1964 Mem.WriteByte(flag^.State);
1965 // Íàïðàâëåíèå ôëàãà:
1966 if flag^.Direction = D_LEFT then
1967 b := 1
1968 else // D_RIGHT
1969 b := 2;
1970 Mem.WriteByte(b);
1971 // Îáúåêò ôëàãà:
1972 Obj_SaveState(@flag^.Obj, Mem);
1973 end;
1975 begin
1976 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
1978 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
1979 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
1980 SavePanelArray(gWalls);
1981 // Ñîõðàíÿåì ïàíåëè ôîíà:
1982 SavePanelArray(gRenderBackgrounds);
1983 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
1984 SavePanelArray(gRenderForegrounds);
1985 // Ñîõðàíÿåì ïàíåëè âîäû:
1986 SavePanelArray(gWater);
1987 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
1988 SavePanelArray(gAcid1);
1989 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
1990 SavePanelArray(gAcid2);
1991 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
1992 SavePanelArray(gSteps);
1993 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
1994 SavePanelArray(gLifts);
1995 ///// /////
1997 ///// Ñîõðàíÿåì ìóçûêó: /////
1998 // Ñèãíàòóðà ìóçûêè:
1999 dw := MUSIC_SIGNATURE; // 'MUSI'
2000 Mem.WriteDWORD(dw);
2001 // Íàçâàíèå ìóçûêè:
2002 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2003 if gMusic.NoMusic then
2004 str := ''
2005 else
2006 str := gMusic.Name;
2007 Mem.WriteString(str, 64);
2008 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2009 dw := gMusic.GetPosition();
2010 Mem.WriteDWORD(dw);
2011 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2012 boo := gMusic.SpecPause;
2013 Mem.WriteBoolean(boo);
2014 ///// /////
2016 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2017 Mem.WriteInt(gTotalMonsters);
2018 ///// /////
2020 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2021 if gGameSettings.GameMode = GM_CTF then
2022 begin
2023 // Ôëàã Êðàñíîé êîìàíäû:
2024 SaveFlag(@gFlags[FLAG_RED]);
2025 // Ôëàã Ñèíåé êîìàíäû:
2026 SaveFlag(@gFlags[FLAG_BLUE]);
2027 end;
2028 ///// /////
2030 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2031 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2032 begin
2033 // Î÷êè Êðàñíîé êîìàíäû:
2034 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2035 // Î÷êè Ñèíåé êîìàíäû:
2036 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2037 end;
2038 ///// /////
2039 end;
2041 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2042 var
2043 dw: DWORD;
2044 b: Byte;
2045 str: String;
2046 boo: Boolean;
2048 procedure LoadPanelArray(var panels: TPanelArray);
2049 var
2050 PAMem: TBinMemoryReader;
2051 i, id: Integer;
2052 begin
2053 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2054 PAMem := TBinMemoryReader.Create();
2055 PAMem.LoadFromMemory(Mem);
2057 for i := 0 to Length(panels)-1 do
2058 if panels[i].SaveIt then
2059 begin
2060 // ID ïàíåëè:
2061 PAMem.ReadInt(id);
2062 if id <> i then
2063 begin
2064 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2065 end;
2066 // Çàãðóæàåì ïàíåëü:
2067 panels[i].LoadState(PAMem);
2068 end;
2070 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2071 PAMem.Free();
2072 end;
2074 procedure LoadFlag(flag: PFlag);
2075 begin
2076 // Ñèãíàòóðà ôëàãà:
2077 Mem.ReadDWORD(dw);
2078 if dw <> FLAG_SIGNATURE then // 'FLAG'
2079 begin
2080 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2081 end;
2082 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2083 Mem.ReadByte(flag^.RespawnType);
2084 // Ñîñòîÿíèå ôëàãà:
2085 Mem.ReadByte(flag^.State);
2086 // Íàïðàâëåíèå ôëàãà:
2087 Mem.ReadByte(b);
2088 if b = 1 then
2089 flag^.Direction := D_LEFT
2090 else // b = 2
2091 flag^.Direction := D_RIGHT;
2092 // Îáúåêò ôëàãà:
2093 Obj_LoadState(@flag^.Obj, Mem);
2094 end;
2096 begin
2097 if Mem = nil then
2098 Exit;
2100 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2101 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2102 LoadPanelArray(gWalls);
2103 // Çàãðóæàåì ïàíåëè ôîíà:
2104 LoadPanelArray(gRenderBackgrounds);
2105 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2106 LoadPanelArray(gRenderForegrounds);
2107 // Çàãðóæàåì ïàíåëè âîäû:
2108 LoadPanelArray(gWater);
2109 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2110 LoadPanelArray(gAcid1);
2111 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2112 LoadPanelArray(gAcid2);
2113 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2114 LoadPanelArray(gSteps);
2115 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2116 LoadPanelArray(gLifts);
2117 ///// /////
2119 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2120 g_GFX_Init();
2122 ///// Çàãðóæàåì ìóçûêó: /////
2123 // Ñèãíàòóðà ìóçûêè:
2124 Mem.ReadDWORD(dw);
2125 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2126 begin
2127 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2128 end;
2129 // Íàçâàíèå ìóçûêè:
2130 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2131 Mem.ReadString(str);
2132 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2133 Mem.ReadDWORD(dw);
2134 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2135 Mem.ReadBoolean(boo);
2136 // Çàïóñêàåì ýòó ìóçûêó:
2137 gMusic.SetByName(str);
2138 gMusic.SpecPause := boo;
2139 gMusic.Play();
2140 gMusic.Pause(True);
2141 gMusic.SetPosition(dw);
2142 ///// /////
2144 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2145 Mem.ReadInt(gTotalMonsters);
2146 ///// /////
2148 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2149 if gGameSettings.GameMode = GM_CTF then
2150 begin
2151 // Ôëàã Êðàñíîé êîìàíäû:
2152 LoadFlag(@gFlags[FLAG_RED]);
2153 // Ôëàã Ñèíåé êîìàíäû:
2154 LoadFlag(@gFlags[FLAG_BLUE]);
2155 end;
2156 ///// /////
2158 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2159 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2160 begin
2161 // Î÷êè Êðàñíîé êîìàíäû:
2162 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2163 // Î÷êè Ñèíåé êîìàíäû:
2164 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2165 end;
2166 ///// /////
2167 end;
2169 end.