DEADSOFTWARE

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