DEADSOFTWARE

added common file with compiler flags; cosmetic fix in g_monsters.pas
[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 {$INCLUDE g_amodes.inc}
17 unit g_map;
19 interface
21 uses
22 e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
23 g_phys, wadreader, BinEditor, g_panel, g_grid, 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();
65 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
67 procedure g_Map_DrawBack(dx, dy: Integer);
68 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
69 PanelType: Word; b1x3: Boolean): Boolean;
70 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
71 procedure g_Map_EnableWall(ID: DWORD);
72 procedure g_Map_DisableWall(ID: DWORD);
73 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
74 procedure g_Map_SetLift(ID: DWORD; t: Integer);
75 procedure g_Map_ReAdd_DieTriggers();
76 function g_Map_IsSpecialTexture(Texture: String): Boolean;
78 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
79 function g_Map_GetPointCount(PointType: Byte): Word;
81 function g_Map_HaveFlagPoints(): Boolean;
83 procedure g_Map_ResetFlag(Flag: Byte);
84 procedure g_Map_DrawFlags();
86 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
88 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
89 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
91 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
93 const
94 RESPAWNPOINT_PLAYER1 = 1;
95 RESPAWNPOINT_PLAYER2 = 2;
96 RESPAWNPOINT_DM = 3;
97 RESPAWNPOINT_RED = 4;
98 RESPAWNPOINT_BLUE = 5;
100 FLAG_NONE = 0;
101 FLAG_RED = 1;
102 FLAG_BLUE = 2;
103 FLAG_DOM = 3;
105 FLAG_STATE_NONE = 0;
106 FLAG_STATE_NORMAL = 1;
107 FLAG_STATE_DROPPED = 2;
108 FLAG_STATE_CAPTURED = 3;
109 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
110 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
112 FLAG_TIME = 720; // 20 seconds
114 SKY_STRETCH: Single = 1.5;
116 var
117 gWalls: TPanelArray;
118 gRenderBackgrounds: TPanelArray;
119 gRenderForegrounds: TPanelArray;
120 gWater, gAcid1, gAcid2: TPanelArray;
121 gSteps: TPanelArray;
122 gLifts: TPanelArray;
123 gBlockMon: TPanelArray;
124 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
125 //gDOMFlags: array of TFlag;
126 gMapInfo: TMapInfo;
127 gBackSize: TPoint;
128 gDoorMap: array of array of DWORD;
129 gLiftMap: array of array of DWORD;
130 gWADHash: TMD5Digest;
131 BackID: DWORD = DWORD(-1);
132 gExternalResources: TStringList;
134 implementation
136 uses
137 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
138 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
139 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
140 Math, g_monsters, g_saveload, g_language, g_netmsg,
141 utils, sfs,
142 ImagingTypes, Imaging, ImagingUtility,
143 ImagingGif, ImagingNetworkGraphics;
145 const
146 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
147 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
148 FLAG_SIGNATURE = $47414C46; // 'FLAG'
150 GridTagInvalid = -1;
151 GridTagWallDoor = 0;
152 GridTagBack = 1;
153 GridTagFore = 2;
154 GridTagWater = 3;
155 GridTagAcid1 = 4;
156 GridTagAcid2 = 5;
157 GridTagStep = 6;
158 GridTagLift = 7;
159 GridTagBlockMon = 8;
162 function panelTypeToTag (panelType: Word): Integer;
163 begin
164 case panelType of
165 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR: result := GridTagWallDoor; // gWalls
166 PANEL_BACK: result := GridTagBack; // gRenderBackgrounds
167 PANEL_FORE: result := GridTagFore; // gRenderForegrounds
168 PANEL_WATER: result := GridTagWater; // gWater
169 PANEL_ACID1: result := GridTagAcid1; // gAcid1
170 PANEL_ACID2: result := GridTagAcid2; // gAcid2
171 PANEL_STEP: result := GridTagStep; // gSteps
172 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT: result := GridTagLift; // gLifts -- this is for all lifts
173 PANEL_BLOCKMON: result := GridTagBlockMon; // gBlockMon -- this is for all blockmons
174 else result := GridTagInvalid;
175 end;
176 end;
179 type
180 TPanelID = record
181 PWhere: ^TPanelArray;
182 PArrID: Integer;
183 end;
185 var
186 PanelById: array of TPanelID;
187 Textures: TLevelTextureArray;
188 RespawnPoints: Array of TRespawnPoint;
189 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
190 //DOMFlagPoints: Array of TFlagPoint;
191 gMapGrid: TBodyGrid = nil;
194 function g_Map_IsSpecialTexture(Texture: String): Boolean;
195 begin
196 Result := (Texture = TEXTURE_NAME_WATER) or
197 (Texture = TEXTURE_NAME_ACID1) or
198 (Texture = TEXTURE_NAME_ACID2);
199 end;
201 procedure CreateDoorMap();
202 var
203 PanelArray: Array of record
204 X, Y: Integer;
205 Width, Height: Word;
206 Active: Boolean;
207 PanelID: DWORD;
208 end;
209 a, b, c, m, i, len: Integer;
210 ok: Boolean;
211 begin
212 if gWalls = nil then
213 Exit;
215 i := 0;
216 len := 128;
217 SetLength(PanelArray, len);
219 for a := 0 to High(gWalls) do
220 if gWalls[a].Door then
221 begin
222 PanelArray[i].X := gWalls[a].X;
223 PanelArray[i].Y := gWalls[a].Y;
224 PanelArray[i].Width := gWalls[a].Width;
225 PanelArray[i].Height := gWalls[a].Height;
226 PanelArray[i].Active := True;
227 PanelArray[i].PanelID := a;
229 i := i + 1;
230 if i = len then
231 begin
232 len := len + 128;
233 SetLength(PanelArray, len);
234 end;
235 end;
237 // Íåò äâåðåé:
238 if i = 0 then
239 begin
240 PanelArray := nil;
241 Exit;
242 end;
244 SetLength(gDoorMap, 0);
246 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
248 for a := 0 to i-1 do
249 if PanelArray[a].Active then
250 begin
251 PanelArray[a].Active := False;
252 m := Length(gDoorMap);
253 SetLength(gDoorMap, m+1);
254 SetLength(gDoorMap[m], 1);
255 gDoorMap[m, 0] := PanelArray[a].PanelID;
256 ok := True;
258 while ok do
259 begin
260 ok := False;
262 for b := 0 to i-1 do
263 if PanelArray[b].Active then
264 for c := 0 to High(gDoorMap[m]) do
265 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
266 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
267 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
268 PanelArray[b].Width, PanelArray[b].Height,
269 gWalls[gDoorMap[m, c]].X,
270 gWalls[gDoorMap[m, c]].Y,
271 gWalls[gDoorMap[m, c]].Width,
272 gWalls[gDoorMap[m, c]].Height) then
273 begin
274 PanelArray[b].Active := False;
275 SetLength(gDoorMap[m],
276 Length(gDoorMap[m])+1);
277 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
278 ok := True;
279 Break;
280 end;
281 end;
283 g_Game_StepLoading();
284 end;
286 PanelArray := nil;
287 end;
289 procedure CreateLiftMap();
290 var
291 PanelArray: Array of record
292 X, Y: Integer;
293 Width, Height: Word;
294 Active: Boolean;
295 end;
296 a, b, c, len, i, j: Integer;
297 ok: Boolean;
298 begin
299 if gLifts = nil then
300 Exit;
302 len := Length(gLifts);
303 SetLength(PanelArray, len);
305 for a := 0 to len-1 do
306 begin
307 PanelArray[a].X := gLifts[a].X;
308 PanelArray[a].Y := gLifts[a].Y;
309 PanelArray[a].Width := gLifts[a].Width;
310 PanelArray[a].Height := gLifts[a].Height;
311 PanelArray[a].Active := True;
312 end;
314 SetLength(gLiftMap, len);
315 i := 0;
317 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
319 for a := 0 to len-1 do
320 if PanelArray[a].Active then
321 begin
322 PanelArray[a].Active := False;
323 SetLength(gLiftMap[i], 32);
324 j := 0;
325 gLiftMap[i, j] := a;
326 ok := True;
328 while ok do
329 begin
330 ok := False;
331 for b := 0 to len-1 do
332 if PanelArray[b].Active then
333 for c := 0 to j do
334 if g_CollideAround(PanelArray[b].X,
335 PanelArray[b].Y,
336 PanelArray[b].Width,
337 PanelArray[b].Height,
338 PanelArray[gLiftMap[i, c]].X,
339 PanelArray[gLiftMap[i, c]].Y,
340 PanelArray[gLiftMap[i, c]].Width,
341 PanelArray[gLiftMap[i, c]].Height) then
342 begin
343 PanelArray[b].Active := False;
344 j := j+1;
345 if j > High(gLiftMap[i]) then
346 SetLength(gLiftMap[i],
347 Length(gLiftMap[i])+32);
349 gLiftMap[i, j] := b;
350 ok := True;
352 Break;
353 end;
354 end;
356 SetLength(gLiftMap[i], j+1);
357 i := i+1;
359 g_Game_StepLoading();
360 end;
362 SetLength(gLiftMap, i);
364 PanelArray := nil;
365 end;
367 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
368 CurTex: Integer; sav: Boolean): Integer;
369 var
370 len: Integer;
371 panels: ^TPanelArray;
372 begin
373 Result := -1;
375 case PanelRec.PanelType of
376 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
377 panels := @gWalls;
378 PANEL_BACK:
379 panels := @gRenderBackgrounds;
380 PANEL_FORE:
381 panels := @gRenderForegrounds;
382 PANEL_WATER:
383 panels := @gWater;
384 PANEL_ACID1:
385 panels := @gAcid1;
386 PANEL_ACID2:
387 panels := @gAcid2;
388 PANEL_STEP:
389 panels := @gSteps;
390 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
391 panels := @gLifts;
392 PANEL_BLOCKMON:
393 panels := @gBlockMon;
394 else
395 Exit;
396 end;
398 len := Length(panels^);
399 SetLength(panels^, len + 1);
401 panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures);
402 panels^[len].ArrIdx := len;
403 if sav then
404 panels^[len].SaveIt := True;
406 Result := len;
408 len := Length(PanelByID);
409 SetLength(PanelByID, len + 1);
410 PanelByID[len].PWhere := panels;
411 PanelByID[len].PArrID := Result;
412 end;
414 function CreateNullTexture(RecName: String): Integer;
415 begin
416 SetLength(Textures, Length(Textures)+1);
417 result := High(Textures);
419 with Textures[High(Textures)] do
420 begin
421 TextureName := RecName;
422 Width := 1;
423 Height := 1;
424 Anim := False;
425 TextureID := TEXTURE_NONE;
426 end;
427 end;
429 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
430 var
431 WAD: TWADFile;
432 TextureData: Pointer;
433 WADName, txname: String;
434 a, ResLength: Integer;
435 begin
436 Result := -1;
438 if Textures <> nil then
439 for a := 0 to High(Textures) do
440 if Textures[a].TextureName = RecName then
441 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
442 Result := a;
443 Exit;
444 end;
446 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
447 if (RecName = TEXTURE_NAME_WATER) or
448 (RecName = TEXTURE_NAME_ACID1) or
449 (RecName = TEXTURE_NAME_ACID2) then
450 begin
451 SetLength(Textures, Length(Textures)+1);
453 with Textures[High(Textures)] do
454 begin
455 TextureName := RecName;
457 if TextureName = TEXTURE_NAME_WATER then
458 TextureID := TEXTURE_SPECIAL_WATER
459 else
460 if TextureName = TEXTURE_NAME_ACID1 then
461 TextureID := TEXTURE_SPECIAL_ACID1
462 else
463 if TextureName = TEXTURE_NAME_ACID2 then
464 TextureID := TEXTURE_SPECIAL_ACID2;
466 Anim := False;
467 end;
469 result := High(Textures);
470 Exit;
471 end;
473 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
474 WADName := g_ExtractWadName(RecName);
476 WAD := TWADFile.Create();
478 if WADName <> '' then
479 WADName := GameDir+'/wads/'+WADName
480 else
481 WADName := Map;
483 WAD.ReadFile(WADName);
485 txname := RecName;
487 if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
488 begin
489 FreeMem(TextureData);
490 RecName := 'COMMON\ALIEN';
491 end;
494 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
495 begin
496 SetLength(Textures, Length(Textures)+1);
497 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
498 Exit;
499 e_GetTextureSize(Textures[High(Textures)].TextureID,
500 @Textures[High(Textures)].Width,
501 @Textures[High(Textures)].Height);
502 FreeMem(TextureData);
503 Textures[High(Textures)].TextureName := {RecName}txname;
504 Textures[High(Textures)].Anim := False;
506 result := High(Textures);
507 end
508 else // Íåò òàêîãî ðåóñðñà â WAD'å
509 begin
510 //e_WriteLog(Format('SHIT! Error loading texture %s : %s : %s', [RecName, txname, g_ExtractFilePathName(RecName)]), MSG_WARNING);
511 if log then
512 begin
513 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
514 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
515 end;
516 end;
518 WAD.Free();
519 end;
521 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
522 var
523 WAD: TWADFile;
524 TextureWAD: PChar = nil;
525 TextData: Pointer = nil;
526 TextureData: Pointer = nil;
527 cfg: TConfig = nil;
528 WADName: String;
529 ResLength: Integer;
530 TextureResource: String;
531 _width, _height, _framecount, _speed: Integer;
532 _backanimation: Boolean;
533 //imgfmt: string;
534 ia: TDynImageDataArray = nil;
535 f, c, frdelay, frloop: Integer;
536 begin
537 result := -1;
539 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
541 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
542 WADName := g_ExtractWadName(RecName);
544 WAD := TWADFile.Create();
545 try
546 if WADName <> '' then
547 WADName := GameDir+'/wads/'+WADName
548 else
549 WADName := Map;
551 WAD.ReadFile(WADName);
553 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
554 begin
555 if log then
556 begin
557 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
558 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
559 end;
560 exit;
561 end;
563 {TEST
564 if WADName = Map then
565 begin
566 //FreeMem(TextureWAD);
567 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
568 end;
571 WAD.FreeWAD();
573 if ResLength < 6 then
574 begin
575 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
576 exit;
577 end;
579 // ýòî ïòèöà? ýòî ñàìîë¸ò?
580 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
581 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
582 begin
583 // íåò, ýòî ñóïåðìåí!
584 if not WAD.ReadMemory(TextureWAD, ResLength) then
585 begin
586 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
587 exit;
588 end;
590 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
591 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
592 begin
593 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
594 exit;
595 end;
597 cfg := TConfig.CreateMem(TextData, ResLength);
599 TextureResource := cfg.ReadStr('', 'resource', '');
600 if TextureResource = '' then
601 begin
602 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
603 exit;
604 end;
606 _width := cfg.ReadInt('', 'framewidth', 0);
607 _height := cfg.ReadInt('', 'frameheight', 0);
608 _framecount := cfg.ReadInt('', 'framecount', 0);
609 _speed := cfg.ReadInt('', 'waitcount', 0);
610 _backanimation := cfg.ReadBool('', 'backanimation', False);
612 cfg.Free();
613 cfg := nil;
615 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
616 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
617 begin
618 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
619 exit;
620 end;
622 WAD.Free();
623 WAD := nil;
625 SetLength(Textures, Length(Textures)+1);
626 with Textures[High(Textures)] do
627 begin
628 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
629 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
630 begin
631 TextureName := RecName;
632 Width := _width;
633 Height := _height;
634 Anim := True;
635 FramesCount := _framecount;
636 Speed := _speed;
637 result := High(Textures);
638 end
639 else
640 begin
641 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
642 end;
643 end;
644 end
645 else
646 begin
647 // try animated image
649 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
650 if length(imgfmt) = 0 then
651 begin
652 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
653 exit;
654 end;
656 GlobalMetadata.ClearMetaItems();
657 GlobalMetadata.ClearMetaItemsForSaving();
658 if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
659 begin
660 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
661 exit;
662 end;
663 if length(ia) = 0 then
664 begin
665 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
666 exit;
667 end;
669 WAD.Free();
670 WAD := nil;
672 _width := ia[0].width;
673 _height := ia[0].height;
674 _framecount := length(ia);
675 _speed := 1;
676 _backanimation := false;
677 frdelay := -1;
678 frloop := -666;
679 if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then
680 begin
681 //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]);
682 try
683 f := GlobalMetadata.MetaItems[SMetaFrameDelay];
684 frdelay := f;
685 if f < 0 then f := 0;
686 // rounding ;-)
687 c := f mod 28;
688 if c < 13 then c := 0 else c := 1;
689 f := (f div 28)+c;
690 if f < 1 then f := 1 else if f > 255 then f := 255;
691 _speed := f;
692 except
693 end;
694 end;
695 if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then
696 begin
697 //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]);
698 try
699 f := GlobalMetadata.MetaItems[SMetaAnimationLoops];
700 frloop := f;
701 if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back
702 except
703 end;
704 end;
705 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
706 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
707 f := ord(_backanimation);
708 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);
710 SetLength(Textures, Length(Textures)+1);
711 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
712 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
713 begin
714 Textures[High(Textures)].TextureName := RecName;
715 Textures[High(Textures)].Width := _width;
716 Textures[High(Textures)].Height := _height;
717 Textures[High(Textures)].Anim := True;
718 Textures[High(Textures)].FramesCount := length(ia);
719 Textures[High(Textures)].Speed := _speed;
720 result := High(Textures);
721 //writeln(' CREATED!');
722 end
723 else
724 begin
725 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
726 end;
727 end;
728 finally
729 for f := 0 to High(ia) do FreeImage(ia[f]);
730 WAD.Free();
731 cfg.Free();
732 if TextureWAD <> nil then FreeMem(TextureWAD);
733 if TextData <> nil then FreeMem(TextData);
734 if TextureData <> nil then FreeMem(TextureData);
735 end;
736 end;
738 procedure CreateItem(Item: TItemRec_1);
739 begin
740 if g_Game_IsClient then Exit;
742 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
743 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
744 Exit;
746 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
747 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
748 end;
750 procedure CreateArea(Area: TAreaRec_1);
751 var
752 a: Integer;
753 id: DWORD;
754 begin
755 case Area.AreaType of
756 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
757 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
758 begin
759 SetLength(RespawnPoints, Length(RespawnPoints)+1);
760 with RespawnPoints[High(RespawnPoints)] do
761 begin
762 X := Area.X;
763 Y := Area.Y;
764 Direction := TDirection(Area.Direction);
766 case Area.AreaType of
767 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
768 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
769 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
770 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
771 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
772 end;
773 end;
774 end;
776 AREA_REDFLAG, AREA_BLUEFLAG:
777 begin
778 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
780 if FlagPoints[a] <> nil then Exit;
782 New(FlagPoints[a]);
784 with FlagPoints[a]^ do
785 begin
786 X := Area.X-FLAGRECT.X;
787 Y := Area.Y-FLAGRECT.Y;
788 Direction := TDirection(Area.Direction);
789 end;
791 with gFlags[a] do
792 begin
793 case a of
794 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
795 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
796 end;
798 Animation := TAnimation.Create(id, True, 8);
799 Obj.Rect := FLAGRECT;
801 g_Map_ResetFlag(a);
802 end;
803 end;
805 AREA_DOMFLAG:
806 begin
807 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
808 with DOMFlagPoints[High(DOMFlagPoints)] do
809 begin
810 X := Area.X;
811 Y := Area.Y;
812 Direction := TDirection(Area.Direction);
813 end;
815 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
816 end;
817 end;
818 end;
820 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
821 var
822 _trigger: TTrigger;
823 begin
824 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
826 with _trigger do
827 begin
828 X := Trigger.X;
829 Y := Trigger.Y;
830 Width := Trigger.Width;
831 Height := Trigger.Height;
832 Enabled := ByteBool(Trigger.Enabled);
833 TexturePanel := Trigger.TexturePanel;
834 TexturePanelType := fTexturePanel1Type;
835 ShotPanelType := fTexturePanel2Type;
836 TriggerType := Trigger.TriggerType;
837 ActivateType := Trigger.ActivateType;
838 Keys := Trigger.Keys;
839 Data.Default := Trigger.DATA;
840 end;
842 g_Triggers_Create(_trigger);
843 end;
845 procedure CreateMonster(monster: TMonsterRec_1);
846 var
847 a, i: Integer;
848 begin
849 if g_Game_IsClient then Exit;
851 if (gGameSettings.GameType = GT_SINGLE)
852 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
853 begin
854 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
855 TDirection(monster.Direction));
857 if gTriggers <> nil then
858 for a := 0 to High(gTriggers) do
859 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
860 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
861 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
862 gMonsters[i].AddTrigger(a);
864 if monster.MonsterType <> MONSTER_BARREL then
865 Inc(gTotalMonsters);
866 end;
867 end;
869 procedure g_Map_ReAdd_DieTriggers();
870 var
871 i, a: Integer;
872 begin
873 if g_Game_IsClient then Exit;
875 for i := 0 to High(gMonsters) do
876 if gMonsters[i] <> nil then
877 begin
878 gMonsters[i].ClearTriggers();
880 for a := 0 to High(gTriggers) do
881 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
882 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
883 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
884 gMonsters[i].AddTrigger(a);
885 end;
886 end;
888 function extractWadName(resourceName: string): string;
889 var
890 posN: Integer;
891 begin
892 posN := Pos(':', resourceName);
893 if posN > 0 then
894 Result:= Copy(resourceName, 0, posN-1)
895 else
896 Result := '';
897 end;
899 procedure addResToExternalResList(res: string);
900 begin
901 res := extractWadName(res);
902 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
903 gExternalResources.Add(res);
904 end;
906 procedure generateExternalResourcesList(mapReader: TMapReader_1);
907 var
908 textures: TTexturesRec1Array;
909 mapHeader: TMapHeaderRec_1;
910 i: integer;
911 resFile: String = '';
912 begin
913 if gExternalResources = nil then
914 gExternalResources := TStringList.Create;
916 gExternalResources.Clear;
917 textures := mapReader.GetTextures();
918 for i := 0 to High(textures) do
919 begin
920 addResToExternalResList(resFile);
921 end;
923 textures := nil;
925 mapHeader := mapReader.GetMapHeader;
927 addResToExternalResList(mapHeader.MusicName);
928 addResToExternalResList(mapHeader.SkyName);
929 end;
931 procedure mapCreateGrid ();
932 var
933 mapX0: Integer = $3fffffff;
934 mapY0: Integer = $3fffffff;
935 mapX1: Integer = -$3fffffff;
936 mapY1: Integer = -$3fffffff;
938 procedure fixMinMax (var panels: TPanelArray);
939 var
940 idx: Integer;
941 begin
942 for idx := 0 to High(panels) do
943 begin
944 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
945 if mapX0 > panels[idx].X then mapX0 := panels[idx].X;
946 if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y;
947 if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1;
948 if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1;
949 end;
950 end;
952 procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer);
953 var
954 idx: Integer;
955 begin
956 tag := panelTypeToTag(tag);
957 for idx := High(panels) downto 0 do
958 begin
959 gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
960 end;
961 end;
963 begin
964 gMapGrid.Free();
965 gMapGrid := nil;
967 fixMinMax(gWalls);
968 fixMinMax(gRenderBackgrounds);
969 fixMinMax(gRenderForegrounds);
970 fixMinMax(gWater);
971 fixMinMax(gAcid1);
972 fixMinMax(gAcid2);
973 fixMinMax(gSteps);
974 fixMinMax(gLifts);
975 fixMinMax(gBlockMon);
977 if (mapX0 < 0) or (mapY0 < 0) then
978 begin
979 e_WriteLog(Format('funny map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING);
980 //raise Exception.Create('we are fucked');
981 end;
983 gMapGrid := TBodyGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1);
985 addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR
986 addPanelsToGrid(gRenderBackgrounds, PANEL_BACK);
987 addPanelsToGrid(gRenderForegrounds, PANEL_FORE);
988 addPanelsToGrid(gWater, PANEL_WATER);
989 addPanelsToGrid(gAcid1, PANEL_ACID1);
990 addPanelsToGrid(gAcid2, PANEL_ACID2);
991 addPanelsToGrid(gSteps, PANEL_STEP);
992 addPanelsToGrid(gLifts, PANEL_LIFTUP); // it doesn't matter which LIFT type is used here
993 addPanelsToGrid(gBlockMon, PANEL_BLOCKMON);
995 gMapGrid.dumpStats();
996 end;
998 function g_Map_Load(Res: String): Boolean;
999 const
1000 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
1001 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
1002 var
1003 WAD: TWADFile;
1004 MapReader: TMapReader_1;
1005 Header: TMapHeaderRec_1;
1006 _textures: TTexturesRec1Array;
1007 _texnummap: array of Integer; // `_textures` -> `Textures`
1008 panels: TPanelsRec1Array;
1009 items: TItemsRec1Array;
1010 monsters: TMonsterRec1Array;
1011 areas: TAreasRec1Array;
1012 triggers: TTriggersRec1Array;
1013 a, b, c, k: Integer;
1014 PanelID: DWORD;
1015 AddTextures: TAddTextureArray;
1016 texture: TTextureRec_1;
1017 TriggersTable: Array of record
1018 TexturePanel: Integer;
1019 LiftPanel: Integer;
1020 DoorPanel: Integer;
1021 ShotPanel: Integer;
1022 end;
1023 FileName, mapResName, s, TexName: String;
1024 Data: Pointer;
1025 Len: Integer;
1026 ok, isAnim, trigRef: Boolean;
1027 CurTex, ntn: Integer;
1029 begin
1030 gMapGrid.Free();
1031 gMapGrid := nil;
1033 Result := False;
1034 gMapInfo.Map := Res;
1035 TriggersTable := nil;
1036 FillChar(texture, SizeOf(texture), 0);
1038 sfsGCDisable(); // temporary disable removing of temporary volumes
1039 try
1040 // Çàãðóçêà WAD:
1041 FileName := g_ExtractWadName(Res);
1042 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
1043 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
1045 WAD := TWADFile.Create();
1046 if not WAD.ReadFile(FileName) then
1047 begin
1048 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
1049 WAD.Free();
1050 Exit;
1051 end;
1052 //k8: why loader ignores path here?
1053 mapResName := g_ExtractFileName(Res);
1054 if not WAD.GetMapResource(mapResName, Data, Len) then
1055 begin
1056 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
1057 WAD.Free();
1058 Exit;
1059 end;
1061 WAD.Free();
1063 // Çàãðóçêà êàðòû:
1064 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
1065 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
1066 MapReader := TMapReader_1.Create();
1068 if not MapReader.LoadMap(Data) then
1069 begin
1070 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
1071 FreeMem(Data);
1072 MapReader.Free();
1073 Exit;
1074 end;
1076 FreeMem(Data);
1077 generateExternalResourcesList(MapReader);
1078 // Çàãðóçêà òåêñòóð:
1079 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
1080 _textures := MapReader.GetTextures();
1081 _texnummap := nil;
1083 // Äîáàâëåíèå òåêñòóð â Textures[]:
1084 if _textures <> nil then
1085 begin
1086 e_WriteLog(' Loading textures:', MSG_NOTIFY);
1087 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
1088 SetLength(_texnummap, length(_textures));
1090 for a := 0 to High(_textures) do
1091 begin
1092 SetLength(s, 64);
1093 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
1094 for b := 1 to Length(s) do
1095 if s[b] = #0 then
1096 begin
1097 SetLength(s, b-1);
1098 Break;
1099 end;
1100 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
1101 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
1102 // Àíèìèðîâàííàÿ òåêñòóðà:
1103 if ByteBool(_textures[a].Anim) then
1104 begin
1105 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1106 if ntn < 0 then
1107 begin
1108 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1109 ntn := CreateNullTexture(_textures[a].Resource);
1110 end;
1111 end
1112 else // Îáû÷íàÿ òåêñòóðà:
1113 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1114 if ntn < 0 then
1115 begin
1116 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1117 ntn := CreateNullTexture(_textures[a].Resource);
1118 end;
1120 _texnummap[a] := ntn; // fix texture number
1121 g_Game_StepLoading();
1122 end;
1123 end;
1125 // Çàãðóçêà òðèããåðîâ:
1126 gTriggerClientID := 0;
1127 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1128 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1129 triggers := MapReader.GetTriggers();
1131 // Çàãðóçêà ïàíåëåé:
1132 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1133 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1134 panels := MapReader.GetPanels();
1136 // check texture numbers for panels
1137 for a := 0 to High(panels) do
1138 begin
1139 if panels[a].TextureNum > High(_textures) then
1140 begin
1141 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1142 result := false;
1143 exit;
1144 end;
1145 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1146 end;
1148 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1149 if triggers <> nil then
1150 begin
1151 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1152 SetLength(TriggersTable, Length(triggers));
1153 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1155 for a := 0 to High(TriggersTable) do
1156 begin
1157 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1158 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1159 // Ëèôòû:
1160 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1161 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1162 else
1163 TriggersTable[a].LiftPanel := -1;
1164 // Äâåðè:
1165 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1166 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1167 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1168 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1169 else
1170 TriggersTable[a].DoorPanel := -1;
1171 // Òóðåëü:
1172 if triggers[a].TriggerType = TRIGGER_SHOT then
1173 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1174 else
1175 TriggersTable[a].ShotPanel := -1;
1177 g_Game_StepLoading();
1178 end;
1179 end;
1181 // Ñîçäàåì ïàíåëè:
1182 if panels <> nil then
1183 begin
1184 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1185 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1187 for a := 0 to High(panels) do
1188 begin
1189 SetLength(AddTextures, 0);
1190 trigRef := False;
1191 CurTex := -1;
1192 if _textures <> nil then
1193 begin
1194 texture := _textures[panels[a].TextureNum];
1195 ok := True;
1196 end
1197 else
1198 ok := False;
1200 if ok then
1201 begin
1202 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1203 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1204 ok := False;
1205 if (TriggersTable <> nil) and (_textures <> nil) then
1206 for b := 0 to High(TriggersTable) do
1207 if (TriggersTable[b].TexturePanel = a)
1208 or (TriggersTable[b].ShotPanel = a) then
1209 begin
1210 trigRef := True;
1211 ok := True;
1212 Break;
1213 end;
1214 end;
1216 if ok then
1217 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1218 SetLength(s, 64);
1219 CopyMemory(@s[1], @texture.Resource[0], 64);
1220 // Èçìåðÿåì äëèíó:
1221 Len := Length(s);
1222 for c := Len downto 1 do
1223 if s[c] <> #0 then
1224 begin
1225 Len := c;
1226 Break;
1227 end;
1228 SetLength(s, Len);
1230 // Ñïåö-òåêñòóðû çàïðåùåíû:
1231 if g_Map_IsSpecialTexture(s) then
1232 ok := False
1233 else
1234 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1235 ok := g_Texture_NumNameFindStart(s);
1237 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1238 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1239 if ok then
1240 begin
1241 k := NNF_NAME_BEFORE;
1242 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1243 while ok or (k = NNF_NAME_BEFORE) or
1244 (k = NNF_NAME_EQUALS) do
1245 begin
1246 k := g_Texture_NumNameFindNext(TexName);
1248 if (k = NNF_NAME_BEFORE) or
1249 (k = NNF_NAME_AFTER) then
1250 begin
1251 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1252 if ByteBool(texture.Anim) then
1253 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1254 isAnim := True;
1255 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1256 if not ok then
1257 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1258 isAnim := False;
1259 ok := CreateTexture(TexName, FileName, False) >= 0;
1260 end;
1261 end
1262 else
1263 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1264 isAnim := False;
1265 ok := CreateTexture(TexName, FileName, False) >= 0;
1266 if not ok then
1267 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1268 isAnim := True;
1269 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1270 end;
1271 end;
1273 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1274 if ok then
1275 begin
1276 for c := 0 to High(Textures) do
1277 if Textures[c].TextureName = TexName then
1278 begin
1279 SetLength(AddTextures, Length(AddTextures)+1);
1280 AddTextures[High(AddTextures)].Texture := c;
1281 AddTextures[High(AddTextures)].Anim := isAnim;
1282 Break;
1283 end;
1284 end;
1285 end
1286 else
1287 if k = NNF_NAME_EQUALS then
1288 begin
1289 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1290 SetLength(AddTextures, Length(AddTextures)+1);
1291 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1292 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1293 CurTex := High(AddTextures);
1294 ok := True;
1295 end
1296 else // NNF_NO_NAME
1297 ok := False;
1298 end; // while ok...
1300 ok := True;
1301 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1302 end; // if ok - ññûëàþòñÿ òðèããåðû
1304 if not ok then
1305 begin
1306 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1307 SetLength(AddTextures, 1);
1308 AddTextures[0].Texture := panels[a].TextureNum;
1309 AddTextures[0].Anim := ByteBool(texture.Anim);
1310 CurTex := 0;
1311 end;
1313 //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);
1315 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1316 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1318 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1319 if TriggersTable <> nil then
1320 for b := 0 to High(TriggersTable) do
1321 begin
1322 // Òðèããåð äâåðè/ëèôòà:
1323 if (TriggersTable[b].LiftPanel = a) or
1324 (TriggersTable[b].DoorPanel = a) then
1325 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1326 // Òðèããåð ñìåíû òåêñòóðû:
1327 if TriggersTable[b].TexturePanel = a then
1328 triggers[b].TexturePanel := PanelID;
1329 // Òðèããåð "Òóðåëü":
1330 if TriggersTable[b].ShotPanel = a then
1331 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1332 end;
1334 g_Game_StepLoading();
1335 end;
1336 end;
1338 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1339 if (triggers <> nil) and not gLoadGameMode then
1340 begin
1341 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1342 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1343 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1344 for a := 0 to High(triggers) do
1345 begin
1346 if triggers[a].TexturePanel <> -1 then
1347 b := panels[TriggersTable[a].TexturePanel].PanelType
1348 else
1349 b := 0;
1350 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1351 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1352 c := panels[TriggersTable[a].ShotPanel].PanelType
1353 else
1354 c := 0;
1355 CreateTrigger(triggers[a], b, c);
1356 end;
1357 end;
1359 // Çàãðóçêà ïðåäìåòîâ:
1360 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1361 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1362 items := MapReader.GetItems();
1364 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1365 if (items <> nil) and not gLoadGameMode then
1366 begin
1367 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1368 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1369 for a := 0 to High(items) do
1370 CreateItem(Items[a]);
1371 end;
1373 // Çàãðóçêà îáëàñòåé:
1374 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1375 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1376 areas := MapReader.GetAreas();
1378 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1379 if areas <> nil then
1380 begin
1381 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1382 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1383 for a := 0 to High(areas) do
1384 CreateArea(areas[a]);
1385 end;
1387 // Çàãðóçêà ìîíñòðîâ:
1388 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1389 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1390 monsters := MapReader.GetMonsters();
1392 gTotalMonsters := 0;
1394 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1395 if (monsters <> nil) and not gLoadGameMode then
1396 begin
1397 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1398 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1399 for a := 0 to High(monsters) do
1400 CreateMonster(monsters[a]);
1401 end;
1403 // Çàãðóçêà îïèñàíèÿ êàðòû:
1404 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1405 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1406 Header := MapReader.GetMapHeader();
1408 MapReader.Free();
1410 with gMapInfo do
1411 begin
1412 Name := Header.MapName;
1413 Description := Header.MapDescription;
1414 Author := Header.MapAuthor;
1415 MusicName := Header.MusicName;
1416 SkyName := Header.SkyName;
1417 Height := Header.Height;
1418 Width := Header.Width;
1419 end;
1421 // Çàãðóçêà íåáà:
1422 if gMapInfo.SkyName <> '' then
1423 begin
1424 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1425 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1426 FileName := g_ExtractWadName(gMapInfo.SkyName);
1428 if FileName <> '' then
1429 FileName := GameDir+'/wads/'+FileName
1430 else
1431 begin
1432 FileName := g_ExtractWadName(Res);
1433 end;
1435 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1436 if g_Texture_CreateWAD(BackID, s) then
1437 begin
1438 g_Game_SetupScreenSize();
1439 end
1440 else
1441 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1442 end;
1444 // Çàãðóçêà ìóçûêè:
1445 ok := False;
1446 if gMapInfo.MusicName <> '' then
1447 begin
1448 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1449 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1450 FileName := g_ExtractWadName(gMapInfo.MusicName);
1452 if FileName <> '' then
1453 FileName := GameDir+'/wads/'+FileName
1454 else
1455 begin
1456 FileName := g_ExtractWadName(Res);
1457 end;
1459 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1460 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1461 ok := True
1462 else
1463 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1464 end;
1466 // Îñòàëüíûå óñòàíâêè:
1467 CreateDoorMap();
1468 CreateLiftMap();
1470 g_Items_Init();
1471 g_Weapon_Init();
1472 g_Monsters_Init();
1474 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1475 if not gLoadGameMode then
1476 g_GFX_Init();
1478 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1479 _textures := nil;
1480 panels := nil;
1481 items := nil;
1482 areas := nil;
1483 triggers := nil;
1484 TriggersTable := nil;
1485 AddTextures := nil;
1487 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1488 if ok and (not gLoadGameMode) then
1489 begin
1490 gMusic.SetByName(gMapInfo.MusicName);
1491 gMusic.Play();
1492 end
1493 else
1494 gMusic.SetByName('');
1495 finally
1496 sfsGCEnable(); // enable releasing unused volumes
1497 end;
1499 e_WriteLog('Creating map grid', MSG_NOTIFY);
1500 mapCreateGrid();
1502 e_WriteLog('Done loading map.', MSG_NOTIFY);
1503 Result := True;
1504 end;
1506 function g_Map_GetMapInfo(Res: String): TMapInfo;
1507 var
1508 WAD: TWADFile;
1509 MapReader: TMapReader_1;
1510 Header: TMapHeaderRec_1;
1511 FileName: String;
1512 Data: Pointer;
1513 Len: Integer;
1514 begin
1515 FillChar(Result, SizeOf(Result), 0);
1516 FileName := g_ExtractWadName(Res);
1518 WAD := TWADFile.Create();
1519 if not WAD.ReadFile(FileName) then
1520 begin
1521 WAD.Free();
1522 Exit;
1523 end;
1525 //k8: it ignores path again
1526 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1527 begin
1528 WAD.Free();
1529 Exit;
1530 end;
1532 WAD.Free();
1534 MapReader := TMapReader_1.Create();
1536 if not MapReader.LoadMap(Data) then
1537 begin
1538 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1539 ZeroMemory(@Header, SizeOf(Header));
1540 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1541 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1542 end
1543 else
1544 begin
1545 Header := MapReader.GetMapHeader();
1546 Result.Name := Header.MapName;
1547 Result.Description := Header.MapDescription;
1548 end;
1550 FreeMem(Data);
1551 MapReader.Free();
1553 Result.Map := Res;
1554 Result.Author := Header.MapAuthor;
1555 Result.Height := Header.Height;
1556 Result.Width := Header.Width;
1557 end;
1559 function g_Map_GetMapsList(WADName: string): SArray;
1560 var
1561 WAD: TWADFile;
1562 a: Integer;
1563 ResList: SArray;
1564 begin
1565 Result := nil;
1566 WAD := TWADFile.Create();
1567 if not WAD.ReadFile(WADName) then
1568 begin
1569 WAD.Free();
1570 Exit;
1571 end;
1572 ResList := WAD.GetMapResources();
1573 if ResList <> nil then
1574 begin
1575 for a := 0 to High(ResList) do
1576 begin
1577 SetLength(Result, Length(Result)+1);
1578 Result[High(Result)] := ResList[a];
1579 end;
1580 end;
1581 WAD.Free();
1582 end;
1584 function g_Map_Exist(Res: string): Boolean;
1585 var
1586 WAD: TWADFile;
1587 FileName, mnn: string;
1588 ResList: SArray;
1589 a: Integer;
1590 begin
1591 Result := False;
1593 FileName := addWadExtension(g_ExtractWadName(Res));
1595 WAD := TWADFile.Create;
1596 if not WAD.ReadFile(FileName) then
1597 begin
1598 WAD.Free();
1599 Exit;
1600 end;
1602 ResList := WAD.GetMapResources();
1603 WAD.Free();
1605 mnn := g_ExtractFileName(Res);
1606 if ResList <> nil then
1607 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1608 begin
1609 Result := True;
1610 Exit;
1611 end;
1612 end;
1614 procedure g_Map_Free();
1615 var
1616 a: Integer;
1618 procedure FreePanelArray(var panels: TPanelArray);
1619 var
1620 i: Integer;
1622 begin
1623 if panels <> nil then
1624 begin
1625 for i := 0 to High(panels) do
1626 panels[i].Free();
1627 panels := nil;
1628 end;
1629 end;
1631 begin
1632 g_GFX_Free();
1633 g_Weapon_Free();
1634 g_Items_Free();
1635 g_Triggers_Free();
1636 g_Monsters_Free();
1638 RespawnPoints := nil;
1639 if FlagPoints[FLAG_RED] <> nil then
1640 begin
1641 Dispose(FlagPoints[FLAG_RED]);
1642 FlagPoints[FLAG_RED] := nil;
1643 end;
1644 if FlagPoints[FLAG_BLUE] <> nil then
1645 begin
1646 Dispose(FlagPoints[FLAG_BLUE]);
1647 FlagPoints[FLAG_BLUE] := nil;
1648 end;
1649 //DOMFlagPoints := nil;
1651 //gDOMFlags := nil;
1653 if Textures <> nil then
1654 begin
1655 for a := 0 to High(Textures) do
1656 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1657 if Textures[a].Anim then
1658 g_Frames_DeleteByID(Textures[a].FramesID)
1659 else
1660 if Textures[a].TextureID <> TEXTURE_NONE then
1661 e_DeleteTexture(Textures[a].TextureID);
1663 Textures := nil;
1664 end;
1666 FreePanelArray(gWalls);
1667 FreePanelArray(gRenderBackgrounds);
1668 FreePanelArray(gRenderForegrounds);
1669 FreePanelArray(gWater);
1670 FreePanelArray(gAcid1);
1671 FreePanelArray(gAcid2);
1672 FreePanelArray(gSteps);
1673 FreePanelArray(gLifts);
1674 FreePanelArray(gBlockMon);
1676 if BackID <> DWORD(-1) then
1677 begin
1678 gBackSize.X := 0;
1679 gBackSize.Y := 0;
1680 e_DeleteTexture(BackID);
1681 BackID := DWORD(-1);
1682 end;
1684 g_Game_StopAllSounds(False);
1685 gMusic.FreeSound();
1686 g_Sound_Delete(gMapInfo.MusicName);
1688 gMapInfo.Name := '';
1689 gMapInfo.Description := '';
1690 gMapInfo.MusicName := '';
1691 gMapInfo.Height := 0;
1692 gMapInfo.Width := 0;
1694 gDoorMap := nil;
1695 gLiftMap := nil;
1697 PanelByID := nil;
1698 end;
1700 procedure g_Map_Update();
1701 var
1702 a, d, j: Integer;
1703 m: Word;
1704 s: String;
1706 procedure UpdatePanelArray(var panels: TPanelArray);
1707 var
1708 i: Integer;
1710 begin
1711 if panels <> nil then
1712 for i := 0 to High(panels) do
1713 panels[i].Update();
1714 end;
1716 begin
1717 UpdatePanelArray(gWalls);
1718 UpdatePanelArray(gRenderBackgrounds);
1719 UpdatePanelArray(gRenderForegrounds);
1720 UpdatePanelArray(gWater);
1721 UpdatePanelArray(gAcid1);
1722 UpdatePanelArray(gAcid2);
1723 UpdatePanelArray(gSteps);
1725 if gGameSettings.GameMode = GM_CTF then
1726 begin
1727 for a := FLAG_RED to FLAG_BLUE do
1728 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1729 with gFlags[a] do
1730 begin
1731 if gFlags[a].Animation <> nil then
1732 gFlags[a].Animation.Update();
1734 m := g_Obj_Move(@Obj, True, True);
1736 if gTime mod (GAME_TICK*2) <> 0 then
1737 Continue;
1739 // Ñîïðîòèâëåíèå âîçäóõà:
1740 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1742 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1743 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1744 begin
1745 g_Map_ResetFlag(a);
1746 gFlags[a].CaptureTime := 0;
1747 if a = FLAG_RED then
1748 s := _lc[I_PLAYER_FLAG_RED]
1749 else
1750 s := _lc[I_PLAYER_FLAG_BLUE];
1751 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1753 if g_Game_IsNet then
1754 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1755 Continue;
1756 end;
1758 if Count > 0 then
1759 Count := Count - 1;
1761 // Èãðîê áåðåò ôëàã:
1762 if gPlayers <> nil then
1763 begin
1764 j := Random(Length(gPlayers)) - 1;
1766 for d := 0 to High(gPlayers) do
1767 begin
1768 Inc(j);
1769 if j > High(gPlayers) then
1770 j := 0;
1772 if gPlayers[j] <> nil then
1773 if gPlayers[j].Live and
1774 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1775 begin
1776 if gPlayers[j].GetFlag(a) then
1777 Break;
1778 end;
1779 end;
1780 end;
1781 end;
1782 end;
1783 end;
1786 procedure g_Map_DrawPanelsOld(PanelType: Word);
1788 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1789 var
1790 idx: Integer;
1791 begin
1792 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1793 begin
1794 // alas, no visible set
1795 for idx := 0 to High(panels) do
1796 begin
1797 if not (drawDoors xor panels[idx].Door) then panels[idx].Draw();
1798 end;
1799 end;
1800 end;
1802 begin
1803 case PanelType of
1804 PANEL_WALL: DrawPanels(0, gWalls);
1805 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1806 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1807 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1808 PANEL_WATER: DrawPanels(3, gWater);
1809 PANEL_ACID1: DrawPanels(4, gAcid1);
1810 PANEL_ACID2: DrawPanels(5, gAcid2);
1811 PANEL_STEP: DrawPanels(6, gSteps);
1812 end;
1813 end;
1816 var
1817 gDrawPanelList: TBinaryHeapObj = nil;
1819 function dplLess (a, b: TObject): Boolean;
1820 begin
1821 result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx);
1822 end;
1824 procedure dplClear ();
1825 begin
1826 if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear();
1827 end;
1829 procedure dplAddPanel (pan: TPanel);
1830 begin
1831 if pan = nil then exit;
1832 gDrawPanelList.insert(pan);
1833 end;
1836 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
1837 var
1838 ptag: Integer;
1840 function checker (obj: TObject; tag: Integer): Boolean;
1841 var
1842 pan: TPanel;
1843 begin
1844 result := false; // don't stop, ever
1845 if (tag <> ptag) then exit;
1846 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1848 if obj = nil then begin e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
1849 if not (obj is TPanel) then begin e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
1850 //pan := (obj as TPanel);
1851 //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1853 pan := (obj as TPanel);
1854 if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end;
1855 //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1856 dplAddPanel(pan);
1857 end;
1859 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1860 var
1861 idx: Integer;
1862 pan: TPanel;
1863 begin
1864 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1865 begin
1866 // alas, no visible set
1867 for idx := 0 to High(panels) do
1868 begin
1869 if not (drawDoors xor panels[idx].Door) then
1870 begin
1871 pan := panels[idx];
1872 if (pan.Width < 1) or (pan.Height < 1) then continue;
1873 if (pan.X+pan.Width <= x0) or (pan.Y+pan.Height <= y0) then continue;
1874 if (pan.X >= x0+wdt) or (pan.Y >= y0+hgt) then continue;
1875 e_WriteLog(Format(' *body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, PanelType, PanelType]), MSG_NOTIFY);
1876 end;
1877 end;
1878 end;
1879 end;
1881 begin
1882 //g_Map_DrawPanelsOld(PanelType); exit;
1883 //e_WriteLog('==================', MSG_NOTIFY);
1884 //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1885 dplClear();
1886 ptag := panelTypeToTag(PanelType);
1887 gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker);
1889 // debug
1891 e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1892 case PanelType of
1893 PANEL_WALL: DrawPanels(0, gWalls);
1894 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1895 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1896 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1897 PANEL_WATER: DrawPanels(3, gWater);
1898 PANEL_ACID1: DrawPanels(4, gAcid1);
1899 PANEL_ACID2: DrawPanels(5, gAcid2);
1900 PANEL_STEP: DrawPanels(6, gSteps);
1901 end;
1902 e_WriteLog('==================', MSG_NOTIFY);
1905 // sort and draw the list (we need to sort it, or rendering is fucked)
1906 while gDrawPanelList.count > 0 do
1907 begin
1908 (gDrawPanelList.front() as TPanel).Draw();
1909 gDrawPanelList.popFront();
1910 end;
1911 end;
1914 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
1915 function checker (obj: TObject; tag: Integer): Boolean;
1916 var
1917 pan: TPanel;
1918 begin
1919 result := false; // don't stop, ever
1920 if (tag <> GridTagWallDoor) then exit; // only walls
1921 pan := (obj as TPanel);
1922 pan.DrawShadowVolume(lightX, lightY, radius);
1923 end;
1925 begin
1926 gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker);
1927 end;
1930 procedure g_Map_DrawBack(dx, dy: Integer);
1931 begin
1932 if gDrawBackGround and (BackID <> DWORD(-1)) then
1933 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1934 else
1935 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1936 end;
1938 (*
1939 function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word;
1940 PanelType: Word; b1x3: Boolean): Boolean;
1941 var
1942 a, h: Integer;
1943 begin
1944 Result := False;
1946 if WordBool(PanelType and PANEL_WALL) then
1947 if gWalls <> nil then
1948 begin
1949 h := High(gWalls);
1951 for a := 0 to h do
1952 if gWalls[a].Enabled and
1953 g_Collide(X, Y, Width, Height,
1954 gWalls[a].X, gWalls[a].Y,
1955 gWalls[a].Width, gWalls[a].Height) then
1956 begin
1957 Result := True;
1958 Exit;
1959 end;
1960 end;
1962 if WordBool(PanelType and PANEL_WATER) then
1963 if gWater <> nil then
1964 begin
1965 h := High(gWater);
1967 for a := 0 to h do
1968 if g_Collide(X, Y, Width, Height,
1969 gWater[a].X, gWater[a].Y,
1970 gWater[a].Width, gWater[a].Height) then
1971 begin
1972 Result := True;
1973 Exit;
1974 end;
1975 end;
1977 if WordBool(PanelType and PANEL_ACID1) then
1978 if gAcid1 <> nil then
1979 begin
1980 h := High(gAcid1);
1982 for a := 0 to h do
1983 if g_Collide(X, Y, Width, Height,
1984 gAcid1[a].X, gAcid1[a].Y,
1985 gAcid1[a].Width, gAcid1[a].Height) then
1986 begin
1987 Result := True;
1988 Exit;
1989 end;
1990 end;
1992 if WordBool(PanelType and PANEL_ACID2) then
1993 if gAcid2 <> nil then
1994 begin
1995 h := High(gAcid2);
1997 for a := 0 to h do
1998 if g_Collide(X, Y, Width, Height,
1999 gAcid2[a].X, gAcid2[a].Y,
2000 gAcid2[a].Width, gAcid2[a].Height) then
2001 begin
2002 Result := True;
2003 Exit;
2004 end;
2005 end;
2007 if WordBool(PanelType and PANEL_STEP) then
2008 if gSteps <> nil then
2009 begin
2010 h := High(gSteps);
2012 for a := 0 to h do
2013 if g_Collide(X, Y, Width, Height,
2014 gSteps[a].X, gSteps[a].Y,
2015 gSteps[a].Width, gSteps[a].Height) then
2016 begin
2017 Result := True;
2018 Exit;
2019 end;
2020 end;
2022 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
2023 if gLifts <> nil then
2024 begin
2025 h := High(gLifts);
2027 for a := 0 to h do
2028 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2029 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2030 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2031 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2032 g_Collide(X, Y, Width, Height,
2033 gLifts[a].X, gLifts[a].Y,
2034 gLifts[a].Width, gLifts[a].Height) then
2035 begin
2036 Result := True;
2037 Exit;
2038 end;
2039 end;
2041 if WordBool(PanelType and PANEL_BLOCKMON) then
2042 if gBlockMon <> nil then
2043 begin
2044 h := High(gBlockMon);
2046 for a := 0 to h do
2047 if ( (not b1x3) or
2048 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2049 g_Collide(X, Y, Width, Height,
2050 gBlockMon[a].X, gBlockMon[a].Y,
2051 gBlockMon[a].Width, gBlockMon[a].Height) then
2052 begin
2053 Result := True;
2054 Exit;
2055 end;
2056 end;
2057 end;
2058 *)
2060 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean;
2062 function checker (obj: TObject; tag: Integer): Boolean;
2063 var
2064 pan: TPanel;
2065 a: Integer;
2066 begin
2067 result := false; // don't stop, ever
2069 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2071 if obj = nil then
2072 begin
2073 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2074 end;
2075 if not (obj is TPanel) then
2076 begin
2077 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2078 exit;
2079 end;
2081 pan := (obj as TPanel);
2082 a := pan.ArrIdx;
2084 if WordBool(PanelType and PANEL_WALL) and (tag = GridTagWallDoor) then
2085 begin
2086 if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then
2087 begin
2088 result := true;
2089 exit;
2090 end;
2091 end;
2093 if WordBool(PanelType and PANEL_WATER) and (tag = GridTagWater) then
2094 begin
2095 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2096 begin
2097 result := True;
2098 exit;
2099 end;
2100 end;
2102 if WordBool(PanelType and PANEL_ACID1) and (tag = GridTagAcid1) then
2103 begin
2104 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2105 begin
2106 result := True;
2107 exit;
2108 end;
2109 end;
2111 if WordBool(PanelType and PANEL_ACID2) and (tag = GridTagAcid2) then
2112 begin
2113 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2114 begin
2115 result := True;
2116 exit;
2117 end;
2118 end;
2120 if WordBool(PanelType and PANEL_STEP) and (tag = GridTagStep) then
2121 begin
2122 if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then
2123 begin
2124 result := True;
2125 exit;
2126 end;
2127 end;
2129 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (tag = GridTagLift) then
2130 begin
2131 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2132 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2133 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2134 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2135 g_Collide(X, Y, Width, Height, gLifts[a].X, gLifts[a].Y, gLifts[a].Width, gLifts[a].Height) then
2136 begin
2137 result := true;
2138 exit;
2139 end;
2140 end;
2142 if WordBool(PanelType and PANEL_BLOCKMON)and (tag = GridTagBlockMon) then
2143 begin
2144 if ((not b1x3) or ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64)) and
2145 g_Collide(X, Y, Width, Height, gBlockMon[a].X, gBlockMon[a].Y, gBlockMon[a].Width, gBlockMon[a].Height) then
2146 begin
2147 result := True;
2148 exit;
2149 end;
2150 end;
2151 end;
2153 begin
2154 result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
2155 end;
2158 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
2159 var
2160 cctype: Integer = 3; // priority: 0: water, 1: acid1, 2: acid2; 3: others (nothing)
2161 texid: DWORD;
2163 // slightly different from the old code, but meh...
2164 function checker (obj: TObject; tag: Integer): Boolean;
2165 var
2166 pan: TPanel;
2167 a: Integer;
2168 begin
2169 result := false; // don't stop, ever
2170 pan := (obj as TPanel);
2171 a := pan.ArrIdx;
2172 // water
2173 if (tag = GridTagWater) then
2174 begin
2175 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2176 begin
2177 result := true; // water has highest priority, so stop right here
2178 texid := gWater[a].GetTextureID();
2179 exit;
2180 end;
2181 end;
2182 // acid1
2183 if (cctype > 1) and (tag = GridTagAcid1) then
2184 begin
2185 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2186 begin
2187 cctype := 1;
2188 texid := gAcid1[a].GetTextureID();
2189 exit;
2190 end;
2191 end;
2192 // acid2
2193 if (cctype > 2) and (tag = GridTagAcid2) then
2194 begin
2195 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2196 begin
2197 cctype := 2;
2198 texid := gAcid2[a].GetTextureID();
2199 exit;
2200 end;
2201 end;
2202 end;
2204 begin
2205 texid := TEXTURE_NONE;
2206 gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
2207 result := texid;
2208 end;
2210 procedure g_Map_EnableWall(ID: DWORD);
2211 begin
2212 with gWalls[ID] do
2213 begin
2214 Enabled := True;
2215 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
2217 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2218 end;
2219 end;
2221 procedure g_Map_DisableWall(ID: DWORD);
2222 begin
2223 with gWalls[ID] do
2224 begin
2225 Enabled := False;
2226 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
2228 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2229 end;
2230 end;
2232 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
2233 var
2234 tp: TPanel;
2235 begin
2236 case PanelType of
2237 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2238 tp := gWalls[ID];
2239 PANEL_FORE:
2240 tp := gRenderForegrounds[ID];
2241 PANEL_BACK:
2242 tp := gRenderBackgrounds[ID];
2243 PANEL_WATER:
2244 tp := gWater[ID];
2245 PANEL_ACID1:
2246 tp := gAcid1[ID];
2247 PANEL_ACID2:
2248 tp := gAcid2[ID];
2249 PANEL_STEP:
2250 tp := gSteps[ID];
2251 else
2252 Exit;
2253 end;
2255 tp.NextTexture(AnimLoop);
2256 if g_Game_IsServer and g_Game_IsNet then
2257 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
2258 end;
2260 procedure g_Map_SetLift(ID: DWORD; t: Integer);
2261 begin
2262 if gLifts[ID].LiftType = t then
2263 Exit;
2265 with gLifts[ID] do
2266 begin
2267 LiftType := t;
2269 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
2271 if LiftType = 0 then
2272 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
2273 else if LiftType = 1 then
2274 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
2275 else if LiftType = 2 then
2276 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
2277 else if LiftType = 3 then
2278 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
2280 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2281 end;
2282 end;
2284 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
2285 var
2286 a: Integer;
2287 PointsArray: Array of TRespawnPoint;
2288 begin
2289 Result := False;
2290 SetLength(PointsArray, 0);
2292 if RespawnPoints = nil then
2293 Exit;
2295 for a := 0 to High(RespawnPoints) do
2296 if RespawnPoints[a].PointType = PointType then
2297 begin
2298 SetLength(PointsArray, Length(PointsArray)+1);
2299 PointsArray[High(PointsArray)] := RespawnPoints[a];
2300 end;
2302 if PointsArray = nil then
2303 Exit;
2305 RespawnPoint := PointsArray[Random(Length(PointsArray))];
2306 Result := True;
2307 end;
2309 function g_Map_GetPointCount(PointType: Byte): Word;
2310 var
2311 a: Integer;
2312 begin
2313 Result := 0;
2315 if RespawnPoints = nil then
2316 Exit;
2318 for a := 0 to High(RespawnPoints) do
2319 if RespawnPoints[a].PointType = PointType then
2320 Result := Result + 1;
2321 end;
2323 function g_Map_HaveFlagPoints(): Boolean;
2324 begin
2325 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
2326 end;
2328 procedure g_Map_ResetFlag(Flag: Byte);
2329 begin
2330 with gFlags[Flag] do
2331 begin
2332 Obj.X := -1000;
2333 Obj.Y := -1000;
2334 Obj.Vel.X := 0;
2335 Obj.Vel.Y := 0;
2336 Direction := D_LEFT;
2337 State := FLAG_STATE_NONE;
2338 if FlagPoints[Flag] <> nil then
2339 begin
2340 Obj.X := FlagPoints[Flag]^.X;
2341 Obj.Y := FlagPoints[Flag]^.Y;
2342 Direction := FlagPoints[Flag]^.Direction;
2343 State := FLAG_STATE_NORMAL;
2344 end;
2345 Count := -1;
2346 end;
2347 end;
2349 procedure g_Map_DrawFlags();
2350 var
2351 i, dx: Integer;
2352 Mirror: TMirrorType;
2353 begin
2354 if gGameSettings.GameMode <> GM_CTF then
2355 Exit;
2357 for i := FLAG_RED to FLAG_BLUE do
2358 with gFlags[i] do
2359 if State <> FLAG_STATE_CAPTURED then
2360 begin
2361 if State = FLAG_STATE_NONE then
2362 continue;
2364 if Direction = D_LEFT then
2365 begin
2366 Mirror := M_HORIZONTAL;
2367 dx := -1;
2368 end
2369 else
2370 begin
2371 Mirror := M_NONE;
2372 dx := 1;
2373 end;
2375 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2377 if g_debug_Frames then
2378 begin
2379 e_DrawQuad(Obj.X+Obj.Rect.X,
2380 Obj.Y+Obj.Rect.Y,
2381 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2382 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2383 0, 255, 0);
2384 end;
2385 end;
2386 end;
2388 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2389 var
2390 dw: DWORD;
2391 b: Byte;
2392 str: String;
2393 boo: Boolean;
2395 procedure SavePanelArray(var panels: TPanelArray);
2396 var
2397 PAMem: TBinMemoryWriter;
2398 i: Integer;
2399 begin
2400 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2401 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2403 i := 0;
2404 while i < Length(panels) do
2405 begin
2406 if panels[i].SaveIt then
2407 begin
2408 // ID ïàíåëè:
2409 PAMem.WriteInt(i);
2410 // Ñîõðàíÿåì ïàíåëü:
2411 panels[i].SaveState(PAMem);
2412 end;
2413 Inc(i);
2414 end;
2416 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2417 PAMem.SaveToMemory(Mem);
2418 PAMem.Free();
2419 end;
2421 procedure SaveFlag(flag: PFlag);
2422 begin
2423 // Ñèãíàòóðà ôëàãà:
2424 dw := FLAG_SIGNATURE; // 'FLAG'
2425 Mem.WriteDWORD(dw);
2426 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2427 Mem.WriteByte(flag^.RespawnType);
2428 // Ñîñòîÿíèå ôëàãà:
2429 Mem.WriteByte(flag^.State);
2430 // Íàïðàâëåíèå ôëàãà:
2431 if flag^.Direction = D_LEFT then
2432 b := 1
2433 else // D_RIGHT
2434 b := 2;
2435 Mem.WriteByte(b);
2436 // Îáúåêò ôëàãà:
2437 Obj_SaveState(@flag^.Obj, Mem);
2438 end;
2440 begin
2441 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2443 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2444 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2445 SavePanelArray(gWalls);
2446 // Ñîõðàíÿåì ïàíåëè ôîíà:
2447 SavePanelArray(gRenderBackgrounds);
2448 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2449 SavePanelArray(gRenderForegrounds);
2450 // Ñîõðàíÿåì ïàíåëè âîäû:
2451 SavePanelArray(gWater);
2452 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2453 SavePanelArray(gAcid1);
2454 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2455 SavePanelArray(gAcid2);
2456 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2457 SavePanelArray(gSteps);
2458 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2459 SavePanelArray(gLifts);
2460 ///// /////
2462 ///// Ñîõðàíÿåì ìóçûêó: /////
2463 // Ñèãíàòóðà ìóçûêè:
2464 dw := MUSIC_SIGNATURE; // 'MUSI'
2465 Mem.WriteDWORD(dw);
2466 // Íàçâàíèå ìóçûêè:
2467 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2468 if gMusic.NoMusic then
2469 str := ''
2470 else
2471 str := gMusic.Name;
2472 Mem.WriteString(str, 64);
2473 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2474 dw := gMusic.GetPosition();
2475 Mem.WriteDWORD(dw);
2476 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2477 boo := gMusic.SpecPause;
2478 Mem.WriteBoolean(boo);
2479 ///// /////
2481 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2482 Mem.WriteInt(gTotalMonsters);
2483 ///// /////
2485 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2486 if gGameSettings.GameMode = GM_CTF then
2487 begin
2488 // Ôëàã Êðàñíîé êîìàíäû:
2489 SaveFlag(@gFlags[FLAG_RED]);
2490 // Ôëàã Ñèíåé êîìàíäû:
2491 SaveFlag(@gFlags[FLAG_BLUE]);
2492 end;
2493 ///// /////
2495 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2496 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2497 begin
2498 // Î÷êè Êðàñíîé êîìàíäû:
2499 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2500 // Î÷êè Ñèíåé êîìàíäû:
2501 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2502 end;
2503 ///// /////
2504 end;
2506 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2507 var
2508 dw: DWORD;
2509 b: Byte;
2510 str: String;
2511 boo: Boolean;
2513 procedure LoadPanelArray(var panels: TPanelArray);
2514 var
2515 PAMem: TBinMemoryReader;
2516 i, id: Integer;
2517 begin
2518 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2519 PAMem := TBinMemoryReader.Create();
2520 PAMem.LoadFromMemory(Mem);
2522 for i := 0 to Length(panels)-1 do
2523 if panels[i].SaveIt then
2524 begin
2525 // ID ïàíåëè:
2526 PAMem.ReadInt(id);
2527 if id <> i then
2528 begin
2529 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2530 end;
2531 // Çàãðóæàåì ïàíåëü:
2532 panels[i].LoadState(PAMem);
2533 end;
2535 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2536 PAMem.Free();
2537 end;
2539 procedure LoadFlag(flag: PFlag);
2540 begin
2541 // Ñèãíàòóðà ôëàãà:
2542 Mem.ReadDWORD(dw);
2543 if dw <> FLAG_SIGNATURE then // 'FLAG'
2544 begin
2545 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2546 end;
2547 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2548 Mem.ReadByte(flag^.RespawnType);
2549 // Ñîñòîÿíèå ôëàãà:
2550 Mem.ReadByte(flag^.State);
2551 // Íàïðàâëåíèå ôëàãà:
2552 Mem.ReadByte(b);
2553 if b = 1 then
2554 flag^.Direction := D_LEFT
2555 else // b = 2
2556 flag^.Direction := D_RIGHT;
2557 // Îáúåêò ôëàãà:
2558 Obj_LoadState(@flag^.Obj, Mem);
2559 end;
2561 begin
2562 if Mem = nil then
2563 Exit;
2565 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2566 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2567 LoadPanelArray(gWalls);
2568 // Çàãðóæàåì ïàíåëè ôîíà:
2569 LoadPanelArray(gRenderBackgrounds);
2570 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2571 LoadPanelArray(gRenderForegrounds);
2572 // Çàãðóæàåì ïàíåëè âîäû:
2573 LoadPanelArray(gWater);
2574 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2575 LoadPanelArray(gAcid1);
2576 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2577 LoadPanelArray(gAcid2);
2578 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2579 LoadPanelArray(gSteps);
2580 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2581 LoadPanelArray(gLifts);
2582 ///// /////
2584 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé è ñåòêó:
2585 g_GFX_Init();
2586 mapCreateGrid();
2588 ///// Çàãðóæàåì ìóçûêó: /////
2589 // Ñèãíàòóðà ìóçûêè:
2590 Mem.ReadDWORD(dw);
2591 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2592 begin
2593 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2594 end;
2595 // Íàçâàíèå ìóçûêè:
2596 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2597 Mem.ReadString(str);
2598 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2599 Mem.ReadDWORD(dw);
2600 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2601 Mem.ReadBoolean(boo);
2602 // Çàïóñêàåì ýòó ìóçûêó:
2603 gMusic.SetByName(str);
2604 gMusic.SpecPause := boo;
2605 gMusic.Play();
2606 gMusic.Pause(True);
2607 gMusic.SetPosition(dw);
2608 ///// /////
2610 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2611 Mem.ReadInt(gTotalMonsters);
2612 ///// /////
2614 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2615 if gGameSettings.GameMode = GM_CTF then
2616 begin
2617 // Ôëàã Êðàñíîé êîìàíäû:
2618 LoadFlag(@gFlags[FLAG_RED]);
2619 // Ôëàã Ñèíåé êîìàíäû:
2620 LoadFlag(@gFlags[FLAG_BLUE]);
2621 end;
2622 ///// /////
2624 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2625 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2626 begin
2627 // Î÷êè Êðàñíîé êîìàíäû:
2628 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2629 // Î÷êè Ñèíåé êîìàíäû:
2630 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2631 end;
2632 ///// /////
2633 end;
2635 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
2636 var
2637 Arr: TPanelArray;
2638 begin
2639 Result := nil;
2640 if (PanelID < 0) or (PanelID > High(PanelByID)) then Exit;
2641 Arr := PanelByID[PanelID].PWhere^;
2642 PanelArrayID := PanelByID[PanelID].PArrID;
2643 Result := Addr(Arr[PanelByID[PanelID].PArrID]);
2644 end;
2646 end.