DEADSOFTWARE

animated images from gif/apng
[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 il: TImageFileFormat = nil;
475 meta: TMetadata = nil;
476 f: Integer;
477 gf: TGIFFileFormat;
478 pf: TPNGFileFormat;
479 begin
480 result := -1;
482 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
484 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
485 WADName := g_ExtractWadName(RecName);
487 WAD := TWADFile.Create();
488 try
489 if WADName <> '' then
490 WADName := GameDir+'/wads/'+WADName
491 else
492 WADName := Map;
494 WAD.ReadFile(WADName);
496 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
497 begin
498 if log then
499 begin
500 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
501 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
502 end;
503 exit;
504 end;
506 {TEST
507 if WADName = Map then
508 begin
509 //FreeMem(TextureWAD);
510 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
511 end;
514 WAD.FreeWAD();
516 if ResLength < 6 then
517 begin
518 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
519 exit;
520 end;
522 // ýòî ïòèöà? ýòî ñàìîë¸ò?
523 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
524 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
525 begin
526 // íåò, ýòî ñóïåðìåí!
527 if not WAD.ReadMemory(TextureWAD, ResLength) then
528 begin
529 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
530 exit;
531 end;
533 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
534 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
535 begin
536 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
537 exit;
538 end;
540 cfg := TConfig.CreateMem(TextData, ResLength);
542 TextureResource := cfg.ReadStr('', 'resource', '');
543 if TextureResource = '' then
544 begin
545 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
546 exit;
547 end;
549 _width := cfg.ReadInt('', 'framewidth', 0);
550 _height := cfg.ReadInt('', 'frameheight', 0);
551 _framecount := cfg.ReadInt('', 'framecount', 0);
552 _speed := cfg.ReadInt('', 'waitcount', 0);
553 _backanimation := cfg.ReadBool('', 'backanimation', False);
555 cfg.Free();
556 cfg := nil;
558 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
559 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
560 begin
561 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
562 exit;
563 end;
565 WAD.Free();
566 WAD := nil;
568 SetLength(Textures, Length(Textures)+1);
569 with Textures[High(Textures)] do
570 begin
571 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
572 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
573 begin
574 TextureName := RecName;
575 Width := _width;
576 Height := _height;
577 Anim := True;
578 FramesCount := _framecount;
579 Speed := _speed;
580 result := High(Textures);
581 end
582 else
583 begin
584 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
585 end;
586 end;
587 end
588 else
589 begin
590 // try animated image
591 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
592 if length(imgfmt) = 0 then
593 begin
594 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
595 exit;
596 end;
597 if imgfmt = 'gif' then
598 begin
599 meta := TMetadata.Create();
600 gf := TGIFFileFormat.Create(meta);
601 gf.LoadAnimated := true;
602 il := gf;
603 end
604 else if imgfmt = 'png' then
605 begin
606 meta := TMetadata.Create();
607 pf := TPNGFileFormat.Create(meta);
608 pf.LoadAnimated := true;
609 il := pf;
610 end;
611 if il <> nil then
612 begin
613 if not il.LoadFromMemory(TextureWAD, ResLength, ia) then
614 begin
615 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
616 exit;
617 end;
618 end
619 else if LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
620 begin
621 if length(ia) > 1 then
622 begin
623 for f := 1 to High(ia) do FreeImage(ia[f]);
624 SetLength(ia, 1);
625 end;
626 end
627 else
628 begin
629 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
630 exit;
631 end;
632 if length(ia) = 0 then
633 begin
634 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
635 exit;
636 end;
638 WAD.Free();
639 WAD := nil;
641 _width := ia[0].width;
642 _height := ia[0].height;
643 _framecount := length(ia);
644 _speed := 1;
645 _backanimation := false;
646 if meta <> nil then
647 begin
648 if meta.HasMetaItem(SMetaFrameDelay) then
649 begin
650 //writeln(' frame delay: ', meta.MetaItems[SMetaFrameDelay]);
651 try
652 f := meta.MetaItems[SMetaFrameDelay];
653 f := f div 27;
654 if f < 1 then f := 1 else if f > 255 then f := 255;
655 _speed := f;
656 except
657 end;
658 end;
659 if meta.HasMetaItem(SMetaAnimationLoops) then
660 begin
661 //writeln(' frame loop : ', meta.MetaItems[SMetaAnimationLoops]);
662 try
663 f := meta.MetaItems[SMetaAnimationLoops];
664 if f <> 0 then _backanimation := true;
665 except
666 end;
667 end;
668 end;
669 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
670 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
671 //e_WriteLog(Format('Animated texture file "%s": %d frames (delay:%d), %dx%d', [RecName, length(ia), _speed, _width, _height]), MSG_NOTIFY);
673 SetLength(Textures, Length(Textures)+1);
674 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
675 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
676 begin
677 Textures[High(Textures)].TextureName := RecName;
678 Textures[High(Textures)].Width := _width;
679 Textures[High(Textures)].Height := _height;
680 Textures[High(Textures)].Anim := True;
681 Textures[High(Textures)].FramesCount := length(ia);
682 Textures[High(Textures)].Speed := _speed;
683 result := High(Textures);
684 //writeln(' CREATED!');
685 end
686 else
687 begin
688 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
689 end;
690 end;
691 finally
692 for f := 0 to High(ia) do FreeImage(ia[f]);
693 il.Free();
694 //???meta.Free();
695 WAD.Free();
696 cfg.Free();
697 if TextureWAD <> nil then FreeMem(TextureWAD);
698 if TextData <> nil then FreeMem(TextData);
699 if TextureData <> nil then FreeMem(TextureData);
700 end;
701 end;
703 procedure CreateItem(Item: TItemRec_1);
704 begin
705 if g_Game_IsClient then Exit;
707 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
708 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
709 Exit;
711 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
712 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
713 end;
715 procedure CreateArea(Area: TAreaRec_1);
716 var
717 a: Integer;
718 id: DWORD;
719 begin
720 case Area.AreaType of
721 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
722 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
723 begin
724 SetLength(RespawnPoints, Length(RespawnPoints)+1);
725 with RespawnPoints[High(RespawnPoints)] do
726 begin
727 X := Area.X;
728 Y := Area.Y;
729 Direction := TDirection(Area.Direction);
731 case Area.AreaType of
732 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
733 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
734 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
735 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
736 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
737 end;
738 end;
739 end;
741 AREA_REDFLAG, AREA_BLUEFLAG:
742 begin
743 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
745 if FlagPoints[a] <> nil then Exit;
747 New(FlagPoints[a]);
749 with FlagPoints[a]^ do
750 begin
751 X := Area.X-FLAGRECT.X;
752 Y := Area.Y-FLAGRECT.Y;
753 Direction := TDirection(Area.Direction);
754 end;
756 with gFlags[a] do
757 begin
758 case a of
759 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
760 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
761 end;
763 Animation := TAnimation.Create(id, True, 8);
764 Obj.Rect := FLAGRECT;
766 g_Map_ResetFlag(a);
767 end;
768 end;
770 AREA_DOMFLAG:
771 begin
772 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
773 with DOMFlagPoints[High(DOMFlagPoints)] do
774 begin
775 X := Area.X;
776 Y := Area.Y;
777 Direction := TDirection(Area.Direction);
778 end;
780 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
781 end;
782 end;
783 end;
785 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
786 var
787 _trigger: TTrigger;
788 begin
789 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
791 with _trigger do
792 begin
793 X := Trigger.X;
794 Y := Trigger.Y;
795 Width := Trigger.Width;
796 Height := Trigger.Height;
797 Enabled := ByteBool(Trigger.Enabled);
798 TexturePanel := Trigger.TexturePanel;
799 TexturePanelType := fTexturePanel1Type;
800 ShotPanelType := fTexturePanel2Type;
801 TriggerType := Trigger.TriggerType;
802 ActivateType := Trigger.ActivateType;
803 Keys := Trigger.Keys;
804 Data.Default := Trigger.DATA;
805 end;
807 g_Triggers_Create(_trigger);
808 end;
810 procedure CreateMonster(monster: TMonsterRec_1);
811 var
812 a, i: Integer;
813 begin
814 if g_Game_IsClient then Exit;
816 if (gGameSettings.GameType = GT_SINGLE)
817 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
818 begin
819 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
820 TDirection(monster.Direction));
822 if gTriggers <> nil then
823 for a := 0 to High(gTriggers) do
824 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
825 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
826 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
827 gMonsters[i].AddTrigger(a);
829 if monster.MonsterType <> MONSTER_BARREL then
830 Inc(gTotalMonsters);
831 end;
832 end;
834 procedure g_Map_ReAdd_DieTriggers();
835 var
836 i, a: Integer;
837 begin
838 if g_Game_IsClient then Exit;
840 for i := 0 to High(gMonsters) do
841 if gMonsters[i] <> nil then
842 begin
843 gMonsters[i].ClearTriggers();
845 for a := 0 to High(gTriggers) do
846 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
847 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
848 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
849 gMonsters[i].AddTrigger(a);
850 end;
851 end;
853 function extractWadName(resourceName: string): string;
854 var
855 posN: Integer;
856 begin
857 posN := Pos(':', resourceName);
858 if posN > 0 then
859 Result:= Copy(resourceName, 0, posN-1)
860 else
861 Result := '';
862 end;
864 procedure addResToExternalResList(res: string);
865 begin
866 res := extractWadName(res);
867 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
868 gExternalResources.Add(res);
869 end;
871 procedure generateExternalResourcesList(mapReader: TMapReader_1);
872 var
873 textures: TTexturesRec1Array;
874 mapHeader: TMapHeaderRec_1;
875 i: integer;
876 resFile: String = '';
877 begin
878 if gExternalResources = nil then
879 gExternalResources := TStringList.Create;
881 gExternalResources.Clear;
882 textures := mapReader.GetTextures();
883 for i := 0 to High(textures) do
884 begin
885 addResToExternalResList(resFile);
886 end;
888 textures := nil;
890 mapHeader := mapReader.GetMapHeader;
892 addResToExternalResList(mapHeader.MusicName);
893 addResToExternalResList(mapHeader.SkyName);
894 end;
896 function g_Map_Load(Res: String): Boolean;
897 const
898 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
899 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
900 var
901 WAD: TWADFile;
902 MapReader: TMapReader_1;
903 Header: TMapHeaderRec_1;
904 _textures: TTexturesRec1Array;
905 _texnummap: array of Integer; // `_textures` -> `Textures`
906 panels: TPanelsRec1Array;
907 items: TItemsRec1Array;
908 monsters: TMonsterRec1Array;
909 areas: TAreasRec1Array;
910 triggers: TTriggersRec1Array;
911 a, b, c, k: Integer;
912 PanelID: DWORD;
913 AddTextures: TAddTextureArray;
914 texture: TTextureRec_1;
915 TriggersTable: Array of record
916 TexturePanel: Integer;
917 LiftPanel: Integer;
918 DoorPanel: Integer;
919 ShotPanel: Integer;
920 end;
921 FileName, mapResName, s, TexName: String;
922 Data: Pointer;
923 Len: Integer;
924 ok, isAnim, trigRef: Boolean;
925 CurTex, ntn: Integer;
926 begin
927 Result := False;
928 gMapInfo.Map := Res;
929 TriggersTable := nil;
930 FillChar(texture, SizeOf(texture), 0);
932 sfsGCDisable(); // temporary disable removing of temporary volumes
933 try
934 // Çàãðóçêà WAD:
935 FileName := g_ExtractWadName(Res);
936 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
937 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
939 WAD := TWADFile.Create();
940 if not WAD.ReadFile(FileName) then
941 begin
942 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
943 WAD.Free();
944 Exit;
945 end;
946 //k8: why loader ignores path here?
947 mapResName := g_ExtractFileName(Res);
948 if not WAD.GetMapResource(mapResName, Data, Len) then
949 begin
950 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
951 WAD.Free();
952 Exit;
953 end;
954 WAD.Free();
956 // Çàãðóçêà êàðòû:
957 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
958 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
959 MapReader := TMapReader_1.Create();
961 if not MapReader.LoadMap(Data) then
962 begin
963 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
964 FreeMem(Data);
965 MapReader.Free();
966 Exit;
967 end;
969 FreeMem(Data);
970 generateExternalResourcesList(MapReader);
971 // Çàãðóçêà òåêñòóð:
972 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
973 _textures := MapReader.GetTextures();
974 _texnummap := nil;
976 // Äîáàâëåíèå òåêñòóð â Textures[]:
977 if _textures <> nil then
978 begin
979 e_WriteLog(' Loading textures:', MSG_NOTIFY);
980 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
981 SetLength(_texnummap, length(_textures));
983 for a := 0 to High(_textures) do
984 begin
985 SetLength(s, 64);
986 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
987 for b := 1 to Length(s) do
988 if s[b] = #0 then
989 begin
990 SetLength(s, b-1);
991 Break;
992 end;
993 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
994 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
995 // Àíèìèðîâàííàÿ òåêñòóðà:
996 if ByteBool(_textures[a].Anim) then
997 begin
998 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
999 if ntn < 0 then
1000 begin
1001 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1002 ntn := CreateNullTexture(_textures[a].Resource);
1003 end;
1004 end
1005 else // Îáû÷íàÿ òåêñòóðà:
1006 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1007 if ntn < 0 then
1008 begin
1009 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1010 ntn := CreateNullTexture(_textures[a].Resource);
1011 end;
1013 _texnummap[a] := ntn; // fix texture number
1014 g_Game_StepLoading();
1015 end;
1016 end;
1018 // Çàãðóçêà òðèããåðîâ:
1019 gTriggerClientID := 0;
1020 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1021 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1022 triggers := MapReader.GetTriggers();
1024 // Çàãðóçêà ïàíåëåé:
1025 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1026 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1027 panels := MapReader.GetPanels();
1029 // check texture numbers for panels
1030 for a := 0 to High(panels) do
1031 begin
1032 if panels[a].TextureNum > High(_textures) then
1033 begin
1034 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1035 result := false;
1036 exit;
1037 end;
1038 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1039 end;
1041 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1042 if triggers <> nil then
1043 begin
1044 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1045 SetLength(TriggersTable, Length(triggers));
1046 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1048 for a := 0 to High(TriggersTable) do
1049 begin
1050 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1051 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1052 // Ëèôòû:
1053 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1054 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1055 else
1056 TriggersTable[a].LiftPanel := -1;
1057 // Äâåðè:
1058 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1059 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1060 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1061 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1062 else
1063 TriggersTable[a].DoorPanel := -1;
1064 // Òóðåëü:
1065 if triggers[a].TriggerType = TRIGGER_SHOT then
1066 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1067 else
1068 TriggersTable[a].ShotPanel := -1;
1070 g_Game_StepLoading();
1071 end;
1072 end;
1074 // Ñîçäàåì ïàíåëè:
1075 if panels <> nil then
1076 begin
1077 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1078 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1080 for a := 0 to High(panels) do
1081 begin
1082 SetLength(AddTextures, 0);
1083 trigRef := False;
1084 CurTex := -1;
1085 if _textures <> nil then
1086 begin
1087 texture := _textures[panels[a].TextureNum];
1088 ok := True;
1089 end
1090 else
1091 ok := False;
1093 if ok then
1094 begin
1095 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1096 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1097 ok := False;
1098 if (TriggersTable <> nil) and (_textures <> nil) then
1099 for b := 0 to High(TriggersTable) do
1100 if (TriggersTable[b].TexturePanel = a)
1101 or (TriggersTable[b].ShotPanel = a) then
1102 begin
1103 trigRef := True;
1104 ok := True;
1105 Break;
1106 end;
1107 end;
1109 if ok then
1110 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1111 SetLength(s, 64);
1112 CopyMemory(@s[1], @texture.Resource[0], 64);
1113 // Èçìåðÿåì äëèíó:
1114 Len := Length(s);
1115 for c := Len downto 1 do
1116 if s[c] <> #0 then
1117 begin
1118 Len := c;
1119 Break;
1120 end;
1121 SetLength(s, Len);
1123 // Ñïåö-òåêñòóðû çàïðåùåíû:
1124 if g_Map_IsSpecialTexture(s) then
1125 ok := False
1126 else
1127 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1128 ok := g_Texture_NumNameFindStart(s);
1130 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1131 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1132 if ok then
1133 begin
1134 k := NNF_NAME_BEFORE;
1135 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1136 while ok or (k = NNF_NAME_BEFORE) or
1137 (k = NNF_NAME_EQUALS) do
1138 begin
1139 k := g_Texture_NumNameFindNext(TexName);
1141 if (k = NNF_NAME_BEFORE) or
1142 (k = NNF_NAME_AFTER) then
1143 begin
1144 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1145 if ByteBool(texture.Anim) then
1146 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1147 isAnim := True;
1148 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1149 if not ok then
1150 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1151 isAnim := False;
1152 ok := CreateTexture(TexName, FileName, False) >= 0;
1153 end;
1154 end
1155 else
1156 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1157 isAnim := False;
1158 ok := CreateTexture(TexName, FileName, False) >= 0;
1159 if not ok then
1160 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1161 isAnim := True;
1162 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1163 end;
1164 end;
1166 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1167 if ok then
1168 begin
1169 for c := 0 to High(Textures) do
1170 if Textures[c].TextureName = TexName then
1171 begin
1172 SetLength(AddTextures, Length(AddTextures)+1);
1173 AddTextures[High(AddTextures)].Texture := c;
1174 AddTextures[High(AddTextures)].Anim := isAnim;
1175 Break;
1176 end;
1177 end;
1178 end
1179 else
1180 if k = NNF_NAME_EQUALS then
1181 begin
1182 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1183 SetLength(AddTextures, Length(AddTextures)+1);
1184 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1185 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1186 CurTex := High(AddTextures);
1187 ok := True;
1188 end
1189 else // NNF_NO_NAME
1190 ok := False;
1191 end; // while ok...
1193 ok := True;
1194 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1195 end; // if ok - ññûëàþòñÿ òðèããåðû
1197 if not ok then
1198 begin
1199 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1200 SetLength(AddTextures, 1);
1201 AddTextures[0].Texture := panels[a].TextureNum;
1202 AddTextures[0].Anim := ByteBool(texture.Anim);
1203 CurTex := 0;
1204 end;
1206 //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);
1208 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1209 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1211 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1212 if TriggersTable <> nil then
1213 for b := 0 to High(TriggersTable) do
1214 begin
1215 // Òðèããåð äâåðè/ëèôòà:
1216 if (TriggersTable[b].LiftPanel = a) or
1217 (TriggersTable[b].DoorPanel = a) then
1218 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1219 // Òðèããåð ñìåíû òåêñòóðû:
1220 if TriggersTable[b].TexturePanel = a then
1221 triggers[b].TexturePanel := PanelID;
1222 // Òðèããåð "Òóðåëü":
1223 if TriggersTable[b].ShotPanel = a then
1224 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1225 end;
1227 g_Game_StepLoading();
1228 end;
1229 end;
1231 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1232 if (triggers <> nil) and not gLoadGameMode then
1233 begin
1234 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1235 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1236 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1237 for a := 0 to High(triggers) do
1238 begin
1239 if triggers[a].TexturePanel <> -1 then
1240 b := panels[TriggersTable[a].TexturePanel].PanelType
1241 else
1242 b := 0;
1243 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1244 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1245 c := panels[TriggersTable[a].ShotPanel].PanelType
1246 else
1247 c := 0;
1248 CreateTrigger(triggers[a], b, c);
1249 end;
1250 end;
1252 // Çàãðóçêà ïðåäìåòîâ:
1253 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1254 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1255 items := MapReader.GetItems();
1257 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1258 if (items <> nil) and not gLoadGameMode then
1259 begin
1260 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1261 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1262 for a := 0 to High(items) do
1263 CreateItem(Items[a]);
1264 end;
1266 // Çàãðóçêà îáëàñòåé:
1267 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1268 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1269 areas := MapReader.GetAreas();
1271 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1272 if areas <> nil then
1273 begin
1274 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1275 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1276 for a := 0 to High(areas) do
1277 CreateArea(areas[a]);
1278 end;
1280 // Çàãðóçêà ìîíñòðîâ:
1281 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1282 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1283 monsters := MapReader.GetMonsters();
1285 gTotalMonsters := 0;
1287 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1288 if (monsters <> nil) and not gLoadGameMode then
1289 begin
1290 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1291 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1292 for a := 0 to High(monsters) do
1293 CreateMonster(monsters[a]);
1294 end;
1296 // Çàãðóçêà îïèñàíèÿ êàðòû:
1297 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1298 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1299 Header := MapReader.GetMapHeader();
1301 MapReader.Free();
1303 with gMapInfo do
1304 begin
1305 Name := Header.MapName;
1306 Description := Header.MapDescription;
1307 Author := Header.MapAuthor;
1308 MusicName := Header.MusicName;
1309 SkyName := Header.SkyName;
1310 Height := Header.Height;
1311 Width := Header.Width;
1312 end;
1314 // Çàãðóçêà íåáà:
1315 if gMapInfo.SkyName <> '' then
1316 begin
1317 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1318 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1319 FileName := g_ExtractWadName(gMapInfo.SkyName);
1321 if FileName <> '' then
1322 FileName := GameDir+'/wads/'+FileName
1323 else
1324 begin
1325 FileName := g_ExtractWadName(Res);
1326 end;
1328 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1329 if g_Texture_CreateWAD(BackID, s) then
1330 begin
1331 g_Game_SetupScreenSize();
1332 end
1333 else
1334 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1335 end;
1337 // Çàãðóçêà ìóçûêè:
1338 ok := False;
1339 if gMapInfo.MusicName <> '' then
1340 begin
1341 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1342 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1343 FileName := g_ExtractWadName(gMapInfo.MusicName);
1345 if FileName <> '' then
1346 FileName := GameDir+'/wads/'+FileName
1347 else
1348 begin
1349 FileName := g_ExtractWadName(Res);
1350 end;
1352 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1353 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1354 ok := True
1355 else
1356 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1357 end;
1359 // Îñòàëüíûå óñòàíâêè:
1360 CreateDoorMap();
1361 CreateLiftMap();
1363 g_Items_Init();
1364 g_Weapon_Init();
1365 g_Monsters_Init();
1367 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1368 if not gLoadGameMode then
1369 g_GFX_Init();
1371 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1372 _textures := nil;
1373 panels := nil;
1374 items := nil;
1375 areas := nil;
1376 triggers := nil;
1377 TriggersTable := nil;
1378 AddTextures := nil;
1380 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1381 if ok and (not gLoadGameMode) then
1382 begin
1383 gMusic.SetByName(gMapInfo.MusicName);
1384 gMusic.Play();
1385 end
1386 else
1387 gMusic.SetByName('');
1388 finally
1389 sfsGCEnable(); // enable releasing unused volumes
1390 end;
1392 e_WriteLog('Done loading map.', MSG_NOTIFY);
1393 Result := True;
1394 end;
1396 function g_Map_GetMapInfo(Res: String): TMapInfo;
1397 var
1398 WAD: TWADFile;
1399 MapReader: TMapReader_1;
1400 Header: TMapHeaderRec_1;
1401 FileName: String;
1402 Data: Pointer;
1403 Len: Integer;
1404 begin
1405 FillChar(Result, SizeOf(Result), 0);
1406 FileName := g_ExtractWadName(Res);
1408 WAD := TWADFile.Create();
1409 if not WAD.ReadFile(FileName) then
1410 begin
1411 WAD.Free();
1412 Exit;
1413 end;
1415 //k8: it ignores path again
1416 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1417 begin
1418 WAD.Free();
1419 Exit;
1420 end;
1422 WAD.Free();
1424 MapReader := TMapReader_1.Create();
1426 if not MapReader.LoadMap(Data) then
1427 begin
1428 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1429 ZeroMemory(@Header, SizeOf(Header));
1430 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1431 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1432 end
1433 else
1434 begin
1435 Header := MapReader.GetMapHeader();
1436 Result.Name := Header.MapName;
1437 Result.Description := Header.MapDescription;
1438 end;
1440 FreeMem(Data);
1441 MapReader.Free();
1443 Result.Map := Res;
1444 Result.Author := Header.MapAuthor;
1445 Result.Height := Header.Height;
1446 Result.Width := Header.Width;
1447 end;
1449 function g_Map_GetMapsList(WADName: string): SArray;
1450 var
1451 WAD: TWADFile;
1452 a: Integer;
1453 ResList: SArray;
1454 begin
1455 Result := nil;
1456 WAD := TWADFile.Create();
1457 if not WAD.ReadFile(WADName) then
1458 begin
1459 WAD.Free();
1460 Exit;
1461 end;
1462 ResList := WAD.GetMapResources();
1463 if ResList <> nil then
1464 begin
1465 for a := 0 to High(ResList) do
1466 begin
1467 SetLength(Result, Length(Result)+1);
1468 Result[High(Result)] := ResList[a];
1469 end;
1470 end;
1471 WAD.Free();
1472 end;
1474 function g_Map_Exist(Res: string): Boolean;
1475 var
1476 WAD: TWADFile;
1477 FileName, mnn: string;
1478 ResList: SArray;
1479 a: Integer;
1480 begin
1481 Result := False;
1483 FileName := addWadExtension(g_ExtractWadName(Res));
1485 WAD := TWADFile.Create;
1486 if not WAD.ReadFile(FileName) then
1487 begin
1488 WAD.Free();
1489 Exit;
1490 end;
1492 ResList := WAD.GetMapResources();
1493 WAD.Free();
1495 mnn := g_ExtractFileName(Res);
1496 if ResList <> nil then
1497 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1498 begin
1499 Result := True;
1500 Exit;
1501 end;
1502 end;
1504 procedure g_Map_Free();
1505 var
1506 a: Integer;
1508 procedure FreePanelArray(var panels: TPanelArray);
1509 var
1510 i: Integer;
1512 begin
1513 if panels <> nil then
1514 begin
1515 for i := 0 to High(panels) do
1516 panels[i].Free();
1517 panels := nil;
1518 end;
1519 end;
1521 begin
1522 g_GFX_Free();
1523 g_Weapon_Free();
1524 g_Items_Free();
1525 g_Triggers_Free();
1526 g_Monsters_Free();
1528 RespawnPoints := nil;
1529 if FlagPoints[FLAG_RED] <> nil then
1530 begin
1531 Dispose(FlagPoints[FLAG_RED]);
1532 FlagPoints[FLAG_RED] := nil;
1533 end;
1534 if FlagPoints[FLAG_BLUE] <> nil then
1535 begin
1536 Dispose(FlagPoints[FLAG_BLUE]);
1537 FlagPoints[FLAG_BLUE] := nil;
1538 end;
1539 //DOMFlagPoints := nil;
1541 //gDOMFlags := nil;
1543 if Textures <> nil then
1544 begin
1545 for a := 0 to High(Textures) do
1546 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1547 if Textures[a].Anim then
1548 g_Frames_DeleteByID(Textures[a].FramesID)
1549 else
1550 if Textures[a].TextureID <> TEXTURE_NONE then
1551 e_DeleteTexture(Textures[a].TextureID);
1553 Textures := nil;
1554 end;
1556 FreePanelArray(gWalls);
1557 FreePanelArray(gRenderBackgrounds);
1558 FreePanelArray(gRenderForegrounds);
1559 FreePanelArray(gWater);
1560 FreePanelArray(gAcid1);
1561 FreePanelArray(gAcid2);
1562 FreePanelArray(gSteps);
1563 FreePanelArray(gLifts);
1564 FreePanelArray(gBlockMon);
1566 if BackID <> DWORD(-1) then
1567 begin
1568 gBackSize.X := 0;
1569 gBackSize.Y := 0;
1570 e_DeleteTexture(BackID);
1571 BackID := DWORD(-1);
1572 end;
1574 g_Game_StopAllSounds(False);
1575 gMusic.FreeSound();
1576 g_Sound_Delete(gMapInfo.MusicName);
1578 gMapInfo.Name := '';
1579 gMapInfo.Description := '';
1580 gMapInfo.MusicName := '';
1581 gMapInfo.Height := 0;
1582 gMapInfo.Width := 0;
1584 gDoorMap := nil;
1585 gLiftMap := nil;
1586 end;
1588 procedure g_Map_Update();
1589 var
1590 a, d, j: Integer;
1591 m: Word;
1592 s: String;
1594 procedure UpdatePanelArray(var panels: TPanelArray);
1595 var
1596 i: Integer;
1598 begin
1599 if panels <> nil then
1600 for i := 0 to High(panels) do
1601 panels[i].Update();
1602 end;
1604 begin
1605 UpdatePanelArray(gWalls);
1606 UpdatePanelArray(gRenderBackgrounds);
1607 UpdatePanelArray(gRenderForegrounds);
1608 UpdatePanelArray(gWater);
1609 UpdatePanelArray(gAcid1);
1610 UpdatePanelArray(gAcid2);
1611 UpdatePanelArray(gSteps);
1613 if gGameSettings.GameMode = GM_CTF then
1614 begin
1615 for a := FLAG_RED to FLAG_BLUE do
1616 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1617 with gFlags[a] do
1618 begin
1619 if gFlags[a].Animation <> nil then
1620 gFlags[a].Animation.Update();
1622 m := g_Obj_Move(@Obj, True, True);
1624 if gTime mod (GAME_TICK*2) <> 0 then
1625 Continue;
1627 // Ñîïðîòèâëåíèå âîçäóõà:
1628 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1630 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1631 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1632 begin
1633 g_Map_ResetFlag(a);
1634 gFlags[a].CaptureTime := 0;
1635 if a = FLAG_RED then
1636 s := _lc[I_PLAYER_FLAG_RED]
1637 else
1638 s := _lc[I_PLAYER_FLAG_BLUE];
1639 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1641 if g_Game_IsNet then
1642 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1643 Continue;
1644 end;
1646 if Count > 0 then
1647 Count := Count - 1;
1649 // Èãðîê áåðåò ôëàã:
1650 if gPlayers <> nil then
1651 begin
1652 j := Random(Length(gPlayers)) - 1;
1654 for d := 0 to High(gPlayers) do
1655 begin
1656 Inc(j);
1657 if j > High(gPlayers) then
1658 j := 0;
1660 if gPlayers[j] <> nil then
1661 if gPlayers[j].Live and
1662 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1663 begin
1664 if gPlayers[j].GetFlag(a) then
1665 Break;
1666 end;
1667 end;
1668 end;
1669 end;
1670 end;
1671 end;
1673 procedure g_Map_DrawPanels(PanelType: Word);
1675 procedure DrawPanels(var panels: TPanelArray;
1676 drawDoors: Boolean = False);
1677 var
1678 a: Integer;
1680 begin
1681 if panels <> nil then
1682 for a := 0 to High(panels) do
1683 if not (drawDoors xor panels[a].Door) then
1684 panels[a].Draw();
1685 end;
1687 begin
1688 case PanelType of
1689 PANEL_WALL: DrawPanels(gWalls);
1690 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1691 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1692 PANEL_FORE: DrawPanels(gRenderForegrounds);
1693 PANEL_WATER: DrawPanels(gWater);
1694 PANEL_ACID1: DrawPanels(gAcid1);
1695 PANEL_ACID2: DrawPanels(gAcid2);
1696 PANEL_STEP: DrawPanels(gSteps);
1697 end;
1698 end;
1700 procedure g_Map_DrawBack(dx, dy: Integer);
1701 begin
1702 if gDrawBackGround and (BackID <> DWORD(-1)) then
1703 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1704 else
1705 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1706 end;
1708 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1709 PanelType: Word; b1x3: Boolean): Boolean;
1710 var
1711 a, h: Integer;
1712 begin
1713 Result := False;
1715 if WordBool(PanelType and PANEL_WALL) then
1716 if gWalls <> nil then
1717 begin
1718 h := High(gWalls);
1720 for a := 0 to h do
1721 if gWalls[a].Enabled and
1722 g_Collide(X, Y, Width, Height,
1723 gWalls[a].X, gWalls[a].Y,
1724 gWalls[a].Width, gWalls[a].Height) then
1725 begin
1726 Result := True;
1727 Exit;
1728 end;
1729 end;
1731 if WordBool(PanelType and PANEL_WATER) then
1732 if gWater <> nil then
1733 begin
1734 h := High(gWater);
1736 for a := 0 to h do
1737 if g_Collide(X, Y, Width, Height,
1738 gWater[a].X, gWater[a].Y,
1739 gWater[a].Width, gWater[a].Height) then
1740 begin
1741 Result := True;
1742 Exit;
1743 end;
1744 end;
1746 if WordBool(PanelType and PANEL_ACID1) then
1747 if gAcid1 <> nil then
1748 begin
1749 h := High(gAcid1);
1751 for a := 0 to h do
1752 if g_Collide(X, Y, Width, Height,
1753 gAcid1[a].X, gAcid1[a].Y,
1754 gAcid1[a].Width, gAcid1[a].Height) then
1755 begin
1756 Result := True;
1757 Exit;
1758 end;
1759 end;
1761 if WordBool(PanelType and PANEL_ACID2) then
1762 if gAcid2 <> nil then
1763 begin
1764 h := High(gAcid2);
1766 for a := 0 to h do
1767 if g_Collide(X, Y, Width, Height,
1768 gAcid2[a].X, gAcid2[a].Y,
1769 gAcid2[a].Width, gAcid2[a].Height) then
1770 begin
1771 Result := True;
1772 Exit;
1773 end;
1774 end;
1776 if WordBool(PanelType and PANEL_STEP) then
1777 if gSteps <> nil then
1778 begin
1779 h := High(gSteps);
1781 for a := 0 to h do
1782 if g_Collide(X, Y, Width, Height,
1783 gSteps[a].X, gSteps[a].Y,
1784 gSteps[a].Width, gSteps[a].Height) then
1785 begin
1786 Result := True;
1787 Exit;
1788 end;
1789 end;
1791 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1792 if gLifts <> nil then
1793 begin
1794 h := High(gLifts);
1796 for a := 0 to h do
1797 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1798 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1799 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1800 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1801 g_Collide(X, Y, Width, Height,
1802 gLifts[a].X, gLifts[a].Y,
1803 gLifts[a].Width, gLifts[a].Height) then
1804 begin
1805 Result := True;
1806 Exit;
1807 end;
1808 end;
1810 if WordBool(PanelType and PANEL_BLOCKMON) then
1811 if gBlockMon <> nil then
1812 begin
1813 h := High(gBlockMon);
1815 for a := 0 to h do
1816 if ( (not b1x3) or
1817 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1818 g_Collide(X, Y, Width, Height,
1819 gBlockMon[a].X, gBlockMon[a].Y,
1820 gBlockMon[a].Width, gBlockMon[a].Height) then
1821 begin
1822 Result := True;
1823 Exit;
1824 end;
1825 end;
1826 end;
1828 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1829 var
1830 a, h: Integer;
1831 begin
1832 Result := TEXTURE_NONE;
1834 if gWater <> nil then
1835 begin
1836 h := High(gWater);
1838 for a := 0 to h do
1839 if g_Collide(X, Y, Width, Height,
1840 gWater[a].X, gWater[a].Y,
1841 gWater[a].Width, gWater[a].Height) then
1842 begin
1843 Result := gWater[a].GetTextureID();
1844 Exit;
1845 end;
1846 end;
1848 if gAcid1 <> nil then
1849 begin
1850 h := High(gAcid1);
1852 for a := 0 to h do
1853 if g_Collide(X, Y, Width, Height,
1854 gAcid1[a].X, gAcid1[a].Y,
1855 gAcid1[a].Width, gAcid1[a].Height) then
1856 begin
1857 Result := gAcid1[a].GetTextureID();
1858 Exit;
1859 end;
1860 end;
1862 if gAcid2 <> nil then
1863 begin
1864 h := High(gAcid2);
1866 for a := 0 to h do
1867 if g_Collide(X, Y, Width, Height,
1868 gAcid2[a].X, gAcid2[a].Y,
1869 gAcid2[a].Width, gAcid2[a].Height) then
1870 begin
1871 Result := gAcid2[a].GetTextureID();
1872 Exit;
1873 end;
1874 end;
1875 end;
1877 procedure g_Map_EnableWall(ID: DWORD);
1878 begin
1879 with gWalls[ID] do
1880 begin
1881 Enabled := True;
1882 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1884 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1885 end;
1886 end;
1888 procedure g_Map_DisableWall(ID: DWORD);
1889 begin
1890 with gWalls[ID] do
1891 begin
1892 Enabled := False;
1893 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1895 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1896 end;
1897 end;
1899 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1900 var
1901 tp: TPanel;
1902 begin
1903 case PanelType of
1904 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1905 tp := gWalls[ID];
1906 PANEL_FORE:
1907 tp := gRenderForegrounds[ID];
1908 PANEL_BACK:
1909 tp := gRenderBackgrounds[ID];
1910 PANEL_WATER:
1911 tp := gWater[ID];
1912 PANEL_ACID1:
1913 tp := gAcid1[ID];
1914 PANEL_ACID2:
1915 tp := gAcid2[ID];
1916 PANEL_STEP:
1917 tp := gSteps[ID];
1918 else
1919 Exit;
1920 end;
1922 tp.NextTexture(AnimLoop);
1923 if g_Game_IsServer and g_Game_IsNet then
1924 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1925 end;
1927 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1928 begin
1929 if gLifts[ID].LiftType = t then
1930 Exit;
1932 with gLifts[ID] do
1933 begin
1934 LiftType := t;
1936 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1938 if LiftType = 0 then
1939 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1940 else if LiftType = 1 then
1941 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1942 else if LiftType = 2 then
1943 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1944 else if LiftType = 3 then
1945 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1947 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1948 end;
1949 end;
1951 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1952 var
1953 a: Integer;
1954 PointsArray: Array of TRespawnPoint;
1955 begin
1956 Result := False;
1957 SetLength(PointsArray, 0);
1959 if RespawnPoints = nil then
1960 Exit;
1962 for a := 0 to High(RespawnPoints) do
1963 if RespawnPoints[a].PointType = PointType then
1964 begin
1965 SetLength(PointsArray, Length(PointsArray)+1);
1966 PointsArray[High(PointsArray)] := RespawnPoints[a];
1967 end;
1969 if PointsArray = nil then
1970 Exit;
1972 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1973 Result := True;
1974 end;
1976 function g_Map_GetPointCount(PointType: Byte): Word;
1977 var
1978 a: Integer;
1979 begin
1980 Result := 0;
1982 if RespawnPoints = nil then
1983 Exit;
1985 for a := 0 to High(RespawnPoints) do
1986 if RespawnPoints[a].PointType = PointType then
1987 Result := Result + 1;
1988 end;
1990 function g_Map_HaveFlagPoints(): Boolean;
1991 begin
1992 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1993 end;
1995 procedure g_Map_ResetFlag(Flag: Byte);
1996 begin
1997 with gFlags[Flag] do
1998 begin
1999 Obj.X := -1000;
2000 Obj.Y := -1000;
2001 Obj.Vel.X := 0;
2002 Obj.Vel.Y := 0;
2003 Direction := D_LEFT;
2004 State := FLAG_STATE_NONE;
2005 if FlagPoints[Flag] <> nil then
2006 begin
2007 Obj.X := FlagPoints[Flag]^.X;
2008 Obj.Y := FlagPoints[Flag]^.Y;
2009 Direction := FlagPoints[Flag]^.Direction;
2010 State := FLAG_STATE_NORMAL;
2011 end;
2012 Count := -1;
2013 end;
2014 end;
2016 procedure g_Map_DrawFlags();
2017 var
2018 i, dx: Integer;
2019 Mirror: TMirrorType;
2020 begin
2021 if gGameSettings.GameMode <> GM_CTF then
2022 Exit;
2024 for i := FLAG_RED to FLAG_BLUE do
2025 with gFlags[i] do
2026 if State <> FLAG_STATE_CAPTURED then
2027 begin
2028 if State = FLAG_STATE_NONE then
2029 continue;
2031 if Direction = D_LEFT then
2032 begin
2033 Mirror := M_HORIZONTAL;
2034 dx := -1;
2035 end
2036 else
2037 begin
2038 Mirror := M_NONE;
2039 dx := 1;
2040 end;
2042 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2044 if g_debug_Frames then
2045 begin
2046 e_DrawQuad(Obj.X+Obj.Rect.X,
2047 Obj.Y+Obj.Rect.Y,
2048 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2049 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2050 0, 255, 0);
2051 end;
2052 end;
2053 end;
2055 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2056 var
2057 dw: DWORD;
2058 b: Byte;
2059 str: String;
2060 boo: Boolean;
2062 procedure SavePanelArray(var panels: TPanelArray);
2063 var
2064 PAMem: TBinMemoryWriter;
2065 i: Integer;
2066 begin
2067 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2068 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2070 i := 0;
2071 while i < Length(panels) do
2072 begin
2073 if panels[i].SaveIt then
2074 begin
2075 // ID ïàíåëè:
2076 PAMem.WriteInt(i);
2077 // Ñîõðàíÿåì ïàíåëü:
2078 panels[i].SaveState(PAMem);
2079 end;
2080 Inc(i);
2081 end;
2083 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2084 PAMem.SaveToMemory(Mem);
2085 PAMem.Free();
2086 end;
2088 procedure SaveFlag(flag: PFlag);
2089 begin
2090 // Ñèãíàòóðà ôëàãà:
2091 dw := FLAG_SIGNATURE; // 'FLAG'
2092 Mem.WriteDWORD(dw);
2093 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2094 Mem.WriteByte(flag^.RespawnType);
2095 // Ñîñòîÿíèå ôëàãà:
2096 Mem.WriteByte(flag^.State);
2097 // Íàïðàâëåíèå ôëàãà:
2098 if flag^.Direction = D_LEFT then
2099 b := 1
2100 else // D_RIGHT
2101 b := 2;
2102 Mem.WriteByte(b);
2103 // Îáúåêò ôëàãà:
2104 Obj_SaveState(@flag^.Obj, Mem);
2105 end;
2107 begin
2108 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2110 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2111 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2112 SavePanelArray(gWalls);
2113 // Ñîõðàíÿåì ïàíåëè ôîíà:
2114 SavePanelArray(gRenderBackgrounds);
2115 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2116 SavePanelArray(gRenderForegrounds);
2117 // Ñîõðàíÿåì ïàíåëè âîäû:
2118 SavePanelArray(gWater);
2119 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2120 SavePanelArray(gAcid1);
2121 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2122 SavePanelArray(gAcid2);
2123 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2124 SavePanelArray(gSteps);
2125 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2126 SavePanelArray(gLifts);
2127 ///// /////
2129 ///// Ñîõðàíÿåì ìóçûêó: /////
2130 // Ñèãíàòóðà ìóçûêè:
2131 dw := MUSIC_SIGNATURE; // 'MUSI'
2132 Mem.WriteDWORD(dw);
2133 // Íàçâàíèå ìóçûêè:
2134 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2135 if gMusic.NoMusic then
2136 str := ''
2137 else
2138 str := gMusic.Name;
2139 Mem.WriteString(str, 64);
2140 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2141 dw := gMusic.GetPosition();
2142 Mem.WriteDWORD(dw);
2143 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2144 boo := gMusic.SpecPause;
2145 Mem.WriteBoolean(boo);
2146 ///// /////
2148 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2149 Mem.WriteInt(gTotalMonsters);
2150 ///// /////
2152 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2153 if gGameSettings.GameMode = GM_CTF then
2154 begin
2155 // Ôëàã Êðàñíîé êîìàíäû:
2156 SaveFlag(@gFlags[FLAG_RED]);
2157 // Ôëàã Ñèíåé êîìàíäû:
2158 SaveFlag(@gFlags[FLAG_BLUE]);
2159 end;
2160 ///// /////
2162 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2163 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2164 begin
2165 // Î÷êè Êðàñíîé êîìàíäû:
2166 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2167 // Î÷êè Ñèíåé êîìàíäû:
2168 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2169 end;
2170 ///// /////
2171 end;
2173 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2174 var
2175 dw: DWORD;
2176 b: Byte;
2177 str: String;
2178 boo: Boolean;
2180 procedure LoadPanelArray(var panels: TPanelArray);
2181 var
2182 PAMem: TBinMemoryReader;
2183 i, id: Integer;
2184 begin
2185 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2186 PAMem := TBinMemoryReader.Create();
2187 PAMem.LoadFromMemory(Mem);
2189 for i := 0 to Length(panels)-1 do
2190 if panels[i].SaveIt then
2191 begin
2192 // ID ïàíåëè:
2193 PAMem.ReadInt(id);
2194 if id <> i then
2195 begin
2196 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2197 end;
2198 // Çàãðóæàåì ïàíåëü:
2199 panels[i].LoadState(PAMem);
2200 end;
2202 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2203 PAMem.Free();
2204 end;
2206 procedure LoadFlag(flag: PFlag);
2207 begin
2208 // Ñèãíàòóðà ôëàãà:
2209 Mem.ReadDWORD(dw);
2210 if dw <> FLAG_SIGNATURE then // 'FLAG'
2211 begin
2212 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2213 end;
2214 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2215 Mem.ReadByte(flag^.RespawnType);
2216 // Ñîñòîÿíèå ôëàãà:
2217 Mem.ReadByte(flag^.State);
2218 // Íàïðàâëåíèå ôëàãà:
2219 Mem.ReadByte(b);
2220 if b = 1 then
2221 flag^.Direction := D_LEFT
2222 else // b = 2
2223 flag^.Direction := D_RIGHT;
2224 // Îáúåêò ôëàãà:
2225 Obj_LoadState(@flag^.Obj, Mem);
2226 end;
2228 begin
2229 if Mem = nil then
2230 Exit;
2232 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2233 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2234 LoadPanelArray(gWalls);
2235 // Çàãðóæàåì ïàíåëè ôîíà:
2236 LoadPanelArray(gRenderBackgrounds);
2237 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2238 LoadPanelArray(gRenderForegrounds);
2239 // Çàãðóæàåì ïàíåëè âîäû:
2240 LoadPanelArray(gWater);
2241 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2242 LoadPanelArray(gAcid1);
2243 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2244 LoadPanelArray(gAcid2);
2245 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2246 LoadPanelArray(gSteps);
2247 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2248 LoadPanelArray(gLifts);
2249 ///// /////
2251 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2252 g_GFX_Init();
2254 ///// Çàãðóæàåì ìóçûêó: /////
2255 // Ñèãíàòóðà ìóçûêè:
2256 Mem.ReadDWORD(dw);
2257 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2258 begin
2259 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2260 end;
2261 // Íàçâàíèå ìóçûêè:
2262 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2263 Mem.ReadString(str);
2264 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2265 Mem.ReadDWORD(dw);
2266 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2267 Mem.ReadBoolean(boo);
2268 // Çàïóñêàåì ýòó ìóçûêó:
2269 gMusic.SetByName(str);
2270 gMusic.SpecPause := boo;
2271 gMusic.Play();
2272 gMusic.Pause(True);
2273 gMusic.SetPosition(dw);
2274 ///// /////
2276 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2277 Mem.ReadInt(gTotalMonsters);
2278 ///// /////
2280 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2281 if gGameSettings.GameMode = GM_CTF then
2282 begin
2283 // Ôëàã Êðàñíîé êîìàíäû:
2284 LoadFlag(@gFlags[FLAG_RED]);
2285 // Ôëàã Ñèíåé êîìàíäû:
2286 LoadFlag(@gFlags[FLAG_BLUE]);
2287 end;
2288 ///// /////
2290 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2291 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2292 begin
2293 // Î÷êè Êðàñíîé êîìàíäû:
2294 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2295 // Î÷êè Ñèíåé êîìàíäû:
2296 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2297 end;
2298 ///// /////
2299 end;
2301 end.