DEADSOFTWARE

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