DEADSOFTWARE

animated textures loader simplified alot
[d2df-sdl.git] / src / game / g_map.pas
1 {$MODE DELPHI}
2 unit g_map;
4 interface
6 uses
7 e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
8 g_phys, wadreader, BinEditor, g_panel, md5;
10 type
11 TMapInfo = record
12 Map: String;
13 Name: String;
14 Description: String;
15 Author: String;
16 MusicName: String;
17 SkyName: String;
18 Height: Word;
19 Width: Word;
20 end;
22 PRespawnPoint = ^TRespawnPoint;
23 TRespawnPoint = record
24 X, Y: Integer;
25 Direction: TDirection;
26 PointType: Byte;
27 end;
29 PFlagPoint = ^TFlagPoint;
30 TFlagPoint = TRespawnPoint;
32 PFlag = ^TFlag;
33 TFlag = record
34 Obj: TObj;
35 RespawnType: Byte;
36 State: Byte;
37 Count: Integer;
38 CaptureTime: LongWord;
39 Animation: TAnimation;
40 Direction: TDirection;
41 end;
44 function g_Map_Load(Res: String): Boolean;
45 function g_Map_GetMapInfo(Res: String): TMapInfo;
46 function g_Map_GetMapsList(WADName: String): SArray;
47 function g_Map_Exist(Res: String): Boolean;
48 procedure g_Map_Free();
49 procedure g_Map_Update();
50 procedure g_Map_DrawPanels(PanelType: Word);
51 procedure g_Map_DrawBack(dx, dy: Integer);
52 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
53 PanelType: Word; b1x3: Boolean): Boolean;
54 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
55 procedure g_Map_EnableWall(ID: DWORD);
56 procedure g_Map_DisableWall(ID: DWORD);
57 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
58 procedure g_Map_SetLift(ID: DWORD; t: Integer);
59 procedure g_Map_ReAdd_DieTriggers();
60 function g_Map_IsSpecialTexture(Texture: String): Boolean;
62 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
63 function g_Map_GetPointCount(PointType: Byte): Word;
65 function g_Map_HaveFlagPoints(): Boolean;
67 procedure g_Map_ResetFlag(Flag: Byte);
68 procedure g_Map_DrawFlags();
70 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
71 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
73 const
74 RESPAWNPOINT_PLAYER1 = 1;
75 RESPAWNPOINT_PLAYER2 = 2;
76 RESPAWNPOINT_DM = 3;
77 RESPAWNPOINT_RED = 4;
78 RESPAWNPOINT_BLUE = 5;
80 FLAG_NONE = 0;
81 FLAG_RED = 1;
82 FLAG_BLUE = 2;
83 FLAG_DOM = 3;
85 FLAG_STATE_NONE = 0;
86 FLAG_STATE_NORMAL = 1;
87 FLAG_STATE_DROPPED = 2;
88 FLAG_STATE_CAPTURED = 3;
89 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
90 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
92 FLAG_TIME = 720; // 20 seconds
94 SKY_STRETCH: Single = 1.5;
96 var
97 gWalls: TPanelArray;
98 gRenderBackgrounds: TPanelArray;
99 gRenderForegrounds: TPanelArray;
100 gWater, gAcid1, gAcid2: TPanelArray;
101 gSteps: TPanelArray;
102 gLifts: TPanelArray;
103 gBlockMon: TPanelArray;
104 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
105 //gDOMFlags: array of TFlag;
106 gMapInfo: TMapInfo;
107 gBackSize: TPoint;
108 gDoorMap: array of array of DWORD;
109 gLiftMap: array of array of DWORD;
110 gWADHash: TMD5Digest;
111 BackID: DWORD = DWORD(-1);
112 gExternalResources: TStringList;
114 implementation
116 uses
117 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
118 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
119 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
120 Math, g_monsters, g_saveload, g_language, g_netmsg,
121 utils, sfs,
122 ImagingTypes, Imaging, ImagingUtility,
123 ImagingGif, ImagingNetworkGraphics;
125 const
126 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
127 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
128 FLAG_SIGNATURE = $47414C46; // 'FLAG'
130 var
131 Textures: TLevelTextureArray;
132 RespawnPoints: Array of TRespawnPoint;
133 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
134 //DOMFlagPoints: Array of TFlagPoint;
137 function g_Map_IsSpecialTexture(Texture: String): Boolean;
138 begin
139 Result := (Texture = TEXTURE_NAME_WATER) or
140 (Texture = TEXTURE_NAME_ACID1) or
141 (Texture = TEXTURE_NAME_ACID2);
142 end;
144 procedure CreateDoorMap();
145 var
146 PanelArray: Array of record
147 X, Y: Integer;
148 Width, Height: Word;
149 Active: Boolean;
150 PanelID: DWORD;
151 end;
152 a, b, c, m, i, len: Integer;
153 ok: Boolean;
154 begin
155 if gWalls = nil then
156 Exit;
158 i := 0;
159 len := 128;
160 SetLength(PanelArray, len);
162 for a := 0 to High(gWalls) do
163 if gWalls[a].Door then
164 begin
165 PanelArray[i].X := gWalls[a].X;
166 PanelArray[i].Y := gWalls[a].Y;
167 PanelArray[i].Width := gWalls[a].Width;
168 PanelArray[i].Height := gWalls[a].Height;
169 PanelArray[i].Active := True;
170 PanelArray[i].PanelID := a;
172 i := i + 1;
173 if i = len then
174 begin
175 len := len + 128;
176 SetLength(PanelArray, len);
177 end;
178 end;
180 // Íåò äâåðåé:
181 if i = 0 then
182 begin
183 PanelArray := nil;
184 Exit;
185 end;
187 SetLength(gDoorMap, 0);
189 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
191 for a := 0 to i-1 do
192 if PanelArray[a].Active then
193 begin
194 PanelArray[a].Active := False;
195 m := Length(gDoorMap);
196 SetLength(gDoorMap, m+1);
197 SetLength(gDoorMap[m], 1);
198 gDoorMap[m, 0] := PanelArray[a].PanelID;
199 ok := True;
201 while ok do
202 begin
203 ok := False;
205 for b := 0 to i-1 do
206 if PanelArray[b].Active then
207 for c := 0 to High(gDoorMap[m]) do
208 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
209 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
210 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
211 PanelArray[b].Width, PanelArray[b].Height,
212 gWalls[gDoorMap[m, c]].X,
213 gWalls[gDoorMap[m, c]].Y,
214 gWalls[gDoorMap[m, c]].Width,
215 gWalls[gDoorMap[m, c]].Height) then
216 begin
217 PanelArray[b].Active := False;
218 SetLength(gDoorMap[m],
219 Length(gDoorMap[m])+1);
220 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
221 ok := True;
222 Break;
223 end;
224 end;
226 g_Game_StepLoading();
227 end;
229 PanelArray := nil;
230 end;
232 procedure CreateLiftMap();
233 var
234 PanelArray: Array of record
235 X, Y: Integer;
236 Width, Height: Word;
237 Active: Boolean;
238 end;
239 a, b, c, len, i, j: Integer;
240 ok: Boolean;
241 begin
242 if gLifts = nil then
243 Exit;
245 len := Length(gLifts);
246 SetLength(PanelArray, len);
248 for a := 0 to len-1 do
249 begin
250 PanelArray[a].X := gLifts[a].X;
251 PanelArray[a].Y := gLifts[a].Y;
252 PanelArray[a].Width := gLifts[a].Width;
253 PanelArray[a].Height := gLifts[a].Height;
254 PanelArray[a].Active := True;
255 end;
257 SetLength(gLiftMap, len);
258 i := 0;
260 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
262 for a := 0 to len-1 do
263 if PanelArray[a].Active then
264 begin
265 PanelArray[a].Active := False;
266 SetLength(gLiftMap[i], 32);
267 j := 0;
268 gLiftMap[i, j] := a;
269 ok := True;
271 while ok do
272 begin
273 ok := False;
274 for b := 0 to len-1 do
275 if PanelArray[b].Active then
276 for c := 0 to j do
277 if g_CollideAround(PanelArray[b].X,
278 PanelArray[b].Y,
279 PanelArray[b].Width,
280 PanelArray[b].Height,
281 PanelArray[gLiftMap[i, c]].X,
282 PanelArray[gLiftMap[i, c]].Y,
283 PanelArray[gLiftMap[i, c]].Width,
284 PanelArray[gLiftMap[i, c]].Height) then
285 begin
286 PanelArray[b].Active := False;
287 j := j+1;
288 if j > High(gLiftMap[i]) then
289 SetLength(gLiftMap[i],
290 Length(gLiftMap[i])+32);
292 gLiftMap[i, j] := b;
293 ok := True;
295 Break;
296 end;
297 end;
299 SetLength(gLiftMap[i], j+1);
300 i := i+1;
302 g_Game_StepLoading();
303 end;
305 SetLength(gLiftMap, i);
307 PanelArray := nil;
308 end;
310 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
311 CurTex: Integer; sav: Boolean): Integer;
312 var
313 len: Integer;
314 panels: ^TPanelArray;
315 begin
316 Result := -1;
318 case PanelRec.PanelType of
319 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
320 panels := @gWalls;
321 PANEL_BACK:
322 panels := @gRenderBackgrounds;
323 PANEL_FORE:
324 panels := @gRenderForegrounds;
325 PANEL_WATER:
326 panels := @gWater;
327 PANEL_ACID1:
328 panels := @gAcid1;
329 PANEL_ACID2:
330 panels := @gAcid2;
331 PANEL_STEP:
332 panels := @gSteps;
333 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
334 panels := @gLifts;
335 PANEL_BLOCKMON:
336 panels := @gBlockMon;
337 else
338 Exit;
339 end;
341 len := Length(panels^);
342 SetLength(panels^, len + 1);
344 panels^[len] := TPanel.Create(PanelRec, AddTextures,
345 CurTex, Textures);
346 if sav then
347 panels^[len].SaveIt := True;
349 Result := len;
350 end;
352 function CreateNullTexture(RecName: String): Integer;
353 begin
354 SetLength(Textures, Length(Textures)+1);
355 result := High(Textures);
357 with Textures[High(Textures)] do
358 begin
359 TextureName := RecName;
360 Width := 1;
361 Height := 1;
362 Anim := False;
363 TextureID := TEXTURE_NONE;
364 end;
365 end;
367 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
368 var
369 WAD: TWADFile;
370 TextureData: Pointer;
371 WADName, txname: String;
372 a, ResLength: Integer;
373 begin
374 Result := -1;
376 if Textures <> nil then
377 for a := 0 to High(Textures) do
378 if Textures[a].TextureName = RecName then
379 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
380 Result := a;
381 Exit;
382 end;
384 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
385 if (RecName = TEXTURE_NAME_WATER) or
386 (RecName = TEXTURE_NAME_ACID1) or
387 (RecName = TEXTURE_NAME_ACID2) then
388 begin
389 SetLength(Textures, Length(Textures)+1);
391 with Textures[High(Textures)] do
392 begin
393 TextureName := RecName;
395 if TextureName = TEXTURE_NAME_WATER then
396 TextureID := TEXTURE_SPECIAL_WATER
397 else
398 if TextureName = TEXTURE_NAME_ACID1 then
399 TextureID := TEXTURE_SPECIAL_ACID1
400 else
401 if TextureName = TEXTURE_NAME_ACID2 then
402 TextureID := TEXTURE_SPECIAL_ACID2;
404 Anim := False;
405 end;
407 result := High(Textures);
408 Exit;
409 end;
411 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
412 WADName := g_ExtractWadName(RecName);
414 WAD := TWADFile.Create();
416 if WADName <> '' then
417 WADName := GameDir+'/wads/'+WADName
418 else
419 WADName := Map;
421 WAD.ReadFile(WADName);
423 txname := RecName;
425 if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
426 begin
427 FreeMem(TextureData);
428 RecName := 'COMMON\ALIEN';
429 end;
432 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
433 begin
434 SetLength(Textures, Length(Textures)+1);
435 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
436 Exit;
437 e_GetTextureSize(Textures[High(Textures)].TextureID,
438 @Textures[High(Textures)].Width,
439 @Textures[High(Textures)].Height);
440 FreeMem(TextureData);
441 Textures[High(Textures)].TextureName := {RecName}txname;
442 Textures[High(Textures)].Anim := False;
444 result := High(Textures);
445 end
446 else // Íåò òàêîãî ðåóñðñà â WAD'å
447 begin
448 //e_WriteLog(Format('SHIT! Error loading texture %s : %s : %s', [RecName, txname, g_ExtractFilePathName(RecName)]), MSG_WARNING);
449 if log then
450 begin
451 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
452 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
453 end;
454 end;
456 WAD.Free();
457 end;
459 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
460 var
461 WAD: TWADFile;
462 TextureWAD: PChar = nil;
463 ttw: PChar = nil;
464 TextData: Pointer = nil;
465 TextureData: Pointer = nil;
466 cfg: TConfig = nil;
467 WADName: String;
468 ResLength, rrl: Integer;
469 TextureResource: String;
470 _width, _height, _framecount, _speed: Integer;
471 _backanimation: Boolean;
472 //imgfmt: string;
473 ia: TDynImageDataArray = nil;
474 f, c, frdelay, frloop: Integer;
475 begin
476 result := -1;
478 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
480 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
481 WADName := g_ExtractWadName(RecName);
483 WAD := TWADFile.Create();
484 try
485 if WADName <> '' then
486 WADName := GameDir+'/wads/'+WADName
487 else
488 WADName := Map;
490 WAD.ReadFile(WADName);
492 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
493 begin
494 if log then
495 begin
496 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
497 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
498 end;
499 exit;
500 end;
502 {TEST
503 if WADName = Map then
504 begin
505 //FreeMem(TextureWAD);
506 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
507 end;
510 WAD.FreeWAD();
512 if ResLength < 6 then
513 begin
514 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
515 exit;
516 end;
518 // ýòî ïòèöà? ýòî ñàìîë¸ò?
519 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
520 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
521 begin
522 // íåò, ýòî ñóïåðìåí!
523 if not WAD.ReadMemory(TextureWAD, ResLength) then
524 begin
525 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
526 exit;
527 end;
529 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
530 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
531 begin
532 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
533 exit;
534 end;
536 cfg := TConfig.CreateMem(TextData, ResLength);
538 TextureResource := cfg.ReadStr('', 'resource', '');
539 if TextureResource = '' then
540 begin
541 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
542 exit;
543 end;
545 _width := cfg.ReadInt('', 'framewidth', 0);
546 _height := cfg.ReadInt('', 'frameheight', 0);
547 _framecount := cfg.ReadInt('', 'framecount', 0);
548 _speed := cfg.ReadInt('', 'waitcount', 0);
549 _backanimation := cfg.ReadBool('', 'backanimation', False);
551 cfg.Free();
552 cfg := nil;
554 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
555 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
556 begin
557 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
558 exit;
559 end;
561 WAD.Free();
562 WAD := nil;
564 SetLength(Textures, Length(Textures)+1);
565 with Textures[High(Textures)] do
566 begin
567 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
568 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
569 begin
570 TextureName := RecName;
571 Width := _width;
572 Height := _height;
573 Anim := True;
574 FramesCount := _framecount;
575 Speed := _speed;
576 result := High(Textures);
577 end
578 else
579 begin
580 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
581 end;
582 end;
583 end
584 else
585 begin
586 // try animated image
588 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
589 if length(imgfmt) = 0 then
590 begin
591 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
592 exit;
593 end;
595 GlobalMetadata.ClearMetaItems();
596 GlobalMetadata.ClearMetaItemsForSaving();
597 if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
598 begin
599 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
600 exit;
601 end;
602 if length(ia) = 0 then
603 begin
604 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
605 exit;
606 end;
608 WAD.Free();
609 WAD := nil;
611 _width := ia[0].width;
612 _height := ia[0].height;
613 _framecount := length(ia);
614 _speed := 1;
615 _backanimation := false;
616 frdelay := -1;
617 frloop := -666;
618 if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then
619 begin
620 //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]);
621 try
622 f := GlobalMetadata.MetaItems[SMetaFrameDelay];
623 frdelay := f;
624 if f < 0 then f := 0;
625 // rounding ;-)
626 c := f mod 28;
627 if c < 13 then c := 0 else c := 1;
628 f := (f div 28)+c;
629 if f < 1 then f := 1 else if f > 255 then f := 255;
630 _speed := f;
631 except
632 end;
633 end;
634 if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then
635 begin
636 //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]);
637 try
638 f := GlobalMetadata.MetaItems[SMetaAnimationLoops];
639 frloop := f;
640 if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back
641 except
642 end;
643 end;
644 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
645 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
646 f := ord(_backanimation);
647 e_WriteLog(Format('Animated texture file "%s": %d frames (delay:%d; back:%d; frdelay:%d; frloop:%d), %dx%d', [RecName, length(ia), _speed, f, frdelay, frloop, _width, _height]), MSG_NOTIFY);
649 SetLength(Textures, Length(Textures)+1);
650 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
651 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
652 begin
653 Textures[High(Textures)].TextureName := RecName;
654 Textures[High(Textures)].Width := _width;
655 Textures[High(Textures)].Height := _height;
656 Textures[High(Textures)].Anim := True;
657 Textures[High(Textures)].FramesCount := length(ia);
658 Textures[High(Textures)].Speed := _speed;
659 result := High(Textures);
660 //writeln(' CREATED!');
661 end
662 else
663 begin
664 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
665 end;
666 end;
667 finally
668 for f := 0 to High(ia) do FreeImage(ia[f]);
669 WAD.Free();
670 cfg.Free();
671 if TextureWAD <> nil then FreeMem(TextureWAD);
672 if TextData <> nil then FreeMem(TextData);
673 if TextureData <> nil then FreeMem(TextureData);
674 end;
675 end;
677 procedure CreateItem(Item: TItemRec_1);
678 begin
679 if g_Game_IsClient then Exit;
681 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
682 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
683 Exit;
685 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
686 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
687 end;
689 procedure CreateArea(Area: TAreaRec_1);
690 var
691 a: Integer;
692 id: DWORD;
693 begin
694 case Area.AreaType of
695 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
696 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
697 begin
698 SetLength(RespawnPoints, Length(RespawnPoints)+1);
699 with RespawnPoints[High(RespawnPoints)] do
700 begin
701 X := Area.X;
702 Y := Area.Y;
703 Direction := TDirection(Area.Direction);
705 case Area.AreaType of
706 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
707 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
708 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
709 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
710 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
711 end;
712 end;
713 end;
715 AREA_REDFLAG, AREA_BLUEFLAG:
716 begin
717 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
719 if FlagPoints[a] <> nil then Exit;
721 New(FlagPoints[a]);
723 with FlagPoints[a]^ do
724 begin
725 X := Area.X-FLAGRECT.X;
726 Y := Area.Y-FLAGRECT.Y;
727 Direction := TDirection(Area.Direction);
728 end;
730 with gFlags[a] do
731 begin
732 case a of
733 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
734 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
735 end;
737 Animation := TAnimation.Create(id, True, 8);
738 Obj.Rect := FLAGRECT;
740 g_Map_ResetFlag(a);
741 end;
742 end;
744 AREA_DOMFLAG:
745 begin
746 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
747 with DOMFlagPoints[High(DOMFlagPoints)] do
748 begin
749 X := Area.X;
750 Y := Area.Y;
751 Direction := TDirection(Area.Direction);
752 end;
754 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
755 end;
756 end;
757 end;
759 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
760 var
761 _trigger: TTrigger;
762 begin
763 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
765 with _trigger do
766 begin
767 X := Trigger.X;
768 Y := Trigger.Y;
769 Width := Trigger.Width;
770 Height := Trigger.Height;
771 Enabled := ByteBool(Trigger.Enabled);
772 TexturePanel := Trigger.TexturePanel;
773 TexturePanelType := fTexturePanel1Type;
774 ShotPanelType := fTexturePanel2Type;
775 TriggerType := Trigger.TriggerType;
776 ActivateType := Trigger.ActivateType;
777 Keys := Trigger.Keys;
778 Data.Default := Trigger.DATA;
779 end;
781 g_Triggers_Create(_trigger);
782 end;
784 procedure CreateMonster(monster: TMonsterRec_1);
785 var
786 a, i: Integer;
787 begin
788 if g_Game_IsClient then Exit;
790 if (gGameSettings.GameType = GT_SINGLE)
791 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
792 begin
793 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
794 TDirection(monster.Direction));
796 if gTriggers <> nil then
797 for a := 0 to High(gTriggers) do
798 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
799 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
800 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
801 gMonsters[i].AddTrigger(a);
803 if monster.MonsterType <> MONSTER_BARREL then
804 Inc(gTotalMonsters);
805 end;
806 end;
808 procedure g_Map_ReAdd_DieTriggers();
809 var
810 i, a: Integer;
811 begin
812 if g_Game_IsClient then Exit;
814 for i := 0 to High(gMonsters) do
815 if gMonsters[i] <> nil then
816 begin
817 gMonsters[i].ClearTriggers();
819 for a := 0 to High(gTriggers) do
820 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
821 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
822 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
823 gMonsters[i].AddTrigger(a);
824 end;
825 end;
827 function extractWadName(resourceName: string): string;
828 var
829 posN: Integer;
830 begin
831 posN := Pos(':', resourceName);
832 if posN > 0 then
833 Result:= Copy(resourceName, 0, posN-1)
834 else
835 Result := '';
836 end;
838 procedure addResToExternalResList(res: string);
839 begin
840 res := extractWadName(res);
841 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
842 gExternalResources.Add(res);
843 end;
845 procedure generateExternalResourcesList(mapReader: TMapReader_1);
846 var
847 textures: TTexturesRec1Array;
848 mapHeader: TMapHeaderRec_1;
849 i: integer;
850 resFile: String = '';
851 begin
852 if gExternalResources = nil then
853 gExternalResources := TStringList.Create;
855 gExternalResources.Clear;
856 textures := mapReader.GetTextures();
857 for i := 0 to High(textures) do
858 begin
859 addResToExternalResList(resFile);
860 end;
862 textures := nil;
864 mapHeader := mapReader.GetMapHeader;
866 addResToExternalResList(mapHeader.MusicName);
867 addResToExternalResList(mapHeader.SkyName);
868 end;
870 function g_Map_Load(Res: String): Boolean;
871 const
872 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
873 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
874 var
875 WAD: TWADFile;
876 MapReader: TMapReader_1;
877 Header: TMapHeaderRec_1;
878 _textures: TTexturesRec1Array;
879 _texnummap: array of Integer; // `_textures` -> `Textures`
880 panels: TPanelsRec1Array;
881 items: TItemsRec1Array;
882 monsters: TMonsterRec1Array;
883 areas: TAreasRec1Array;
884 triggers: TTriggersRec1Array;
885 a, b, c, k: Integer;
886 PanelID: DWORD;
887 AddTextures: TAddTextureArray;
888 texture: TTextureRec_1;
889 TriggersTable: Array of record
890 TexturePanel: Integer;
891 LiftPanel: Integer;
892 DoorPanel: Integer;
893 ShotPanel: Integer;
894 end;
895 FileName, mapResName, s, TexName: String;
896 Data: Pointer;
897 Len: Integer;
898 ok, isAnim, trigRef: Boolean;
899 CurTex, ntn: Integer;
900 begin
901 Result := False;
902 gMapInfo.Map := Res;
903 TriggersTable := nil;
904 FillChar(texture, SizeOf(texture), 0);
906 sfsGCDisable(); // temporary disable removing of temporary volumes
907 try
908 // Çàãðóçêà WAD:
909 FileName := g_ExtractWadName(Res);
910 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
911 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
913 WAD := TWADFile.Create();
914 if not WAD.ReadFile(FileName) then
915 begin
916 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
917 WAD.Free();
918 Exit;
919 end;
920 //k8: why loader ignores path here?
921 mapResName := g_ExtractFileName(Res);
922 if not WAD.GetMapResource(mapResName, Data, Len) then
923 begin
924 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
925 WAD.Free();
926 Exit;
927 end;
928 WAD.Free();
930 // Çàãðóçêà êàðòû:
931 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
932 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
933 MapReader := TMapReader_1.Create();
935 if not MapReader.LoadMap(Data) then
936 begin
937 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
938 FreeMem(Data);
939 MapReader.Free();
940 Exit;
941 end;
943 FreeMem(Data);
944 generateExternalResourcesList(MapReader);
945 // Çàãðóçêà òåêñòóð:
946 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
947 _textures := MapReader.GetTextures();
948 _texnummap := nil;
950 // Äîáàâëåíèå òåêñòóð â Textures[]:
951 if _textures <> nil then
952 begin
953 e_WriteLog(' Loading textures:', MSG_NOTIFY);
954 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
955 SetLength(_texnummap, length(_textures));
957 for a := 0 to High(_textures) do
958 begin
959 SetLength(s, 64);
960 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
961 for b := 1 to Length(s) do
962 if s[b] = #0 then
963 begin
964 SetLength(s, b-1);
965 Break;
966 end;
967 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
968 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
969 // Àíèìèðîâàííàÿ òåêñòóðà:
970 if ByteBool(_textures[a].Anim) then
971 begin
972 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
973 if ntn < 0 then
974 begin
975 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
976 ntn := CreateNullTexture(_textures[a].Resource);
977 end;
978 end
979 else // Îáû÷íàÿ òåêñòóðà:
980 ntn := CreateTexture(_textures[a].Resource, FileName, True);
981 if ntn < 0 then
982 begin
983 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
984 ntn := CreateNullTexture(_textures[a].Resource);
985 end;
987 _texnummap[a] := ntn; // fix texture number
988 g_Game_StepLoading();
989 end;
990 end;
992 // Çàãðóçêà òðèããåðîâ:
993 gTriggerClientID := 0;
994 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
995 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
996 triggers := MapReader.GetTriggers();
998 // Çàãðóçêà ïàíåëåé:
999 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1000 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1001 panels := MapReader.GetPanels();
1003 // check texture numbers for panels
1004 for a := 0 to High(panels) do
1005 begin
1006 if panels[a].TextureNum > High(_textures) then
1007 begin
1008 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1009 result := false;
1010 exit;
1011 end;
1012 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1013 end;
1015 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1016 if triggers <> nil then
1017 begin
1018 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1019 SetLength(TriggersTable, Length(triggers));
1020 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1022 for a := 0 to High(TriggersTable) do
1023 begin
1024 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1025 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1026 // Ëèôòû:
1027 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1028 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1029 else
1030 TriggersTable[a].LiftPanel := -1;
1031 // Äâåðè:
1032 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1033 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1034 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1035 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1036 else
1037 TriggersTable[a].DoorPanel := -1;
1038 // Òóðåëü:
1039 if triggers[a].TriggerType = TRIGGER_SHOT then
1040 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1041 else
1042 TriggersTable[a].ShotPanel := -1;
1044 g_Game_StepLoading();
1045 end;
1046 end;
1048 // Ñîçäàåì ïàíåëè:
1049 if panels <> nil then
1050 begin
1051 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1052 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1054 for a := 0 to High(panels) do
1055 begin
1056 SetLength(AddTextures, 0);
1057 trigRef := False;
1058 CurTex := -1;
1059 if _textures <> nil then
1060 begin
1061 texture := _textures[panels[a].TextureNum];
1062 ok := True;
1063 end
1064 else
1065 ok := False;
1067 if ok then
1068 begin
1069 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1070 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1071 ok := False;
1072 if (TriggersTable <> nil) and (_textures <> nil) then
1073 for b := 0 to High(TriggersTable) do
1074 if (TriggersTable[b].TexturePanel = a)
1075 or (TriggersTable[b].ShotPanel = a) then
1076 begin
1077 trigRef := True;
1078 ok := True;
1079 Break;
1080 end;
1081 end;
1083 if ok then
1084 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1085 SetLength(s, 64);
1086 CopyMemory(@s[1], @texture.Resource[0], 64);
1087 // Èçìåðÿåì äëèíó:
1088 Len := Length(s);
1089 for c := Len downto 1 do
1090 if s[c] <> #0 then
1091 begin
1092 Len := c;
1093 Break;
1094 end;
1095 SetLength(s, Len);
1097 // Ñïåö-òåêñòóðû çàïðåùåíû:
1098 if g_Map_IsSpecialTexture(s) then
1099 ok := False
1100 else
1101 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1102 ok := g_Texture_NumNameFindStart(s);
1104 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1105 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1106 if ok then
1107 begin
1108 k := NNF_NAME_BEFORE;
1109 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1110 while ok or (k = NNF_NAME_BEFORE) or
1111 (k = NNF_NAME_EQUALS) do
1112 begin
1113 k := g_Texture_NumNameFindNext(TexName);
1115 if (k = NNF_NAME_BEFORE) or
1116 (k = NNF_NAME_AFTER) then
1117 begin
1118 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1119 if ByteBool(texture.Anim) then
1120 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1121 isAnim := True;
1122 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1123 if not ok then
1124 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1125 isAnim := False;
1126 ok := CreateTexture(TexName, FileName, False) >= 0;
1127 end;
1128 end
1129 else
1130 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1131 isAnim := False;
1132 ok := CreateTexture(TexName, FileName, False) >= 0;
1133 if not ok then
1134 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1135 isAnim := True;
1136 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1137 end;
1138 end;
1140 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1141 if ok then
1142 begin
1143 for c := 0 to High(Textures) do
1144 if Textures[c].TextureName = TexName then
1145 begin
1146 SetLength(AddTextures, Length(AddTextures)+1);
1147 AddTextures[High(AddTextures)].Texture := c;
1148 AddTextures[High(AddTextures)].Anim := isAnim;
1149 Break;
1150 end;
1151 end;
1152 end
1153 else
1154 if k = NNF_NAME_EQUALS then
1155 begin
1156 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1157 SetLength(AddTextures, Length(AddTextures)+1);
1158 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1159 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1160 CurTex := High(AddTextures);
1161 ok := True;
1162 end
1163 else // NNF_NO_NAME
1164 ok := False;
1165 end; // while ok...
1167 ok := True;
1168 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1169 end; // if ok - ññûëàþòñÿ òðèããåðû
1171 if not ok then
1172 begin
1173 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1174 SetLength(AddTextures, 1);
1175 AddTextures[0].Texture := panels[a].TextureNum;
1176 AddTextures[0].Anim := ByteBool(texture.Anim);
1177 CurTex := 0;
1178 end;
1180 //e_WriteLog(Format('panel #%d: TextureNum=%d; ht=%d; ht1=%d; atl=%d', [a, panels[a].TextureNum, High(_textures), High(Textures), High(AddTextures)]), MSG_NOTIFY);
1182 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1183 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1185 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1186 if TriggersTable <> nil then
1187 for b := 0 to High(TriggersTable) do
1188 begin
1189 // Òðèããåð äâåðè/ëèôòà:
1190 if (TriggersTable[b].LiftPanel = a) or
1191 (TriggersTable[b].DoorPanel = a) then
1192 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1193 // Òðèããåð ñìåíû òåêñòóðû:
1194 if TriggersTable[b].TexturePanel = a then
1195 triggers[b].TexturePanel := PanelID;
1196 // Òðèããåð "Òóðåëü":
1197 if TriggersTable[b].ShotPanel = a then
1198 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1199 end;
1201 g_Game_StepLoading();
1202 end;
1203 end;
1205 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1206 if (triggers <> nil) and not gLoadGameMode then
1207 begin
1208 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1209 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1210 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1211 for a := 0 to High(triggers) do
1212 begin
1213 if triggers[a].TexturePanel <> -1 then
1214 b := panels[TriggersTable[a].TexturePanel].PanelType
1215 else
1216 b := 0;
1217 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1218 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1219 c := panels[TriggersTable[a].ShotPanel].PanelType
1220 else
1221 c := 0;
1222 CreateTrigger(triggers[a], b, c);
1223 end;
1224 end;
1226 // Çàãðóçêà ïðåäìåòîâ:
1227 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1228 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1229 items := MapReader.GetItems();
1231 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1232 if (items <> nil) and not gLoadGameMode then
1233 begin
1234 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1235 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1236 for a := 0 to High(items) do
1237 CreateItem(Items[a]);
1238 end;
1240 // Çàãðóçêà îáëàñòåé:
1241 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1242 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1243 areas := MapReader.GetAreas();
1245 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1246 if areas <> nil then
1247 begin
1248 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1249 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1250 for a := 0 to High(areas) do
1251 CreateArea(areas[a]);
1252 end;
1254 // Çàãðóçêà ìîíñòðîâ:
1255 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1256 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1257 monsters := MapReader.GetMonsters();
1259 gTotalMonsters := 0;
1261 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1262 if (monsters <> nil) and not gLoadGameMode then
1263 begin
1264 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1265 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1266 for a := 0 to High(monsters) do
1267 CreateMonster(monsters[a]);
1268 end;
1270 // Çàãðóçêà îïèñàíèÿ êàðòû:
1271 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1272 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1273 Header := MapReader.GetMapHeader();
1275 MapReader.Free();
1277 with gMapInfo do
1278 begin
1279 Name := Header.MapName;
1280 Description := Header.MapDescription;
1281 Author := Header.MapAuthor;
1282 MusicName := Header.MusicName;
1283 SkyName := Header.SkyName;
1284 Height := Header.Height;
1285 Width := Header.Width;
1286 end;
1288 // Çàãðóçêà íåáà:
1289 if gMapInfo.SkyName <> '' then
1290 begin
1291 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1292 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1293 FileName := g_ExtractWadName(gMapInfo.SkyName);
1295 if FileName <> '' then
1296 FileName := GameDir+'/wads/'+FileName
1297 else
1298 begin
1299 FileName := g_ExtractWadName(Res);
1300 end;
1302 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1303 if g_Texture_CreateWAD(BackID, s) then
1304 begin
1305 g_Game_SetupScreenSize();
1306 end
1307 else
1308 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1309 end;
1311 // Çàãðóçêà ìóçûêè:
1312 ok := False;
1313 if gMapInfo.MusicName <> '' then
1314 begin
1315 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1316 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1317 FileName := g_ExtractWadName(gMapInfo.MusicName);
1319 if FileName <> '' then
1320 FileName := GameDir+'/wads/'+FileName
1321 else
1322 begin
1323 FileName := g_ExtractWadName(Res);
1324 end;
1326 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1327 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1328 ok := True
1329 else
1330 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1331 end;
1333 // Îñòàëüíûå óñòàíâêè:
1334 CreateDoorMap();
1335 CreateLiftMap();
1337 g_Items_Init();
1338 g_Weapon_Init();
1339 g_Monsters_Init();
1341 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1342 if not gLoadGameMode then
1343 g_GFX_Init();
1345 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1346 _textures := nil;
1347 panels := nil;
1348 items := nil;
1349 areas := nil;
1350 triggers := nil;
1351 TriggersTable := nil;
1352 AddTextures := nil;
1354 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1355 if ok and (not gLoadGameMode) then
1356 begin
1357 gMusic.SetByName(gMapInfo.MusicName);
1358 gMusic.Play();
1359 end
1360 else
1361 gMusic.SetByName('');
1362 finally
1363 sfsGCEnable(); // enable releasing unused volumes
1364 end;
1366 e_WriteLog('Done loading map.', MSG_NOTIFY);
1367 Result := True;
1368 end;
1370 function g_Map_GetMapInfo(Res: String): TMapInfo;
1371 var
1372 WAD: TWADFile;
1373 MapReader: TMapReader_1;
1374 Header: TMapHeaderRec_1;
1375 FileName: String;
1376 Data: Pointer;
1377 Len: Integer;
1378 begin
1379 FillChar(Result, SizeOf(Result), 0);
1380 FileName := g_ExtractWadName(Res);
1382 WAD := TWADFile.Create();
1383 if not WAD.ReadFile(FileName) then
1384 begin
1385 WAD.Free();
1386 Exit;
1387 end;
1389 //k8: it ignores path again
1390 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1391 begin
1392 WAD.Free();
1393 Exit;
1394 end;
1396 WAD.Free();
1398 MapReader := TMapReader_1.Create();
1400 if not MapReader.LoadMap(Data) then
1401 begin
1402 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1403 ZeroMemory(@Header, SizeOf(Header));
1404 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1405 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1406 end
1407 else
1408 begin
1409 Header := MapReader.GetMapHeader();
1410 Result.Name := Header.MapName;
1411 Result.Description := Header.MapDescription;
1412 end;
1414 FreeMem(Data);
1415 MapReader.Free();
1417 Result.Map := Res;
1418 Result.Author := Header.MapAuthor;
1419 Result.Height := Header.Height;
1420 Result.Width := Header.Width;
1421 end;
1423 function g_Map_GetMapsList(WADName: string): SArray;
1424 var
1425 WAD: TWADFile;
1426 a: Integer;
1427 ResList: SArray;
1428 begin
1429 Result := nil;
1430 WAD := TWADFile.Create();
1431 if not WAD.ReadFile(WADName) then
1432 begin
1433 WAD.Free();
1434 Exit;
1435 end;
1436 ResList := WAD.GetMapResources();
1437 if ResList <> nil then
1438 begin
1439 for a := 0 to High(ResList) do
1440 begin
1441 SetLength(Result, Length(Result)+1);
1442 Result[High(Result)] := ResList[a];
1443 end;
1444 end;
1445 WAD.Free();
1446 end;
1448 function g_Map_Exist(Res: string): Boolean;
1449 var
1450 WAD: TWADFile;
1451 FileName, mnn: string;
1452 ResList: SArray;
1453 a: Integer;
1454 begin
1455 Result := False;
1457 FileName := addWadExtension(g_ExtractWadName(Res));
1459 WAD := TWADFile.Create;
1460 if not WAD.ReadFile(FileName) then
1461 begin
1462 WAD.Free();
1463 Exit;
1464 end;
1466 ResList := WAD.GetMapResources();
1467 WAD.Free();
1469 mnn := g_ExtractFileName(Res);
1470 if ResList <> nil then
1471 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1472 begin
1473 Result := True;
1474 Exit;
1475 end;
1476 end;
1478 procedure g_Map_Free();
1479 var
1480 a: Integer;
1482 procedure FreePanelArray(var panels: TPanelArray);
1483 var
1484 i: Integer;
1486 begin
1487 if panels <> nil then
1488 begin
1489 for i := 0 to High(panels) do
1490 panels[i].Free();
1491 panels := nil;
1492 end;
1493 end;
1495 begin
1496 g_GFX_Free();
1497 g_Weapon_Free();
1498 g_Items_Free();
1499 g_Triggers_Free();
1500 g_Monsters_Free();
1502 RespawnPoints := nil;
1503 if FlagPoints[FLAG_RED] <> nil then
1504 begin
1505 Dispose(FlagPoints[FLAG_RED]);
1506 FlagPoints[FLAG_RED] := nil;
1507 end;
1508 if FlagPoints[FLAG_BLUE] <> nil then
1509 begin
1510 Dispose(FlagPoints[FLAG_BLUE]);
1511 FlagPoints[FLAG_BLUE] := nil;
1512 end;
1513 //DOMFlagPoints := nil;
1515 //gDOMFlags := nil;
1517 if Textures <> nil then
1518 begin
1519 for a := 0 to High(Textures) do
1520 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1521 if Textures[a].Anim then
1522 g_Frames_DeleteByID(Textures[a].FramesID)
1523 else
1524 if Textures[a].TextureID <> TEXTURE_NONE then
1525 e_DeleteTexture(Textures[a].TextureID);
1527 Textures := nil;
1528 end;
1530 FreePanelArray(gWalls);
1531 FreePanelArray(gRenderBackgrounds);
1532 FreePanelArray(gRenderForegrounds);
1533 FreePanelArray(gWater);
1534 FreePanelArray(gAcid1);
1535 FreePanelArray(gAcid2);
1536 FreePanelArray(gSteps);
1537 FreePanelArray(gLifts);
1538 FreePanelArray(gBlockMon);
1540 if BackID <> DWORD(-1) then
1541 begin
1542 gBackSize.X := 0;
1543 gBackSize.Y := 0;
1544 e_DeleteTexture(BackID);
1545 BackID := DWORD(-1);
1546 end;
1548 g_Game_StopAllSounds(False);
1549 gMusic.FreeSound();
1550 g_Sound_Delete(gMapInfo.MusicName);
1552 gMapInfo.Name := '';
1553 gMapInfo.Description := '';
1554 gMapInfo.MusicName := '';
1555 gMapInfo.Height := 0;
1556 gMapInfo.Width := 0;
1558 gDoorMap := nil;
1559 gLiftMap := nil;
1560 end;
1562 procedure g_Map_Update();
1563 var
1564 a, d, j: Integer;
1565 m: Word;
1566 s: String;
1568 procedure UpdatePanelArray(var panels: TPanelArray);
1569 var
1570 i: Integer;
1572 begin
1573 if panels <> nil then
1574 for i := 0 to High(panels) do
1575 panels[i].Update();
1576 end;
1578 begin
1579 UpdatePanelArray(gWalls);
1580 UpdatePanelArray(gRenderBackgrounds);
1581 UpdatePanelArray(gRenderForegrounds);
1582 UpdatePanelArray(gWater);
1583 UpdatePanelArray(gAcid1);
1584 UpdatePanelArray(gAcid2);
1585 UpdatePanelArray(gSteps);
1587 if gGameSettings.GameMode = GM_CTF then
1588 begin
1589 for a := FLAG_RED to FLAG_BLUE do
1590 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1591 with gFlags[a] do
1592 begin
1593 if gFlags[a].Animation <> nil then
1594 gFlags[a].Animation.Update();
1596 m := g_Obj_Move(@Obj, True, True);
1598 if gTime mod (GAME_TICK*2) <> 0 then
1599 Continue;
1601 // Ñîïðîòèâëåíèå âîçäóõà:
1602 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1604 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1605 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1606 begin
1607 g_Map_ResetFlag(a);
1608 gFlags[a].CaptureTime := 0;
1609 if a = FLAG_RED then
1610 s := _lc[I_PLAYER_FLAG_RED]
1611 else
1612 s := _lc[I_PLAYER_FLAG_BLUE];
1613 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1615 if g_Game_IsNet then
1616 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1617 Continue;
1618 end;
1620 if Count > 0 then
1621 Count := Count - 1;
1623 // Èãðîê áåðåò ôëàã:
1624 if gPlayers <> nil then
1625 begin
1626 j := Random(Length(gPlayers)) - 1;
1628 for d := 0 to High(gPlayers) do
1629 begin
1630 Inc(j);
1631 if j > High(gPlayers) then
1632 j := 0;
1634 if gPlayers[j] <> nil then
1635 if gPlayers[j].Live and
1636 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1637 begin
1638 if gPlayers[j].GetFlag(a) then
1639 Break;
1640 end;
1641 end;
1642 end;
1643 end;
1644 end;
1645 end;
1647 procedure g_Map_DrawPanels(PanelType: Word);
1649 procedure DrawPanels(var panels: TPanelArray;
1650 drawDoors: Boolean = False);
1651 var
1652 a: Integer;
1654 begin
1655 if panels <> nil then
1656 for a := 0 to High(panels) do
1657 if not (drawDoors xor panels[a].Door) then
1658 panels[a].Draw();
1659 end;
1661 begin
1662 case PanelType of
1663 PANEL_WALL: DrawPanels(gWalls);
1664 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1665 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1666 PANEL_FORE: DrawPanels(gRenderForegrounds);
1667 PANEL_WATER: DrawPanels(gWater);
1668 PANEL_ACID1: DrawPanels(gAcid1);
1669 PANEL_ACID2: DrawPanels(gAcid2);
1670 PANEL_STEP: DrawPanels(gSteps);
1671 end;
1672 end;
1674 procedure g_Map_DrawBack(dx, dy: Integer);
1675 begin
1676 if gDrawBackGround and (BackID <> DWORD(-1)) then
1677 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1678 else
1679 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1680 end;
1682 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1683 PanelType: Word; b1x3: Boolean): Boolean;
1684 var
1685 a, h: Integer;
1686 begin
1687 Result := False;
1689 if WordBool(PanelType and PANEL_WALL) then
1690 if gWalls <> nil then
1691 begin
1692 h := High(gWalls);
1694 for a := 0 to h do
1695 if gWalls[a].Enabled and
1696 g_Collide(X, Y, Width, Height,
1697 gWalls[a].X, gWalls[a].Y,
1698 gWalls[a].Width, gWalls[a].Height) then
1699 begin
1700 Result := True;
1701 Exit;
1702 end;
1703 end;
1705 if WordBool(PanelType and PANEL_WATER) then
1706 if gWater <> nil then
1707 begin
1708 h := High(gWater);
1710 for a := 0 to h do
1711 if g_Collide(X, Y, Width, Height,
1712 gWater[a].X, gWater[a].Y,
1713 gWater[a].Width, gWater[a].Height) then
1714 begin
1715 Result := True;
1716 Exit;
1717 end;
1718 end;
1720 if WordBool(PanelType and PANEL_ACID1) then
1721 if gAcid1 <> nil then
1722 begin
1723 h := High(gAcid1);
1725 for a := 0 to h do
1726 if g_Collide(X, Y, Width, Height,
1727 gAcid1[a].X, gAcid1[a].Y,
1728 gAcid1[a].Width, gAcid1[a].Height) then
1729 begin
1730 Result := True;
1731 Exit;
1732 end;
1733 end;
1735 if WordBool(PanelType and PANEL_ACID2) then
1736 if gAcid2 <> nil then
1737 begin
1738 h := High(gAcid2);
1740 for a := 0 to h do
1741 if g_Collide(X, Y, Width, Height,
1742 gAcid2[a].X, gAcid2[a].Y,
1743 gAcid2[a].Width, gAcid2[a].Height) then
1744 begin
1745 Result := True;
1746 Exit;
1747 end;
1748 end;
1750 if WordBool(PanelType and PANEL_STEP) then
1751 if gSteps <> nil then
1752 begin
1753 h := High(gSteps);
1755 for a := 0 to h do
1756 if g_Collide(X, Y, Width, Height,
1757 gSteps[a].X, gSteps[a].Y,
1758 gSteps[a].Width, gSteps[a].Height) then
1759 begin
1760 Result := True;
1761 Exit;
1762 end;
1763 end;
1765 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1766 if gLifts <> nil then
1767 begin
1768 h := High(gLifts);
1770 for a := 0 to h do
1771 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1772 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1773 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1774 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1775 g_Collide(X, Y, Width, Height,
1776 gLifts[a].X, gLifts[a].Y,
1777 gLifts[a].Width, gLifts[a].Height) then
1778 begin
1779 Result := True;
1780 Exit;
1781 end;
1782 end;
1784 if WordBool(PanelType and PANEL_BLOCKMON) then
1785 if gBlockMon <> nil then
1786 begin
1787 h := High(gBlockMon);
1789 for a := 0 to h do
1790 if ( (not b1x3) or
1791 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1792 g_Collide(X, Y, Width, Height,
1793 gBlockMon[a].X, gBlockMon[a].Y,
1794 gBlockMon[a].Width, gBlockMon[a].Height) then
1795 begin
1796 Result := True;
1797 Exit;
1798 end;
1799 end;
1800 end;
1802 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1803 var
1804 a, h: Integer;
1805 begin
1806 Result := TEXTURE_NONE;
1808 if gWater <> nil then
1809 begin
1810 h := High(gWater);
1812 for a := 0 to h do
1813 if g_Collide(X, Y, Width, Height,
1814 gWater[a].X, gWater[a].Y,
1815 gWater[a].Width, gWater[a].Height) then
1816 begin
1817 Result := gWater[a].GetTextureID();
1818 Exit;
1819 end;
1820 end;
1822 if gAcid1 <> nil then
1823 begin
1824 h := High(gAcid1);
1826 for a := 0 to h do
1827 if g_Collide(X, Y, Width, Height,
1828 gAcid1[a].X, gAcid1[a].Y,
1829 gAcid1[a].Width, gAcid1[a].Height) then
1830 begin
1831 Result := gAcid1[a].GetTextureID();
1832 Exit;
1833 end;
1834 end;
1836 if gAcid2 <> nil then
1837 begin
1838 h := High(gAcid2);
1840 for a := 0 to h do
1841 if g_Collide(X, Y, Width, Height,
1842 gAcid2[a].X, gAcid2[a].Y,
1843 gAcid2[a].Width, gAcid2[a].Height) then
1844 begin
1845 Result := gAcid2[a].GetTextureID();
1846 Exit;
1847 end;
1848 end;
1849 end;
1851 procedure g_Map_EnableWall(ID: DWORD);
1852 begin
1853 with gWalls[ID] do
1854 begin
1855 Enabled := True;
1856 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1858 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1859 end;
1860 end;
1862 procedure g_Map_DisableWall(ID: DWORD);
1863 begin
1864 with gWalls[ID] do
1865 begin
1866 Enabled := False;
1867 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1869 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1870 end;
1871 end;
1873 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1874 var
1875 tp: TPanel;
1876 begin
1877 case PanelType of
1878 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1879 tp := gWalls[ID];
1880 PANEL_FORE:
1881 tp := gRenderForegrounds[ID];
1882 PANEL_BACK:
1883 tp := gRenderBackgrounds[ID];
1884 PANEL_WATER:
1885 tp := gWater[ID];
1886 PANEL_ACID1:
1887 tp := gAcid1[ID];
1888 PANEL_ACID2:
1889 tp := gAcid2[ID];
1890 PANEL_STEP:
1891 tp := gSteps[ID];
1892 else
1893 Exit;
1894 end;
1896 tp.NextTexture(AnimLoop);
1897 if g_Game_IsServer and g_Game_IsNet then
1898 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1899 end;
1901 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1902 begin
1903 if gLifts[ID].LiftType = t then
1904 Exit;
1906 with gLifts[ID] do
1907 begin
1908 LiftType := t;
1910 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1912 if LiftType = 0 then
1913 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1914 else if LiftType = 1 then
1915 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1916 else if LiftType = 2 then
1917 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1918 else if LiftType = 3 then
1919 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1921 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1922 end;
1923 end;
1925 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1926 var
1927 a: Integer;
1928 PointsArray: Array of TRespawnPoint;
1929 begin
1930 Result := False;
1931 SetLength(PointsArray, 0);
1933 if RespawnPoints = nil then
1934 Exit;
1936 for a := 0 to High(RespawnPoints) do
1937 if RespawnPoints[a].PointType = PointType then
1938 begin
1939 SetLength(PointsArray, Length(PointsArray)+1);
1940 PointsArray[High(PointsArray)] := RespawnPoints[a];
1941 end;
1943 if PointsArray = nil then
1944 Exit;
1946 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1947 Result := True;
1948 end;
1950 function g_Map_GetPointCount(PointType: Byte): Word;
1951 var
1952 a: Integer;
1953 begin
1954 Result := 0;
1956 if RespawnPoints = nil then
1957 Exit;
1959 for a := 0 to High(RespawnPoints) do
1960 if RespawnPoints[a].PointType = PointType then
1961 Result := Result + 1;
1962 end;
1964 function g_Map_HaveFlagPoints(): Boolean;
1965 begin
1966 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1967 end;
1969 procedure g_Map_ResetFlag(Flag: Byte);
1970 begin
1971 with gFlags[Flag] do
1972 begin
1973 Obj.X := -1000;
1974 Obj.Y := -1000;
1975 Obj.Vel.X := 0;
1976 Obj.Vel.Y := 0;
1977 Direction := D_LEFT;
1978 State := FLAG_STATE_NONE;
1979 if FlagPoints[Flag] <> nil then
1980 begin
1981 Obj.X := FlagPoints[Flag]^.X;
1982 Obj.Y := FlagPoints[Flag]^.Y;
1983 Direction := FlagPoints[Flag]^.Direction;
1984 State := FLAG_STATE_NORMAL;
1985 end;
1986 Count := -1;
1987 end;
1988 end;
1990 procedure g_Map_DrawFlags();
1991 var
1992 i, dx: Integer;
1993 Mirror: TMirrorType;
1994 begin
1995 if gGameSettings.GameMode <> GM_CTF then
1996 Exit;
1998 for i := FLAG_RED to FLAG_BLUE do
1999 with gFlags[i] do
2000 if State <> FLAG_STATE_CAPTURED then
2001 begin
2002 if State = FLAG_STATE_NONE then
2003 continue;
2005 if Direction = D_LEFT then
2006 begin
2007 Mirror := M_HORIZONTAL;
2008 dx := -1;
2009 end
2010 else
2011 begin
2012 Mirror := M_NONE;
2013 dx := 1;
2014 end;
2016 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2018 if g_debug_Frames then
2019 begin
2020 e_DrawQuad(Obj.X+Obj.Rect.X,
2021 Obj.Y+Obj.Rect.Y,
2022 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2023 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2024 0, 255, 0);
2025 end;
2026 end;
2027 end;
2029 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2030 var
2031 dw: DWORD;
2032 b: Byte;
2033 str: String;
2034 boo: Boolean;
2036 procedure SavePanelArray(var panels: TPanelArray);
2037 var
2038 PAMem: TBinMemoryWriter;
2039 i: Integer;
2040 begin
2041 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2042 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2044 i := 0;
2045 while i < Length(panels) do
2046 begin
2047 if panels[i].SaveIt then
2048 begin
2049 // ID ïàíåëè:
2050 PAMem.WriteInt(i);
2051 // Ñîõðàíÿåì ïàíåëü:
2052 panels[i].SaveState(PAMem);
2053 end;
2054 Inc(i);
2055 end;
2057 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2058 PAMem.SaveToMemory(Mem);
2059 PAMem.Free();
2060 end;
2062 procedure SaveFlag(flag: PFlag);
2063 begin
2064 // Ñèãíàòóðà ôëàãà:
2065 dw := FLAG_SIGNATURE; // 'FLAG'
2066 Mem.WriteDWORD(dw);
2067 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2068 Mem.WriteByte(flag^.RespawnType);
2069 // Ñîñòîÿíèå ôëàãà:
2070 Mem.WriteByte(flag^.State);
2071 // Íàïðàâëåíèå ôëàãà:
2072 if flag^.Direction = D_LEFT then
2073 b := 1
2074 else // D_RIGHT
2075 b := 2;
2076 Mem.WriteByte(b);
2077 // Îáúåêò ôëàãà:
2078 Obj_SaveState(@flag^.Obj, Mem);
2079 end;
2081 begin
2082 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2084 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2085 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2086 SavePanelArray(gWalls);
2087 // Ñîõðàíÿåì ïàíåëè ôîíà:
2088 SavePanelArray(gRenderBackgrounds);
2089 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2090 SavePanelArray(gRenderForegrounds);
2091 // Ñîõðàíÿåì ïàíåëè âîäû:
2092 SavePanelArray(gWater);
2093 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2094 SavePanelArray(gAcid1);
2095 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2096 SavePanelArray(gAcid2);
2097 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2098 SavePanelArray(gSteps);
2099 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2100 SavePanelArray(gLifts);
2101 ///// /////
2103 ///// Ñîõðàíÿåì ìóçûêó: /////
2104 // Ñèãíàòóðà ìóçûêè:
2105 dw := MUSIC_SIGNATURE; // 'MUSI'
2106 Mem.WriteDWORD(dw);
2107 // Íàçâàíèå ìóçûêè:
2108 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2109 if gMusic.NoMusic then
2110 str := ''
2111 else
2112 str := gMusic.Name;
2113 Mem.WriteString(str, 64);
2114 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2115 dw := gMusic.GetPosition();
2116 Mem.WriteDWORD(dw);
2117 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2118 boo := gMusic.SpecPause;
2119 Mem.WriteBoolean(boo);
2120 ///// /////
2122 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2123 Mem.WriteInt(gTotalMonsters);
2124 ///// /////
2126 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2127 if gGameSettings.GameMode = GM_CTF then
2128 begin
2129 // Ôëàã Êðàñíîé êîìàíäû:
2130 SaveFlag(@gFlags[FLAG_RED]);
2131 // Ôëàã Ñèíåé êîìàíäû:
2132 SaveFlag(@gFlags[FLAG_BLUE]);
2133 end;
2134 ///// /////
2136 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2137 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2138 begin
2139 // Î÷êè Êðàñíîé êîìàíäû:
2140 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2141 // Î÷êè Ñèíåé êîìàíäû:
2142 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2143 end;
2144 ///// /////
2145 end;
2147 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2148 var
2149 dw: DWORD;
2150 b: Byte;
2151 str: String;
2152 boo: Boolean;
2154 procedure LoadPanelArray(var panels: TPanelArray);
2155 var
2156 PAMem: TBinMemoryReader;
2157 i, id: Integer;
2158 begin
2159 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2160 PAMem := TBinMemoryReader.Create();
2161 PAMem.LoadFromMemory(Mem);
2163 for i := 0 to Length(panels)-1 do
2164 if panels[i].SaveIt then
2165 begin
2166 // ID ïàíåëè:
2167 PAMem.ReadInt(id);
2168 if id <> i then
2169 begin
2170 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2171 end;
2172 // Çàãðóæàåì ïàíåëü:
2173 panels[i].LoadState(PAMem);
2174 end;
2176 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2177 PAMem.Free();
2178 end;
2180 procedure LoadFlag(flag: PFlag);
2181 begin
2182 // Ñèãíàòóðà ôëàãà:
2183 Mem.ReadDWORD(dw);
2184 if dw <> FLAG_SIGNATURE then // 'FLAG'
2185 begin
2186 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2187 end;
2188 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2189 Mem.ReadByte(flag^.RespawnType);
2190 // Ñîñòîÿíèå ôëàãà:
2191 Mem.ReadByte(flag^.State);
2192 // Íàïðàâëåíèå ôëàãà:
2193 Mem.ReadByte(b);
2194 if b = 1 then
2195 flag^.Direction := D_LEFT
2196 else // b = 2
2197 flag^.Direction := D_RIGHT;
2198 // Îáúåêò ôëàãà:
2199 Obj_LoadState(@flag^.Obj, Mem);
2200 end;
2202 begin
2203 if Mem = nil then
2204 Exit;
2206 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2207 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2208 LoadPanelArray(gWalls);
2209 // Çàãðóæàåì ïàíåëè ôîíà:
2210 LoadPanelArray(gRenderBackgrounds);
2211 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2212 LoadPanelArray(gRenderForegrounds);
2213 // Çàãðóæàåì ïàíåëè âîäû:
2214 LoadPanelArray(gWater);
2215 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2216 LoadPanelArray(gAcid1);
2217 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2218 LoadPanelArray(gAcid2);
2219 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2220 LoadPanelArray(gSteps);
2221 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2222 LoadPanelArray(gLifts);
2223 ///// /////
2225 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2226 g_GFX_Init();
2228 ///// Çàãðóæàåì ìóçûêó: /////
2229 // Ñèãíàòóðà ìóçûêè:
2230 Mem.ReadDWORD(dw);
2231 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2232 begin
2233 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2234 end;
2235 // Íàçâàíèå ìóçûêè:
2236 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2237 Mem.ReadString(str);
2238 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2239 Mem.ReadDWORD(dw);
2240 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2241 Mem.ReadBoolean(boo);
2242 // Çàïóñêàåì ýòó ìóçûêó:
2243 gMusic.SetByName(str);
2244 gMusic.SpecPause := boo;
2245 gMusic.Play();
2246 gMusic.Pause(True);
2247 gMusic.SetPosition(dw);
2248 ///// /////
2250 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2251 Mem.ReadInt(gTotalMonsters);
2252 ///// /////
2254 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2255 if gGameSettings.GameMode = GM_CTF then
2256 begin
2257 // Ôëàã Êðàñíîé êîìàíäû:
2258 LoadFlag(@gFlags[FLAG_RED]);
2259 // Ôëàã Ñèíåé êîìàíäû:
2260 LoadFlag(@gFlags[FLAG_BLUE]);
2261 end;
2262 ///// /////
2264 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2265 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2266 begin
2267 // Î÷êè Êðàñíîé êîìàíäû:
2268 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2269 // Î÷êè Ñèíåé êîìàíäû:
2270 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2271 end;
2272 ///// /////
2273 end;
2275 end.