DEADSOFTWARE

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