DEADSOFTWARE

one game tick is closer to 28 milliseconds, so i made it 28
[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, c: 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 if f < 0 then f := 0;
654 // rounding ;-)
655 c := f mod 28;
656 if c < 13 then c := 0 else c := 1;
657 f := (f div 28)+c;
658 if f < 1 then f := 1 else if f > 255 then f := 255;
659 _speed := f;
660 except
661 end;
662 end;
663 if meta.HasMetaItem(SMetaAnimationLoops) then
664 begin
665 //writeln(' frame loop : ', meta.MetaItems[SMetaAnimationLoops]);
666 try
667 f := meta.MetaItems[SMetaAnimationLoops];
668 if f <> 0 then _backanimation := true;
669 except
670 end;
671 end;
672 end;
673 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
674 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
675 //e_WriteLog(Format('Animated texture file "%s": %d frames (delay:%d), %dx%d', [RecName, length(ia), _speed, _width, _height]), MSG_NOTIFY);
677 SetLength(Textures, Length(Textures)+1);
678 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
679 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
680 begin
681 Textures[High(Textures)].TextureName := RecName;
682 Textures[High(Textures)].Width := _width;
683 Textures[High(Textures)].Height := _height;
684 Textures[High(Textures)].Anim := True;
685 Textures[High(Textures)].FramesCount := length(ia);
686 Textures[High(Textures)].Speed := _speed;
687 result := High(Textures);
688 //writeln(' CREATED!');
689 end
690 else
691 begin
692 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
693 end;
694 end;
695 finally
696 for f := 0 to High(ia) do FreeImage(ia[f]);
697 il.Free();
698 //???meta.Free();
699 WAD.Free();
700 cfg.Free();
701 if TextureWAD <> nil then FreeMem(TextureWAD);
702 if TextData <> nil then FreeMem(TextData);
703 if TextureData <> nil then FreeMem(TextureData);
704 end;
705 end;
707 procedure CreateItem(Item: TItemRec_1);
708 begin
709 if g_Game_IsClient then Exit;
711 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
712 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
713 Exit;
715 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
716 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
717 end;
719 procedure CreateArea(Area: TAreaRec_1);
720 var
721 a: Integer;
722 id: DWORD;
723 begin
724 case Area.AreaType of
725 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
726 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
727 begin
728 SetLength(RespawnPoints, Length(RespawnPoints)+1);
729 with RespawnPoints[High(RespawnPoints)] do
730 begin
731 X := Area.X;
732 Y := Area.Y;
733 Direction := TDirection(Area.Direction);
735 case Area.AreaType of
736 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
737 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
738 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
739 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
740 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
741 end;
742 end;
743 end;
745 AREA_REDFLAG, AREA_BLUEFLAG:
746 begin
747 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
749 if FlagPoints[a] <> nil then Exit;
751 New(FlagPoints[a]);
753 with FlagPoints[a]^ do
754 begin
755 X := Area.X-FLAGRECT.X;
756 Y := Area.Y-FLAGRECT.Y;
757 Direction := TDirection(Area.Direction);
758 end;
760 with gFlags[a] do
761 begin
762 case a of
763 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
764 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
765 end;
767 Animation := TAnimation.Create(id, True, 8);
768 Obj.Rect := FLAGRECT;
770 g_Map_ResetFlag(a);
771 end;
772 end;
774 AREA_DOMFLAG:
775 begin
776 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
777 with DOMFlagPoints[High(DOMFlagPoints)] do
778 begin
779 X := Area.X;
780 Y := Area.Y;
781 Direction := TDirection(Area.Direction);
782 end;
784 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
785 end;
786 end;
787 end;
789 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
790 var
791 _trigger: TTrigger;
792 begin
793 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
795 with _trigger do
796 begin
797 X := Trigger.X;
798 Y := Trigger.Y;
799 Width := Trigger.Width;
800 Height := Trigger.Height;
801 Enabled := ByteBool(Trigger.Enabled);
802 TexturePanel := Trigger.TexturePanel;
803 TexturePanelType := fTexturePanel1Type;
804 ShotPanelType := fTexturePanel2Type;
805 TriggerType := Trigger.TriggerType;
806 ActivateType := Trigger.ActivateType;
807 Keys := Trigger.Keys;
808 Data.Default := Trigger.DATA;
809 end;
811 g_Triggers_Create(_trigger);
812 end;
814 procedure CreateMonster(monster: TMonsterRec_1);
815 var
816 a, i: Integer;
817 begin
818 if g_Game_IsClient then Exit;
820 if (gGameSettings.GameType = GT_SINGLE)
821 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
822 begin
823 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
824 TDirection(monster.Direction));
826 if gTriggers <> nil then
827 for a := 0 to High(gTriggers) do
828 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
829 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
830 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
831 gMonsters[i].AddTrigger(a);
833 if monster.MonsterType <> MONSTER_BARREL then
834 Inc(gTotalMonsters);
835 end;
836 end;
838 procedure g_Map_ReAdd_DieTriggers();
839 var
840 i, a: Integer;
841 begin
842 if g_Game_IsClient then Exit;
844 for i := 0 to High(gMonsters) do
845 if gMonsters[i] <> nil then
846 begin
847 gMonsters[i].ClearTriggers();
849 for a := 0 to High(gTriggers) do
850 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
851 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
852 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
853 gMonsters[i].AddTrigger(a);
854 end;
855 end;
857 function extractWadName(resourceName: string): string;
858 var
859 posN: Integer;
860 begin
861 posN := Pos(':', resourceName);
862 if posN > 0 then
863 Result:= Copy(resourceName, 0, posN-1)
864 else
865 Result := '';
866 end;
868 procedure addResToExternalResList(res: string);
869 begin
870 res := extractWadName(res);
871 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
872 gExternalResources.Add(res);
873 end;
875 procedure generateExternalResourcesList(mapReader: TMapReader_1);
876 var
877 textures: TTexturesRec1Array;
878 mapHeader: TMapHeaderRec_1;
879 i: integer;
880 resFile: String = '';
881 begin
882 if gExternalResources = nil then
883 gExternalResources := TStringList.Create;
885 gExternalResources.Clear;
886 textures := mapReader.GetTextures();
887 for i := 0 to High(textures) do
888 begin
889 addResToExternalResList(resFile);
890 end;
892 textures := nil;
894 mapHeader := mapReader.GetMapHeader;
896 addResToExternalResList(mapHeader.MusicName);
897 addResToExternalResList(mapHeader.SkyName);
898 end;
900 function g_Map_Load(Res: String): Boolean;
901 const
902 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
903 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
904 var
905 WAD: TWADFile;
906 MapReader: TMapReader_1;
907 Header: TMapHeaderRec_1;
908 _textures: TTexturesRec1Array;
909 _texnummap: array of Integer; // `_textures` -> `Textures`
910 panels: TPanelsRec1Array;
911 items: TItemsRec1Array;
912 monsters: TMonsterRec1Array;
913 areas: TAreasRec1Array;
914 triggers: TTriggersRec1Array;
915 a, b, c, k: Integer;
916 PanelID: DWORD;
917 AddTextures: TAddTextureArray;
918 texture: TTextureRec_1;
919 TriggersTable: Array of record
920 TexturePanel: Integer;
921 LiftPanel: Integer;
922 DoorPanel: Integer;
923 ShotPanel: Integer;
924 end;
925 FileName, mapResName, s, TexName: String;
926 Data: Pointer;
927 Len: Integer;
928 ok, isAnim, trigRef: Boolean;
929 CurTex, ntn: Integer;
930 begin
931 Result := False;
932 gMapInfo.Map := Res;
933 TriggersTable := nil;
934 FillChar(texture, SizeOf(texture), 0);
936 sfsGCDisable(); // temporary disable removing of temporary volumes
937 try
938 // Çàãðóçêà WAD:
939 FileName := g_ExtractWadName(Res);
940 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
941 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
943 WAD := TWADFile.Create();
944 if not WAD.ReadFile(FileName) then
945 begin
946 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
947 WAD.Free();
948 Exit;
949 end;
950 //k8: why loader ignores path here?
951 mapResName := g_ExtractFileName(Res);
952 if not WAD.GetMapResource(mapResName, Data, Len) then
953 begin
954 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
955 WAD.Free();
956 Exit;
957 end;
958 WAD.Free();
960 // Çàãðóçêà êàðòû:
961 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
962 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
963 MapReader := TMapReader_1.Create();
965 if not MapReader.LoadMap(Data) then
966 begin
967 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
968 FreeMem(Data);
969 MapReader.Free();
970 Exit;
971 end;
973 FreeMem(Data);
974 generateExternalResourcesList(MapReader);
975 // Çàãðóçêà òåêñòóð:
976 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
977 _textures := MapReader.GetTextures();
978 _texnummap := nil;
980 // Äîáàâëåíèå òåêñòóð â Textures[]:
981 if _textures <> nil then
982 begin
983 e_WriteLog(' Loading textures:', MSG_NOTIFY);
984 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
985 SetLength(_texnummap, length(_textures));
987 for a := 0 to High(_textures) do
988 begin
989 SetLength(s, 64);
990 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
991 for b := 1 to Length(s) do
992 if s[b] = #0 then
993 begin
994 SetLength(s, b-1);
995 Break;
996 end;
997 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
998 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
999 // Àíèìèðîâàííàÿ òåêñòóðà:
1000 if ByteBool(_textures[a].Anim) then
1001 begin
1002 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1003 if ntn < 0 then
1004 begin
1005 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1006 ntn := CreateNullTexture(_textures[a].Resource);
1007 end;
1008 end
1009 else // Îáû÷íàÿ òåêñòóðà:
1010 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1011 if ntn < 0 then
1012 begin
1013 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1014 ntn := CreateNullTexture(_textures[a].Resource);
1015 end;
1017 _texnummap[a] := ntn; // fix texture number
1018 g_Game_StepLoading();
1019 end;
1020 end;
1022 // Çàãðóçêà òðèããåðîâ:
1023 gTriggerClientID := 0;
1024 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1025 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1026 triggers := MapReader.GetTriggers();
1028 // Çàãðóçêà ïàíåëåé:
1029 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1030 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1031 panels := MapReader.GetPanels();
1033 // check texture numbers for panels
1034 for a := 0 to High(panels) do
1035 begin
1036 if panels[a].TextureNum > High(_textures) then
1037 begin
1038 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1039 result := false;
1040 exit;
1041 end;
1042 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1043 end;
1045 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1046 if triggers <> nil then
1047 begin
1048 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1049 SetLength(TriggersTable, Length(triggers));
1050 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1052 for a := 0 to High(TriggersTable) do
1053 begin
1054 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1055 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1056 // Ëèôòû:
1057 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1058 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1059 else
1060 TriggersTable[a].LiftPanel := -1;
1061 // Äâåðè:
1062 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1063 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1064 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1065 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1066 else
1067 TriggersTable[a].DoorPanel := -1;
1068 // Òóðåëü:
1069 if triggers[a].TriggerType = TRIGGER_SHOT then
1070 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1071 else
1072 TriggersTable[a].ShotPanel := -1;
1074 g_Game_StepLoading();
1075 end;
1076 end;
1078 // Ñîçäàåì ïàíåëè:
1079 if panels <> nil then
1080 begin
1081 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1082 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1084 for a := 0 to High(panels) do
1085 begin
1086 SetLength(AddTextures, 0);
1087 trigRef := False;
1088 CurTex := -1;
1089 if _textures <> nil then
1090 begin
1091 texture := _textures[panels[a].TextureNum];
1092 ok := True;
1093 end
1094 else
1095 ok := False;
1097 if ok then
1098 begin
1099 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1100 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1101 ok := False;
1102 if (TriggersTable <> nil) and (_textures <> nil) then
1103 for b := 0 to High(TriggersTable) do
1104 if (TriggersTable[b].TexturePanel = a)
1105 or (TriggersTable[b].ShotPanel = a) then
1106 begin
1107 trigRef := True;
1108 ok := True;
1109 Break;
1110 end;
1111 end;
1113 if ok then
1114 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1115 SetLength(s, 64);
1116 CopyMemory(@s[1], @texture.Resource[0], 64);
1117 // Èçìåðÿåì äëèíó:
1118 Len := Length(s);
1119 for c := Len downto 1 do
1120 if s[c] <> #0 then
1121 begin
1122 Len := c;
1123 Break;
1124 end;
1125 SetLength(s, Len);
1127 // Ñïåö-òåêñòóðû çàïðåùåíû:
1128 if g_Map_IsSpecialTexture(s) then
1129 ok := False
1130 else
1131 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1132 ok := g_Texture_NumNameFindStart(s);
1134 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1135 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1136 if ok then
1137 begin
1138 k := NNF_NAME_BEFORE;
1139 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1140 while ok or (k = NNF_NAME_BEFORE) or
1141 (k = NNF_NAME_EQUALS) do
1142 begin
1143 k := g_Texture_NumNameFindNext(TexName);
1145 if (k = NNF_NAME_BEFORE) or
1146 (k = NNF_NAME_AFTER) then
1147 begin
1148 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1149 if ByteBool(texture.Anim) then
1150 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1151 isAnim := True;
1152 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1153 if not ok then
1154 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1155 isAnim := False;
1156 ok := CreateTexture(TexName, FileName, False) >= 0;
1157 end;
1158 end
1159 else
1160 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1161 isAnim := False;
1162 ok := CreateTexture(TexName, FileName, False) >= 0;
1163 if not ok then
1164 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1165 isAnim := True;
1166 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1167 end;
1168 end;
1170 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1171 if ok then
1172 begin
1173 for c := 0 to High(Textures) do
1174 if Textures[c].TextureName = TexName then
1175 begin
1176 SetLength(AddTextures, Length(AddTextures)+1);
1177 AddTextures[High(AddTextures)].Texture := c;
1178 AddTextures[High(AddTextures)].Anim := isAnim;
1179 Break;
1180 end;
1181 end;
1182 end
1183 else
1184 if k = NNF_NAME_EQUALS then
1185 begin
1186 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1187 SetLength(AddTextures, Length(AddTextures)+1);
1188 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1189 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1190 CurTex := High(AddTextures);
1191 ok := True;
1192 end
1193 else // NNF_NO_NAME
1194 ok := False;
1195 end; // while ok...
1197 ok := True;
1198 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1199 end; // if ok - ññûëàþòñÿ òðèããåðû
1201 if not ok then
1202 begin
1203 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1204 SetLength(AddTextures, 1);
1205 AddTextures[0].Texture := panels[a].TextureNum;
1206 AddTextures[0].Anim := ByteBool(texture.Anim);
1207 CurTex := 0;
1208 end;
1210 //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);
1212 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1213 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1215 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1216 if TriggersTable <> nil then
1217 for b := 0 to High(TriggersTable) do
1218 begin
1219 // Òðèããåð äâåðè/ëèôòà:
1220 if (TriggersTable[b].LiftPanel = a) or
1221 (TriggersTable[b].DoorPanel = a) then
1222 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1223 // Òðèããåð ñìåíû òåêñòóðû:
1224 if TriggersTable[b].TexturePanel = a then
1225 triggers[b].TexturePanel := PanelID;
1226 // Òðèããåð "Òóðåëü":
1227 if TriggersTable[b].ShotPanel = a then
1228 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1229 end;
1231 g_Game_StepLoading();
1232 end;
1233 end;
1235 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1236 if (triggers <> nil) and not gLoadGameMode then
1237 begin
1238 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1239 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1240 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1241 for a := 0 to High(triggers) do
1242 begin
1243 if triggers[a].TexturePanel <> -1 then
1244 b := panels[TriggersTable[a].TexturePanel].PanelType
1245 else
1246 b := 0;
1247 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1248 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1249 c := panels[TriggersTable[a].ShotPanel].PanelType
1250 else
1251 c := 0;
1252 CreateTrigger(triggers[a], b, c);
1253 end;
1254 end;
1256 // Çàãðóçêà ïðåäìåòîâ:
1257 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1258 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1259 items := MapReader.GetItems();
1261 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1262 if (items <> nil) and not gLoadGameMode then
1263 begin
1264 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1265 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1266 for a := 0 to High(items) do
1267 CreateItem(Items[a]);
1268 end;
1270 // Çàãðóçêà îáëàñòåé:
1271 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1272 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1273 areas := MapReader.GetAreas();
1275 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1276 if areas <> nil then
1277 begin
1278 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1279 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1280 for a := 0 to High(areas) do
1281 CreateArea(areas[a]);
1282 end;
1284 // Çàãðóçêà ìîíñòðîâ:
1285 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1286 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1287 monsters := MapReader.GetMonsters();
1289 gTotalMonsters := 0;
1291 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1292 if (monsters <> nil) and not gLoadGameMode then
1293 begin
1294 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1295 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1296 for a := 0 to High(monsters) do
1297 CreateMonster(monsters[a]);
1298 end;
1300 // Çàãðóçêà îïèñàíèÿ êàðòû:
1301 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1302 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1303 Header := MapReader.GetMapHeader();
1305 MapReader.Free();
1307 with gMapInfo do
1308 begin
1309 Name := Header.MapName;
1310 Description := Header.MapDescription;
1311 Author := Header.MapAuthor;
1312 MusicName := Header.MusicName;
1313 SkyName := Header.SkyName;
1314 Height := Header.Height;
1315 Width := Header.Width;
1316 end;
1318 // Çàãðóçêà íåáà:
1319 if gMapInfo.SkyName <> '' then
1320 begin
1321 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1322 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1323 FileName := g_ExtractWadName(gMapInfo.SkyName);
1325 if FileName <> '' then
1326 FileName := GameDir+'/wads/'+FileName
1327 else
1328 begin
1329 FileName := g_ExtractWadName(Res);
1330 end;
1332 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1333 if g_Texture_CreateWAD(BackID, s) then
1334 begin
1335 g_Game_SetupScreenSize();
1336 end
1337 else
1338 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1339 end;
1341 // Çàãðóçêà ìóçûêè:
1342 ok := False;
1343 if gMapInfo.MusicName <> '' then
1344 begin
1345 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1346 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1347 FileName := g_ExtractWadName(gMapInfo.MusicName);
1349 if FileName <> '' then
1350 FileName := GameDir+'/wads/'+FileName
1351 else
1352 begin
1353 FileName := g_ExtractWadName(Res);
1354 end;
1356 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1357 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1358 ok := True
1359 else
1360 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1361 end;
1363 // Îñòàëüíûå óñòàíâêè:
1364 CreateDoorMap();
1365 CreateLiftMap();
1367 g_Items_Init();
1368 g_Weapon_Init();
1369 g_Monsters_Init();
1371 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1372 if not gLoadGameMode then
1373 g_GFX_Init();
1375 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1376 _textures := nil;
1377 panels := nil;
1378 items := nil;
1379 areas := nil;
1380 triggers := nil;
1381 TriggersTable := nil;
1382 AddTextures := nil;
1384 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1385 if ok and (not gLoadGameMode) then
1386 begin
1387 gMusic.SetByName(gMapInfo.MusicName);
1388 gMusic.Play();
1389 end
1390 else
1391 gMusic.SetByName('');
1392 finally
1393 sfsGCEnable(); // enable releasing unused volumes
1394 end;
1396 e_WriteLog('Done loading map.', MSG_NOTIFY);
1397 Result := True;
1398 end;
1400 function g_Map_GetMapInfo(Res: String): TMapInfo;
1401 var
1402 WAD: TWADFile;
1403 MapReader: TMapReader_1;
1404 Header: TMapHeaderRec_1;
1405 FileName: String;
1406 Data: Pointer;
1407 Len: Integer;
1408 begin
1409 FillChar(Result, SizeOf(Result), 0);
1410 FileName := g_ExtractWadName(Res);
1412 WAD := TWADFile.Create();
1413 if not WAD.ReadFile(FileName) then
1414 begin
1415 WAD.Free();
1416 Exit;
1417 end;
1419 //k8: it ignores path again
1420 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1421 begin
1422 WAD.Free();
1423 Exit;
1424 end;
1426 WAD.Free();
1428 MapReader := TMapReader_1.Create();
1430 if not MapReader.LoadMap(Data) then
1431 begin
1432 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1433 ZeroMemory(@Header, SizeOf(Header));
1434 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1435 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1436 end
1437 else
1438 begin
1439 Header := MapReader.GetMapHeader();
1440 Result.Name := Header.MapName;
1441 Result.Description := Header.MapDescription;
1442 end;
1444 FreeMem(Data);
1445 MapReader.Free();
1447 Result.Map := Res;
1448 Result.Author := Header.MapAuthor;
1449 Result.Height := Header.Height;
1450 Result.Width := Header.Width;
1451 end;
1453 function g_Map_GetMapsList(WADName: string): SArray;
1454 var
1455 WAD: TWADFile;
1456 a: Integer;
1457 ResList: SArray;
1458 begin
1459 Result := nil;
1460 WAD := TWADFile.Create();
1461 if not WAD.ReadFile(WADName) then
1462 begin
1463 WAD.Free();
1464 Exit;
1465 end;
1466 ResList := WAD.GetMapResources();
1467 if ResList <> nil then
1468 begin
1469 for a := 0 to High(ResList) do
1470 begin
1471 SetLength(Result, Length(Result)+1);
1472 Result[High(Result)] := ResList[a];
1473 end;
1474 end;
1475 WAD.Free();
1476 end;
1478 function g_Map_Exist(Res: string): Boolean;
1479 var
1480 WAD: TWADFile;
1481 FileName, mnn: string;
1482 ResList: SArray;
1483 a: Integer;
1484 begin
1485 Result := False;
1487 FileName := addWadExtension(g_ExtractWadName(Res));
1489 WAD := TWADFile.Create;
1490 if not WAD.ReadFile(FileName) then
1491 begin
1492 WAD.Free();
1493 Exit;
1494 end;
1496 ResList := WAD.GetMapResources();
1497 WAD.Free();
1499 mnn := g_ExtractFileName(Res);
1500 if ResList <> nil then
1501 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1502 begin
1503 Result := True;
1504 Exit;
1505 end;
1506 end;
1508 procedure g_Map_Free();
1509 var
1510 a: Integer;
1512 procedure FreePanelArray(var panels: TPanelArray);
1513 var
1514 i: Integer;
1516 begin
1517 if panels <> nil then
1518 begin
1519 for i := 0 to High(panels) do
1520 panels[i].Free();
1521 panels := nil;
1522 end;
1523 end;
1525 begin
1526 g_GFX_Free();
1527 g_Weapon_Free();
1528 g_Items_Free();
1529 g_Triggers_Free();
1530 g_Monsters_Free();
1532 RespawnPoints := nil;
1533 if FlagPoints[FLAG_RED] <> nil then
1534 begin
1535 Dispose(FlagPoints[FLAG_RED]);
1536 FlagPoints[FLAG_RED] := nil;
1537 end;
1538 if FlagPoints[FLAG_BLUE] <> nil then
1539 begin
1540 Dispose(FlagPoints[FLAG_BLUE]);
1541 FlagPoints[FLAG_BLUE] := nil;
1542 end;
1543 //DOMFlagPoints := nil;
1545 //gDOMFlags := nil;
1547 if Textures <> nil then
1548 begin
1549 for a := 0 to High(Textures) do
1550 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1551 if Textures[a].Anim then
1552 g_Frames_DeleteByID(Textures[a].FramesID)
1553 else
1554 if Textures[a].TextureID <> TEXTURE_NONE then
1555 e_DeleteTexture(Textures[a].TextureID);
1557 Textures := nil;
1558 end;
1560 FreePanelArray(gWalls);
1561 FreePanelArray(gRenderBackgrounds);
1562 FreePanelArray(gRenderForegrounds);
1563 FreePanelArray(gWater);
1564 FreePanelArray(gAcid1);
1565 FreePanelArray(gAcid2);
1566 FreePanelArray(gSteps);
1567 FreePanelArray(gLifts);
1568 FreePanelArray(gBlockMon);
1570 if BackID <> DWORD(-1) then
1571 begin
1572 gBackSize.X := 0;
1573 gBackSize.Y := 0;
1574 e_DeleteTexture(BackID);
1575 BackID := DWORD(-1);
1576 end;
1578 g_Game_StopAllSounds(False);
1579 gMusic.FreeSound();
1580 g_Sound_Delete(gMapInfo.MusicName);
1582 gMapInfo.Name := '';
1583 gMapInfo.Description := '';
1584 gMapInfo.MusicName := '';
1585 gMapInfo.Height := 0;
1586 gMapInfo.Width := 0;
1588 gDoorMap := nil;
1589 gLiftMap := nil;
1590 end;
1592 procedure g_Map_Update();
1593 var
1594 a, d, j: Integer;
1595 m: Word;
1596 s: String;
1598 procedure UpdatePanelArray(var panels: TPanelArray);
1599 var
1600 i: Integer;
1602 begin
1603 if panels <> nil then
1604 for i := 0 to High(panels) do
1605 panels[i].Update();
1606 end;
1608 begin
1609 UpdatePanelArray(gWalls);
1610 UpdatePanelArray(gRenderBackgrounds);
1611 UpdatePanelArray(gRenderForegrounds);
1612 UpdatePanelArray(gWater);
1613 UpdatePanelArray(gAcid1);
1614 UpdatePanelArray(gAcid2);
1615 UpdatePanelArray(gSteps);
1617 if gGameSettings.GameMode = GM_CTF then
1618 begin
1619 for a := FLAG_RED to FLAG_BLUE do
1620 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1621 with gFlags[a] do
1622 begin
1623 if gFlags[a].Animation <> nil then
1624 gFlags[a].Animation.Update();
1626 m := g_Obj_Move(@Obj, True, True);
1628 if gTime mod (GAME_TICK*2) <> 0 then
1629 Continue;
1631 // Ñîïðîòèâëåíèå âîçäóõà:
1632 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1634 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1635 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1636 begin
1637 g_Map_ResetFlag(a);
1638 gFlags[a].CaptureTime := 0;
1639 if a = FLAG_RED then
1640 s := _lc[I_PLAYER_FLAG_RED]
1641 else
1642 s := _lc[I_PLAYER_FLAG_BLUE];
1643 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1645 if g_Game_IsNet then
1646 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1647 Continue;
1648 end;
1650 if Count > 0 then
1651 Count := Count - 1;
1653 // Èãðîê áåðåò ôëàã:
1654 if gPlayers <> nil then
1655 begin
1656 j := Random(Length(gPlayers)) - 1;
1658 for d := 0 to High(gPlayers) do
1659 begin
1660 Inc(j);
1661 if j > High(gPlayers) then
1662 j := 0;
1664 if gPlayers[j] <> nil then
1665 if gPlayers[j].Live and
1666 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1667 begin
1668 if gPlayers[j].GetFlag(a) then
1669 Break;
1670 end;
1671 end;
1672 end;
1673 end;
1674 end;
1675 end;
1677 procedure g_Map_DrawPanels(PanelType: Word);
1679 procedure DrawPanels(var panels: TPanelArray;
1680 drawDoors: Boolean = False);
1681 var
1682 a: Integer;
1684 begin
1685 if panels <> nil then
1686 for a := 0 to High(panels) do
1687 if not (drawDoors xor panels[a].Door) then
1688 panels[a].Draw();
1689 end;
1691 begin
1692 case PanelType of
1693 PANEL_WALL: DrawPanels(gWalls);
1694 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1695 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1696 PANEL_FORE: DrawPanels(gRenderForegrounds);
1697 PANEL_WATER: DrawPanels(gWater);
1698 PANEL_ACID1: DrawPanels(gAcid1);
1699 PANEL_ACID2: DrawPanels(gAcid2);
1700 PANEL_STEP: DrawPanels(gSteps);
1701 end;
1702 end;
1704 procedure g_Map_DrawBack(dx, dy: Integer);
1705 begin
1706 if gDrawBackGround and (BackID <> DWORD(-1)) then
1707 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1708 else
1709 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1710 end;
1712 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1713 PanelType: Word; b1x3: Boolean): Boolean;
1714 var
1715 a, h: Integer;
1716 begin
1717 Result := False;
1719 if WordBool(PanelType and PANEL_WALL) then
1720 if gWalls <> nil then
1721 begin
1722 h := High(gWalls);
1724 for a := 0 to h do
1725 if gWalls[a].Enabled and
1726 g_Collide(X, Y, Width, Height,
1727 gWalls[a].X, gWalls[a].Y,
1728 gWalls[a].Width, gWalls[a].Height) then
1729 begin
1730 Result := True;
1731 Exit;
1732 end;
1733 end;
1735 if WordBool(PanelType and PANEL_WATER) then
1736 if gWater <> nil then
1737 begin
1738 h := High(gWater);
1740 for a := 0 to h do
1741 if g_Collide(X, Y, Width, Height,
1742 gWater[a].X, gWater[a].Y,
1743 gWater[a].Width, gWater[a].Height) then
1744 begin
1745 Result := True;
1746 Exit;
1747 end;
1748 end;
1750 if WordBool(PanelType and PANEL_ACID1) then
1751 if gAcid1 <> nil then
1752 begin
1753 h := High(gAcid1);
1755 for a := 0 to h do
1756 if g_Collide(X, Y, Width, Height,
1757 gAcid1[a].X, gAcid1[a].Y,
1758 gAcid1[a].Width, gAcid1[a].Height) then
1759 begin
1760 Result := True;
1761 Exit;
1762 end;
1763 end;
1765 if WordBool(PanelType and PANEL_ACID2) then
1766 if gAcid2 <> nil then
1767 begin
1768 h := High(gAcid2);
1770 for a := 0 to h do
1771 if g_Collide(X, Y, Width, Height,
1772 gAcid2[a].X, gAcid2[a].Y,
1773 gAcid2[a].Width, gAcid2[a].Height) then
1774 begin
1775 Result := True;
1776 Exit;
1777 end;
1778 end;
1780 if WordBool(PanelType and PANEL_STEP) then
1781 if gSteps <> nil then
1782 begin
1783 h := High(gSteps);
1785 for a := 0 to h do
1786 if g_Collide(X, Y, Width, Height,
1787 gSteps[a].X, gSteps[a].Y,
1788 gSteps[a].Width, gSteps[a].Height) then
1789 begin
1790 Result := True;
1791 Exit;
1792 end;
1793 end;
1795 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1796 if gLifts <> nil then
1797 begin
1798 h := High(gLifts);
1800 for a := 0 to h do
1801 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1802 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1803 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1804 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1805 g_Collide(X, Y, Width, Height,
1806 gLifts[a].X, gLifts[a].Y,
1807 gLifts[a].Width, gLifts[a].Height) then
1808 begin
1809 Result := True;
1810 Exit;
1811 end;
1812 end;
1814 if WordBool(PanelType and PANEL_BLOCKMON) then
1815 if gBlockMon <> nil then
1816 begin
1817 h := High(gBlockMon);
1819 for a := 0 to h do
1820 if ( (not b1x3) or
1821 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1822 g_Collide(X, Y, Width, Height,
1823 gBlockMon[a].X, gBlockMon[a].Y,
1824 gBlockMon[a].Width, gBlockMon[a].Height) then
1825 begin
1826 Result := True;
1827 Exit;
1828 end;
1829 end;
1830 end;
1832 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1833 var
1834 a, h: Integer;
1835 begin
1836 Result := TEXTURE_NONE;
1838 if gWater <> nil then
1839 begin
1840 h := High(gWater);
1842 for a := 0 to h do
1843 if g_Collide(X, Y, Width, Height,
1844 gWater[a].X, gWater[a].Y,
1845 gWater[a].Width, gWater[a].Height) then
1846 begin
1847 Result := gWater[a].GetTextureID();
1848 Exit;
1849 end;
1850 end;
1852 if gAcid1 <> nil then
1853 begin
1854 h := High(gAcid1);
1856 for a := 0 to h do
1857 if g_Collide(X, Y, Width, Height,
1858 gAcid1[a].X, gAcid1[a].Y,
1859 gAcid1[a].Width, gAcid1[a].Height) then
1860 begin
1861 Result := gAcid1[a].GetTextureID();
1862 Exit;
1863 end;
1864 end;
1866 if gAcid2 <> nil then
1867 begin
1868 h := High(gAcid2);
1870 for a := 0 to h do
1871 if g_Collide(X, Y, Width, Height,
1872 gAcid2[a].X, gAcid2[a].Y,
1873 gAcid2[a].Width, gAcid2[a].Height) then
1874 begin
1875 Result := gAcid2[a].GetTextureID();
1876 Exit;
1877 end;
1878 end;
1879 end;
1881 procedure g_Map_EnableWall(ID: DWORD);
1882 begin
1883 with gWalls[ID] do
1884 begin
1885 Enabled := True;
1886 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1888 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1889 end;
1890 end;
1892 procedure g_Map_DisableWall(ID: DWORD);
1893 begin
1894 with gWalls[ID] do
1895 begin
1896 Enabled := False;
1897 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1899 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1900 end;
1901 end;
1903 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1904 var
1905 tp: TPanel;
1906 begin
1907 case PanelType of
1908 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1909 tp := gWalls[ID];
1910 PANEL_FORE:
1911 tp := gRenderForegrounds[ID];
1912 PANEL_BACK:
1913 tp := gRenderBackgrounds[ID];
1914 PANEL_WATER:
1915 tp := gWater[ID];
1916 PANEL_ACID1:
1917 tp := gAcid1[ID];
1918 PANEL_ACID2:
1919 tp := gAcid2[ID];
1920 PANEL_STEP:
1921 tp := gSteps[ID];
1922 else
1923 Exit;
1924 end;
1926 tp.NextTexture(AnimLoop);
1927 if g_Game_IsServer and g_Game_IsNet then
1928 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1929 end;
1931 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1932 begin
1933 if gLifts[ID].LiftType = t then
1934 Exit;
1936 with gLifts[ID] do
1937 begin
1938 LiftType := t;
1940 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1942 if LiftType = 0 then
1943 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1944 else if LiftType = 1 then
1945 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1946 else if LiftType = 2 then
1947 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1948 else if LiftType = 3 then
1949 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1951 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1952 end;
1953 end;
1955 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1956 var
1957 a: Integer;
1958 PointsArray: Array of TRespawnPoint;
1959 begin
1960 Result := False;
1961 SetLength(PointsArray, 0);
1963 if RespawnPoints = nil then
1964 Exit;
1966 for a := 0 to High(RespawnPoints) do
1967 if RespawnPoints[a].PointType = PointType then
1968 begin
1969 SetLength(PointsArray, Length(PointsArray)+1);
1970 PointsArray[High(PointsArray)] := RespawnPoints[a];
1971 end;
1973 if PointsArray = nil then
1974 Exit;
1976 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1977 Result := True;
1978 end;
1980 function g_Map_GetPointCount(PointType: Byte): Word;
1981 var
1982 a: Integer;
1983 begin
1984 Result := 0;
1986 if RespawnPoints = nil then
1987 Exit;
1989 for a := 0 to High(RespawnPoints) do
1990 if RespawnPoints[a].PointType = PointType then
1991 Result := Result + 1;
1992 end;
1994 function g_Map_HaveFlagPoints(): Boolean;
1995 begin
1996 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1997 end;
1999 procedure g_Map_ResetFlag(Flag: Byte);
2000 begin
2001 with gFlags[Flag] do
2002 begin
2003 Obj.X := -1000;
2004 Obj.Y := -1000;
2005 Obj.Vel.X := 0;
2006 Obj.Vel.Y := 0;
2007 Direction := D_LEFT;
2008 State := FLAG_STATE_NONE;
2009 if FlagPoints[Flag] <> nil then
2010 begin
2011 Obj.X := FlagPoints[Flag]^.X;
2012 Obj.Y := FlagPoints[Flag]^.Y;
2013 Direction := FlagPoints[Flag]^.Direction;
2014 State := FLAG_STATE_NORMAL;
2015 end;
2016 Count := -1;
2017 end;
2018 end;
2020 procedure g_Map_DrawFlags();
2021 var
2022 i, dx: Integer;
2023 Mirror: TMirrorType;
2024 begin
2025 if gGameSettings.GameMode <> GM_CTF then
2026 Exit;
2028 for i := FLAG_RED to FLAG_BLUE do
2029 with gFlags[i] do
2030 if State <> FLAG_STATE_CAPTURED then
2031 begin
2032 if State = FLAG_STATE_NONE then
2033 continue;
2035 if Direction = D_LEFT then
2036 begin
2037 Mirror := M_HORIZONTAL;
2038 dx := -1;
2039 end
2040 else
2041 begin
2042 Mirror := M_NONE;
2043 dx := 1;
2044 end;
2046 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2048 if g_debug_Frames then
2049 begin
2050 e_DrawQuad(Obj.X+Obj.Rect.X,
2051 Obj.Y+Obj.Rect.Y,
2052 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2053 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2054 0, 255, 0);
2055 end;
2056 end;
2057 end;
2059 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2060 var
2061 dw: DWORD;
2062 b: Byte;
2063 str: String;
2064 boo: Boolean;
2066 procedure SavePanelArray(var panels: TPanelArray);
2067 var
2068 PAMem: TBinMemoryWriter;
2069 i: Integer;
2070 begin
2071 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2072 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2074 i := 0;
2075 while i < Length(panels) do
2076 begin
2077 if panels[i].SaveIt then
2078 begin
2079 // ID ïàíåëè:
2080 PAMem.WriteInt(i);
2081 // Ñîõðàíÿåì ïàíåëü:
2082 panels[i].SaveState(PAMem);
2083 end;
2084 Inc(i);
2085 end;
2087 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2088 PAMem.SaveToMemory(Mem);
2089 PAMem.Free();
2090 end;
2092 procedure SaveFlag(flag: PFlag);
2093 begin
2094 // Ñèãíàòóðà ôëàãà:
2095 dw := FLAG_SIGNATURE; // 'FLAG'
2096 Mem.WriteDWORD(dw);
2097 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2098 Mem.WriteByte(flag^.RespawnType);
2099 // Ñîñòîÿíèå ôëàãà:
2100 Mem.WriteByte(flag^.State);
2101 // Íàïðàâëåíèå ôëàãà:
2102 if flag^.Direction = D_LEFT then
2103 b := 1
2104 else // D_RIGHT
2105 b := 2;
2106 Mem.WriteByte(b);
2107 // Îáúåêò ôëàãà:
2108 Obj_SaveState(@flag^.Obj, Mem);
2109 end;
2111 begin
2112 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2114 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2115 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2116 SavePanelArray(gWalls);
2117 // Ñîõðàíÿåì ïàíåëè ôîíà:
2118 SavePanelArray(gRenderBackgrounds);
2119 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2120 SavePanelArray(gRenderForegrounds);
2121 // Ñîõðàíÿåì ïàíåëè âîäû:
2122 SavePanelArray(gWater);
2123 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2124 SavePanelArray(gAcid1);
2125 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2126 SavePanelArray(gAcid2);
2127 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2128 SavePanelArray(gSteps);
2129 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2130 SavePanelArray(gLifts);
2131 ///// /////
2133 ///// Ñîõðàíÿåì ìóçûêó: /////
2134 // Ñèãíàòóðà ìóçûêè:
2135 dw := MUSIC_SIGNATURE; // 'MUSI'
2136 Mem.WriteDWORD(dw);
2137 // Íàçâàíèå ìóçûêè:
2138 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2139 if gMusic.NoMusic then
2140 str := ''
2141 else
2142 str := gMusic.Name;
2143 Mem.WriteString(str, 64);
2144 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2145 dw := gMusic.GetPosition();
2146 Mem.WriteDWORD(dw);
2147 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2148 boo := gMusic.SpecPause;
2149 Mem.WriteBoolean(boo);
2150 ///// /////
2152 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2153 Mem.WriteInt(gTotalMonsters);
2154 ///// /////
2156 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2157 if gGameSettings.GameMode = GM_CTF then
2158 begin
2159 // Ôëàã Êðàñíîé êîìàíäû:
2160 SaveFlag(@gFlags[FLAG_RED]);
2161 // Ôëàã Ñèíåé êîìàíäû:
2162 SaveFlag(@gFlags[FLAG_BLUE]);
2163 end;
2164 ///// /////
2166 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2167 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2168 begin
2169 // Î÷êè Êðàñíîé êîìàíäû:
2170 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2171 // Î÷êè Ñèíåé êîìàíäû:
2172 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2173 end;
2174 ///// /////
2175 end;
2177 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2178 var
2179 dw: DWORD;
2180 b: Byte;
2181 str: String;
2182 boo: Boolean;
2184 procedure LoadPanelArray(var panels: TPanelArray);
2185 var
2186 PAMem: TBinMemoryReader;
2187 i, id: Integer;
2188 begin
2189 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2190 PAMem := TBinMemoryReader.Create();
2191 PAMem.LoadFromMemory(Mem);
2193 for i := 0 to Length(panels)-1 do
2194 if panels[i].SaveIt then
2195 begin
2196 // ID ïàíåëè:
2197 PAMem.ReadInt(id);
2198 if id <> i then
2199 begin
2200 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2201 end;
2202 // Çàãðóæàåì ïàíåëü:
2203 panels[i].LoadState(PAMem);
2204 end;
2206 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2207 PAMem.Free();
2208 end;
2210 procedure LoadFlag(flag: PFlag);
2211 begin
2212 // Ñèãíàòóðà ôëàãà:
2213 Mem.ReadDWORD(dw);
2214 if dw <> FLAG_SIGNATURE then // 'FLAG'
2215 begin
2216 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2217 end;
2218 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2219 Mem.ReadByte(flag^.RespawnType);
2220 // Ñîñòîÿíèå ôëàãà:
2221 Mem.ReadByte(flag^.State);
2222 // Íàïðàâëåíèå ôëàãà:
2223 Mem.ReadByte(b);
2224 if b = 1 then
2225 flag^.Direction := D_LEFT
2226 else // b = 2
2227 flag^.Direction := D_RIGHT;
2228 // Îáúåêò ôëàãà:
2229 Obj_LoadState(@flag^.Obj, Mem);
2230 end;
2232 begin
2233 if Mem = nil then
2234 Exit;
2236 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2237 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2238 LoadPanelArray(gWalls);
2239 // Çàãðóæàåì ïàíåëè ôîíà:
2240 LoadPanelArray(gRenderBackgrounds);
2241 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2242 LoadPanelArray(gRenderForegrounds);
2243 // Çàãðóæàåì ïàíåëè âîäû:
2244 LoadPanelArray(gWater);
2245 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2246 LoadPanelArray(gAcid1);
2247 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2248 LoadPanelArray(gAcid2);
2249 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2250 LoadPanelArray(gSteps);
2251 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2252 LoadPanelArray(gLifts);
2253 ///// /////
2255 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2256 g_GFX_Init();
2258 ///// Çàãðóæàåì ìóçûêó: /////
2259 // Ñèãíàòóðà ìóçûêè:
2260 Mem.ReadDWORD(dw);
2261 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2262 begin
2263 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2264 end;
2265 // Íàçâàíèå ìóçûêè:
2266 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2267 Mem.ReadString(str);
2268 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2269 Mem.ReadDWORD(dw);
2270 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2271 Mem.ReadBoolean(boo);
2272 // Çàïóñêàåì ýòó ìóçûêó:
2273 gMusic.SetByName(str);
2274 gMusic.SpecPause := boo;
2275 gMusic.Play();
2276 gMusic.Pause(True);
2277 gMusic.SetPosition(dw);
2278 ///// /////
2280 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2281 Mem.ReadInt(gTotalMonsters);
2282 ///// /////
2284 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2285 if gGameSettings.GameMode = GM_CTF then
2286 begin
2287 // Ôëàã Êðàñíîé êîìàíäû:
2288 LoadFlag(@gFlags[FLAG_RED]);
2289 // Ôëàã Ñèíåé êîìàíäû:
2290 LoadFlag(@gFlags[FLAG_BLUE]);
2291 end;
2292 ///// /////
2294 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2295 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2296 begin
2297 // Î÷êè Êðàñíîé êîìàíäû:
2298 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2299 // Î÷êè Ñèíåé êîìàíäû:
2300 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2301 end;
2302 ///// /////
2303 end;
2305 end.