DEADSOFTWARE

cb934b81705666abe9dcd89ace6d7ae251fa47cb
[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, g_scripts,
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, ScrStr: String;
911 Data, ScrText: Pointer;
912 ScrEnd: PByte;
913 Len, ScrLen: Integer;
914 ok, isAnim, trigRef: Boolean;
915 CurTex, ntn: Integer;
916 begin
917 Result := False;
918 gMapInfo.Map := Res;
919 TriggersTable := nil;
920 FillChar(texture, SizeOf(texture), 0);
922 sfsGCDisable(); // temporary disable removing of temporary volumes
923 try
924 // Çàãðóçêà WAD:
925 FileName := g_ExtractWadName(Res);
926 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
927 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
929 WAD := TWADFile.Create();
930 if not WAD.ReadFile(FileName) then
931 begin
932 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
933 WAD.Free();
934 Exit;
935 end;
936 //k8: why loader ignores path here?
937 mapResName := g_ExtractFileName(Res);
938 if not WAD.GetMapResource(mapResName, Data, Len) then
939 begin
940 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
941 WAD.Free();
942 Exit;
943 end;
945 // try to load the map script
946 g_Scripts_Reset(RESET_MAP);
947 ScrText := nil;
948 ScrLen := 0;
949 if WAD.GetResource('SCRIPTS/'+mapResName, ScrText, ScrLen) then
950 begin
951 g_Console_Add('SCRIPT: Found script for this map. Loading...');
952 SetString(ScrStr, ScrText, ScrLen);
953 g_Scripts_Load(ScrStr);
954 FreeMem(ScrText);
955 end;
957 WAD.Free();
959 // Çàãðóçêà êàðòû:
960 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
961 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
962 MapReader := TMapReader_1.Create();
964 if not MapReader.LoadMap(Data) then
965 begin
966 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
967 FreeMem(Data);
968 MapReader.Free();
969 Exit;
970 end;
972 FreeMem(Data);
973 generateExternalResourcesList(MapReader);
974 // Çàãðóçêà òåêñòóð:
975 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
976 _textures := MapReader.GetTextures();
977 _texnummap := nil;
979 // Äîáàâëåíèå òåêñòóð â Textures[]:
980 if _textures <> nil then
981 begin
982 e_WriteLog(' Loading textures:', MSG_NOTIFY);
983 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
984 SetLength(_texnummap, length(_textures));
986 for a := 0 to High(_textures) do
987 begin
988 SetLength(s, 64);
989 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
990 for b := 1 to Length(s) do
991 if s[b] = #0 then
992 begin
993 SetLength(s, b-1);
994 Break;
995 end;
996 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
997 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
998 // Àíèìèðîâàííàÿ òåêñòóðà:
999 if ByteBool(_textures[a].Anim) then
1000 begin
1001 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1002 if ntn < 0 then
1003 begin
1004 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1005 ntn := CreateNullTexture(_textures[a].Resource);
1006 end;
1007 end
1008 else // Îáû÷íàÿ òåêñòóðà:
1009 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1010 if ntn < 0 then
1011 begin
1012 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1013 ntn := CreateNullTexture(_textures[a].Resource);
1014 end;
1016 _texnummap[a] := ntn; // fix texture number
1017 g_Game_StepLoading();
1018 end;
1019 end;
1021 // Çàãðóçêà òðèããåðîâ:
1022 gTriggerClientID := 0;
1023 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1024 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1025 triggers := MapReader.GetTriggers();
1027 // Çàãðóçêà ïàíåëåé:
1028 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1029 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1030 panels := MapReader.GetPanels();
1032 // check texture numbers for panels
1033 for a := 0 to High(panels) do
1034 begin
1035 if panels[a].TextureNum > High(_textures) then
1036 begin
1037 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1038 result := false;
1039 exit;
1040 end;
1041 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1042 end;
1044 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1045 if triggers <> nil then
1046 begin
1047 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1048 SetLength(TriggersTable, Length(triggers));
1049 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1051 for a := 0 to High(TriggersTable) do
1052 begin
1053 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1054 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1055 // Ëèôòû:
1056 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1057 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1058 else
1059 TriggersTable[a].LiftPanel := -1;
1060 // Äâåðè:
1061 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1062 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1063 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1064 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1065 else
1066 TriggersTable[a].DoorPanel := -1;
1067 // Òóðåëü:
1068 if triggers[a].TriggerType = TRIGGER_SHOT then
1069 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1070 else
1071 TriggersTable[a].ShotPanel := -1;
1073 g_Game_StepLoading();
1074 end;
1075 end;
1077 // Ñîçäàåì ïàíåëè:
1078 if panels <> nil then
1079 begin
1080 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1081 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1083 for a := 0 to High(panels) do
1084 begin
1085 SetLength(AddTextures, 0);
1086 trigRef := False;
1087 CurTex := -1;
1088 if _textures <> nil then
1089 begin
1090 texture := _textures[panels[a].TextureNum];
1091 ok := True;
1092 end
1093 else
1094 ok := False;
1096 if ok then
1097 begin
1098 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1099 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1100 ok := False;
1101 if (TriggersTable <> nil) and (_textures <> nil) then
1102 for b := 0 to High(TriggersTable) do
1103 if (TriggersTable[b].TexturePanel = a)
1104 or (TriggersTable[b].ShotPanel = a) then
1105 begin
1106 trigRef := True;
1107 ok := True;
1108 Break;
1109 end;
1110 end;
1112 if ok then
1113 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1114 SetLength(s, 64);
1115 CopyMemory(@s[1], @texture.Resource[0], 64);
1116 // Èçìåðÿåì äëèíó:
1117 Len := Length(s);
1118 for c := Len downto 1 do
1119 if s[c] <> #0 then
1120 begin
1121 Len := c;
1122 Break;
1123 end;
1124 SetLength(s, Len);
1126 // Ñïåö-òåêñòóðû çàïðåùåíû:
1127 if g_Map_IsSpecialTexture(s) then
1128 ok := False
1129 else
1130 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1131 ok := g_Texture_NumNameFindStart(s);
1133 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1134 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1135 if ok then
1136 begin
1137 k := NNF_NAME_BEFORE;
1138 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1139 while ok or (k = NNF_NAME_BEFORE) or
1140 (k = NNF_NAME_EQUALS) do
1141 begin
1142 k := g_Texture_NumNameFindNext(TexName);
1144 if (k = NNF_NAME_BEFORE) or
1145 (k = NNF_NAME_AFTER) then
1146 begin
1147 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1148 if ByteBool(texture.Anim) then
1149 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1150 isAnim := True;
1151 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1152 if not ok then
1153 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1154 isAnim := False;
1155 ok := CreateTexture(TexName, FileName, False) >= 0;
1156 end;
1157 end
1158 else
1159 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1160 isAnim := False;
1161 ok := CreateTexture(TexName, FileName, False) >= 0;
1162 if not ok then
1163 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1164 isAnim := True;
1165 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1166 end;
1167 end;
1169 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1170 if ok then
1171 begin
1172 for c := 0 to High(Textures) do
1173 if Textures[c].TextureName = TexName then
1174 begin
1175 SetLength(AddTextures, Length(AddTextures)+1);
1176 AddTextures[High(AddTextures)].Texture := c;
1177 AddTextures[High(AddTextures)].Anim := isAnim;
1178 Break;
1179 end;
1180 end;
1181 end
1182 else
1183 if k = NNF_NAME_EQUALS then
1184 begin
1185 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1186 SetLength(AddTextures, Length(AddTextures)+1);
1187 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1188 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1189 CurTex := High(AddTextures);
1190 ok := True;
1191 end
1192 else // NNF_NO_NAME
1193 ok := False;
1194 end; // while ok...
1196 ok := True;
1197 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1198 end; // if ok - ññûëàþòñÿ òðèããåðû
1200 if not ok then
1201 begin
1202 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1203 SetLength(AddTextures, 1);
1204 AddTextures[0].Texture := panels[a].TextureNum;
1205 AddTextures[0].Anim := ByteBool(texture.Anim);
1206 CurTex := 0;
1207 end;
1209 //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);
1211 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1212 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1214 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1215 if TriggersTable <> nil then
1216 for b := 0 to High(TriggersTable) do
1217 begin
1218 // Òðèããåð äâåðè/ëèôòà:
1219 if (TriggersTable[b].LiftPanel = a) or
1220 (TriggersTable[b].DoorPanel = a) then
1221 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1222 // Òðèããåð ñìåíû òåêñòóðû:
1223 if TriggersTable[b].TexturePanel = a then
1224 triggers[b].TexturePanel := PanelID;
1225 // Òðèããåð "Òóðåëü":
1226 if TriggersTable[b].ShotPanel = a then
1227 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1228 end;
1230 g_Game_StepLoading();
1231 end;
1232 end;
1234 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1235 if (triggers <> nil) and not gLoadGameMode then
1236 begin
1237 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1238 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1239 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1240 for a := 0 to High(triggers) do
1241 begin
1242 if triggers[a].TexturePanel <> -1 then
1243 b := panels[TriggersTable[a].TexturePanel].PanelType
1244 else
1245 b := 0;
1246 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1247 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1248 c := panels[TriggersTable[a].ShotPanel].PanelType
1249 else
1250 c := 0;
1251 CreateTrigger(triggers[a], b, c);
1252 end;
1253 end;
1255 // Çàãðóçêà ïðåäìåòîâ:
1256 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1257 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1258 items := MapReader.GetItems();
1260 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1261 if (items <> nil) and not gLoadGameMode then
1262 begin
1263 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1264 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1265 for a := 0 to High(items) do
1266 CreateItem(Items[a]);
1267 end;
1269 // Çàãðóçêà îáëàñòåé:
1270 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1271 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1272 areas := MapReader.GetAreas();
1274 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1275 if areas <> nil then
1276 begin
1277 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1278 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1279 for a := 0 to High(areas) do
1280 CreateArea(areas[a]);
1281 end;
1283 // Çàãðóçêà ìîíñòðîâ:
1284 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1285 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1286 monsters := MapReader.GetMonsters();
1288 gTotalMonsters := 0;
1290 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1291 if (monsters <> nil) and not gLoadGameMode then
1292 begin
1293 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1294 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1295 for a := 0 to High(monsters) do
1296 CreateMonster(monsters[a]);
1297 end;
1299 // Çàãðóçêà îïèñàíèÿ êàðòû:
1300 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1301 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1302 Header := MapReader.GetMapHeader();
1304 MapReader.Free();
1306 with gMapInfo do
1307 begin
1308 Name := Header.MapName;
1309 Description := Header.MapDescription;
1310 Author := Header.MapAuthor;
1311 MusicName := Header.MusicName;
1312 SkyName := Header.SkyName;
1313 Height := Header.Height;
1314 Width := Header.Width;
1315 end;
1317 // Çàãðóçêà íåáà:
1318 if gMapInfo.SkyName <> '' then
1319 begin
1320 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1321 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1322 FileName := g_ExtractWadName(gMapInfo.SkyName);
1324 if FileName <> '' then
1325 FileName := GameDir+'/wads/'+FileName
1326 else
1327 begin
1328 FileName := g_ExtractWadName(Res);
1329 end;
1331 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1332 if g_Texture_CreateWAD(BackID, s) then
1333 begin
1334 g_Game_SetupScreenSize();
1335 end
1336 else
1337 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1338 end;
1340 // Çàãðóçêà ìóçûêè:
1341 ok := False;
1342 if gMapInfo.MusicName <> '' then
1343 begin
1344 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1345 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1346 FileName := g_ExtractWadName(gMapInfo.MusicName);
1348 if FileName <> '' then
1349 FileName := GameDir+'/wads/'+FileName
1350 else
1351 begin
1352 FileName := g_ExtractWadName(Res);
1353 end;
1355 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1356 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1357 ok := True
1358 else
1359 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1360 end;
1362 // Îñòàëüíûå óñòàíâêè:
1363 CreateDoorMap();
1364 CreateLiftMap();
1366 g_Items_Init();
1367 g_Weapon_Init();
1368 g_Monsters_Init();
1370 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1371 if not gLoadGameMode then
1372 g_GFX_Init();
1374 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1375 _textures := nil;
1376 panels := nil;
1377 items := nil;
1378 areas := nil;
1379 triggers := nil;
1380 TriggersTable := nil;
1381 AddTextures := nil;
1383 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1384 if ok and (not gLoadGameMode) then
1385 begin
1386 gMusic.SetByName(gMapInfo.MusicName);
1387 gMusic.Play();
1388 end
1389 else
1390 gMusic.SetByName('');
1391 finally
1392 sfsGCEnable(); // enable releasing unused volumes
1393 end;
1395 e_WriteLog('Done loading map.', MSG_NOTIFY);
1396 Result := True;
1397 end;
1399 function g_Map_GetMapInfo(Res: String): TMapInfo;
1400 var
1401 WAD: TWADFile;
1402 MapReader: TMapReader_1;
1403 Header: TMapHeaderRec_1;
1404 FileName: String;
1405 Data: Pointer;
1406 Len: Integer;
1407 begin
1408 FillChar(Result, SizeOf(Result), 0);
1409 FileName := g_ExtractWadName(Res);
1411 WAD := TWADFile.Create();
1412 if not WAD.ReadFile(FileName) then
1413 begin
1414 WAD.Free();
1415 Exit;
1416 end;
1418 //k8: it ignores path again
1419 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1420 begin
1421 WAD.Free();
1422 Exit;
1423 end;
1425 WAD.Free();
1427 MapReader := TMapReader_1.Create();
1429 if not MapReader.LoadMap(Data) then
1430 begin
1431 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1432 ZeroMemory(@Header, SizeOf(Header));
1433 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1434 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1435 end
1436 else
1437 begin
1438 Header := MapReader.GetMapHeader();
1439 Result.Name := Header.MapName;
1440 Result.Description := Header.MapDescription;
1441 end;
1443 FreeMem(Data);
1444 MapReader.Free();
1446 Result.Map := Res;
1447 Result.Author := Header.MapAuthor;
1448 Result.Height := Header.Height;
1449 Result.Width := Header.Width;
1450 end;
1452 function g_Map_GetMapsList(WADName: string): SArray;
1453 var
1454 WAD: TWADFile;
1455 a: Integer;
1456 ResList: SArray;
1457 begin
1458 Result := nil;
1459 WAD := TWADFile.Create();
1460 if not WAD.ReadFile(WADName) then
1461 begin
1462 WAD.Free();
1463 Exit;
1464 end;
1465 ResList := WAD.GetMapResources();
1466 if ResList <> nil then
1467 begin
1468 for a := 0 to High(ResList) do
1469 begin
1470 SetLength(Result, Length(Result)+1);
1471 Result[High(Result)] := ResList[a];
1472 end;
1473 end;
1474 WAD.Free();
1475 end;
1477 function g_Map_Exist(Res: string): Boolean;
1478 var
1479 WAD: TWADFile;
1480 FileName, mnn: string;
1481 ResList: SArray;
1482 a: Integer;
1483 begin
1484 Result := False;
1486 FileName := addWadExtension(g_ExtractWadName(Res));
1488 WAD := TWADFile.Create;
1489 if not WAD.ReadFile(FileName) then
1490 begin
1491 WAD.Free();
1492 Exit;
1493 end;
1495 ResList := WAD.GetMapResources();
1496 WAD.Free();
1498 mnn := g_ExtractFileName(Res);
1499 if ResList <> nil then
1500 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1501 begin
1502 Result := True;
1503 Exit;
1504 end;
1505 end;
1507 procedure g_Map_Free();
1508 var
1509 a: Integer;
1511 procedure FreePanelArray(var panels: TPanelArray);
1512 var
1513 i: Integer;
1515 begin
1516 if panels <> nil then
1517 begin
1518 for i := 0 to High(panels) do
1519 panels[i].Free();
1520 panels := nil;
1521 end;
1522 end;
1524 begin
1525 g_GFX_Free();
1526 g_Weapon_Free();
1527 g_Items_Free();
1528 g_Triggers_Free();
1529 g_Monsters_Free();
1531 RespawnPoints := nil;
1532 if FlagPoints[FLAG_RED] <> nil then
1533 begin
1534 Dispose(FlagPoints[FLAG_RED]);
1535 FlagPoints[FLAG_RED] := nil;
1536 end;
1537 if FlagPoints[FLAG_BLUE] <> nil then
1538 begin
1539 Dispose(FlagPoints[FLAG_BLUE]);
1540 FlagPoints[FLAG_BLUE] := nil;
1541 end;
1542 //DOMFlagPoints := nil;
1544 //gDOMFlags := nil;
1546 if Textures <> nil then
1547 begin
1548 for a := 0 to High(Textures) do
1549 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1550 if Textures[a].Anim then
1551 g_Frames_DeleteByID(Textures[a].FramesID)
1552 else
1553 if Textures[a].TextureID <> TEXTURE_NONE then
1554 e_DeleteTexture(Textures[a].TextureID);
1556 Textures := nil;
1557 end;
1559 FreePanelArray(gWalls);
1560 FreePanelArray(gRenderBackgrounds);
1561 FreePanelArray(gRenderForegrounds);
1562 FreePanelArray(gWater);
1563 FreePanelArray(gAcid1);
1564 FreePanelArray(gAcid2);
1565 FreePanelArray(gSteps);
1566 FreePanelArray(gLifts);
1567 FreePanelArray(gBlockMon);
1569 if BackID <> DWORD(-1) then
1570 begin
1571 gBackSize.X := 0;
1572 gBackSize.Y := 0;
1573 e_DeleteTexture(BackID);
1574 BackID := DWORD(-1);
1575 end;
1577 g_Game_StopAllSounds(False);
1578 gMusic.FreeSound();
1579 g_Sound_Delete(gMapInfo.MusicName);
1581 gMapInfo.Name := '';
1582 gMapInfo.Description := '';
1583 gMapInfo.MusicName := '';
1584 gMapInfo.Height := 0;
1585 gMapInfo.Width := 0;
1587 gDoorMap := nil;
1588 gLiftMap := nil;
1589 end;
1591 procedure g_Map_Update();
1592 var
1593 a, d, j: Integer;
1594 m: Word;
1595 s: String;
1597 procedure UpdatePanelArray(var panels: TPanelArray);
1598 var
1599 i: Integer;
1601 begin
1602 if panels <> nil then
1603 for i := 0 to High(panels) do
1604 panels[i].Update();
1605 end;
1607 begin
1608 UpdatePanelArray(gWalls);
1609 UpdatePanelArray(gRenderBackgrounds);
1610 UpdatePanelArray(gRenderForegrounds);
1611 UpdatePanelArray(gWater);
1612 UpdatePanelArray(gAcid1);
1613 UpdatePanelArray(gAcid2);
1614 UpdatePanelArray(gSteps);
1616 if gGameSettings.GameMode = GM_CTF then
1617 begin
1618 for a := FLAG_RED to FLAG_BLUE do
1619 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1620 with gFlags[a] do
1621 begin
1622 if gFlags[a].Animation <> nil then
1623 gFlags[a].Animation.Update();
1625 m := g_Obj_Move(@Obj, True, True);
1627 if gTime mod (GAME_TICK*2) <> 0 then
1628 Continue;
1630 // Ñîïðîòèâëåíèå âîçäóõà:
1631 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1633 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1634 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1635 begin
1636 g_Map_ResetFlag(a);
1637 gFlags[a].CaptureTime := 0;
1638 if a = FLAG_RED then
1639 s := _lc[I_PLAYER_FLAG_RED]
1640 else
1641 s := _lc[I_PLAYER_FLAG_BLUE];
1642 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1644 if g_Game_IsNet then
1645 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1646 Continue;
1647 end;
1649 if Count > 0 then
1650 Count := Count - 1;
1652 // Èãðîê áåðåò ôëàã:
1653 if gPlayers <> nil then
1654 begin
1655 j := Random(Length(gPlayers)) - 1;
1657 for d := 0 to High(gPlayers) do
1658 begin
1659 Inc(j);
1660 if j > High(gPlayers) then
1661 j := 0;
1663 if gPlayers[j] <> nil then
1664 if gPlayers[j].Live and
1665 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1666 begin
1667 if gPlayers[j].GetFlag(a) then
1668 Break;
1669 end;
1670 end;
1671 end;
1672 end;
1673 end;
1674 end;
1676 procedure g_Map_DrawPanels(PanelType: Word);
1678 procedure DrawPanels(var panels: TPanelArray;
1679 drawDoors: Boolean = False);
1680 var
1681 a: Integer;
1683 begin
1684 if panels <> nil then
1685 for a := 0 to High(panels) do
1686 if not (drawDoors xor panels[a].Door) then
1687 panels[a].Draw();
1688 end;
1690 begin
1691 case PanelType of
1692 PANEL_WALL: DrawPanels(gWalls);
1693 PANEL_CLOSEDOOR: DrawPanels(gWalls, True);
1694 PANEL_BACK: DrawPanels(gRenderBackgrounds);
1695 PANEL_FORE: DrawPanels(gRenderForegrounds);
1696 PANEL_WATER: DrawPanels(gWater);
1697 PANEL_ACID1: DrawPanels(gAcid1);
1698 PANEL_ACID2: DrawPanels(gAcid2);
1699 PANEL_STEP: DrawPanels(gSteps);
1700 end;
1701 end;
1703 procedure g_Map_DrawBack(dx, dy: Integer);
1704 begin
1705 if gDrawBackGround and (BackID <> DWORD(-1)) then
1706 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1707 else
1708 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1709 end;
1711 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
1712 PanelType: Word; b1x3: Boolean): Boolean;
1713 var
1714 a, h: Integer;
1715 begin
1716 Result := False;
1718 if WordBool(PanelType and PANEL_WALL) then
1719 if gWalls <> nil then
1720 begin
1721 h := High(gWalls);
1723 for a := 0 to h do
1724 if gWalls[a].Enabled and
1725 g_Collide(X, Y, Width, Height,
1726 gWalls[a].X, gWalls[a].Y,
1727 gWalls[a].Width, gWalls[a].Height) then
1728 begin
1729 Result := True;
1730 Exit;
1731 end;
1732 end;
1734 if WordBool(PanelType and PANEL_WATER) then
1735 if gWater <> nil then
1736 begin
1737 h := High(gWater);
1739 for a := 0 to h do
1740 if g_Collide(X, Y, Width, Height,
1741 gWater[a].X, gWater[a].Y,
1742 gWater[a].Width, gWater[a].Height) then
1743 begin
1744 Result := True;
1745 Exit;
1746 end;
1747 end;
1749 if WordBool(PanelType and PANEL_ACID1) then
1750 if gAcid1 <> nil then
1751 begin
1752 h := High(gAcid1);
1754 for a := 0 to h do
1755 if g_Collide(X, Y, Width, Height,
1756 gAcid1[a].X, gAcid1[a].Y,
1757 gAcid1[a].Width, gAcid1[a].Height) then
1758 begin
1759 Result := True;
1760 Exit;
1761 end;
1762 end;
1764 if WordBool(PanelType and PANEL_ACID2) then
1765 if gAcid2 <> nil then
1766 begin
1767 h := High(gAcid2);
1769 for a := 0 to h do
1770 if g_Collide(X, Y, Width, Height,
1771 gAcid2[a].X, gAcid2[a].Y,
1772 gAcid2[a].Width, gAcid2[a].Height) then
1773 begin
1774 Result := True;
1775 Exit;
1776 end;
1777 end;
1779 if WordBool(PanelType and PANEL_STEP) then
1780 if gSteps <> nil then
1781 begin
1782 h := High(gSteps);
1784 for a := 0 to h do
1785 if g_Collide(X, Y, Width, Height,
1786 gSteps[a].X, gSteps[a].Y,
1787 gSteps[a].Width, gSteps[a].Height) then
1788 begin
1789 Result := True;
1790 Exit;
1791 end;
1792 end;
1794 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
1795 if gLifts <> nil then
1796 begin
1797 h := High(gLifts);
1799 for a := 0 to h do
1800 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
1801 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
1802 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
1803 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
1804 g_Collide(X, Y, Width, Height,
1805 gLifts[a].X, gLifts[a].Y,
1806 gLifts[a].Width, gLifts[a].Height) then
1807 begin
1808 Result := True;
1809 Exit;
1810 end;
1811 end;
1813 if WordBool(PanelType and PANEL_BLOCKMON) then
1814 if gBlockMon <> nil then
1815 begin
1816 h := High(gBlockMon);
1818 for a := 0 to h do
1819 if ( (not b1x3) or
1820 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
1821 g_Collide(X, Y, Width, Height,
1822 gBlockMon[a].X, gBlockMon[a].Y,
1823 gBlockMon[a].Width, gBlockMon[a].Height) then
1824 begin
1825 Result := True;
1826 Exit;
1827 end;
1828 end;
1829 end;
1831 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
1832 var
1833 a, h: Integer;
1834 begin
1835 Result := TEXTURE_NONE;
1837 if gWater <> nil then
1838 begin
1839 h := High(gWater);
1841 for a := 0 to h do
1842 if g_Collide(X, Y, Width, Height,
1843 gWater[a].X, gWater[a].Y,
1844 gWater[a].Width, gWater[a].Height) then
1845 begin
1846 Result := gWater[a].GetTextureID();
1847 Exit;
1848 end;
1849 end;
1851 if gAcid1 <> nil then
1852 begin
1853 h := High(gAcid1);
1855 for a := 0 to h do
1856 if g_Collide(X, Y, Width, Height,
1857 gAcid1[a].X, gAcid1[a].Y,
1858 gAcid1[a].Width, gAcid1[a].Height) then
1859 begin
1860 Result := gAcid1[a].GetTextureID();
1861 Exit;
1862 end;
1863 end;
1865 if gAcid2 <> nil then
1866 begin
1867 h := High(gAcid2);
1869 for a := 0 to h do
1870 if g_Collide(X, Y, Width, Height,
1871 gAcid2[a].X, gAcid2[a].Y,
1872 gAcid2[a].Width, gAcid2[a].Height) then
1873 begin
1874 Result := gAcid2[a].GetTextureID();
1875 Exit;
1876 end;
1877 end;
1878 end;
1880 procedure g_Map_EnableWall(ID: DWORD);
1881 begin
1882 with gWalls[ID] do
1883 begin
1884 Enabled := True;
1885 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
1887 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1888 end;
1889 end;
1891 procedure g_Map_DisableWall(ID: DWORD);
1892 begin
1893 with gWalls[ID] do
1894 begin
1895 Enabled := False;
1896 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
1898 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1899 end;
1900 end;
1902 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
1903 var
1904 tp: TPanel;
1905 begin
1906 case PanelType of
1907 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
1908 tp := gWalls[ID];
1909 PANEL_FORE:
1910 tp := gRenderForegrounds[ID];
1911 PANEL_BACK:
1912 tp := gRenderBackgrounds[ID];
1913 PANEL_WATER:
1914 tp := gWater[ID];
1915 PANEL_ACID1:
1916 tp := gAcid1[ID];
1917 PANEL_ACID2:
1918 tp := gAcid2[ID];
1919 PANEL_STEP:
1920 tp := gSteps[ID];
1921 else
1922 Exit;
1923 end;
1925 tp.NextTexture(AnimLoop);
1926 if g_Game_IsServer and g_Game_IsNet then
1927 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
1928 end;
1930 procedure g_Map_SetLift(ID: DWORD; t: Integer);
1931 begin
1932 if gLifts[ID].LiftType = t then
1933 Exit;
1935 with gLifts[ID] do
1936 begin
1937 LiftType := t;
1939 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
1941 if LiftType = 0 then
1942 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
1943 else if LiftType = 1 then
1944 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
1945 else if LiftType = 2 then
1946 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
1947 else if LiftType = 3 then
1948 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
1950 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
1951 end;
1952 end;
1954 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
1955 var
1956 a: Integer;
1957 PointsArray: Array of TRespawnPoint;
1958 begin
1959 Result := False;
1960 SetLength(PointsArray, 0);
1962 if RespawnPoints = nil then
1963 Exit;
1965 for a := 0 to High(RespawnPoints) do
1966 if RespawnPoints[a].PointType = PointType then
1967 begin
1968 SetLength(PointsArray, Length(PointsArray)+1);
1969 PointsArray[High(PointsArray)] := RespawnPoints[a];
1970 end;
1972 if PointsArray = nil then
1973 Exit;
1975 RespawnPoint := PointsArray[Random(Length(PointsArray))];
1976 Result := True;
1977 end;
1979 function g_Map_GetPointCount(PointType: Byte): Word;
1980 var
1981 a: Integer;
1982 begin
1983 Result := 0;
1985 if RespawnPoints = nil then
1986 Exit;
1988 for a := 0 to High(RespawnPoints) do
1989 if RespawnPoints[a].PointType = PointType then
1990 Result := Result + 1;
1991 end;
1993 function g_Map_HaveFlagPoints(): Boolean;
1994 begin
1995 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
1996 end;
1998 procedure g_Map_ResetFlag(Flag: Byte);
1999 begin
2000 with gFlags[Flag] do
2001 begin
2002 Obj.X := -1000;
2003 Obj.Y := -1000;
2004 Obj.Vel.X := 0;
2005 Obj.Vel.Y := 0;
2006 Direction := D_LEFT;
2007 State := FLAG_STATE_NONE;
2008 if FlagPoints[Flag] <> nil then
2009 begin
2010 Obj.X := FlagPoints[Flag]^.X;
2011 Obj.Y := FlagPoints[Flag]^.Y;
2012 Direction := FlagPoints[Flag]^.Direction;
2013 State := FLAG_STATE_NORMAL;
2014 end;
2015 Count := -1;
2016 end;
2017 end;
2019 procedure g_Map_DrawFlags();
2020 var
2021 i, dx: Integer;
2022 Mirror: TMirrorType;
2023 begin
2024 if gGameSettings.GameMode <> GM_CTF then
2025 Exit;
2027 for i := FLAG_RED to FLAG_BLUE do
2028 with gFlags[i] do
2029 if State <> FLAG_STATE_CAPTURED then
2030 begin
2031 if State = FLAG_STATE_NONE then
2032 continue;
2034 if Direction = D_LEFT then
2035 begin
2036 Mirror := M_HORIZONTAL;
2037 dx := -1;
2038 end
2039 else
2040 begin
2041 Mirror := M_NONE;
2042 dx := 1;
2043 end;
2045 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2047 if g_debug_Frames then
2048 begin
2049 e_DrawQuad(Obj.X+Obj.Rect.X,
2050 Obj.Y+Obj.Rect.Y,
2051 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2052 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2053 0, 255, 0);
2054 end;
2055 end;
2056 end;
2058 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2059 var
2060 dw: DWORD;
2061 b: Byte;
2062 str: String;
2063 boo: Boolean;
2065 procedure SavePanelArray(var panels: TPanelArray);
2066 var
2067 PAMem: TBinMemoryWriter;
2068 i: Integer;
2069 begin
2070 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2071 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2073 i := 0;
2074 while i < Length(panels) do
2075 begin
2076 if panels[i].SaveIt then
2077 begin
2078 // ID ïàíåëè:
2079 PAMem.WriteInt(i);
2080 // Ñîõðàíÿåì ïàíåëü:
2081 panels[i].SaveState(PAMem);
2082 end;
2083 Inc(i);
2084 end;
2086 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2087 PAMem.SaveToMemory(Mem);
2088 PAMem.Free();
2089 end;
2091 procedure SaveFlag(flag: PFlag);
2092 begin
2093 // Ñèãíàòóðà ôëàãà:
2094 dw := FLAG_SIGNATURE; // 'FLAG'
2095 Mem.WriteDWORD(dw);
2096 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2097 Mem.WriteByte(flag^.RespawnType);
2098 // Ñîñòîÿíèå ôëàãà:
2099 Mem.WriteByte(flag^.State);
2100 // Íàïðàâëåíèå ôëàãà:
2101 if flag^.Direction = D_LEFT then
2102 b := 1
2103 else // D_RIGHT
2104 b := 2;
2105 Mem.WriteByte(b);
2106 // Îáúåêò ôëàãà:
2107 Obj_SaveState(@flag^.Obj, Mem);
2108 end;
2110 begin
2111 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2113 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2114 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2115 SavePanelArray(gWalls);
2116 // Ñîõðàíÿåì ïàíåëè ôîíà:
2117 SavePanelArray(gRenderBackgrounds);
2118 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2119 SavePanelArray(gRenderForegrounds);
2120 // Ñîõðàíÿåì ïàíåëè âîäû:
2121 SavePanelArray(gWater);
2122 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2123 SavePanelArray(gAcid1);
2124 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2125 SavePanelArray(gAcid2);
2126 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2127 SavePanelArray(gSteps);
2128 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2129 SavePanelArray(gLifts);
2130 ///// /////
2132 ///// Ñîõðàíÿåì ìóçûêó: /////
2133 // Ñèãíàòóðà ìóçûêè:
2134 dw := MUSIC_SIGNATURE; // 'MUSI'
2135 Mem.WriteDWORD(dw);
2136 // Íàçâàíèå ìóçûêè:
2137 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2138 if gMusic.NoMusic then
2139 str := ''
2140 else
2141 str := gMusic.Name;
2142 Mem.WriteString(str, 64);
2143 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2144 dw := gMusic.GetPosition();
2145 Mem.WriteDWORD(dw);
2146 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2147 boo := gMusic.SpecPause;
2148 Mem.WriteBoolean(boo);
2149 ///// /////
2151 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2152 Mem.WriteInt(gTotalMonsters);
2153 ///// /////
2155 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2156 if gGameSettings.GameMode = GM_CTF then
2157 begin
2158 // Ôëàã Êðàñíîé êîìàíäû:
2159 SaveFlag(@gFlags[FLAG_RED]);
2160 // Ôëàã Ñèíåé êîìàíäû:
2161 SaveFlag(@gFlags[FLAG_BLUE]);
2162 end;
2163 ///// /////
2165 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2166 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2167 begin
2168 // Î÷êè Êðàñíîé êîìàíäû:
2169 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2170 // Î÷êè Ñèíåé êîìàíäû:
2171 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2172 end;
2173 ///// /////
2174 end;
2176 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2177 var
2178 dw: DWORD;
2179 b: Byte;
2180 str: String;
2181 boo: Boolean;
2183 procedure LoadPanelArray(var panels: TPanelArray);
2184 var
2185 PAMem: TBinMemoryReader;
2186 i, id: Integer;
2187 begin
2188 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2189 PAMem := TBinMemoryReader.Create();
2190 PAMem.LoadFromMemory(Mem);
2192 for i := 0 to Length(panels)-1 do
2193 if panels[i].SaveIt then
2194 begin
2195 // ID ïàíåëè:
2196 PAMem.ReadInt(id);
2197 if id <> i then
2198 begin
2199 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2200 end;
2201 // Çàãðóæàåì ïàíåëü:
2202 panels[i].LoadState(PAMem);
2203 end;
2205 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2206 PAMem.Free();
2207 end;
2209 procedure LoadFlag(flag: PFlag);
2210 begin
2211 // Ñèãíàòóðà ôëàãà:
2212 Mem.ReadDWORD(dw);
2213 if dw <> FLAG_SIGNATURE then // 'FLAG'
2214 begin
2215 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2216 end;
2217 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2218 Mem.ReadByte(flag^.RespawnType);
2219 // Ñîñòîÿíèå ôëàãà:
2220 Mem.ReadByte(flag^.State);
2221 // Íàïðàâëåíèå ôëàãà:
2222 Mem.ReadByte(b);
2223 if b = 1 then
2224 flag^.Direction := D_LEFT
2225 else // b = 2
2226 flag^.Direction := D_RIGHT;
2227 // Îáúåêò ôëàãà:
2228 Obj_LoadState(@flag^.Obj, Mem);
2229 end;
2231 begin
2232 if Mem = nil then
2233 Exit;
2235 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2236 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2237 LoadPanelArray(gWalls);
2238 // Çàãðóæàåì ïàíåëè ôîíà:
2239 LoadPanelArray(gRenderBackgrounds);
2240 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2241 LoadPanelArray(gRenderForegrounds);
2242 // Çàãðóæàåì ïàíåëè âîäû:
2243 LoadPanelArray(gWater);
2244 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2245 LoadPanelArray(gAcid1);
2246 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2247 LoadPanelArray(gAcid2);
2248 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2249 LoadPanelArray(gSteps);
2250 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2251 LoadPanelArray(gLifts);
2252 ///// /////
2254 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2255 g_GFX_Init();
2257 ///// Çàãðóæàåì ìóçûêó: /////
2258 // Ñèãíàòóðà ìóçûêè:
2259 Mem.ReadDWORD(dw);
2260 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2261 begin
2262 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2263 end;
2264 // Íàçâàíèå ìóçûêè:
2265 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2266 Mem.ReadString(str);
2267 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2268 Mem.ReadDWORD(dw);
2269 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2270 Mem.ReadBoolean(boo);
2271 // Çàïóñêàåì ýòó ìóçûêó:
2272 gMusic.SetByName(str);
2273 gMusic.SpecPause := boo;
2274 gMusic.Play();
2275 gMusic.Pause(True);
2276 gMusic.SetPosition(dw);
2277 ///// /////
2279 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2280 Mem.ReadInt(gTotalMonsters);
2281 ///// /////
2283 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2284 if gGameSettings.GameMode = GM_CTF then
2285 begin
2286 // Ôëàã Êðàñíîé êîìàíäû:
2287 LoadFlag(@gFlags[FLAG_RED]);
2288 // Ôëàã Ñèíåé êîìàíäû:
2289 LoadFlag(@gFlags[FLAG_BLUE]);
2290 end;
2291 ///// /////
2293 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2294 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2295 begin
2296 // Î÷êè Êðàñíîé êîìàíäû:
2297 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2298 // Î÷êè Ñèíåé êîìàíäû:
2299 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2300 end;
2301 ///// /////
2302 end;
2304 end.