DEADSOFTWARE

proper (i hope) support for '.wad', '.pk3' and '.zip' extensions
[d2df-sdl.git] / src / game / g_map.pas
1 unit g_map;
3 interface
5 uses
6 e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
7 g_phys, WADEDITOR, BinEditor, g_panel, md5;
9 type
10 TMapInfo = record
11 Map: String;
12 Name: String;
13 Description: String;
14 Author: String;
15 MusicName: String;
16 SkyName: String;
17 Height: Word;
18 Width: Word;
19 end;
21 PRespawnPoint = ^TRespawnPoint;
22 TRespawnPoint = record
23 X, Y: Integer;
24 Direction: TDirection;
25 PointType: Byte;
26 end;
28 PFlagPoint = ^TFlagPoint;
29 TFlagPoint = TRespawnPoint;
31 PFlag = ^TFlag;
32 TFlag = record
33 Obj: TObj;
34 RespawnType: Byte;
35 State: Byte;
36 Count: Integer;
37 CaptureTime: LongWord;
38 Animation: TAnimation;
39 Direction: TDirection;
40 end;
43 function g_Map_Load(Res: String): Boolean;
44 function g_Map_GetMapInfo(Res: String): TMapInfo;
45 function g_Map_GetMapsList(WADName: String): SArray;
46 function g_Map_Exist(Res: String): Boolean;
47 procedure g_Map_Free();
48 procedure g_Map_Update();
49 procedure g_Map_DrawPanels(PanelType: Word);
50 procedure g_Map_DrawBack(dx, dy: Integer);
51 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
52 PanelType: Word; b1x3: Boolean): Boolean;
53 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
54 procedure g_Map_EnableWall(ID: DWORD);
55 procedure g_Map_DisableWall(ID: DWORD);
56 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
57 procedure g_Map_SetLift(ID: DWORD; t: Integer);
58 procedure g_Map_ReAdd_DieTriggers();
59 function g_Map_IsSpecialTexture(Texture: String): Boolean;
61 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
62 function g_Map_GetPointCount(PointType: Byte): Word;
64 function g_Map_HaveFlagPoints(): Boolean;
66 procedure g_Map_ResetFlag(Flag: Byte);
67 procedure g_Map_DrawFlags();
69 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
70 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
72 const
73 RESPAWNPOINT_PLAYER1 = 1;
74 RESPAWNPOINT_PLAYER2 = 2;
75 RESPAWNPOINT_DM = 3;
76 RESPAWNPOINT_RED = 4;
77 RESPAWNPOINT_BLUE = 5;
79 FLAG_NONE = 0;
80 FLAG_RED = 1;
81 FLAG_BLUE = 2;
82 FLAG_DOM = 3;
84 FLAG_STATE_NONE = 0;
85 FLAG_STATE_NORMAL = 1;
86 FLAG_STATE_DROPPED = 2;
87 FLAG_STATE_CAPTURED = 3;
88 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
89 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
91 FLAG_TIME = 720; // 20 seconds
93 SKY_STRETCH: Single = 1.5;
95 var
96 gWalls: TPanelArray;
97 gRenderBackgrounds: TPanelArray;
98 gRenderForegrounds: TPanelArray;
99 gWater, gAcid1, gAcid2: TPanelArray;
100 gSteps: TPanelArray;
101 gLifts: TPanelArray;
102 gBlockMon: TPanelArray;
103 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
104 //gDOMFlags: array of TFlag;
105 gMapInfo: TMapInfo;
106 gBackSize: TPoint;
107 gDoorMap: array of array of DWORD;
108 gLiftMap: array of array of DWORD;
109 gWADHash: TMD5Digest;
110 BackID: DWORD = DWORD(-1);
111 gExternalResources: TStringList;
113 implementation
115 uses
116 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
117 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
118 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
119 Math, g_monsters, g_saveload, g_language, g_netmsg,
120 utils;
122 const
123 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
124 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
125 FLAG_SIGNATURE = $47414C46; // 'FLAG'
127 var
128 Textures: TLevelTextureArray;
129 RespawnPoints: Array of TRespawnPoint;
130 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
131 //DOMFlagPoints: Array of TFlagPoint;
134 function g_Map_IsSpecialTexture(Texture: String): Boolean;
135 begin
136 Result := (Texture = TEXTURE_NAME_WATER) or
137 (Texture = TEXTURE_NAME_ACID1) or
138 (Texture = TEXTURE_NAME_ACID2);
139 end;
141 procedure CreateDoorMap();
142 var
143 PanelArray: Array of record
144 X, Y: Integer;
145 Width, Height: Word;
146 Active: Boolean;
147 PanelID: DWORD;
148 end;
149 a, b, c, m, i, len: Integer;
150 ok: Boolean;
151 begin
152 if gWalls = nil then
153 Exit;
155 i := 0;
156 len := 128;
157 SetLength(PanelArray, len);
159 for a := 0 to High(gWalls) do
160 if gWalls[a].Door then
161 begin
162 PanelArray[i].X := gWalls[a].X;
163 PanelArray[i].Y := gWalls[a].Y;
164 PanelArray[i].Width := gWalls[a].Width;
165 PanelArray[i].Height := gWalls[a].Height;
166 PanelArray[i].Active := True;
167 PanelArray[i].PanelID := a;
169 i := i + 1;
170 if i = len then
171 begin
172 len := len + 128;
173 SetLength(PanelArray, len);
174 end;
175 end;
177 // Íåò äâåðåé:
178 if i = 0 then
179 begin
180 PanelArray := nil;
181 Exit;
182 end;
184 SetLength(gDoorMap, 0);
186 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
188 for a := 0 to i-1 do
189 if PanelArray[a].Active then
190 begin
191 PanelArray[a].Active := False;
192 m := Length(gDoorMap);
193 SetLength(gDoorMap, m+1);
194 SetLength(gDoorMap[m], 1);
195 gDoorMap[m, 0] := PanelArray[a].PanelID;
196 ok := True;
198 while ok do
199 begin
200 ok := False;
202 for b := 0 to i-1 do
203 if PanelArray[b].Active then
204 for c := 0 to High(gDoorMap[m]) do
205 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
206 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
207 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
208 PanelArray[b].Width, PanelArray[b].Height,
209 gWalls[gDoorMap[m, c]].X,
210 gWalls[gDoorMap[m, c]].Y,
211 gWalls[gDoorMap[m, c]].Width,
212 gWalls[gDoorMap[m, c]].Height) then
213 begin
214 PanelArray[b].Active := False;
215 SetLength(gDoorMap[m],
216 Length(gDoorMap[m])+1);
217 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
218 ok := True;
219 Break;
220 end;
221 end;
223 g_Game_StepLoading();
224 end;
226 PanelArray := nil;
227 end;
229 procedure CreateLiftMap();
230 var
231 PanelArray: Array of record
232 X, Y: Integer;
233 Width, Height: Word;
234 Active: Boolean;
235 end;
236 a, b, c, len, i, j: Integer;
237 ok: Boolean;
238 begin
239 if gLifts = nil then
240 Exit;
242 len := Length(gLifts);
243 SetLength(PanelArray, len);
245 for a := 0 to len-1 do
246 begin
247 PanelArray[a].X := gLifts[a].X;
248 PanelArray[a].Y := gLifts[a].Y;
249 PanelArray[a].Width := gLifts[a].Width;
250 PanelArray[a].Height := gLifts[a].Height;
251 PanelArray[a].Active := True;
252 end;
254 SetLength(gLiftMap, len);
255 i := 0;
257 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
259 for a := 0 to len-1 do
260 if PanelArray[a].Active then
261 begin
262 PanelArray[a].Active := False;
263 SetLength(gLiftMap[i], 32);
264 j := 0;
265 gLiftMap[i, j] := a;
266 ok := True;
268 while ok do
269 begin
270 ok := False;
271 for b := 0 to len-1 do
272 if PanelArray[b].Active then
273 for c := 0 to j do
274 if g_CollideAround(PanelArray[b].X,
275 PanelArray[b].Y,
276 PanelArray[b].Width,
277 PanelArray[b].Height,
278 PanelArray[gLiftMap[i, c]].X,
279 PanelArray[gLiftMap[i, c]].Y,
280 PanelArray[gLiftMap[i, c]].Width,
281 PanelArray[gLiftMap[i, c]].Height) then
282 begin
283 PanelArray[b].Active := False;
284 j := j+1;
285 if j > High(gLiftMap[i]) then
286 SetLength(gLiftMap[i],
287 Length(gLiftMap[i])+32);
289 gLiftMap[i, j] := b;
290 ok := True;
292 Break;
293 end;
294 end;
296 SetLength(gLiftMap[i], j+1);
297 i := i+1;
299 g_Game_StepLoading();
300 end;
302 SetLength(gLiftMap, i);
304 PanelArray := nil;
305 end;
307 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
308 CurTex: Integer; sav: Boolean): Integer;
309 var
310 len: Integer;
311 panels: ^TPanelArray;
312 begin
313 Result := -1;
315 case PanelRec.PanelType of
316 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
317 panels := @gWalls;
318 PANEL_BACK:
319 panels := @gRenderBackgrounds;
320 PANEL_FORE:
321 panels := @gRenderForegrounds;
322 PANEL_WATER:
323 panels := @gWater;
324 PANEL_ACID1:
325 panels := @gAcid1;
326 PANEL_ACID2:
327 panels := @gAcid2;
328 PANEL_STEP:
329 panels := @gSteps;
330 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
331 panels := @gLifts;
332 PANEL_BLOCKMON:
333 panels := @gBlockMon;
334 else
335 Exit;
336 end;
338 len := Length(panels^);
339 SetLength(panels^, len + 1);
341 panels^[len] := TPanel.Create(PanelRec, AddTextures,
342 CurTex, Textures);
343 if sav then
344 panels^[len].SaveIt := True;
346 Result := len;
347 end;
349 procedure CreateNullTexture(RecName: String);
350 begin
351 SetLength(Textures, Length(Textures)+1);
353 with Textures[High(Textures)] do
354 begin
355 TextureName := RecName;
356 Width := 1;
357 Height := 1;
358 Anim := False;
359 TextureID := TEXTURE_NONE;
360 end;
361 end;
363 function CreateTexture(RecName: String; Map: string; log: Boolean): Boolean;
364 var
365 WAD: TWADEditor_1;
366 TextureData: Pointer;
367 WADName: String;
368 SectionName: String;
369 TextureName: String;
370 a, ResLength: Integer;
371 begin
372 Result := False;
374 if Textures <> nil then
375 for a := 0 to High(Textures) do
376 if Textures[a].TextureName = RecName then
377 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
378 Result := True;
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 := True;
406 Exit;
407 end;
409 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
410 g_ProcessResourceStr(RecName, WADName, SectionName, TextureName);
412 WAD := TWADEditor_1.Create();
414 if WADName <> '' then
415 WADName := GameDir+'/wads/'+WADName
416 else
417 WADName := Map;
419 WAD.ReadFile(WADName);
421 if WAD.GetResource(SectionName, TextureName, TextureData, ResLength) then
422 begin
423 SetLength(Textures, Length(Textures)+1);
424 if not e_CreateTextureMem(TextureData, 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 := True;
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): Boolean;
446 var
447 WAD: TWADEditor_1;
448 TextureWAD: Pointer;
449 TextData: Pointer;
450 TextureData: Pointer;
451 cfg: TConfig;
452 WADName: String;
453 SectionName: String;
454 TextureName: String;
455 ResLength: Integer;
456 TextureResource: String;
457 _width, _height, _framecount, _speed: Integer;
458 _backanimation: Boolean;
459 begin
460 Result := False;
462 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
463 g_ProcessResourceStr(RecName, WADName, SectionName, TextureName);
465 WAD := TWADEditor_1.Create();
467 if WADName <> '' then
468 WADName := GameDir+'/wads/'+WADName
469 else
470 WADName := Map;
472 WAD.ReadFile(WADName);
474 if not WAD.GetResource(SectionName, TextureName, TextureWAD, ResLength) then
475 begin
476 if log then
477 begin
478 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
479 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
480 end;
481 WAD.Free();
482 Exit;
483 end;
485 WAD.FreeWAD();
487 if not WAD.ReadMemory(TextureWAD, ResLength) then
488 begin
489 FreeMem(TextureWAD);
490 WAD.Free();
491 Exit;
492 end;
494 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
495 if not WAD.GetResource('TEXT', 'ANIM', TextData, ResLength) then
496 begin
497 FreeMem(TextureWAD);
498 WAD.Free();
499 Exit;
500 end;
502 cfg := TConfig.CreateMem(TextData, ResLength);
504 TextureResource := cfg.ReadStr('', 'resource', '');
506 if TextureResource = '' then
507 begin
508 FreeMem(TextureWAD);
509 FreeMem(TextData);
510 WAD.Free();
511 cfg.Free();
512 Exit;
513 end;
515 _width := cfg.ReadInt('', 'framewidth', 0);
516 _height := cfg.ReadInt('', 'frameheight', 0);
517 _framecount := cfg.ReadInt('', 'framecount', 0);
518 _speed := cfg.ReadInt('', 'waitcount', 0);
519 _backanimation := cfg.ReadBool('', 'backanimation', False);
521 cfg.Free();
523 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
524 if not WAD.GetResource('TEXTURES', TextureResource, TextureData, ResLength) then
525 begin
526 FreeMem(TextureWAD);
527 FreeMem(TextData);
528 WAD.Free();
529 Exit;
530 end;
532 WAD.Free();
534 SetLength(Textures, Length(Textures)+1);
535 with Textures[High(Textures)] do
536 begin
537 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
538 if g_Frames_CreateMemory(@FramesID, '', TextureData,
539 _width, _height, _framecount, _backanimation) then
540 begin
541 TextureName := RecName;
542 Width := _width;
543 Height := _height;
544 Anim := True;
545 FramesCount := _framecount;
546 Speed := _speed;
548 Result := True;
549 end
550 else
551 if log then
552 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
553 end;
555 FreeMem(TextureWAD);
556 FreeMem(TextData);
557 end;
559 procedure CreateItem(Item: TItemRec_1);
560 begin
561 if g_Game_IsClient then Exit;
563 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
564 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
565 Exit;
567 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
568 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
569 end;
571 procedure CreateArea(Area: TAreaRec_1);
572 var
573 a: Integer;
574 id: DWORD;
575 begin
576 case Area.AreaType of
577 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
578 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
579 begin
580 SetLength(RespawnPoints, Length(RespawnPoints)+1);
581 with RespawnPoints[High(RespawnPoints)] do
582 begin
583 X := Area.X;
584 Y := Area.Y;
585 Direction := TDirection(Area.Direction);
587 case Area.AreaType of
588 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
589 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
590 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
591 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
592 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
593 end;
594 end;
595 end;
597 AREA_REDFLAG, AREA_BLUEFLAG:
598 begin
599 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
601 if FlagPoints[a] <> nil then Exit;
603 New(FlagPoints[a]);
605 with FlagPoints[a]^ do
606 begin
607 X := Area.X-FLAGRECT.X;
608 Y := Area.Y-FLAGRECT.Y;
609 Direction := TDirection(Area.Direction);
610 end;
612 with gFlags[a] do
613 begin
614 case a of
615 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
616 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
617 end;
619 Animation := TAnimation.Create(id, True, 8);
620 Obj.Rect := FLAGRECT;
622 g_Map_ResetFlag(a);
623 end;
624 end;
626 AREA_DOMFLAG:
627 begin
628 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
629 with DOMFlagPoints[High(DOMFlagPoints)] do
630 begin
631 X := Area.X;
632 Y := Area.Y;
633 Direction := TDirection(Area.Direction);
634 end;
636 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
637 end;
638 end;
639 end;
641 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
642 var
643 _trigger: TTrigger;
644 begin
645 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
647 with _trigger do
648 begin
649 X := Trigger.X;
650 Y := Trigger.Y;
651 Width := Trigger.Width;
652 Height := Trigger.Height;
653 Enabled := ByteBool(Trigger.Enabled);
654 TexturePanel := Trigger.TexturePanel;
655 TexturePanelType := fTexturePanel1Type;
656 ShotPanelType := fTexturePanel2Type;
657 TriggerType := Trigger.TriggerType;
658 ActivateType := Trigger.ActivateType;
659 Keys := Trigger.Keys;
660 Data.Default := Trigger.DATA;
661 end;
663 g_Triggers_Create(_trigger);
664 end;
666 procedure CreateMonster(monster: TMonsterRec_1);
667 var
668 a, i: Integer;
669 begin
670 if g_Game_IsClient then Exit;
672 if (gGameSettings.GameType = GT_SINGLE)
673 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
674 begin
675 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
676 TDirection(monster.Direction));
678 if gTriggers <> nil then
679 for a := 0 to High(gTriggers) do
680 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
681 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
682 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
683 gMonsters[i].AddTrigger(a);
685 if monster.MonsterType <> MONSTER_BARREL then
686 Inc(gTotalMonsters);
687 end;
688 end;
690 procedure g_Map_ReAdd_DieTriggers();
691 var
692 i, a: Integer;
693 begin
694 if g_Game_IsClient then Exit;
696 for i := 0 to High(gMonsters) do
697 if gMonsters[i] <> nil then
698 begin
699 gMonsters[i].ClearTriggers();
701 for a := 0 to High(gTriggers) do
702 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
703 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
704 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
705 gMonsters[i].AddTrigger(a);
706 end;
707 end;
709 function extractWadName(resourceName: string): string;
710 var
711 posN: Integer;
712 begin
713 posN := Pos(':', resourceName);
714 if posN > 0 then
715 Result:= Copy(resourceName, 0, posN-1)
716 else
717 Result := '';
718 end;
720 procedure addResToExternalResList(res: string);
721 begin
722 res := extractWadName(res);
723 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
724 gExternalResources.Add(res);
725 end;
727 procedure generateExternalResourcesList(mapReader: TMapReader_1);
728 var
729 textures: TTexturesRec1Array;
730 mapHeader: TMapHeaderRec_1;
731 i: integer;
732 resFile: String = '';
733 begin
734 if gExternalResources = nil then
735 gExternalResources := TStringList.Create;
737 gExternalResources.Clear;
738 textures := mapReader.GetTextures();
739 for i := 0 to High(textures) do
740 begin
741 addResToExternalResList(resFile);
742 end;
744 textures := nil;
746 mapHeader := mapReader.GetMapHeader;
748 addResToExternalResList(mapHeader.MusicName);
749 addResToExternalResList(mapHeader.SkyName);
750 end;
752 function g_Map_Load(Res: String): Boolean;
753 const
754 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
755 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
756 var
757 WAD: TWADEditor_1;
758 MapReader: TMapReader_1;
759 Header: TMapHeaderRec_1;
760 _textures: TTexturesRec1Array;
761 panels: TPanelsRec1Array;
762 items: TItemsRec1Array;
763 monsters: TMonsterRec1Array;
764 areas: TAreasRec1Array;
765 triggers: TTriggersRec1Array;
766 a, b, c, k: Integer;
767 PanelID: DWORD;
768 AddTextures: TAddTextureArray;
769 texture: TTextureRec_1;
770 TriggersTable: Array of record
771 TexturePanel: Integer;
772 LiftPanel: Integer;
773 DoorPanel: Integer;
774 ShotPanel: Integer;
775 end;
776 FileName, SectionName, ResName,
777 FileName2, s, TexName: String;
778 Data: Pointer;
779 Len: Integer;
780 ok, isAnim, trigRef: Boolean;
781 CurTex: Integer;
782 begin
783 Result := False;
784 gMapInfo.Map := Res;
785 TriggersTable := nil;
786 FillChar(texture, SizeOf(texture), 0);
788 // Çàãðóçêà WAD:
789 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
790 e_WriteLog('Loading map WAD: ' + FileName, MSG_NOTIFY);
791 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
793 WAD := TWADEditor_1.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 if not WAD.GetResource('', ResName, Data, Len) then
801 begin
802 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [ResName]));
803 WAD.Free();
804 Exit;
805 end;
806 WAD.Free();
808 // Çàãðóçêà êàðòû:
809 e_WriteLog('Loading map: ' + ResName, MSG_NOTIFY);
810 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
811 MapReader := TMapReader_1.Create();
813 if not MapReader.LoadMap(Data) then
814 begin
815 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
816 FreeMem(Data);
817 MapReader.Free();
818 Exit;
819 end;
821 FreeMem(Data);
822 generateExternalResourcesList(MapReader);
823 // Çàãðóçêà òåêñòóð:
824 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
825 _textures := MapReader.GetTextures();
827 // Äîáàâëåíèå òåêñòóð â Textures[]:
828 if _textures <> nil then
829 begin
830 e_WriteLog(' Loading textures:', MSG_NOTIFY);
831 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
833 for a := 0 to High(_textures) do
834 begin
835 SetLength(s, 64);
836 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
837 for b := 1 to Length(s) do
838 if s[b] = #0 then
839 begin
840 SetLength(s, b-1);
841 Break;
842 end;
843 e_WriteLog(' Loading texture: ' + s, MSG_NOTIFY);
844 // Àíèìèðîâàííàÿ òåêñòóðà:
845 if ByteBool(_textures[a].Anim) then
846 begin
847 if not CreateAnimTexture(_textures[a].Resource, FileName, True) then
848 begin
849 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
850 CreateNullTexture(_textures[a].Resource);
851 end;
852 end
853 else // Îáû÷íàÿ òåêñòóðà:
854 if not CreateTexture(_textures[a].Resource, FileName, True) then
855 begin
856 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
857 CreateNullTexture(_textures[a].Resource);
858 end;
860 g_Game_StepLoading();
861 end;
862 end;
864 // Çàãðóçêà òðèããåðîâ:
865 gTriggerClientID := 0;
866 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
867 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
868 triggers := MapReader.GetTriggers();
870 // Çàãðóçêà ïàíåëåé:
871 e_WriteLog(' Loading panels...', MSG_NOTIFY);
872 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
873 panels := MapReader.GetPanels();
875 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
876 if triggers <> nil then
877 begin
878 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
879 SetLength(TriggersTable, Length(triggers));
880 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
882 for a := 0 to High(TriggersTable) do
883 begin
884 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
885 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
886 // Ëèôòû:
887 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
888 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
889 else
890 TriggersTable[a].LiftPanel := -1;
891 // Äâåðè:
892 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
893 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
894 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
895 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
896 else
897 TriggersTable[a].DoorPanel := -1;
898 // Òóðåëü:
899 if triggers[a].TriggerType = TRIGGER_SHOT then
900 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
901 else
902 TriggersTable[a].ShotPanel := -1;
904 g_Game_StepLoading();
905 end;
906 end;
908 // Ñîçäàåì ïàíåëè:
909 if panels <> nil then
910 begin
911 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
912 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
914 for a := 0 to High(panels) do
915 begin
916 SetLength(AddTextures, 0);
917 trigRef := False;
918 CurTex := -1;
919 if _textures <> nil then
920 begin
921 texture := _textures[panels[a].TextureNum];
922 ok := True;
923 end
924 else
925 ok := False;
927 if ok then
928 begin
929 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
930 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
931 ok := False;
932 if (TriggersTable <> nil) and (_textures <> nil) then
933 for b := 0 to High(TriggersTable) do
934 if (TriggersTable[b].TexturePanel = a)
935 or (TriggersTable[b].ShotPanel = a) then
936 begin
937 trigRef := True;
938 ok := True;
939 Break;
940 end;
941 end;
943 if ok then
944 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
945 SetLength(s, 64);
946 CopyMemory(@s[1], @texture.Resource[0], 64);
947 // Èçìåðÿåì äëèíó:
948 Len := Length(s);
949 for c := Len downto 1 do
950 if s[c] <> #0 then
951 begin
952 Len := c;
953 Break;
954 end;
955 SetLength(s, Len);
957 // Ñïåö-òåêñòóðû çàïðåùåíû:
958 if g_Map_IsSpecialTexture(s) then
959 ok := False
960 else
961 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
962 ok := g_Texture_NumNameFindStart(s);
964 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
965 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
966 if ok then
967 begin
968 k := NNF_NAME_BEFORE;
969 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
970 while ok or (k = NNF_NAME_BEFORE) or
971 (k = NNF_NAME_EQUALS) do
972 begin
973 k := g_Texture_NumNameFindNext(TexName);
975 if (k = NNF_NAME_BEFORE) or
976 (k = NNF_NAME_AFTER) then
977 begin
978 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
979 if ByteBool(texture.Anim) then
980 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
981 isAnim := True;
982 ok := CreateAnimTexture(TexName, FileName, False);
983 if not ok then
984 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
985 isAnim := False;
986 ok := CreateTexture(TexName, FileName, False);
987 end;
988 end
989 else
990 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
991 isAnim := False;
992 ok := CreateTexture(TexName, FileName, False);
993 if not ok then
994 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
995 isAnim := True;
996 ok := CreateAnimTexture(TexName, FileName, False);
997 end;
998 end;
1000 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1001 if ok then
1002 begin
1003 for c := 0 to High(Textures) do
1004 if Textures[c].TextureName = TexName then
1005 begin
1006 SetLength(AddTextures, Length(AddTextures)+1);
1007 AddTextures[High(AddTextures)].Texture := c;
1008 AddTextures[High(AddTextures)].Anim := isAnim;
1009 Break;
1010 end;
1011 end;
1012 end
1013 else
1014 if k = NNF_NAME_EQUALS then
1015 begin
1016 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1017 SetLength(AddTextures, Length(AddTextures)+1);
1018 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1019 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1020 CurTex := High(AddTextures);
1021 ok := True;
1022 end
1023 else // NNF_NO_NAME
1024 ok := False;
1025 end; // while ok...
1027 ok := True;
1028 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1029 end; // if ok - ññûëàþòñÿ òðèããåðû
1031 if not ok then
1032 begin
1033 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1034 SetLength(AddTextures, 1);
1035 AddTextures[0].Texture := panels[a].TextureNum;
1036 AddTextures[0].Anim := ByteBool(texture.Anim);
1037 CurTex := 0;
1038 end;
1040 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1041 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1043 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1044 if TriggersTable <> nil then
1045 for b := 0 to High(TriggersTable) do
1046 begin
1047 // Òðèããåð äâåðè/ëèôòà:
1048 if (TriggersTable[b].LiftPanel = a) or
1049 (TriggersTable[b].DoorPanel = a) then
1050 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1051 // Òðèããåð ñìåíû òåêñòóðû:
1052 if TriggersTable[b].TexturePanel = a then
1053 triggers[b].TexturePanel := PanelID;
1054 // Òðèããåð "Òóðåëü":
1055 if TriggersTable[b].ShotPanel = a then
1056 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1057 end;
1059 g_Game_StepLoading();
1060 end;
1061 end;
1063 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1064 if (triggers <> nil) and not gLoadGameMode then
1065 begin
1066 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1067 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1068 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1069 for a := 0 to High(triggers) do
1070 begin
1071 if triggers[a].TexturePanel <> -1 then
1072 b := panels[TriggersTable[a].TexturePanel].PanelType
1073 else
1074 b := 0;
1075 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1076 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1077 c := panels[TriggersTable[a].ShotPanel].PanelType
1078 else
1079 c := 0;
1080 CreateTrigger(triggers[a], b, c);
1081 end;
1082 end;
1084 // Çàãðóçêà ïðåäìåòîâ:
1085 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1086 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1087 items := MapReader.GetItems();
1089 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1090 if (items <> nil) and not gLoadGameMode then
1091 begin
1092 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1093 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1094 for a := 0 to High(items) do
1095 CreateItem(Items[a]);
1096 end;
1098 // Çàãðóçêà îáëàñòåé:
1099 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1100 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1101 areas := MapReader.GetAreas();
1103 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1104 if areas <> nil then
1105 begin
1106 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1107 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1108 for a := 0 to High(areas) do
1109 CreateArea(areas[a]);
1110 end;
1112 // Çàãðóçêà ìîíñòðîâ:
1113 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1114 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1115 monsters := MapReader.GetMonsters();
1117 gTotalMonsters := 0;
1119 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1120 if (monsters <> nil) and not gLoadGameMode then
1121 begin
1122 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1123 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1124 for a := 0 to High(monsters) do
1125 CreateMonster(monsters[a]);
1126 end;
1128 // Çàãðóçêà îïèñàíèÿ êàðòû:
1129 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1130 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1131 Header := MapReader.GetMapHeader();
1133 MapReader.Free();
1135 with gMapInfo do
1136 begin
1137 Name := Header.MapName;
1138 Description := Header.MapDescription;
1139 Author := Header.MapAuthor;
1140 MusicName := Header.MusicName;
1141 SkyName := Header.SkyName;
1142 Height := Header.Height;
1143 Width := Header.Width;
1144 end;
1146 // Çàãðóçêà íåáà:
1147 if gMapInfo.SkyName <> '' then
1148 begin
1149 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1150 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1151 g_ProcessResourceStr(gMapInfo.SkyName, FileName, SectionName, ResName);
1153 if FileName <> '' then
1154 FileName := GameDir+'/wads/'+FileName
1155 else
1156 begin
1157 g_ProcessResourceStr(Res, @FileName2, nil, nil);
1158 FileName := FileName2;
1159 end;
1161 s := FileName+':'+SectionName+'/'+ResName;
1162 if g_Texture_CreateWAD(BackID, s) then
1163 begin
1164 g_Game_SetupScreenSize();
1165 end
1166 else
1167 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1168 end;
1170 // Çàãðóçêà ìóçûêè:
1171 ok := False;
1172 if gMapInfo.MusicName <> '' then
1173 begin
1174 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1175 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1176 g_ProcessResourceStr(gMapInfo.MusicName, 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_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1188 ok := True
1189 else
1190 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1191 end;
1193 // Îñòàëüíûå óñòàíâêè:
1194 CreateDoorMap();
1195 CreateLiftMap();
1197 g_Items_Init();
1198 g_Weapon_Init();
1199 g_Monsters_Init();
1201 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1202 if not gLoadGameMode then
1203 g_GFX_Init();
1205 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1206 _textures := nil;
1207 panels := nil;
1208 items := nil;
1209 areas := nil;
1210 triggers := nil;
1211 TriggersTable := nil;
1212 AddTextures := nil;
1214 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1215 if ok and (not gLoadGameMode) then
1216 begin
1217 gMusic.SetByName(gMapInfo.MusicName);
1218 gMusic.Play();
1219 end
1220 else
1221 gMusic.SetByName('');
1223 e_WriteLog('Done loading map.', MSG_NOTIFY);
1224 Result := True;
1225 end;
1227 function g_Map_GetMapInfo(Res: String): TMapInfo;
1228 var
1229 WAD: TWADEditor_1;
1230 MapReader: TMapReader_1;
1231 Header: TMapHeaderRec_1;
1232 FileName, SectionName, ResName: String;
1233 Data: Pointer;
1234 Len: Integer;
1235 begin
1236 FillChar(Result, SizeOf(Result), 0);
1237 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
1239 WAD := TWADEditor_1.Create();
1240 if not WAD.ReadFile(FileName) then
1241 begin
1242 WAD.Free();
1243 Exit;
1244 end;
1246 if not WAD.GetResource('', ResName, Data, Len) then
1247 begin
1248 WAD.Free();
1249 Exit;
1250 end;
1252 WAD.Free();
1254 MapReader := TMapReader_1.Create();
1256 if not MapReader.LoadMap(Data) then
1257 begin
1258 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1259 ZeroMemory(@Header, SizeOf(Header));
1260 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1261 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1262 end
1263 else
1264 begin
1265 Header := MapReader.GetMapHeader();
1266 Result.Name := Header.MapName;
1267 Result.Description := Header.MapDescription;
1268 end;
1270 FreeMem(Data);
1271 MapReader.Free();
1273 Result.Map := Res;
1274 Result.Author := Header.MapAuthor;
1275 Result.Height := Header.Height;
1276 Result.Width := Header.Width;
1277 end;
1279 function g_Map_GetMapsList(WADName: string): SArray;
1280 var
1281 WAD: TWADEditor_1;
1282 a: Integer;
1283 ResList: SArray;
1284 Data: Pointer;
1285 Len: Integer;
1286 Sign: Array [0..2] of Char;
1287 begin
1288 Result := nil;
1290 WAD := TWADEditor_1.Create();
1291 if not WAD.ReadFile(WADName) then
1292 begin
1293 WAD.Free();
1294 Exit;
1295 end;
1297 ResList := WAD.GetResourcesList('');
1299 if ResList <> nil then
1300 for a := 0 to High(ResList) do
1301 begin
1302 if not WAD.GetResource('', ResList[a], Data, Len) then Continue;
1303 CopyMemory(@Sign[0], Data, 3);
1304 FreeMem(Data);
1306 if Sign = MAP_SIGNATURE then
1307 begin
1308 SetLength(Result, Length(Result)+1);
1309 Result[High(Result)] := ResList[a];
1310 end;
1312 Sign := '';
1313 end;
1315 WAD.Free();
1316 end;
1318 function g_Map_Exist(Res: string): Boolean;
1319 var
1320 WAD: TWADEditor_1;
1321 FileName, SectionName, ResName: string;
1322 ResList: SArray;
1323 a: Integer;
1324 begin
1325 Result := False;
1327 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
1329 FileName := addWadExtension(FileName);
1331 WAD := TWADEditor_1.Create;
1332 if not WAD.ReadFile(FileName) then
1333 begin
1334 WAD.Free();
1335 Exit;
1336 end;
1338 ResList := WAD.GetResourcesList('');
1339 WAD.Free();
1341 if ResList <> nil then
1342 for a := 0 to High(ResList) do if ResList[a] = ResName then
1343 begin
1344 Result := True;
1345 Exit;
1346 end;
1347 end;
1349 procedure g_Map_Free();
1350 var
1351 a: Integer;
1353 procedure FreePanelArray(var panels: TPanelArray);
1354 var
1355 i: Integer;
1357 begin
1358 if panels <> nil then
1359 begin
1360 for i := 0 to High(panels) do
1361 panels[i].Free();
1362 panels := nil;
1363 end;
1364 end;
1366 begin
1367 g_GFX_Free();
1368 g_Weapon_Free();
1369 g_Items_Free();
1370 g_Triggers_Free();
1371 g_Monsters_Free();
1373 RespawnPoints := nil;
1374 if FlagPoints[FLAG_RED] <> nil then
1375 begin
1376 Dispose(FlagPoints[FLAG_RED]);
1377 FlagPoints[FLAG_RED] := nil;
1378 end;
1379 if FlagPoints[FLAG_BLUE] <> nil then
1380 begin
1381 Dispose(FlagPoints[FLAG_BLUE]);
1382 FlagPoints[FLAG_BLUE] := nil;
1383 end;
1384 //DOMFlagPoints := nil;
1386 //gDOMFlags := nil;
1388 if Textures <> nil then
1389 begin
1390 for a := 0 to High(Textures) do
1391 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1392 if Textures[a].Anim then
1393 g_Frames_DeleteByID(Textures[a].FramesID)
1394 else
1395 if Textures[a].TextureID <> TEXTURE_NONE then
1396 e_DeleteTexture(Textures[a].TextureID);
1398 Textures := nil;
1399 end;
1401 FreePanelArray(gWalls);
1402 FreePanelArray(gRenderBackgrounds);
1403 FreePanelArray(gRenderForegrounds);
1404 FreePanelArray(gWater);
1405 FreePanelArray(gAcid1);
1406 FreePanelArray(gAcid2);
1407 FreePanelArray(gSteps);
1408 FreePanelArray(gLifts);
1409 FreePanelArray(gBlockMon);
1411 if BackID <> DWORD(-1) then
1412 begin
1413 gBackSize.X := 0;
1414 gBackSize.Y := 0;
1415 e_DeleteTexture(BackID);
1416 BackID := DWORD(-1);
1417 end;
1419 g_Game_StopAllSounds(False);
1420 gMusic.FreeSound();
1421 g_Sound_Delete(gMapInfo.MusicName);
1423 gMapInfo.Name := '';
1424 gMapInfo.Description := '';
1425 gMapInfo.MusicName := '';
1426 gMapInfo.Height := 0;
1427 gMapInfo.Width := 0;
1429 gDoorMap := nil;
1430 gLiftMap := nil;
1431 end;
1433 procedure g_Map_Update();
1434 var
1435 a, d, j: Integer;
1436 m: Word;
1437 s: String;
1439 procedure UpdatePanelArray(var panels: TPanelArray);
1440 var
1441 i: Integer;
1443 begin
1444 if panels <> nil then
1445 for i := 0 to High(panels) do
1446 panels[i].Update();
1447 end;
1449 begin
1450 UpdatePanelArray(gWalls);
1451 UpdatePanelArray(gRenderBackgrounds);
1452 UpdatePanelArray(gRenderForegrounds);
1453 UpdatePanelArray(gWater);
1454 UpdatePanelArray(gAcid1);
1455 UpdatePanelArray(gAcid2);
1456 UpdatePanelArray(gSteps);
1458 if gGameSettings.GameMode = GM_CTF then
1459 begin
1460 for a := FLAG_RED to FLAG_BLUE do
1461 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1462 with gFlags[a] do
1463 begin
1464 if gFlags[a].Animation <> nil then
1465 gFlags[a].Animation.Update();
1467 m := g_Obj_Move(@Obj, True, True);
1469 if gTime mod (GAME_TICK*2) <> 0 then
1470 Continue;
1472 // Ñîïðîòèâëåíèå âîçäóõà:
1473 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1475 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1476 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1477 begin
1478 g_Map_ResetFlag(a);
1479 gFlags[a].CaptureTime := 0;
1480 if a = FLAG_RED then
1481 s := _lc[I_PLAYER_FLAG_RED]
1482 else
1483 s := _lc[I_PLAYER_FLAG_BLUE];
1484 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1486 if g_Game_IsNet then
1487 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1488 Continue;
1489 end;
1491 if Count > 0 then
1492 Count := Count - 1;
1494 // Èãðîê áåðåò ôëàã:
1495 if gPlayers <> nil then
1496 begin
1497 j := Random(Length(gPlayers)) - 1;
1499 for d := 0 to High(gPlayers) do
1500 begin
1501 Inc(j);
1502 if j > High(gPlayers) then
1503 j := 0;
1505 if gPlayers[j] <> nil then
1506 if gPlayers[j].Live and
1507 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1508 begin
1509 if gPlayers[j].GetFlag(a) then
1510 Break;
1511 end;
1512 end;
1513 end;
1514 end;
1515 end;
1516 end;
1518 procedure g_Map_DrawPanels(PanelType: Word);
1520 procedure DrawPanels(var panels: TPanelArray;
1521 drawDoors: Boolean = False);
1522 var
1523 a: Integer;
1525 begin
1526 if panels <> nil then
1527 for a := 0 to High(panels) do
1528 if not (drawDoors xor panels[a].Door) then
1529 panels[a].Draw();
1530 end;
1532 begin
1533 case PanelType of
1534 PANEL_WALL: DrawPanels(gWalls);
1535 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1536 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1537 PANEL_FORE: DrawPanels(gRenderForegrounds);
1538 PANEL_WATER: DrawPanels(gWater);
1539 PANEL_ACID1: DrawPanels(gAcid1);
1540 PANEL_ACID2: DrawPanels(gAcid2);
1541 PANEL_STEP: DrawPanels(gSteps);
1542 end;
1543 end;
1545 procedure g_Map_DrawBack(dx, dy: Integer);
1546 begin
1547 if gDrawBackGround and (BackID <> DWORD(-1)) then
1548 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1549 else
1550 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1551 end;
1553 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1554 PanelType: Word; b1x3: Boolean): Boolean;
1555 var
1556 a, h: Integer;
1557 begin
1558 Result := False;
1560 if WordBool(PanelType and PANEL_WALL) then
1561 if gWalls <> nil then
1562 begin
1563 h := High(gWalls);
1565 for a := 0 to h do
1566 if gWalls[a].Enabled and
1567 g_Collide(X, Y, Width, Height,
1568 gWalls[a].X, gWalls[a].Y,
1569 gWalls[a].Width, gWalls[a].Height) then
1570 begin
1571 Result := True;
1572 Exit;
1573 end;
1574 end;
1576 if WordBool(PanelType and PANEL_WATER) then
1577 if gWater <> nil then
1578 begin
1579 h := High(gWater);
1581 for a := 0 to h do
1582 if g_Collide(X, Y, Width, Height,
1583 gWater[a].X, gWater[a].Y,
1584 gWater[a].Width, gWater[a].Height) then
1585 begin
1586 Result := True;
1587 Exit;
1588 end;
1589 end;
1591 if WordBool(PanelType and PANEL_ACID1) then
1592 if gAcid1 <> nil then
1593 begin
1594 h := High(gAcid1);
1596 for a := 0 to h do
1597 if g_Collide(X, Y, Width, Height,
1598 gAcid1[a].X, gAcid1[a].Y,
1599 gAcid1[a].Width, gAcid1[a].Height) then
1600 begin
1601 Result := True;
1602 Exit;
1603 end;
1604 end;
1606 if WordBool(PanelType and PANEL_ACID2) then
1607 if gAcid2 <> nil then
1608 begin
1609 h := High(gAcid2);
1611 for a := 0 to h do
1612 if g_Collide(X, Y, Width, Height,
1613 gAcid2[a].X, gAcid2[a].Y,
1614 gAcid2[a].Width, gAcid2[a].Height) then
1615 begin
1616 Result := True;
1617 Exit;
1618 end;
1619 end;
1621 if WordBool(PanelType and PANEL_STEP) then
1622 if gSteps <> nil then
1623 begin
1624 h := High(gSteps);
1626 for a := 0 to h do
1627 if g_Collide(X, Y, Width, Height,
1628 gSteps[a].X, gSteps[a].Y,
1629 gSteps[a].Width, gSteps[a].Height) then
1630 begin
1631 Result := True;
1632 Exit;
1633 end;
1634 end;
1636 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1637 if gLifts <> nil then
1638 begin
1639 h := High(gLifts);
1641 for a := 0 to h do
1642 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1643 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1644 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1645 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1646 g_Collide(X, Y, Width, Height,
1647 gLifts[a].X, gLifts[a].Y,
1648 gLifts[a].Width, gLifts[a].Height) then
1649 begin
1650 Result := True;
1651 Exit;
1652 end;
1653 end;
1655 if WordBool(PanelType and PANEL_BLOCKMON) then
1656 if gBlockMon <> nil then
1657 begin
1658 h := High(gBlockMon);
1660 for a := 0 to h do
1661 if ( (not b1x3) or
1662 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1663 g_Collide(X, Y, Width, Height,
1664 gBlockMon[a].X, gBlockMon[a].Y,
1665 gBlockMon[a].Width, gBlockMon[a].Height) then
1666 begin
1667 Result := True;
1668 Exit;
1669 end;
1670 end;
1671 end;
1673 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1674 var
1675 a, h: Integer;
1676 begin
1677 Result := TEXTURE_NONE;
1679 if gWater <> nil then
1680 begin
1681 h := High(gWater);
1683 for a := 0 to h do
1684 if g_Collide(X, Y, Width, Height,
1685 gWater[a].X, gWater[a].Y,
1686 gWater[a].Width, gWater[a].Height) then
1687 begin
1688 Result := gWater[a].GetTextureID();
1689 Exit;
1690 end;
1691 end;
1693 if gAcid1 <> nil then
1694 begin
1695 h := High(gAcid1);
1697 for a := 0 to h do
1698 if g_Collide(X, Y, Width, Height,
1699 gAcid1[a].X, gAcid1[a].Y,
1700 gAcid1[a].Width, gAcid1[a].Height) then
1701 begin
1702 Result := gAcid1[a].GetTextureID();
1703 Exit;
1704 end;
1705 end;
1707 if gAcid2 <> nil then
1708 begin
1709 h := High(gAcid2);
1711 for a := 0 to h do
1712 if g_Collide(X, Y, Width, Height,
1713 gAcid2[a].X, gAcid2[a].Y,
1714 gAcid2[a].Width, gAcid2[a].Height) then
1715 begin
1716 Result := gAcid2[a].GetTextureID();
1717 Exit;
1718 end;
1719 end;
1720 end;
1722 procedure g_Map_EnableWall(ID: DWORD);
1723 begin
1724 with gWalls[ID] do
1725 begin
1726 Enabled := True;
1727 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1729 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1730 end;
1731 end;
1733 procedure g_Map_DisableWall(ID: DWORD);
1734 begin
1735 with gWalls[ID] do
1736 begin
1737 Enabled := False;
1738 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1740 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1741 end;
1742 end;
1744 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1745 var
1746 tp: TPanel;
1747 begin
1748 case PanelType of
1749 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1750 tp := gWalls[ID];
1751 PANEL_FORE:
1752 tp := gRenderForegrounds[ID];
1753 PANEL_BACK:
1754 tp := gRenderBackgrounds[ID];
1755 PANEL_WATER:
1756 tp := gWater[ID];
1757 PANEL_ACID1:
1758 tp := gAcid1[ID];
1759 PANEL_ACID2:
1760 tp := gAcid2[ID];
1761 PANEL_STEP:
1762 tp := gSteps[ID];
1763 else
1764 Exit;
1765 end;
1767 tp.NextTexture(AnimLoop);
1768 if g_Game_IsServer and g_Game_IsNet then
1769 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1770 end;
1772 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1773 begin
1774 if gLifts[ID].LiftType = t then
1775 Exit;
1777 with gLifts[ID] do
1778 begin
1779 LiftType := t;
1781 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1783 if LiftType = 0 then
1784 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1785 else if LiftType = 1 then
1786 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1787 else if LiftType = 2 then
1788 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1789 else if LiftType = 3 then
1790 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1792 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1793 end;
1794 end;
1796 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1797 var
1798 a: Integer;
1799 PointsArray: Array of TRespawnPoint;
1800 begin
1801 Result := False;
1802 SetLength(PointsArray, 0);
1804 if RespawnPoints = nil then
1805 Exit;
1807 for a := 0 to High(RespawnPoints) do
1808 if RespawnPoints[a].PointType = PointType then
1809 begin
1810 SetLength(PointsArray, Length(PointsArray)+1);
1811 PointsArray[High(PointsArray)] := RespawnPoints[a];
1812 end;
1814 if PointsArray = nil then
1815 Exit;
1817 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1818 Result := True;
1819 end;
1821 function g_Map_GetPointCount(PointType: Byte): Word;
1822 var
1823 a: Integer;
1824 begin
1825 Result := 0;
1827 if RespawnPoints = nil then
1828 Exit;
1830 for a := 0 to High(RespawnPoints) do
1831 if RespawnPoints[a].PointType = PointType then
1832 Result := Result + 1;
1833 end;
1835 function g_Map_HaveFlagPoints(): Boolean;
1836 begin
1837 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1838 end;
1840 procedure g_Map_ResetFlag(Flag: Byte);
1841 begin
1842 with gFlags[Flag] do
1843 begin
1844 Obj.X := -1000;
1845 Obj.Y := -1000;
1846 Obj.Vel.X := 0;
1847 Obj.Vel.Y := 0;
1848 Direction := D_LEFT;
1849 State := FLAG_STATE_NONE;
1850 if FlagPoints[Flag] <> nil then
1851 begin
1852 Obj.X := FlagPoints[Flag]^.X;
1853 Obj.Y := FlagPoints[Flag]^.Y;
1854 Direction := FlagPoints[Flag]^.Direction;
1855 State := FLAG_STATE_NORMAL;
1856 end;
1857 Count := -1;
1858 end;
1859 end;
1861 procedure g_Map_DrawFlags();
1862 var
1863 i, dx: Integer;
1864 Mirror: TMirrorType;
1865 begin
1866 if gGameSettings.GameMode <> GM_CTF then
1867 Exit;
1869 for i := FLAG_RED to FLAG_BLUE do
1870 with gFlags[i] do
1871 if State <> FLAG_STATE_CAPTURED then
1872 begin
1873 if State = FLAG_STATE_NONE then
1874 continue;
1876 if Direction = D_LEFT then
1877 begin
1878 Mirror := M_HORIZONTAL;
1879 dx := -1;
1880 end
1881 else
1882 begin
1883 Mirror := M_NONE;
1884 dx := 1;
1885 end;
1887 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
1889 if g_debug_Frames then
1890 begin
1891 e_DrawQuad(Obj.X+Obj.Rect.X,
1892 Obj.Y+Obj.Rect.Y,
1893 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
1894 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
1895 0, 255, 0);
1896 end;
1897 end;
1898 end;
1900 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
1901 var
1902 dw: DWORD;
1903 b: Byte;
1904 str: String;
1905 boo: Boolean;
1907 procedure SavePanelArray(var panels: TPanelArray);
1908 var
1909 PAMem: TBinMemoryWriter;
1910 i: Integer;
1911 begin
1912 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
1913 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
1915 i := 0;
1916 while i < Length(panels) do
1917 begin
1918 if panels[i].SaveIt then
1919 begin
1920 // ID ïàíåëè:
1921 PAMem.WriteInt(i);
1922 // Ñîõðàíÿåì ïàíåëü:
1923 panels[i].SaveState(PAMem);
1924 end;
1925 Inc(i);
1926 end;
1928 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
1929 PAMem.SaveToMemory(Mem);
1930 PAMem.Free();
1931 end;
1933 procedure SaveFlag(flag: PFlag);
1934 begin
1935 // Ñèãíàòóðà ôëàãà:
1936 dw := FLAG_SIGNATURE; // 'FLAG'
1937 Mem.WriteDWORD(dw);
1938 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
1939 Mem.WriteByte(flag^.RespawnType);
1940 // Ñîñòîÿíèå ôëàãà:
1941 Mem.WriteByte(flag^.State);
1942 // Íàïðàâëåíèå ôëàãà:
1943 if flag^.Direction = D_LEFT then
1944 b := 1
1945 else // D_RIGHT
1946 b := 2;
1947 Mem.WriteByte(b);
1948 // Îáúåêò ôëàãà:
1949 Obj_SaveState(@flag^.Obj, Mem);
1950 end;
1952 begin
1953 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
1955 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
1956 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
1957 SavePanelArray(gWalls);
1958 // Ñîõðàíÿåì ïàíåëè ôîíà:
1959 SavePanelArray(gRenderBackgrounds);
1960 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
1961 SavePanelArray(gRenderForegrounds);
1962 // Ñîõðàíÿåì ïàíåëè âîäû:
1963 SavePanelArray(gWater);
1964 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
1965 SavePanelArray(gAcid1);
1966 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
1967 SavePanelArray(gAcid2);
1968 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
1969 SavePanelArray(gSteps);
1970 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
1971 SavePanelArray(gLifts);
1972 ///// /////
1974 ///// Ñîõðàíÿåì ìóçûêó: /////
1975 // Ñèãíàòóðà ìóçûêè:
1976 dw := MUSIC_SIGNATURE; // 'MUSI'
1977 Mem.WriteDWORD(dw);
1978 // Íàçâàíèå ìóçûêè:
1979 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
1980 if gMusic.NoMusic then
1981 str := ''
1982 else
1983 str := gMusic.Name;
1984 Mem.WriteString(str, 64);
1985 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
1986 dw := gMusic.GetPosition();
1987 Mem.WriteDWORD(dw);
1988 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
1989 boo := gMusic.SpecPause;
1990 Mem.WriteBoolean(boo);
1991 ///// /////
1993 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
1994 Mem.WriteInt(gTotalMonsters);
1995 ///// /////
1997 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
1998 if gGameSettings.GameMode = GM_CTF then
1999 begin
2000 // Ôëàã Êðàñíîé êîìàíäû:
2001 SaveFlag(@gFlags[FLAG_RED]);
2002 // Ôëàã Ñèíåé êîìàíäû:
2003 SaveFlag(@gFlags[FLAG_BLUE]);
2004 end;
2005 ///// /////
2007 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2008 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2009 begin
2010 // Î÷êè Êðàñíîé êîìàíäû:
2011 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2012 // Î÷êè Ñèíåé êîìàíäû:
2013 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2014 end;
2015 ///// /////
2016 end;
2018 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2019 var
2020 dw: DWORD;
2021 b: Byte;
2022 str: String;
2023 boo: Boolean;
2025 procedure LoadPanelArray(var panels: TPanelArray);
2026 var
2027 PAMem: TBinMemoryReader;
2028 i, id: Integer;
2029 begin
2030 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2031 PAMem := TBinMemoryReader.Create();
2032 PAMem.LoadFromMemory(Mem);
2034 for i := 0 to Length(panels)-1 do
2035 if panels[i].SaveIt then
2036 begin
2037 // ID ïàíåëè:
2038 PAMem.ReadInt(id);
2039 if id <> i then
2040 begin
2041 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2042 end;
2043 // Çàãðóæàåì ïàíåëü:
2044 panels[i].LoadState(PAMem);
2045 end;
2047 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2048 PAMem.Free();
2049 end;
2051 procedure LoadFlag(flag: PFlag);
2052 begin
2053 // Ñèãíàòóðà ôëàãà:
2054 Mem.ReadDWORD(dw);
2055 if dw <> FLAG_SIGNATURE then // 'FLAG'
2056 begin
2057 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2058 end;
2059 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2060 Mem.ReadByte(flag^.RespawnType);
2061 // Ñîñòîÿíèå ôëàãà:
2062 Mem.ReadByte(flag^.State);
2063 // Íàïðàâëåíèå ôëàãà:
2064 Mem.ReadByte(b);
2065 if b = 1 then
2066 flag^.Direction := D_LEFT
2067 else // b = 2
2068 flag^.Direction := D_RIGHT;
2069 // Îáúåêò ôëàãà:
2070 Obj_LoadState(@flag^.Obj, Mem);
2071 end;
2073 begin
2074 if Mem = nil then
2075 Exit;
2077 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2078 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2079 LoadPanelArray(gWalls);
2080 // Çàãðóæàåì ïàíåëè ôîíà:
2081 LoadPanelArray(gRenderBackgrounds);
2082 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2083 LoadPanelArray(gRenderForegrounds);
2084 // Çàãðóæàåì ïàíåëè âîäû:
2085 LoadPanelArray(gWater);
2086 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2087 LoadPanelArray(gAcid1);
2088 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2089 LoadPanelArray(gAcid2);
2090 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2091 LoadPanelArray(gSteps);
2092 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2093 LoadPanelArray(gLifts);
2094 ///// /////
2096 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2097 g_GFX_Init();
2099 ///// Çàãðóæàåì ìóçûêó: /////
2100 // Ñèãíàòóðà ìóçûêè:
2101 Mem.ReadDWORD(dw);
2102 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2103 begin
2104 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2105 end;
2106 // Íàçâàíèå ìóçûêè:
2107 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2108 Mem.ReadString(str);
2109 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2110 Mem.ReadDWORD(dw);
2111 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2112 Mem.ReadBoolean(boo);
2113 // Çàïóñêàåì ýòó ìóçûêó:
2114 gMusic.SetByName(str);
2115 gMusic.SpecPause := boo;
2116 gMusic.Play();
2117 gMusic.Pause(True);
2118 gMusic.SetPosition(dw);
2119 ///// /////
2121 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2122 Mem.ReadInt(gTotalMonsters);
2123 ///// /////
2125 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2126 if gGameSettings.GameMode = GM_CTF then
2127 begin
2128 // Ôëàã Êðàñíîé êîìàíäû:
2129 LoadFlag(@gFlags[FLAG_RED]);
2130 // Ôëàã Ñèíåé êîìàíäû:
2131 LoadFlag(@gFlags[FLAG_BLUE]);
2132 end;
2133 ///// /////
2135 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2136 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2137 begin
2138 // Î÷êè Êðàñíîé êîìàíäû:
2139 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2140 // Î÷êè Ñèíåé êîìàíäû:
2141 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2142 end;
2143 ///// /////
2144 end;
2146 end.