DEADSOFTWARE

added Vampyre Imaging Library; now textures can be in various formats, including...
[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 SectionName: String;
371 TextureName: String;
372 a, ResLength: Integer;
373 begin
374 Result := -1;
376 if Textures <> nil then
377 for a := 0 to High(Textures) do
378 if Textures[a].TextureName = RecName then
379 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
380 Result := a;
381 Exit;
382 end;
384 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
385 if (RecName = TEXTURE_NAME_WATER) or
386 (RecName = TEXTURE_NAME_ACID1) or
387 (RecName = TEXTURE_NAME_ACID2) then
388 begin
389 SetLength(Textures, Length(Textures)+1);
391 with Textures[High(Textures)] do
392 begin
393 TextureName := RecName;
395 if TextureName = TEXTURE_NAME_WATER then
396 TextureID := TEXTURE_SPECIAL_WATER
397 else
398 if TextureName = TEXTURE_NAME_ACID1 then
399 TextureID := TEXTURE_SPECIAL_ACID1
400 else
401 if TextureName = TEXTURE_NAME_ACID2 then
402 TextureID := TEXTURE_SPECIAL_ACID2;
404 Anim := False;
405 end;
407 result := High(Textures);
408 Exit;
409 end;
411 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
412 g_ProcessResourceStr(RecName, WADName, SectionName, TextureName);
414 WAD := TWADFile.Create();
416 if WADName <> '' then
417 WADName := GameDir+'/wads/'+WADName
418 else
419 WADName := Map;
421 WAD.ReadFile(WADName);
423 if WAD.GetResource(SectionName, TextureName, TextureData, ResLength) then
424 begin
425 SetLength(Textures, Length(Textures)+1);
426 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
427 Exit;
428 e_GetTextureSize(Textures[High(Textures)].TextureID,
429 @Textures[High(Textures)].Width,
430 @Textures[High(Textures)].Height);
431 FreeMem(TextureData);
432 Textures[High(Textures)].TextureName := RecName;
433 Textures[High(Textures)].Anim := False;
435 result := High(Textures);
436 end
437 else // Íåò òàêîãî ðåóñðñà â WAD'å
438 if log then
439 begin
440 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
441 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
442 end;
444 WAD.Free();
445 end;
447 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
448 var
449 WAD: TWADFile;
450 TextureWAD: Pointer;
451 TextData: Pointer;
452 TextureData: Pointer;
453 cfg: TConfig;
454 WADName: String;
455 SectionName: String;
456 TextureName: String;
457 ResLength: Integer;
458 TextureResource: String;
459 _width, _height, _framecount, _speed: Integer;
460 _backanimation: Boolean;
461 begin
462 Result := -1;
464 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
465 g_ProcessResourceStr(RecName, WADName, SectionName, TextureName);
467 WAD := TWADFile.Create();
469 if WADName <> '' then
470 WADName := GameDir+'/wads/'+WADName
471 else
472 WADName := Map;
474 WAD.ReadFile(WADName);
476 if not WAD.GetResource(SectionName, TextureName, TextureWAD, ResLength) then
477 begin
478 if log then
479 begin
480 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
481 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
482 end;
483 WAD.Free();
484 Exit;
485 end;
487 WAD.FreeWAD();
489 if not WAD.ReadMemory(TextureWAD, ResLength) then
490 begin
491 FreeMem(TextureWAD);
492 WAD.Free();
493 Exit;
494 end;
496 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
497 if not WAD.GetResource('TEXT', 'ANIM', TextData, ResLength) then
498 begin
499 FreeMem(TextureWAD);
500 WAD.Free();
501 Exit;
502 end;
504 cfg := TConfig.CreateMem(TextData, ResLength);
506 TextureResource := cfg.ReadStr('', 'resource', '');
508 if TextureResource = '' then
509 begin
510 FreeMem(TextureWAD);
511 FreeMem(TextData);
512 WAD.Free();
513 cfg.Free();
514 Exit;
515 end;
517 _width := cfg.ReadInt('', 'framewidth', 0);
518 _height := cfg.ReadInt('', 'frameheight', 0);
519 _framecount := cfg.ReadInt('', 'framecount', 0);
520 _speed := cfg.ReadInt('', 'waitcount', 0);
521 _backanimation := cfg.ReadBool('', 'backanimation', False);
523 cfg.Free();
525 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
526 if not WAD.GetResource('TEXTURES', TextureResource, TextureData, ResLength) then
527 begin
528 FreeMem(TextureWAD);
529 FreeMem(TextData);
530 WAD.Free();
531 Exit;
532 end;
534 WAD.Free();
536 SetLength(Textures, Length(Textures)+1);
537 with Textures[High(Textures)] do
538 begin
539 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
540 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength,
541 _width, _height, _framecount, _backanimation) then
542 begin
543 TextureName := RecName;
544 Width := _width;
545 Height := _height;
546 Anim := True;
547 FramesCount := _framecount;
548 Speed := _speed;
550 result := High(Textures);
551 end
552 else
553 if log then
554 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
555 end;
557 FreeMem(TextureWAD);
558 FreeMem(TextData);
559 end;
561 procedure CreateItem(Item: TItemRec_1);
562 begin
563 if g_Game_IsClient then Exit;
565 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
566 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
567 Exit;
569 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
570 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
571 end;
573 procedure CreateArea(Area: TAreaRec_1);
574 var
575 a: Integer;
576 id: DWORD;
577 begin
578 case Area.AreaType of
579 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
580 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
581 begin
582 SetLength(RespawnPoints, Length(RespawnPoints)+1);
583 with RespawnPoints[High(RespawnPoints)] do
584 begin
585 X := Area.X;
586 Y := Area.Y;
587 Direction := TDirection(Area.Direction);
589 case Area.AreaType of
590 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
591 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
592 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
593 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
594 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
595 end;
596 end;
597 end;
599 AREA_REDFLAG, AREA_BLUEFLAG:
600 begin
601 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
603 if FlagPoints[a] <> nil then Exit;
605 New(FlagPoints[a]);
607 with FlagPoints[a]^ do
608 begin
609 X := Area.X-FLAGRECT.X;
610 Y := Area.Y-FLAGRECT.Y;
611 Direction := TDirection(Area.Direction);
612 end;
614 with gFlags[a] do
615 begin
616 case a of
617 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
618 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
619 end;
621 Animation := TAnimation.Create(id, True, 8);
622 Obj.Rect := FLAGRECT;
624 g_Map_ResetFlag(a);
625 end;
626 end;
628 AREA_DOMFLAG:
629 begin
630 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
631 with DOMFlagPoints[High(DOMFlagPoints)] do
632 begin
633 X := Area.X;
634 Y := Area.Y;
635 Direction := TDirection(Area.Direction);
636 end;
638 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
639 end;
640 end;
641 end;
643 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
644 var
645 _trigger: TTrigger;
646 begin
647 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
649 with _trigger do
650 begin
651 X := Trigger.X;
652 Y := Trigger.Y;
653 Width := Trigger.Width;
654 Height := Trigger.Height;
655 Enabled := ByteBool(Trigger.Enabled);
656 TexturePanel := Trigger.TexturePanel;
657 TexturePanelType := fTexturePanel1Type;
658 ShotPanelType := fTexturePanel2Type;
659 TriggerType := Trigger.TriggerType;
660 ActivateType := Trigger.ActivateType;
661 Keys := Trigger.Keys;
662 Data.Default := Trigger.DATA;
663 end;
665 g_Triggers_Create(_trigger);
666 end;
668 procedure CreateMonster(monster: TMonsterRec_1);
669 var
670 a, i: Integer;
671 begin
672 if g_Game_IsClient then Exit;
674 if (gGameSettings.GameType = GT_SINGLE)
675 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
676 begin
677 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
678 TDirection(monster.Direction));
680 if gTriggers <> nil then
681 for a := 0 to High(gTriggers) do
682 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
683 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
684 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
685 gMonsters[i].AddTrigger(a);
687 if monster.MonsterType <> MONSTER_BARREL then
688 Inc(gTotalMonsters);
689 end;
690 end;
692 procedure g_Map_ReAdd_DieTriggers();
693 var
694 i, a: Integer;
695 begin
696 if g_Game_IsClient then Exit;
698 for i := 0 to High(gMonsters) do
699 if gMonsters[i] <> nil then
700 begin
701 gMonsters[i].ClearTriggers();
703 for a := 0 to High(gTriggers) do
704 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
705 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
706 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
707 gMonsters[i].AddTrigger(a);
708 end;
709 end;
711 function extractWadName(resourceName: string): string;
712 var
713 posN: Integer;
714 begin
715 posN := Pos(':', resourceName);
716 if posN > 0 then
717 Result:= Copy(resourceName, 0, posN-1)
718 else
719 Result := '';
720 end;
722 procedure addResToExternalResList(res: string);
723 begin
724 res := extractWadName(res);
725 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
726 gExternalResources.Add(res);
727 end;
729 procedure generateExternalResourcesList(mapReader: TMapReader_1);
730 var
731 textures: TTexturesRec1Array;
732 mapHeader: TMapHeaderRec_1;
733 i: integer;
734 resFile: String = '';
735 begin
736 if gExternalResources = nil then
737 gExternalResources := TStringList.Create;
739 gExternalResources.Clear;
740 textures := mapReader.GetTextures();
741 for i := 0 to High(textures) do
742 begin
743 addResToExternalResList(resFile);
744 end;
746 textures := nil;
748 mapHeader := mapReader.GetMapHeader;
750 addResToExternalResList(mapHeader.MusicName);
751 addResToExternalResList(mapHeader.SkyName);
752 end;
754 function g_Map_Load(Res: String): Boolean;
755 const
756 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
757 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
758 var
759 WAD: TWADFile;
760 MapReader: TMapReader_1;
761 Header: TMapHeaderRec_1;
762 _textures: TTexturesRec1Array;
763 _texnummap: array of Integer; // `_textures` -> `Textures`
764 panels: TPanelsRec1Array;
765 items: TItemsRec1Array;
766 monsters: TMonsterRec1Array;
767 areas: TAreasRec1Array;
768 triggers: TTriggersRec1Array;
769 a, b, c, k: Integer;
770 PanelID: DWORD;
771 AddTextures: TAddTextureArray;
772 texture: TTextureRec_1;
773 TriggersTable: Array of record
774 TexturePanel: Integer;
775 LiftPanel: Integer;
776 DoorPanel: Integer;
777 ShotPanel: Integer;
778 end;
779 FileName, SectionName, ResName,
780 FileName2, s, TexName: String;
781 Data: Pointer;
782 Len: Integer;
783 ok, isAnim, trigRef: Boolean;
784 CurTex, ntn: Integer;
785 begin
786 Result := False;
787 gMapInfo.Map := Res;
788 TriggersTable := nil;
789 FillChar(texture, SizeOf(texture), 0);
791 sfsGCDisable(); // temporary disable removing of temporary volumes
792 try
793 // Çàãðóçêà WAD:
794 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
795 e_WriteLog('Loading map WAD: ' + FileName, MSG_NOTIFY);
796 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
798 WAD := TWADFile.Create();
799 if not WAD.ReadFile(FileName) then
800 begin
801 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
802 WAD.Free();
803 Exit;
804 end;
805 if not WAD.GetResource('', ResName, Data, Len) then
806 begin
807 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [ResName]));
808 WAD.Free();
809 Exit;
810 end;
811 WAD.Free();
813 // Çàãðóçêà êàðòû:
814 e_WriteLog('Loading map: ' + ResName, MSG_NOTIFY);
815 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
816 MapReader := TMapReader_1.Create();
818 if not MapReader.LoadMap(Data) then
819 begin
820 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
821 FreeMem(Data);
822 MapReader.Free();
823 Exit;
824 end;
826 FreeMem(Data);
827 generateExternalResourcesList(MapReader);
828 // Çàãðóçêà òåêñòóð:
829 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
830 _textures := MapReader.GetTextures();
831 _texnummap := nil;
833 // Äîáàâëåíèå òåêñòóð â Textures[]:
834 if _textures <> nil then
835 begin
836 e_WriteLog(' Loading textures:', MSG_NOTIFY);
837 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
838 SetLength(_texnummap, length(_textures));
840 for a := 0 to High(_textures) do
841 begin
842 SetLength(s, 64);
843 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
844 for b := 1 to Length(s) do
845 if s[b] = #0 then
846 begin
847 SetLength(s, b-1);
848 Break;
849 end;
850 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
851 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
852 // Àíèìèðîâàííàÿ òåêñòóðà:
853 if ByteBool(_textures[a].Anim) then
854 begin
855 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
856 if ntn < 0 then
857 begin
858 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
859 ntn := CreateNullTexture(_textures[a].Resource);
860 end;
861 end
862 else // Îáû÷íàÿ òåêñòóðà:
863 ntn := CreateTexture(_textures[a].Resource, FileName, True);
864 if ntn < 0 then
865 begin
866 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
867 ntn := CreateNullTexture(_textures[a].Resource);
868 end;
870 _texnummap[a] := ntn; // fix texture number
871 g_Game_StepLoading();
872 end;
873 end;
875 // Çàãðóçêà òðèããåðîâ:
876 gTriggerClientID := 0;
877 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
878 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
879 triggers := MapReader.GetTriggers();
881 // Çàãðóçêà ïàíåëåé:
882 e_WriteLog(' Loading panels...', MSG_NOTIFY);
883 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
884 panels := MapReader.GetPanels();
886 // check texture numbers for panels
887 for a := 0 to High(panels) do
888 begin
889 if panels[a].TextureNum > High(_textures) then
890 begin
891 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
892 result := false;
893 exit;
894 end;
895 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
896 end;
898 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
899 if triggers <> nil then
900 begin
901 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
902 SetLength(TriggersTable, Length(triggers));
903 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
905 for a := 0 to High(TriggersTable) do
906 begin
907 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
908 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
909 // Ëèôòû:
910 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
911 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
912 else
913 TriggersTable[a].LiftPanel := -1;
914 // Äâåðè:
915 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
916 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
917 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
918 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
919 else
920 TriggersTable[a].DoorPanel := -1;
921 // Òóðåëü:
922 if triggers[a].TriggerType = TRIGGER_SHOT then
923 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
924 else
925 TriggersTable[a].ShotPanel := -1;
927 g_Game_StepLoading();
928 end;
929 end;
931 // Ñîçäàåì ïàíåëè:
932 if panels <> nil then
933 begin
934 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
935 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
937 for a := 0 to High(panels) do
938 begin
939 SetLength(AddTextures, 0);
940 trigRef := False;
941 CurTex := -1;
942 if _textures <> nil then
943 begin
944 texture := _textures[panels[a].TextureNum];
945 ok := True;
946 end
947 else
948 ok := False;
950 if ok then
951 begin
952 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
953 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
954 ok := False;
955 if (TriggersTable <> nil) and (_textures <> nil) then
956 for b := 0 to High(TriggersTable) do
957 if (TriggersTable[b].TexturePanel = a)
958 or (TriggersTable[b].ShotPanel = a) then
959 begin
960 trigRef := True;
961 ok := True;
962 Break;
963 end;
964 end;
966 if ok then
967 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
968 SetLength(s, 64);
969 CopyMemory(@s[1], @texture.Resource[0], 64);
970 // Èçìåðÿåì äëèíó:
971 Len := Length(s);
972 for c := Len downto 1 do
973 if s[c] <> #0 then
974 begin
975 Len := c;
976 Break;
977 end;
978 SetLength(s, Len);
980 // Ñïåö-òåêñòóðû çàïðåùåíû:
981 if g_Map_IsSpecialTexture(s) then
982 ok := False
983 else
984 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
985 ok := g_Texture_NumNameFindStart(s);
987 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
988 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
989 if ok then
990 begin
991 k := NNF_NAME_BEFORE;
992 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
993 while ok or (k = NNF_NAME_BEFORE) or
994 (k = NNF_NAME_EQUALS) do
995 begin
996 k := g_Texture_NumNameFindNext(TexName);
998 if (k = NNF_NAME_BEFORE) or
999 (k = NNF_NAME_AFTER) then
1000 begin
1001 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1002 if ByteBool(texture.Anim) then
1003 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1004 isAnim := True;
1005 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1006 if not ok then
1007 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1008 isAnim := False;
1009 ok := CreateTexture(TexName, FileName, False) >= 0;
1010 end;
1011 end
1012 else
1013 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1014 isAnim := False;
1015 ok := CreateTexture(TexName, FileName, False) >= 0;
1016 if not ok then
1017 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1018 isAnim := True;
1019 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1020 end;
1021 end;
1023 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1024 if ok then
1025 begin
1026 for c := 0 to High(Textures) do
1027 if Textures[c].TextureName = TexName then
1028 begin
1029 SetLength(AddTextures, Length(AddTextures)+1);
1030 AddTextures[High(AddTextures)].Texture := c;
1031 AddTextures[High(AddTextures)].Anim := isAnim;
1032 Break;
1033 end;
1034 end;
1035 end
1036 else
1037 if k = NNF_NAME_EQUALS then
1038 begin
1039 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1040 SetLength(AddTextures, Length(AddTextures)+1);
1041 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1042 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1043 CurTex := High(AddTextures);
1044 ok := True;
1045 end
1046 else // NNF_NO_NAME
1047 ok := False;
1048 end; // while ok...
1050 ok := True;
1051 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1052 end; // if ok - ññûëàþòñÿ òðèããåðû
1054 if not ok then
1055 begin
1056 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1057 SetLength(AddTextures, 1);
1058 AddTextures[0].Texture := panels[a].TextureNum;
1059 AddTextures[0].Anim := ByteBool(texture.Anim);
1060 CurTex := 0;
1061 end;
1063 //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);
1065 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1066 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1068 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1069 if TriggersTable <> nil then
1070 for b := 0 to High(TriggersTable) do
1071 begin
1072 // Òðèããåð äâåðè/ëèôòà:
1073 if (TriggersTable[b].LiftPanel = a) or
1074 (TriggersTable[b].DoorPanel = a) then
1075 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1076 // Òðèããåð ñìåíû òåêñòóðû:
1077 if TriggersTable[b].TexturePanel = a then
1078 triggers[b].TexturePanel := PanelID;
1079 // Òðèããåð "Òóðåëü":
1080 if TriggersTable[b].ShotPanel = a then
1081 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1082 end;
1084 g_Game_StepLoading();
1085 end;
1086 end;
1088 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1089 if (triggers <> nil) and not gLoadGameMode then
1090 begin
1091 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1092 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1093 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1094 for a := 0 to High(triggers) do
1095 begin
1096 if triggers[a].TexturePanel <> -1 then
1097 b := panels[TriggersTable[a].TexturePanel].PanelType
1098 else
1099 b := 0;
1100 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1101 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1102 c := panels[TriggersTable[a].ShotPanel].PanelType
1103 else
1104 c := 0;
1105 CreateTrigger(triggers[a], b, c);
1106 end;
1107 end;
1109 // Çàãðóçêà ïðåäìåòîâ:
1110 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1111 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1112 items := MapReader.GetItems();
1114 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1115 if (items <> nil) and not gLoadGameMode then
1116 begin
1117 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1118 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1119 for a := 0 to High(items) do
1120 CreateItem(Items[a]);
1121 end;
1123 // Çàãðóçêà îáëàñòåé:
1124 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1125 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1126 areas := MapReader.GetAreas();
1128 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1129 if areas <> nil then
1130 begin
1131 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1132 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1133 for a := 0 to High(areas) do
1134 CreateArea(areas[a]);
1135 end;
1137 // Çàãðóçêà ìîíñòðîâ:
1138 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1139 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1140 monsters := MapReader.GetMonsters();
1142 gTotalMonsters := 0;
1144 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1145 if (monsters <> nil) and not gLoadGameMode then
1146 begin
1147 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1148 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1149 for a := 0 to High(monsters) do
1150 CreateMonster(monsters[a]);
1151 end;
1153 // Çàãðóçêà îïèñàíèÿ êàðòû:
1154 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1155 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1156 Header := MapReader.GetMapHeader();
1158 MapReader.Free();
1160 with gMapInfo do
1161 begin
1162 Name := Header.MapName;
1163 Description := Header.MapDescription;
1164 Author := Header.MapAuthor;
1165 MusicName := Header.MusicName;
1166 SkyName := Header.SkyName;
1167 Height := Header.Height;
1168 Width := Header.Width;
1169 end;
1171 // Çàãðóçêà íåáà:
1172 if gMapInfo.SkyName <> '' then
1173 begin
1174 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1175 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1176 g_ProcessResourceStr(gMapInfo.SkyName, FileName, SectionName, ResName);
1178 if FileName <> '' then
1179 FileName := GameDir+'/wads/'+FileName
1180 else
1181 begin
1182 g_ProcessResourceStr(Res, @FileName2, nil, nil);
1183 FileName := FileName2;
1184 end;
1186 s := FileName+':'+SectionName+'/'+ResName;
1187 if g_Texture_CreateWAD(BackID, s) then
1188 begin
1189 g_Game_SetupScreenSize();
1190 end
1191 else
1192 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1193 end;
1195 // Çàãðóçêà ìóçûêè:
1196 ok := False;
1197 if gMapInfo.MusicName <> '' then
1198 begin
1199 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1200 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1201 g_ProcessResourceStr(gMapInfo.MusicName, FileName, SectionName, ResName);
1203 if FileName <> '' then
1204 FileName := GameDir+'/wads/'+FileName
1205 else
1206 begin
1207 g_ProcessResourceStr(Res, @FileName2, nil, nil);
1208 FileName := FileName2;
1209 end;
1211 s := FileName+':'+SectionName+'/'+ResName;
1212 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1213 ok := True
1214 else
1215 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1216 end;
1218 // Îñòàëüíûå óñòàíâêè:
1219 CreateDoorMap();
1220 CreateLiftMap();
1222 g_Items_Init();
1223 g_Weapon_Init();
1224 g_Monsters_Init();
1226 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1227 if not gLoadGameMode then
1228 g_GFX_Init();
1230 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1231 _textures := nil;
1232 panels := nil;
1233 items := nil;
1234 areas := nil;
1235 triggers := nil;
1236 TriggersTable := nil;
1237 AddTextures := nil;
1239 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1240 if ok and (not gLoadGameMode) then
1241 begin
1242 gMusic.SetByName(gMapInfo.MusicName);
1243 gMusic.Play();
1244 end
1245 else
1246 gMusic.SetByName('');
1247 finally
1248 sfsGCEnable(); // enable releasing unused volumes
1249 end;
1251 e_WriteLog('Done loading map.', MSG_NOTIFY);
1252 Result := True;
1253 end;
1255 function g_Map_GetMapInfo(Res: String): TMapInfo;
1256 var
1257 WAD: TWADFile;
1258 MapReader: TMapReader_1;
1259 Header: TMapHeaderRec_1;
1260 FileName, SectionName, ResName: String;
1261 Data: Pointer;
1262 Len: Integer;
1263 begin
1264 FillChar(Result, SizeOf(Result), 0);
1265 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
1267 WAD := TWADFile.Create();
1268 if not WAD.ReadFile(FileName) then
1269 begin
1270 WAD.Free();
1271 Exit;
1272 end;
1274 if not WAD.GetResource('', ResName, Data, Len) then
1275 begin
1276 WAD.Free();
1277 Exit;
1278 end;
1280 WAD.Free();
1282 MapReader := TMapReader_1.Create();
1284 if not MapReader.LoadMap(Data) then
1285 begin
1286 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1287 ZeroMemory(@Header, SizeOf(Header));
1288 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1289 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1290 end
1291 else
1292 begin
1293 Header := MapReader.GetMapHeader();
1294 Result.Name := Header.MapName;
1295 Result.Description := Header.MapDescription;
1296 end;
1298 FreeMem(Data);
1299 MapReader.Free();
1301 Result.Map := Res;
1302 Result.Author := Header.MapAuthor;
1303 Result.Height := Header.Height;
1304 Result.Width := Header.Width;
1305 end;
1307 function g_Map_GetMapsList(WADName: string): SArray;
1308 var
1309 WAD: TWADFile;
1310 a: Integer;
1311 ResList: SArray;
1312 Data: Pointer;
1313 Len: Integer;
1314 Sign: Array [0..2] of Char;
1315 begin
1316 Result := nil;
1318 WAD := TWADFile.Create();
1319 if not WAD.ReadFile(WADName) then
1320 begin
1321 WAD.Free();
1322 Exit;
1323 end;
1325 ResList := WAD.GetResourcesList('');
1327 if ResList <> nil then
1328 for a := 0 to High(ResList) do
1329 begin
1330 if not WAD.GetResource('', ResList[a], Data, Len) then Continue;
1331 CopyMemory(@Sign[0], Data, 3);
1332 FreeMem(Data);
1334 if Sign = MAP_SIGNATURE then
1335 begin
1336 SetLength(Result, Length(Result)+1);
1337 Result[High(Result)] := ResList[a];
1338 end;
1340 Sign := '';
1341 end;
1343 WAD.Free();
1344 end;
1346 function g_Map_Exist(Res: string): Boolean;
1347 var
1348 WAD: TWADFile;
1349 FileName, SectionName, ResName: string;
1350 ResList: SArray;
1351 a: Integer;
1352 begin
1353 Result := False;
1355 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
1357 FileName := addWadExtension(FileName);
1359 WAD := TWADFile.Create;
1360 if not WAD.ReadFile(FileName) then
1361 begin
1362 WAD.Free();
1363 Exit;
1364 end;
1366 ResList := WAD.GetResourcesList('');
1367 WAD.Free();
1369 if ResList <> nil then
1370 for a := 0 to High(ResList) do if ResList[a] = ResName then
1371 begin
1372 Result := True;
1373 Exit;
1374 end;
1375 end;
1377 procedure g_Map_Free();
1378 var
1379 a: Integer;
1381 procedure FreePanelArray(var panels: TPanelArray);
1382 var
1383 i: Integer;
1385 begin
1386 if panels <> nil then
1387 begin
1388 for i := 0 to High(panels) do
1389 panels[i].Free();
1390 panels := nil;
1391 end;
1392 end;
1394 begin
1395 g_GFX_Free();
1396 g_Weapon_Free();
1397 g_Items_Free();
1398 g_Triggers_Free();
1399 g_Monsters_Free();
1401 RespawnPoints := nil;
1402 if FlagPoints[FLAG_RED] <> nil then
1403 begin
1404 Dispose(FlagPoints[FLAG_RED]);
1405 FlagPoints[FLAG_RED] := nil;
1406 end;
1407 if FlagPoints[FLAG_BLUE] <> nil then
1408 begin
1409 Dispose(FlagPoints[FLAG_BLUE]);
1410 FlagPoints[FLAG_BLUE] := nil;
1411 end;
1412 //DOMFlagPoints := nil;
1414 //gDOMFlags := nil;
1416 if Textures <> nil then
1417 begin
1418 for a := 0 to High(Textures) do
1419 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1420 if Textures[a].Anim then
1421 g_Frames_DeleteByID(Textures[a].FramesID)
1422 else
1423 if Textures[a].TextureID <> TEXTURE_NONE then
1424 e_DeleteTexture(Textures[a].TextureID);
1426 Textures := nil;
1427 end;
1429 FreePanelArray(gWalls);
1430 FreePanelArray(gRenderBackgrounds);
1431 FreePanelArray(gRenderForegrounds);
1432 FreePanelArray(gWater);
1433 FreePanelArray(gAcid1);
1434 FreePanelArray(gAcid2);
1435 FreePanelArray(gSteps);
1436 FreePanelArray(gLifts);
1437 FreePanelArray(gBlockMon);
1439 if BackID <> DWORD(-1) then
1440 begin
1441 gBackSize.X := 0;
1442 gBackSize.Y := 0;
1443 e_DeleteTexture(BackID);
1444 BackID := DWORD(-1);
1445 end;
1447 g_Game_StopAllSounds(False);
1448 gMusic.FreeSound();
1449 g_Sound_Delete(gMapInfo.MusicName);
1451 gMapInfo.Name := '';
1452 gMapInfo.Description := '';
1453 gMapInfo.MusicName := '';
1454 gMapInfo.Height := 0;
1455 gMapInfo.Width := 0;
1457 gDoorMap := nil;
1458 gLiftMap := nil;
1459 end;
1461 procedure g_Map_Update();
1462 var
1463 a, d, j: Integer;
1464 m: Word;
1465 s: String;
1467 procedure UpdatePanelArray(var panels: TPanelArray);
1468 var
1469 i: Integer;
1471 begin
1472 if panels <> nil then
1473 for i := 0 to High(panels) do
1474 panels[i].Update();
1475 end;
1477 begin
1478 UpdatePanelArray(gWalls);
1479 UpdatePanelArray(gRenderBackgrounds);
1480 UpdatePanelArray(gRenderForegrounds);
1481 UpdatePanelArray(gWater);
1482 UpdatePanelArray(gAcid1);
1483 UpdatePanelArray(gAcid2);
1484 UpdatePanelArray(gSteps);
1486 if gGameSettings.GameMode = GM_CTF then
1487 begin
1488 for a := FLAG_RED to FLAG_BLUE do
1489 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1490 with gFlags[a] do
1491 begin
1492 if gFlags[a].Animation <> nil then
1493 gFlags[a].Animation.Update();
1495 m := g_Obj_Move(@Obj, True, True);
1497 if gTime mod (GAME_TICK*2) <> 0 then
1498 Continue;
1500 // Ñîïðîòèâëåíèå âîçäóõà:
1501 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1503 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1504 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1505 begin
1506 g_Map_ResetFlag(a);
1507 gFlags[a].CaptureTime := 0;
1508 if a = FLAG_RED then
1509 s := _lc[I_PLAYER_FLAG_RED]
1510 else
1511 s := _lc[I_PLAYER_FLAG_BLUE];
1512 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1514 if g_Game_IsNet then
1515 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1516 Continue;
1517 end;
1519 if Count > 0 then
1520 Count := Count - 1;
1522 // Èãðîê áåðåò ôëàã:
1523 if gPlayers <> nil then
1524 begin
1525 j := Random(Length(gPlayers)) - 1;
1527 for d := 0 to High(gPlayers) do
1528 begin
1529 Inc(j);
1530 if j > High(gPlayers) then
1531 j := 0;
1533 if gPlayers[j] <> nil then
1534 if gPlayers[j].Live and
1535 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1536 begin
1537 if gPlayers[j].GetFlag(a) then
1538 Break;
1539 end;
1540 end;
1541 end;
1542 end;
1543 end;
1544 end;
1546 procedure g_Map_DrawPanels(PanelType: Word);
1548 procedure DrawPanels(var panels: TPanelArray;
1549 drawDoors: Boolean = False);
1550 var
1551 a: Integer;
1553 begin
1554 if panels <> nil then
1555 for a := 0 to High(panels) do
1556 if not (drawDoors xor panels[a].Door) then
1557 panels[a].Draw();
1558 end;
1560 begin
1561 case PanelType of
1562 PANEL_WALL: DrawPanels(gWalls);
1563 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1564 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1565 PANEL_FORE: DrawPanels(gRenderForegrounds);
1566 PANEL_WATER: DrawPanels(gWater);
1567 PANEL_ACID1: DrawPanels(gAcid1);
1568 PANEL_ACID2: DrawPanels(gAcid2);
1569 PANEL_STEP: DrawPanels(gSteps);
1570 end;
1571 end;
1573 procedure g_Map_DrawBack(dx, dy: Integer);
1574 begin
1575 if gDrawBackGround and (BackID <> DWORD(-1)) then
1576 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1577 else
1578 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1579 end;
1581 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1582 PanelType: Word; b1x3: Boolean): Boolean;
1583 var
1584 a, h: Integer;
1585 begin
1586 Result := False;
1588 if WordBool(PanelType and PANEL_WALL) then
1589 if gWalls <> nil then
1590 begin
1591 h := High(gWalls);
1593 for a := 0 to h do
1594 if gWalls[a].Enabled and
1595 g_Collide(X, Y, Width, Height,
1596 gWalls[a].X, gWalls[a].Y,
1597 gWalls[a].Width, gWalls[a].Height) then
1598 begin
1599 Result := True;
1600 Exit;
1601 end;
1602 end;
1604 if WordBool(PanelType and PANEL_WATER) then
1605 if gWater <> nil then
1606 begin
1607 h := High(gWater);
1609 for a := 0 to h do
1610 if g_Collide(X, Y, Width, Height,
1611 gWater[a].X, gWater[a].Y,
1612 gWater[a].Width, gWater[a].Height) then
1613 begin
1614 Result := True;
1615 Exit;
1616 end;
1617 end;
1619 if WordBool(PanelType and PANEL_ACID1) then
1620 if gAcid1 <> nil then
1621 begin
1622 h := High(gAcid1);
1624 for a := 0 to h do
1625 if g_Collide(X, Y, Width, Height,
1626 gAcid1[a].X, gAcid1[a].Y,
1627 gAcid1[a].Width, gAcid1[a].Height) then
1628 begin
1629 Result := True;
1630 Exit;
1631 end;
1632 end;
1634 if WordBool(PanelType and PANEL_ACID2) then
1635 if gAcid2 <> nil then
1636 begin
1637 h := High(gAcid2);
1639 for a := 0 to h do
1640 if g_Collide(X, Y, Width, Height,
1641 gAcid2[a].X, gAcid2[a].Y,
1642 gAcid2[a].Width, gAcid2[a].Height) then
1643 begin
1644 Result := True;
1645 Exit;
1646 end;
1647 end;
1649 if WordBool(PanelType and PANEL_STEP) then
1650 if gSteps <> nil then
1651 begin
1652 h := High(gSteps);
1654 for a := 0 to h do
1655 if g_Collide(X, Y, Width, Height,
1656 gSteps[a].X, gSteps[a].Y,
1657 gSteps[a].Width, gSteps[a].Height) then
1658 begin
1659 Result := True;
1660 Exit;
1661 end;
1662 end;
1664 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1665 if gLifts <> nil then
1666 begin
1667 h := High(gLifts);
1669 for a := 0 to h do
1670 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1671 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1672 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1673 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1674 g_Collide(X, Y, Width, Height,
1675 gLifts[a].X, gLifts[a].Y,
1676 gLifts[a].Width, gLifts[a].Height) then
1677 begin
1678 Result := True;
1679 Exit;
1680 end;
1681 end;
1683 if WordBool(PanelType and PANEL_BLOCKMON) then
1684 if gBlockMon <> nil then
1685 begin
1686 h := High(gBlockMon);
1688 for a := 0 to h do
1689 if ( (not b1x3) or
1690 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1691 g_Collide(X, Y, Width, Height,
1692 gBlockMon[a].X, gBlockMon[a].Y,
1693 gBlockMon[a].Width, gBlockMon[a].Height) then
1694 begin
1695 Result := True;
1696 Exit;
1697 end;
1698 end;
1699 end;
1701 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1702 var
1703 a, h: Integer;
1704 begin
1705 Result := TEXTURE_NONE;
1707 if gWater <> nil then
1708 begin
1709 h := High(gWater);
1711 for a := 0 to h do
1712 if g_Collide(X, Y, Width, Height,
1713 gWater[a].X, gWater[a].Y,
1714 gWater[a].Width, gWater[a].Height) then
1715 begin
1716 Result := gWater[a].GetTextureID();
1717 Exit;
1718 end;
1719 end;
1721 if gAcid1 <> nil then
1722 begin
1723 h := High(gAcid1);
1725 for a := 0 to h do
1726 if g_Collide(X, Y, Width, Height,
1727 gAcid1[a].X, gAcid1[a].Y,
1728 gAcid1[a].Width, gAcid1[a].Height) then
1729 begin
1730 Result := gAcid1[a].GetTextureID();
1731 Exit;
1732 end;
1733 end;
1735 if gAcid2 <> nil then
1736 begin
1737 h := High(gAcid2);
1739 for a := 0 to h do
1740 if g_Collide(X, Y, Width, Height,
1741 gAcid2[a].X, gAcid2[a].Y,
1742 gAcid2[a].Width, gAcid2[a].Height) then
1743 begin
1744 Result := gAcid2[a].GetTextureID();
1745 Exit;
1746 end;
1747 end;
1748 end;
1750 procedure g_Map_EnableWall(ID: DWORD);
1751 begin
1752 with gWalls[ID] do
1753 begin
1754 Enabled := True;
1755 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1757 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1758 end;
1759 end;
1761 procedure g_Map_DisableWall(ID: DWORD);
1762 begin
1763 with gWalls[ID] do
1764 begin
1765 Enabled := False;
1766 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1768 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1769 end;
1770 end;
1772 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1773 var
1774 tp: TPanel;
1775 begin
1776 case PanelType of
1777 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1778 tp := gWalls[ID];
1779 PANEL_FORE:
1780 tp := gRenderForegrounds[ID];
1781 PANEL_BACK:
1782 tp := gRenderBackgrounds[ID];
1783 PANEL_WATER:
1784 tp := gWater[ID];
1785 PANEL_ACID1:
1786 tp := gAcid1[ID];
1787 PANEL_ACID2:
1788 tp := gAcid2[ID];
1789 PANEL_STEP:
1790 tp := gSteps[ID];
1791 else
1792 Exit;
1793 end;
1795 tp.NextTexture(AnimLoop);
1796 if g_Game_IsServer and g_Game_IsNet then
1797 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1798 end;
1800 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1801 begin
1802 if gLifts[ID].LiftType = t then
1803 Exit;
1805 with gLifts[ID] do
1806 begin
1807 LiftType := t;
1809 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1811 if LiftType = 0 then
1812 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1813 else if LiftType = 1 then
1814 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1815 else if LiftType = 2 then
1816 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1817 else if LiftType = 3 then
1818 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1820 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1821 end;
1822 end;
1824 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1825 var
1826 a: Integer;
1827 PointsArray: Array of TRespawnPoint;
1828 begin
1829 Result := False;
1830 SetLength(PointsArray, 0);
1832 if RespawnPoints = nil then
1833 Exit;
1835 for a := 0 to High(RespawnPoints) do
1836 if RespawnPoints[a].PointType = PointType then
1837 begin
1838 SetLength(PointsArray, Length(PointsArray)+1);
1839 PointsArray[High(PointsArray)] := RespawnPoints[a];
1840 end;
1842 if PointsArray = nil then
1843 Exit;
1845 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1846 Result := True;
1847 end;
1849 function g_Map_GetPointCount(PointType: Byte): Word;
1850 var
1851 a: Integer;
1852 begin
1853 Result := 0;
1855 if RespawnPoints = nil then
1856 Exit;
1858 for a := 0 to High(RespawnPoints) do
1859 if RespawnPoints[a].PointType = PointType then
1860 Result := Result + 1;
1861 end;
1863 function g_Map_HaveFlagPoints(): Boolean;
1864 begin
1865 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1866 end;
1868 procedure g_Map_ResetFlag(Flag: Byte);
1869 begin
1870 with gFlags[Flag] do
1871 begin
1872 Obj.X := -1000;
1873 Obj.Y := -1000;
1874 Obj.Vel.X := 0;
1875 Obj.Vel.Y := 0;
1876 Direction := D_LEFT;
1877 State := FLAG_STATE_NONE;
1878 if FlagPoints[Flag] <> nil then
1879 begin
1880 Obj.X := FlagPoints[Flag]^.X;
1881 Obj.Y := FlagPoints[Flag]^.Y;
1882 Direction := FlagPoints[Flag]^.Direction;
1883 State := FLAG_STATE_NORMAL;
1884 end;
1885 Count := -1;
1886 end;
1887 end;
1889 procedure g_Map_DrawFlags();
1890 var
1891 i, dx: Integer;
1892 Mirror: TMirrorType;
1893 begin
1894 if gGameSettings.GameMode <> GM_CTF then
1895 Exit;
1897 for i := FLAG_RED to FLAG_BLUE do
1898 with gFlags[i] do
1899 if State <> FLAG_STATE_CAPTURED then
1900 begin
1901 if State = FLAG_STATE_NONE then
1902 continue;
1904 if Direction = D_LEFT then
1905 begin
1906 Mirror := M_HORIZONTAL;
1907 dx := -1;
1908 end
1909 else
1910 begin
1911 Mirror := M_NONE;
1912 dx := 1;
1913 end;
1915 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
1917 if g_debug_Frames then
1918 begin
1919 e_DrawQuad(Obj.X+Obj.Rect.X,
1920 Obj.Y+Obj.Rect.Y,
1921 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
1922 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
1923 0, 255, 0);
1924 end;
1925 end;
1926 end;
1928 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
1929 var
1930 dw: DWORD;
1931 b: Byte;
1932 str: String;
1933 boo: Boolean;
1935 procedure SavePanelArray(var panels: TPanelArray);
1936 var
1937 PAMem: TBinMemoryWriter;
1938 i: Integer;
1939 begin
1940 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
1941 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
1943 i := 0;
1944 while i < Length(panels) do
1945 begin
1946 if panels[i].SaveIt then
1947 begin
1948 // ID ïàíåëè:
1949 PAMem.WriteInt(i);
1950 // Ñîõðàíÿåì ïàíåëü:
1951 panels[i].SaveState(PAMem);
1952 end;
1953 Inc(i);
1954 end;
1956 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
1957 PAMem.SaveToMemory(Mem);
1958 PAMem.Free();
1959 end;
1961 procedure SaveFlag(flag: PFlag);
1962 begin
1963 // Ñèãíàòóðà ôëàãà:
1964 dw := FLAG_SIGNATURE; // 'FLAG'
1965 Mem.WriteDWORD(dw);
1966 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
1967 Mem.WriteByte(flag^.RespawnType);
1968 // Ñîñòîÿíèå ôëàãà:
1969 Mem.WriteByte(flag^.State);
1970 // Íàïðàâëåíèå ôëàãà:
1971 if flag^.Direction = D_LEFT then
1972 b := 1
1973 else // D_RIGHT
1974 b := 2;
1975 Mem.WriteByte(b);
1976 // Îáúåêò ôëàãà:
1977 Obj_SaveState(@flag^.Obj, Mem);
1978 end;
1980 begin
1981 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
1983 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
1984 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
1985 SavePanelArray(gWalls);
1986 // Ñîõðàíÿåì ïàíåëè ôîíà:
1987 SavePanelArray(gRenderBackgrounds);
1988 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
1989 SavePanelArray(gRenderForegrounds);
1990 // Ñîõðàíÿåì ïàíåëè âîäû:
1991 SavePanelArray(gWater);
1992 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
1993 SavePanelArray(gAcid1);
1994 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
1995 SavePanelArray(gAcid2);
1996 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
1997 SavePanelArray(gSteps);
1998 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
1999 SavePanelArray(gLifts);
2000 ///// /////
2002 ///// Ñîõðàíÿåì ìóçûêó: /////
2003 // Ñèãíàòóðà ìóçûêè:
2004 dw := MUSIC_SIGNATURE; // 'MUSI'
2005 Mem.WriteDWORD(dw);
2006 // Íàçâàíèå ìóçûêè:
2007 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2008 if gMusic.NoMusic then
2009 str := ''
2010 else
2011 str := gMusic.Name;
2012 Mem.WriteString(str, 64);
2013 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2014 dw := gMusic.GetPosition();
2015 Mem.WriteDWORD(dw);
2016 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2017 boo := gMusic.SpecPause;
2018 Mem.WriteBoolean(boo);
2019 ///// /////
2021 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2022 Mem.WriteInt(gTotalMonsters);
2023 ///// /////
2025 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2026 if gGameSettings.GameMode = GM_CTF then
2027 begin
2028 // Ôëàã Êðàñíîé êîìàíäû:
2029 SaveFlag(@gFlags[FLAG_RED]);
2030 // Ôëàã Ñèíåé êîìàíäû:
2031 SaveFlag(@gFlags[FLAG_BLUE]);
2032 end;
2033 ///// /////
2035 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2036 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2037 begin
2038 // Î÷êè Êðàñíîé êîìàíäû:
2039 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2040 // Î÷êè Ñèíåé êîìàíäû:
2041 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2042 end;
2043 ///// /////
2044 end;
2046 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2047 var
2048 dw: DWORD;
2049 b: Byte;
2050 str: String;
2051 boo: Boolean;
2053 procedure LoadPanelArray(var panels: TPanelArray);
2054 var
2055 PAMem: TBinMemoryReader;
2056 i, id: Integer;
2057 begin
2058 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2059 PAMem := TBinMemoryReader.Create();
2060 PAMem.LoadFromMemory(Mem);
2062 for i := 0 to Length(panels)-1 do
2063 if panels[i].SaveIt then
2064 begin
2065 // ID ïàíåëè:
2066 PAMem.ReadInt(id);
2067 if id <> i then
2068 begin
2069 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2070 end;
2071 // Çàãðóæàåì ïàíåëü:
2072 panels[i].LoadState(PAMem);
2073 end;
2075 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2076 PAMem.Free();
2077 end;
2079 procedure LoadFlag(flag: PFlag);
2080 begin
2081 // Ñèãíàòóðà ôëàãà:
2082 Mem.ReadDWORD(dw);
2083 if dw <> FLAG_SIGNATURE then // 'FLAG'
2084 begin
2085 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2086 end;
2087 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2088 Mem.ReadByte(flag^.RespawnType);
2089 // Ñîñòîÿíèå ôëàãà:
2090 Mem.ReadByte(flag^.State);
2091 // Íàïðàâëåíèå ôëàãà:
2092 Mem.ReadByte(b);
2093 if b = 1 then
2094 flag^.Direction := D_LEFT
2095 else // b = 2
2096 flag^.Direction := D_RIGHT;
2097 // Îáúåêò ôëàãà:
2098 Obj_LoadState(@flag^.Obj, Mem);
2099 end;
2101 begin
2102 if Mem = nil then
2103 Exit;
2105 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2106 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2107 LoadPanelArray(gWalls);
2108 // Çàãðóæàåì ïàíåëè ôîíà:
2109 LoadPanelArray(gRenderBackgrounds);
2110 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2111 LoadPanelArray(gRenderForegrounds);
2112 // Çàãðóæàåì ïàíåëè âîäû:
2113 LoadPanelArray(gWater);
2114 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2115 LoadPanelArray(gAcid1);
2116 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2117 LoadPanelArray(gAcid2);
2118 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2119 LoadPanelArray(gSteps);
2120 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2121 LoadPanelArray(gLifts);
2122 ///// /////
2124 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2125 g_GFX_Init();
2127 ///// Çàãðóæàåì ìóçûêó: /////
2128 // Ñèãíàòóðà ìóçûêè:
2129 Mem.ReadDWORD(dw);
2130 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2131 begin
2132 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2133 end;
2134 // Íàçâàíèå ìóçûêè:
2135 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2136 Mem.ReadString(str);
2137 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2138 Mem.ReadDWORD(dw);
2139 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2140 Mem.ReadBoolean(boo);
2141 // Çàïóñêàåì ýòó ìóçûêó:
2142 gMusic.SetByName(str);
2143 gMusic.SpecPause := boo;
2144 gMusic.Play();
2145 gMusic.Pause(True);
2146 gMusic.SetPosition(dw);
2147 ///// /////
2149 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2150 Mem.ReadInt(gTotalMonsters);
2151 ///// /////
2153 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2154 if gGameSettings.GameMode = GM_CTF then
2155 begin
2156 // Ôëàã Êðàñíîé êîìàíäû:
2157 LoadFlag(@gFlags[FLAG_RED]);
2158 // Ôëàã Ñèíåé êîìàíäû:
2159 LoadFlag(@gFlags[FLAG_BLUE]);
2160 end;
2161 ///// /////
2163 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2164 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2165 begin
2166 // Î÷êè Êðàñíîé êîìàíäû:
2167 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2168 // Î÷êè Ñèíåé êîìàíäû:
2169 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2170 end;
2171 ///// /////
2172 end;
2174 end.