DEADSOFTWARE

temporary disable sfs GC on game startup (this will speedup initial data loading)
[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, sfs;
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 sfsGCDisable(); // temporary disable removing of temporary volumes
789 try
790 // Çàãðóçêà WAD:
791 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
792 e_WriteLog('Loading map WAD: ' + FileName, MSG_NOTIFY);
793 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
795 WAD := TWADEditor_1.Create();
796 if not WAD.ReadFile(FileName) then
797 begin
798 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
799 WAD.Free();
800 Exit;
801 end;
802 if not WAD.GetResource('', ResName, Data, Len) then
803 begin
804 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [ResName]));
805 WAD.Free();
806 Exit;
807 end;
808 WAD.Free();
810 // Çàãðóçêà êàðòû:
811 e_WriteLog('Loading map: ' + ResName, MSG_NOTIFY);
812 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
813 MapReader := TMapReader_1.Create();
815 if not MapReader.LoadMap(Data) then
816 begin
817 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
818 FreeMem(Data);
819 MapReader.Free();
820 Exit;
821 end;
823 FreeMem(Data);
824 generateExternalResourcesList(MapReader);
825 // Çàãðóçêà òåêñòóð:
826 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
827 _textures := MapReader.GetTextures();
829 // Äîáàâëåíèå òåêñòóð â Textures[]:
830 if _textures <> nil then
831 begin
832 e_WriteLog(' Loading textures:', MSG_NOTIFY);
833 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
835 for a := 0 to High(_textures) do
836 begin
837 SetLength(s, 64);
838 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
839 for b := 1 to Length(s) do
840 if s[b] = #0 then
841 begin
842 SetLength(s, b-1);
843 Break;
844 end;
845 e_WriteLog(' Loading texture: ' + s, MSG_NOTIFY);
846 // Àíèìèðîâàííàÿ òåêñòóðà:
847 if ByteBool(_textures[a].Anim) then
848 begin
849 if not CreateAnimTexture(_textures[a].Resource, FileName, True) then
850 begin
851 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
852 CreateNullTexture(_textures[a].Resource);
853 end;
854 end
855 else // Îáû÷íàÿ òåêñòóðà:
856 if not CreateTexture(_textures[a].Resource, FileName, True) then
857 begin
858 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
859 CreateNullTexture(_textures[a].Resource);
860 end;
862 g_Game_StepLoading();
863 end;
864 end;
866 // Çàãðóçêà òðèããåðîâ:
867 gTriggerClientID := 0;
868 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
869 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
870 triggers := MapReader.GetTriggers();
872 // Çàãðóçêà ïàíåëåé:
873 e_WriteLog(' Loading panels...', MSG_NOTIFY);
874 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
875 panels := MapReader.GetPanels();
877 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
878 if triggers <> nil then
879 begin
880 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
881 SetLength(TriggersTable, Length(triggers));
882 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
884 for a := 0 to High(TriggersTable) do
885 begin
886 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
887 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
888 // Ëèôòû:
889 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
890 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
891 else
892 TriggersTable[a].LiftPanel := -1;
893 // Äâåðè:
894 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
895 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
896 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
897 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
898 else
899 TriggersTable[a].DoorPanel := -1;
900 // Òóðåëü:
901 if triggers[a].TriggerType = TRIGGER_SHOT then
902 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
903 else
904 TriggersTable[a].ShotPanel := -1;
906 g_Game_StepLoading();
907 end;
908 end;
910 // Ñîçäàåì ïàíåëè:
911 if panels <> nil then
912 begin
913 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
914 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
916 for a := 0 to High(panels) do
917 begin
918 SetLength(AddTextures, 0);
919 trigRef := False;
920 CurTex := -1;
921 if _textures <> nil then
922 begin
923 texture := _textures[panels[a].TextureNum];
924 ok := True;
925 end
926 else
927 ok := False;
929 if ok then
930 begin
931 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
932 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
933 ok := False;
934 if (TriggersTable <> nil) and (_textures <> nil) then
935 for b := 0 to High(TriggersTable) do
936 if (TriggersTable[b].TexturePanel = a)
937 or (TriggersTable[b].ShotPanel = a) then
938 begin
939 trigRef := True;
940 ok := True;
941 Break;
942 end;
943 end;
945 if ok then
946 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
947 SetLength(s, 64);
948 CopyMemory(@s[1], @texture.Resource[0], 64);
949 // Èçìåðÿåì äëèíó:
950 Len := Length(s);
951 for c := Len downto 1 do
952 if s[c] <> #0 then
953 begin
954 Len := c;
955 Break;
956 end;
957 SetLength(s, Len);
959 // Ñïåö-òåêñòóðû çàïðåùåíû:
960 if g_Map_IsSpecialTexture(s) then
961 ok := False
962 else
963 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
964 ok := g_Texture_NumNameFindStart(s);
966 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
967 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
968 if ok then
969 begin
970 k := NNF_NAME_BEFORE;
971 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
972 while ok or (k = NNF_NAME_BEFORE) or
973 (k = NNF_NAME_EQUALS) do
974 begin
975 k := g_Texture_NumNameFindNext(TexName);
977 if (k = NNF_NAME_BEFORE) or
978 (k = NNF_NAME_AFTER) then
979 begin
980 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
981 if ByteBool(texture.Anim) then
982 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
983 isAnim := True;
984 ok := CreateAnimTexture(TexName, FileName, False);
985 if not ok then
986 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
987 isAnim := False;
988 ok := CreateTexture(TexName, FileName, False);
989 end;
990 end
991 else
992 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
993 isAnim := False;
994 ok := CreateTexture(TexName, FileName, False);
995 if not ok then
996 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
997 isAnim := True;
998 ok := CreateAnimTexture(TexName, FileName, False);
999 end;
1000 end;
1002 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1003 if ok then
1004 begin
1005 for c := 0 to High(Textures) do
1006 if Textures[c].TextureName = TexName then
1007 begin
1008 SetLength(AddTextures, Length(AddTextures)+1);
1009 AddTextures[High(AddTextures)].Texture := c;
1010 AddTextures[High(AddTextures)].Anim := isAnim;
1011 Break;
1012 end;
1013 end;
1014 end
1015 else
1016 if k = NNF_NAME_EQUALS then
1017 begin
1018 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1019 SetLength(AddTextures, Length(AddTextures)+1);
1020 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1021 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1022 CurTex := High(AddTextures);
1023 ok := True;
1024 end
1025 else // NNF_NO_NAME
1026 ok := False;
1027 end; // while ok...
1029 ok := True;
1030 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1031 end; // if ok - ññûëàþòñÿ òðèããåðû
1033 if not ok then
1034 begin
1035 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1036 SetLength(AddTextures, 1);
1037 AddTextures[0].Texture := panels[a].TextureNum;
1038 AddTextures[0].Anim := ByteBool(texture.Anim);
1039 CurTex := 0;
1040 end;
1042 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1043 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1045 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1046 if TriggersTable <> nil then
1047 for b := 0 to High(TriggersTable) do
1048 begin
1049 // Òðèããåð äâåðè/ëèôòà:
1050 if (TriggersTable[b].LiftPanel = a) or
1051 (TriggersTable[b].DoorPanel = a) then
1052 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1053 // Òðèããåð ñìåíû òåêñòóðû:
1054 if TriggersTable[b].TexturePanel = a then
1055 triggers[b].TexturePanel := PanelID;
1056 // Òðèããåð "Òóðåëü":
1057 if TriggersTable[b].ShotPanel = a then
1058 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1059 end;
1061 g_Game_StepLoading();
1062 end;
1063 end;
1065 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1066 if (triggers <> nil) and not gLoadGameMode then
1067 begin
1068 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1069 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1070 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1071 for a := 0 to High(triggers) do
1072 begin
1073 if triggers[a].TexturePanel <> -1 then
1074 b := panels[TriggersTable[a].TexturePanel].PanelType
1075 else
1076 b := 0;
1077 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1078 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1079 c := panels[TriggersTable[a].ShotPanel].PanelType
1080 else
1081 c := 0;
1082 CreateTrigger(triggers[a], b, c);
1083 end;
1084 end;
1086 // Çàãðóçêà ïðåäìåòîâ:
1087 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1088 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1089 items := MapReader.GetItems();
1091 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1092 if (items <> nil) and not gLoadGameMode then
1093 begin
1094 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1095 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1096 for a := 0 to High(items) do
1097 CreateItem(Items[a]);
1098 end;
1100 // Çàãðóçêà îáëàñòåé:
1101 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1102 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1103 areas := MapReader.GetAreas();
1105 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1106 if areas <> nil then
1107 begin
1108 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1109 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1110 for a := 0 to High(areas) do
1111 CreateArea(areas[a]);
1112 end;
1114 // Çàãðóçêà ìîíñòðîâ:
1115 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1116 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1117 monsters := MapReader.GetMonsters();
1119 gTotalMonsters := 0;
1121 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1122 if (monsters <> nil) and not gLoadGameMode then
1123 begin
1124 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1125 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1126 for a := 0 to High(monsters) do
1127 CreateMonster(monsters[a]);
1128 end;
1130 // Çàãðóçêà îïèñàíèÿ êàðòû:
1131 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1132 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1133 Header := MapReader.GetMapHeader();
1135 MapReader.Free();
1137 with gMapInfo do
1138 begin
1139 Name := Header.MapName;
1140 Description := Header.MapDescription;
1141 Author := Header.MapAuthor;
1142 MusicName := Header.MusicName;
1143 SkyName := Header.SkyName;
1144 Height := Header.Height;
1145 Width := Header.Width;
1146 end;
1148 // Çàãðóçêà íåáà:
1149 if gMapInfo.SkyName <> '' then
1150 begin
1151 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1152 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1153 g_ProcessResourceStr(gMapInfo.SkyName, FileName, SectionName, ResName);
1155 if FileName <> '' then
1156 FileName := GameDir+'/wads/'+FileName
1157 else
1158 begin
1159 g_ProcessResourceStr(Res, @FileName2, nil, nil);
1160 FileName := FileName2;
1161 end;
1163 s := FileName+':'+SectionName+'/'+ResName;
1164 if g_Texture_CreateWAD(BackID, s) then
1165 begin
1166 g_Game_SetupScreenSize();
1167 end
1168 else
1169 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1170 end;
1172 // Çàãðóçêà ìóçûêè:
1173 ok := False;
1174 if gMapInfo.MusicName <> '' then
1175 begin
1176 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1177 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1178 g_ProcessResourceStr(gMapInfo.MusicName, FileName, SectionName, ResName);
1180 if FileName <> '' then
1181 FileName := GameDir+'/wads/'+FileName
1182 else
1183 begin
1184 g_ProcessResourceStr(Res, @FileName2, nil, nil);
1185 FileName := FileName2;
1186 end;
1188 s := FileName+':'+SectionName+'/'+ResName;
1189 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1190 ok := True
1191 else
1192 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1193 end;
1195 // Îñòàëüíûå óñòàíâêè:
1196 CreateDoorMap();
1197 CreateLiftMap();
1199 g_Items_Init();
1200 g_Weapon_Init();
1201 g_Monsters_Init();
1203 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1204 if not gLoadGameMode then
1205 g_GFX_Init();
1207 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1208 _textures := nil;
1209 panels := nil;
1210 items := nil;
1211 areas := nil;
1212 triggers := nil;
1213 TriggersTable := nil;
1214 AddTextures := nil;
1216 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1217 if ok and (not gLoadGameMode) then
1218 begin
1219 gMusic.SetByName(gMapInfo.MusicName);
1220 gMusic.Play();
1221 end
1222 else
1223 gMusic.SetByName('');
1224 finally
1225 sfsGCEnable(); // enable releasing unused volumes
1226 end;
1228 e_WriteLog('Done loading map.', MSG_NOTIFY);
1229 Result := True;
1230 end;
1232 function g_Map_GetMapInfo(Res: String): TMapInfo;
1233 var
1234 WAD: TWADEditor_1;
1235 MapReader: TMapReader_1;
1236 Header: TMapHeaderRec_1;
1237 FileName, SectionName, ResName: String;
1238 Data: Pointer;
1239 Len: Integer;
1240 begin
1241 FillChar(Result, SizeOf(Result), 0);
1242 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
1244 WAD := TWADEditor_1.Create();
1245 if not WAD.ReadFile(FileName) then
1246 begin
1247 WAD.Free();
1248 Exit;
1249 end;
1251 if not WAD.GetResource('', ResName, Data, Len) then
1252 begin
1253 WAD.Free();
1254 Exit;
1255 end;
1257 WAD.Free();
1259 MapReader := TMapReader_1.Create();
1261 if not MapReader.LoadMap(Data) then
1262 begin
1263 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1264 ZeroMemory(@Header, SizeOf(Header));
1265 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1266 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1267 end
1268 else
1269 begin
1270 Header := MapReader.GetMapHeader();
1271 Result.Name := Header.MapName;
1272 Result.Description := Header.MapDescription;
1273 end;
1275 FreeMem(Data);
1276 MapReader.Free();
1278 Result.Map := Res;
1279 Result.Author := Header.MapAuthor;
1280 Result.Height := Header.Height;
1281 Result.Width := Header.Width;
1282 end;
1284 function g_Map_GetMapsList(WADName: string): SArray;
1285 var
1286 WAD: TWADEditor_1;
1287 a: Integer;
1288 ResList: SArray;
1289 Data: Pointer;
1290 Len: Integer;
1291 Sign: Array [0..2] of Char;
1292 begin
1293 Result := nil;
1295 WAD := TWADEditor_1.Create();
1296 if not WAD.ReadFile(WADName) then
1297 begin
1298 WAD.Free();
1299 Exit;
1300 end;
1302 ResList := WAD.GetResourcesList('');
1304 if ResList <> nil then
1305 for a := 0 to High(ResList) do
1306 begin
1307 if not WAD.GetResource('', ResList[a], Data, Len) then Continue;
1308 CopyMemory(@Sign[0], Data, 3);
1309 FreeMem(Data);
1311 if Sign = MAP_SIGNATURE then
1312 begin
1313 SetLength(Result, Length(Result)+1);
1314 Result[High(Result)] := ResList[a];
1315 end;
1317 Sign := '';
1318 end;
1320 WAD.Free();
1321 end;
1323 function g_Map_Exist(Res: string): Boolean;
1324 var
1325 WAD: TWADEditor_1;
1326 FileName, SectionName, ResName: string;
1327 ResList: SArray;
1328 a: Integer;
1329 begin
1330 Result := False;
1332 g_ProcessResourceStr(Res, FileName, SectionName, ResName);
1334 FileName := addWadExtension(FileName);
1336 WAD := TWADEditor_1.Create;
1337 if not WAD.ReadFile(FileName) then
1338 begin
1339 WAD.Free();
1340 Exit;
1341 end;
1343 ResList := WAD.GetResourcesList('');
1344 WAD.Free();
1346 if ResList <> nil then
1347 for a := 0 to High(ResList) do if ResList[a] = ResName then
1348 begin
1349 Result := True;
1350 Exit;
1351 end;
1352 end;
1354 procedure g_Map_Free();
1355 var
1356 a: Integer;
1358 procedure FreePanelArray(var panels: TPanelArray);
1359 var
1360 i: Integer;
1362 begin
1363 if panels <> nil then
1364 begin
1365 for i := 0 to High(panels) do
1366 panels[i].Free();
1367 panels := nil;
1368 end;
1369 end;
1371 begin
1372 g_GFX_Free();
1373 g_Weapon_Free();
1374 g_Items_Free();
1375 g_Triggers_Free();
1376 g_Monsters_Free();
1378 RespawnPoints := nil;
1379 if FlagPoints[FLAG_RED] <> nil then
1380 begin
1381 Dispose(FlagPoints[FLAG_RED]);
1382 FlagPoints[FLAG_RED] := nil;
1383 end;
1384 if FlagPoints[FLAG_BLUE] <> nil then
1385 begin
1386 Dispose(FlagPoints[FLAG_BLUE]);
1387 FlagPoints[FLAG_BLUE] := nil;
1388 end;
1389 //DOMFlagPoints := nil;
1391 //gDOMFlags := nil;
1393 if Textures <> nil then
1394 begin
1395 for a := 0 to High(Textures) do
1396 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1397 if Textures[a].Anim then
1398 g_Frames_DeleteByID(Textures[a].FramesID)
1399 else
1400 if Textures[a].TextureID <> TEXTURE_NONE then
1401 e_DeleteTexture(Textures[a].TextureID);
1403 Textures := nil;
1404 end;
1406 FreePanelArray(gWalls);
1407 FreePanelArray(gRenderBackgrounds);
1408 FreePanelArray(gRenderForegrounds);
1409 FreePanelArray(gWater);
1410 FreePanelArray(gAcid1);
1411 FreePanelArray(gAcid2);
1412 FreePanelArray(gSteps);
1413 FreePanelArray(gLifts);
1414 FreePanelArray(gBlockMon);
1416 if BackID <> DWORD(-1) then
1417 begin
1418 gBackSize.X := 0;
1419 gBackSize.Y := 0;
1420 e_DeleteTexture(BackID);
1421 BackID := DWORD(-1);
1422 end;
1424 g_Game_StopAllSounds(False);
1425 gMusic.FreeSound();
1426 g_Sound_Delete(gMapInfo.MusicName);
1428 gMapInfo.Name := '';
1429 gMapInfo.Description := '';
1430 gMapInfo.MusicName := '';
1431 gMapInfo.Height := 0;
1432 gMapInfo.Width := 0;
1434 gDoorMap := nil;
1435 gLiftMap := nil;
1436 end;
1438 procedure g_Map_Update();
1439 var
1440 a, d, j: Integer;
1441 m: Word;
1442 s: String;
1444 procedure UpdatePanelArray(var panels: TPanelArray);
1445 var
1446 i: Integer;
1448 begin
1449 if panels <> nil then
1450 for i := 0 to High(panels) do
1451 panels[i].Update();
1452 end;
1454 begin
1455 UpdatePanelArray(gWalls);
1456 UpdatePanelArray(gRenderBackgrounds);
1457 UpdatePanelArray(gRenderForegrounds);
1458 UpdatePanelArray(gWater);
1459 UpdatePanelArray(gAcid1);
1460 UpdatePanelArray(gAcid2);
1461 UpdatePanelArray(gSteps);
1463 if gGameSettings.GameMode = GM_CTF then
1464 begin
1465 for a := FLAG_RED to FLAG_BLUE do
1466 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1467 with gFlags[a] do
1468 begin
1469 if gFlags[a].Animation <> nil then
1470 gFlags[a].Animation.Update();
1472 m := g_Obj_Move(@Obj, True, True);
1474 if gTime mod (GAME_TICK*2) <> 0 then
1475 Continue;
1477 // Ñîïðîòèâëåíèå âîçäóõà:
1478 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1480 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1481 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1482 begin
1483 g_Map_ResetFlag(a);
1484 gFlags[a].CaptureTime := 0;
1485 if a = FLAG_RED then
1486 s := _lc[I_PLAYER_FLAG_RED]
1487 else
1488 s := _lc[I_PLAYER_FLAG_BLUE];
1489 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1491 if g_Game_IsNet then
1492 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1493 Continue;
1494 end;
1496 if Count > 0 then
1497 Count := Count - 1;
1499 // Èãðîê áåðåò ôëàã:
1500 if gPlayers <> nil then
1501 begin
1502 j := Random(Length(gPlayers)) - 1;
1504 for d := 0 to High(gPlayers) do
1505 begin
1506 Inc(j);
1507 if j > High(gPlayers) then
1508 j := 0;
1510 if gPlayers[j] <> nil then
1511 if gPlayers[j].Live and
1512 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1513 begin
1514 if gPlayers[j].GetFlag(a) then
1515 Break;
1516 end;
1517 end;
1518 end;
1519 end;
1520 end;
1521 end;
1523 procedure g_Map_DrawPanels(PanelType: Word);
1525 procedure DrawPanels(var panels: TPanelArray;
1526 drawDoors: Boolean = False);
1527 var
1528 a: Integer;
1530 begin
1531 if panels <> nil then
1532 for a := 0 to High(panels) do
1533 if not (drawDoors xor panels[a].Door) then
1534 panels[a].Draw();
1535 end;
1537 begin
1538 case PanelType of
1539 PANEL_WALL: DrawPanels(gWalls);
1540 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1541 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1542 PANEL_FORE: DrawPanels(gRenderForegrounds);
1543 PANEL_WATER: DrawPanels(gWater);
1544 PANEL_ACID1: DrawPanels(gAcid1);
1545 PANEL_ACID2: DrawPanels(gAcid2);
1546 PANEL_STEP: DrawPanels(gSteps);
1547 end;
1548 end;
1550 procedure g_Map_DrawBack(dx, dy: Integer);
1551 begin
1552 if gDrawBackGround and (BackID <> DWORD(-1)) then
1553 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1554 else
1555 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1556 end;
1558 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1559 PanelType: Word; b1x3: Boolean): Boolean;
1560 var
1561 a, h: Integer;
1562 begin
1563 Result := False;
1565 if WordBool(PanelType and PANEL_WALL) then
1566 if gWalls <> nil then
1567 begin
1568 h := High(gWalls);
1570 for a := 0 to h do
1571 if gWalls[a].Enabled and
1572 g_Collide(X, Y, Width, Height,
1573 gWalls[a].X, gWalls[a].Y,
1574 gWalls[a].Width, gWalls[a].Height) then
1575 begin
1576 Result := True;
1577 Exit;
1578 end;
1579 end;
1581 if WordBool(PanelType and PANEL_WATER) then
1582 if gWater <> nil then
1583 begin
1584 h := High(gWater);
1586 for a := 0 to h do
1587 if g_Collide(X, Y, Width, Height,
1588 gWater[a].X, gWater[a].Y,
1589 gWater[a].Width, gWater[a].Height) then
1590 begin
1591 Result := True;
1592 Exit;
1593 end;
1594 end;
1596 if WordBool(PanelType and PANEL_ACID1) then
1597 if gAcid1 <> nil then
1598 begin
1599 h := High(gAcid1);
1601 for a := 0 to h do
1602 if g_Collide(X, Y, Width, Height,
1603 gAcid1[a].X, gAcid1[a].Y,
1604 gAcid1[a].Width, gAcid1[a].Height) then
1605 begin
1606 Result := True;
1607 Exit;
1608 end;
1609 end;
1611 if WordBool(PanelType and PANEL_ACID2) then
1612 if gAcid2 <> nil then
1613 begin
1614 h := High(gAcid2);
1616 for a := 0 to h do
1617 if g_Collide(X, Y, Width, Height,
1618 gAcid2[a].X, gAcid2[a].Y,
1619 gAcid2[a].Width, gAcid2[a].Height) then
1620 begin
1621 Result := True;
1622 Exit;
1623 end;
1624 end;
1626 if WordBool(PanelType and PANEL_STEP) then
1627 if gSteps <> nil then
1628 begin
1629 h := High(gSteps);
1631 for a := 0 to h do
1632 if g_Collide(X, Y, Width, Height,
1633 gSteps[a].X, gSteps[a].Y,
1634 gSteps[a].Width, gSteps[a].Height) then
1635 begin
1636 Result := True;
1637 Exit;
1638 end;
1639 end;
1641 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1642 if gLifts <> nil then
1643 begin
1644 h := High(gLifts);
1646 for a := 0 to h do
1647 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1648 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1649 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1650 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1651 g_Collide(X, Y, Width, Height,
1652 gLifts[a].X, gLifts[a].Y,
1653 gLifts[a].Width, gLifts[a].Height) then
1654 begin
1655 Result := True;
1656 Exit;
1657 end;
1658 end;
1660 if WordBool(PanelType and PANEL_BLOCKMON) then
1661 if gBlockMon <> nil then
1662 begin
1663 h := High(gBlockMon);
1665 for a := 0 to h do
1666 if ( (not b1x3) or
1667 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1668 g_Collide(X, Y, Width, Height,
1669 gBlockMon[a].X, gBlockMon[a].Y,
1670 gBlockMon[a].Width, gBlockMon[a].Height) then
1671 begin
1672 Result := True;
1673 Exit;
1674 end;
1675 end;
1676 end;
1678 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1679 var
1680 a, h: Integer;
1681 begin
1682 Result := TEXTURE_NONE;
1684 if gWater <> nil then
1685 begin
1686 h := High(gWater);
1688 for a := 0 to h do
1689 if g_Collide(X, Y, Width, Height,
1690 gWater[a].X, gWater[a].Y,
1691 gWater[a].Width, gWater[a].Height) then
1692 begin
1693 Result := gWater[a].GetTextureID();
1694 Exit;
1695 end;
1696 end;
1698 if gAcid1 <> nil then
1699 begin
1700 h := High(gAcid1);
1702 for a := 0 to h do
1703 if g_Collide(X, Y, Width, Height,
1704 gAcid1[a].X, gAcid1[a].Y,
1705 gAcid1[a].Width, gAcid1[a].Height) then
1706 begin
1707 Result := gAcid1[a].GetTextureID();
1708 Exit;
1709 end;
1710 end;
1712 if gAcid2 <> nil then
1713 begin
1714 h := High(gAcid2);
1716 for a := 0 to h do
1717 if g_Collide(X, Y, Width, Height,
1718 gAcid2[a].X, gAcid2[a].Y,
1719 gAcid2[a].Width, gAcid2[a].Height) then
1720 begin
1721 Result := gAcid2[a].GetTextureID();
1722 Exit;
1723 end;
1724 end;
1725 end;
1727 procedure g_Map_EnableWall(ID: DWORD);
1728 begin
1729 with gWalls[ID] do
1730 begin
1731 Enabled := True;
1732 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1734 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1735 end;
1736 end;
1738 procedure g_Map_DisableWall(ID: DWORD);
1739 begin
1740 with gWalls[ID] do
1741 begin
1742 Enabled := False;
1743 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1745 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1746 end;
1747 end;
1749 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1750 var
1751 tp: TPanel;
1752 begin
1753 case PanelType of
1754 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1755 tp := gWalls[ID];
1756 PANEL_FORE:
1757 tp := gRenderForegrounds[ID];
1758 PANEL_BACK:
1759 tp := gRenderBackgrounds[ID];
1760 PANEL_WATER:
1761 tp := gWater[ID];
1762 PANEL_ACID1:
1763 tp := gAcid1[ID];
1764 PANEL_ACID2:
1765 tp := gAcid2[ID];
1766 PANEL_STEP:
1767 tp := gSteps[ID];
1768 else
1769 Exit;
1770 end;
1772 tp.NextTexture(AnimLoop);
1773 if g_Game_IsServer and g_Game_IsNet then
1774 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1775 end;
1777 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1778 begin
1779 if gLifts[ID].LiftType = t then
1780 Exit;
1782 with gLifts[ID] do
1783 begin
1784 LiftType := t;
1786 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1788 if LiftType = 0 then
1789 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1790 else if LiftType = 1 then
1791 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1792 else if LiftType = 2 then
1793 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1794 else if LiftType = 3 then
1795 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1797 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1798 end;
1799 end;
1801 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1802 var
1803 a: Integer;
1804 PointsArray: Array of TRespawnPoint;
1805 begin
1806 Result := False;
1807 SetLength(PointsArray, 0);
1809 if RespawnPoints = nil then
1810 Exit;
1812 for a := 0 to High(RespawnPoints) do
1813 if RespawnPoints[a].PointType = PointType then
1814 begin
1815 SetLength(PointsArray, Length(PointsArray)+1);
1816 PointsArray[High(PointsArray)] := RespawnPoints[a];
1817 end;
1819 if PointsArray = nil then
1820 Exit;
1822 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1823 Result := True;
1824 end;
1826 function g_Map_GetPointCount(PointType: Byte): Word;
1827 var
1828 a: Integer;
1829 begin
1830 Result := 0;
1832 if RespawnPoints = nil then
1833 Exit;
1835 for a := 0 to High(RespawnPoints) do
1836 if RespawnPoints[a].PointType = PointType then
1837 Result := Result + 1;
1838 end;
1840 function g_Map_HaveFlagPoints(): Boolean;
1841 begin
1842 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1843 end;
1845 procedure g_Map_ResetFlag(Flag: Byte);
1846 begin
1847 with gFlags[Flag] do
1848 begin
1849 Obj.X := -1000;
1850 Obj.Y := -1000;
1851 Obj.Vel.X := 0;
1852 Obj.Vel.Y := 0;
1853 Direction := D_LEFT;
1854 State := FLAG_STATE_NONE;
1855 if FlagPoints[Flag] <> nil then
1856 begin
1857 Obj.X := FlagPoints[Flag]^.X;
1858 Obj.Y := FlagPoints[Flag]^.Y;
1859 Direction := FlagPoints[Flag]^.Direction;
1860 State := FLAG_STATE_NORMAL;
1861 end;
1862 Count := -1;
1863 end;
1864 end;
1866 procedure g_Map_DrawFlags();
1867 var
1868 i, dx: Integer;
1869 Mirror: TMirrorType;
1870 begin
1871 if gGameSettings.GameMode <> GM_CTF then
1872 Exit;
1874 for i := FLAG_RED to FLAG_BLUE do
1875 with gFlags[i] do
1876 if State <> FLAG_STATE_CAPTURED then
1877 begin
1878 if State = FLAG_STATE_NONE then
1879 continue;
1881 if Direction = D_LEFT then
1882 begin
1883 Mirror := M_HORIZONTAL;
1884 dx := -1;
1885 end
1886 else
1887 begin
1888 Mirror := M_NONE;
1889 dx := 1;
1890 end;
1892 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
1894 if g_debug_Frames then
1895 begin
1896 e_DrawQuad(Obj.X+Obj.Rect.X,
1897 Obj.Y+Obj.Rect.Y,
1898 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
1899 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
1900 0, 255, 0);
1901 end;
1902 end;
1903 end;
1905 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
1906 var
1907 dw: DWORD;
1908 b: Byte;
1909 str: String;
1910 boo: Boolean;
1912 procedure SavePanelArray(var panels: TPanelArray);
1913 var
1914 PAMem: TBinMemoryWriter;
1915 i: Integer;
1916 begin
1917 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
1918 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
1920 i := 0;
1921 while i < Length(panels) do
1922 begin
1923 if panels[i].SaveIt then
1924 begin
1925 // ID ïàíåëè:
1926 PAMem.WriteInt(i);
1927 // Ñîõðàíÿåì ïàíåëü:
1928 panels[i].SaveState(PAMem);
1929 end;
1930 Inc(i);
1931 end;
1933 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
1934 PAMem.SaveToMemory(Mem);
1935 PAMem.Free();
1936 end;
1938 procedure SaveFlag(flag: PFlag);
1939 begin
1940 // Ñèãíàòóðà ôëàãà:
1941 dw := FLAG_SIGNATURE; // 'FLAG'
1942 Mem.WriteDWORD(dw);
1943 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
1944 Mem.WriteByte(flag^.RespawnType);
1945 // Ñîñòîÿíèå ôëàãà:
1946 Mem.WriteByte(flag^.State);
1947 // Íàïðàâëåíèå ôëàãà:
1948 if flag^.Direction = D_LEFT then
1949 b := 1
1950 else // D_RIGHT
1951 b := 2;
1952 Mem.WriteByte(b);
1953 // Îáúåêò ôëàãà:
1954 Obj_SaveState(@flag^.Obj, Mem);
1955 end;
1957 begin
1958 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
1960 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
1961 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
1962 SavePanelArray(gWalls);
1963 // Ñîõðàíÿåì ïàíåëè ôîíà:
1964 SavePanelArray(gRenderBackgrounds);
1965 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
1966 SavePanelArray(gRenderForegrounds);
1967 // Ñîõðàíÿåì ïàíåëè âîäû:
1968 SavePanelArray(gWater);
1969 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
1970 SavePanelArray(gAcid1);
1971 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
1972 SavePanelArray(gAcid2);
1973 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
1974 SavePanelArray(gSteps);
1975 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
1976 SavePanelArray(gLifts);
1977 ///// /////
1979 ///// Ñîõðàíÿåì ìóçûêó: /////
1980 // Ñèãíàòóðà ìóçûêè:
1981 dw := MUSIC_SIGNATURE; // 'MUSI'
1982 Mem.WriteDWORD(dw);
1983 // Íàçâàíèå ìóçûêè:
1984 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
1985 if gMusic.NoMusic then
1986 str := ''
1987 else
1988 str := gMusic.Name;
1989 Mem.WriteString(str, 64);
1990 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
1991 dw := gMusic.GetPosition();
1992 Mem.WriteDWORD(dw);
1993 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
1994 boo := gMusic.SpecPause;
1995 Mem.WriteBoolean(boo);
1996 ///// /////
1998 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
1999 Mem.WriteInt(gTotalMonsters);
2000 ///// /////
2002 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2003 if gGameSettings.GameMode = GM_CTF then
2004 begin
2005 // Ôëàã Êðàñíîé êîìàíäû:
2006 SaveFlag(@gFlags[FLAG_RED]);
2007 // Ôëàã Ñèíåé êîìàíäû:
2008 SaveFlag(@gFlags[FLAG_BLUE]);
2009 end;
2010 ///// /////
2012 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2013 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2014 begin
2015 // Î÷êè Êðàñíîé êîìàíäû:
2016 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2017 // Î÷êè Ñèíåé êîìàíäû:
2018 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2019 end;
2020 ///// /////
2021 end;
2023 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2024 var
2025 dw: DWORD;
2026 b: Byte;
2027 str: String;
2028 boo: Boolean;
2030 procedure LoadPanelArray(var panels: TPanelArray);
2031 var
2032 PAMem: TBinMemoryReader;
2033 i, id: Integer;
2034 begin
2035 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2036 PAMem := TBinMemoryReader.Create();
2037 PAMem.LoadFromMemory(Mem);
2039 for i := 0 to Length(panels)-1 do
2040 if panels[i].SaveIt then
2041 begin
2042 // ID ïàíåëè:
2043 PAMem.ReadInt(id);
2044 if id <> i then
2045 begin
2046 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2047 end;
2048 // Çàãðóæàåì ïàíåëü:
2049 panels[i].LoadState(PAMem);
2050 end;
2052 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2053 PAMem.Free();
2054 end;
2056 procedure LoadFlag(flag: PFlag);
2057 begin
2058 // Ñèãíàòóðà ôëàãà:
2059 Mem.ReadDWORD(dw);
2060 if dw <> FLAG_SIGNATURE then // 'FLAG'
2061 begin
2062 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2063 end;
2064 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2065 Mem.ReadByte(flag^.RespawnType);
2066 // Ñîñòîÿíèå ôëàãà:
2067 Mem.ReadByte(flag^.State);
2068 // Íàïðàâëåíèå ôëàãà:
2069 Mem.ReadByte(b);
2070 if b = 1 then
2071 flag^.Direction := D_LEFT
2072 else // b = 2
2073 flag^.Direction := D_RIGHT;
2074 // Îáúåêò ôëàãà:
2075 Obj_LoadState(@flag^.Obj, Mem);
2076 end;
2078 begin
2079 if Mem = nil then
2080 Exit;
2082 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2083 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2084 LoadPanelArray(gWalls);
2085 // Çàãðóæàåì ïàíåëè ôîíà:
2086 LoadPanelArray(gRenderBackgrounds);
2087 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2088 LoadPanelArray(gRenderForegrounds);
2089 // Çàãðóæàåì ïàíåëè âîäû:
2090 LoadPanelArray(gWater);
2091 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2092 LoadPanelArray(gAcid1);
2093 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2094 LoadPanelArray(gAcid2);
2095 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2096 LoadPanelArray(gSteps);
2097 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2098 LoadPanelArray(gLifts);
2099 ///// /////
2101 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2102 g_GFX_Init();
2104 ///// Çàãðóæàåì ìóçûêó: /////
2105 // Ñèãíàòóðà ìóçûêè:
2106 Mem.ReadDWORD(dw);
2107 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2108 begin
2109 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2110 end;
2111 // Íàçâàíèå ìóçûêè:
2112 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2113 Mem.ReadString(str);
2114 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2115 Mem.ReadDWORD(dw);
2116 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2117 Mem.ReadBoolean(boo);
2118 // Çàïóñêàåì ýòó ìóçûêó:
2119 gMusic.SetByName(str);
2120 gMusic.SpecPause := boo;
2121 gMusic.Play();
2122 gMusic.Pause(True);
2123 gMusic.SetPosition(dw);
2124 ///// /////
2126 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2127 Mem.ReadInt(gTotalMonsters);
2128 ///// /////
2130 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2131 if gGameSettings.GameMode = GM_CTF then
2132 begin
2133 // Ôëàã Êðàñíîé êîìàíäû:
2134 LoadFlag(@gFlags[FLAG_RED]);
2135 // Ôëàã Ñèíåé êîìàíäû:
2136 LoadFlag(@gFlags[FLAG_BLUE]);
2137 end;
2138 ///// /////
2140 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2141 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2142 begin
2143 // Î÷êè Êðàñíîé êîìàíäû:
2144 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2145 // Î÷êè Ñèíåé êîìàíäû:
2146 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2147 end;
2148 ///// /////
2149 end;
2151 end.