DEADSOFTWARE

53b4ae2d40986595ee8f6d9e8a6e221c3f3fa8bc
[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 {$modeswitch nestedprocvars}
18 unit g_map;
20 interface
22 uses
23 e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
24 g_phys, wadreader, BinEditor, g_panel, g_grid, md5;
26 type
27 TMapInfo = record
28 Map: String;
29 Name: String;
30 Description: String;
31 Author: String;
32 MusicName: String;
33 SkyName: String;
34 Height: Word;
35 Width: Word;
36 end;
38 PRespawnPoint = ^TRespawnPoint;
39 TRespawnPoint = record
40 X, Y: Integer;
41 Direction: TDirection;
42 PointType: Byte;
43 end;
45 PFlagPoint = ^TFlagPoint;
46 TFlagPoint = TRespawnPoint;
48 PFlag = ^TFlag;
49 TFlag = record
50 Obj: TObj;
51 RespawnType: Byte;
52 State: Byte;
53 Count: Integer;
54 CaptureTime: LongWord;
55 Animation: TAnimation;
56 Direction: TDirection;
57 end;
59 function g_Map_Load(Res: String): Boolean;
60 function g_Map_GetMapInfo(Res: String): TMapInfo;
61 function g_Map_GetMapsList(WADName: String): SArray;
62 function g_Map_Exist(Res: String): Boolean;
63 procedure g_Map_Free();
64 procedure g_Map_Update();
66 // build "potentially visible panels" set, so we can avoid looping over all level panels again and again
67 procedure g_Map_BuildPVP (minx, miny, maxx, maxy: Integer);
68 procedure g_Map_ResetPVP ();
69 // do not call this without calling `g_Map_BuildPVP()` or `g_Map_ResetPVP()` first!
70 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
72 procedure g_Map_DrawBack(dx, dy: Integer);
73 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
74 PanelType: Word; b1x3: Boolean): Boolean;
75 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
76 procedure g_Map_EnableWall(ID: DWORD);
77 procedure g_Map_DisableWall(ID: DWORD);
78 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
79 procedure g_Map_SetLift(ID: DWORD; t: Integer);
80 procedure g_Map_ReAdd_DieTriggers();
81 function g_Map_IsSpecialTexture(Texture: String): Boolean;
83 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
84 function g_Map_GetPointCount(PointType: Byte): Word;
86 function g_Map_HaveFlagPoints(): Boolean;
88 procedure g_Map_ResetFlag(Flag: Byte);
89 procedure g_Map_DrawFlags();
91 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
93 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
94 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
96 // build "possibly lit panels" index, so we can avoid looping over all level panels again and again
97 function g_Map_BuildPLP (ltminx, ltminy, ltmaxx, ltmaxy: Integer): Boolean; // returns `false` if no patels lit
98 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
100 const
101 RESPAWNPOINT_PLAYER1 = 1;
102 RESPAWNPOINT_PLAYER2 = 2;
103 RESPAWNPOINT_DM = 3;
104 RESPAWNPOINT_RED = 4;
105 RESPAWNPOINT_BLUE = 5;
107 FLAG_NONE = 0;
108 FLAG_RED = 1;
109 FLAG_BLUE = 2;
110 FLAG_DOM = 3;
112 FLAG_STATE_NONE = 0;
113 FLAG_STATE_NORMAL = 1;
114 FLAG_STATE_DROPPED = 2;
115 FLAG_STATE_CAPTURED = 3;
116 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
117 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
119 FLAG_TIME = 720; // 20 seconds
121 SKY_STRETCH: Single = 1.5;
123 var
124 gWalls: TPanelArray;
125 gRenderBackgrounds: TPanelArray;
126 gRenderForegrounds: TPanelArray;
127 gWater, gAcid1, gAcid2: TPanelArray;
128 gSteps: TPanelArray;
129 gLifts: TPanelArray;
130 gBlockMon: TPanelArray;
131 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
132 //gDOMFlags: array of TFlag;
133 gMapInfo: TMapInfo;
134 gBackSize: TPoint;
135 gDoorMap: array of array of DWORD;
136 gLiftMap: array of array of DWORD;
137 gWADHash: TMD5Digest;
138 BackID: DWORD = DWORD(-1);
139 gExternalResources: TStringList;
140 gMapGrid: TBodyGrid = nil;
142 implementation
144 uses
145 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
146 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
147 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
148 Math, g_monsters, g_saveload, g_language, g_netmsg,
149 utils, sfs,
150 ImagingTypes, Imaging, ImagingUtility,
151 ImagingGif, ImagingNetworkGraphics;
153 const
154 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
155 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
156 FLAG_SIGNATURE = $47414C46; // 'FLAG'
158 type
159 TPanelID = record
160 PWhere: ^TPanelArray;
161 PArrID: Integer;
162 end;
164 var
165 PanelById: array of TPanelID;
166 Textures: TLevelTextureArray;
167 RespawnPoints: Array of TRespawnPoint;
168 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
169 //DOMFlagPoints: Array of TFlagPoint;
172 function g_Map_IsSpecialTexture(Texture: String): Boolean;
173 begin
174 Result := (Texture = TEXTURE_NAME_WATER) or
175 (Texture = TEXTURE_NAME_ACID1) or
176 (Texture = TEXTURE_NAME_ACID2);
177 end;
179 procedure CreateDoorMap();
180 var
181 PanelArray: Array of record
182 X, Y: Integer;
183 Width, Height: Word;
184 Active: Boolean;
185 PanelID: DWORD;
186 end;
187 a, b, c, m, i, len: Integer;
188 ok: Boolean;
189 begin
190 if gWalls = nil then
191 Exit;
193 i := 0;
194 len := 128;
195 SetLength(PanelArray, len);
197 for a := 0 to High(gWalls) do
198 if gWalls[a].Door then
199 begin
200 PanelArray[i].X := gWalls[a].X;
201 PanelArray[i].Y := gWalls[a].Y;
202 PanelArray[i].Width := gWalls[a].Width;
203 PanelArray[i].Height := gWalls[a].Height;
204 PanelArray[i].Active := True;
205 PanelArray[i].PanelID := a;
207 i := i + 1;
208 if i = len then
209 begin
210 len := len + 128;
211 SetLength(PanelArray, len);
212 end;
213 end;
215 // Íåò äâåðåé:
216 if i = 0 then
217 begin
218 PanelArray := nil;
219 Exit;
220 end;
222 SetLength(gDoorMap, 0);
224 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
226 for a := 0 to i-1 do
227 if PanelArray[a].Active then
228 begin
229 PanelArray[a].Active := False;
230 m := Length(gDoorMap);
231 SetLength(gDoorMap, m+1);
232 SetLength(gDoorMap[m], 1);
233 gDoorMap[m, 0] := PanelArray[a].PanelID;
234 ok := True;
236 while ok do
237 begin
238 ok := False;
240 for b := 0 to i-1 do
241 if PanelArray[b].Active then
242 for c := 0 to High(gDoorMap[m]) do
243 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
244 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
245 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
246 PanelArray[b].Width, PanelArray[b].Height,
247 gWalls[gDoorMap[m, c]].X,
248 gWalls[gDoorMap[m, c]].Y,
249 gWalls[gDoorMap[m, c]].Width,
250 gWalls[gDoorMap[m, c]].Height) then
251 begin
252 PanelArray[b].Active := False;
253 SetLength(gDoorMap[m],
254 Length(gDoorMap[m])+1);
255 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
256 ok := True;
257 Break;
258 end;
259 end;
261 g_Game_StepLoading();
262 end;
264 PanelArray := nil;
265 end;
267 procedure CreateLiftMap();
268 var
269 PanelArray: Array of record
270 X, Y: Integer;
271 Width, Height: Word;
272 Active: Boolean;
273 end;
274 a, b, c, len, i, j: Integer;
275 ok: Boolean;
276 begin
277 if gLifts = nil then
278 Exit;
280 len := Length(gLifts);
281 SetLength(PanelArray, len);
283 for a := 0 to len-1 do
284 begin
285 PanelArray[a].X := gLifts[a].X;
286 PanelArray[a].Y := gLifts[a].Y;
287 PanelArray[a].Width := gLifts[a].Width;
288 PanelArray[a].Height := gLifts[a].Height;
289 PanelArray[a].Active := True;
290 end;
292 SetLength(gLiftMap, len);
293 i := 0;
295 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
297 for a := 0 to len-1 do
298 if PanelArray[a].Active then
299 begin
300 PanelArray[a].Active := False;
301 SetLength(gLiftMap[i], 32);
302 j := 0;
303 gLiftMap[i, j] := a;
304 ok := True;
306 while ok do
307 begin
308 ok := False;
309 for b := 0 to len-1 do
310 if PanelArray[b].Active then
311 for c := 0 to j do
312 if g_CollideAround(PanelArray[b].X,
313 PanelArray[b].Y,
314 PanelArray[b].Width,
315 PanelArray[b].Height,
316 PanelArray[gLiftMap[i, c]].X,
317 PanelArray[gLiftMap[i, c]].Y,
318 PanelArray[gLiftMap[i, c]].Width,
319 PanelArray[gLiftMap[i, c]].Height) then
320 begin
321 PanelArray[b].Active := False;
322 j := j+1;
323 if j > High(gLiftMap[i]) then
324 SetLength(gLiftMap[i],
325 Length(gLiftMap[i])+32);
327 gLiftMap[i, j] := b;
328 ok := True;
330 Break;
331 end;
332 end;
334 SetLength(gLiftMap[i], j+1);
335 i := i+1;
337 g_Game_StepLoading();
338 end;
340 SetLength(gLiftMap, i);
342 PanelArray := nil;
343 end;
345 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
346 CurTex: Integer; sav: Boolean): Integer;
347 var
348 len: Integer;
349 panels: ^TPanelArray;
350 begin
351 Result := -1;
353 case PanelRec.PanelType of
354 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
355 panels := @gWalls;
356 PANEL_BACK:
357 panels := @gRenderBackgrounds;
358 PANEL_FORE:
359 panels := @gRenderForegrounds;
360 PANEL_WATER:
361 panels := @gWater;
362 PANEL_ACID1:
363 panels := @gAcid1;
364 PANEL_ACID2:
365 panels := @gAcid2;
366 PANEL_STEP:
367 panels := @gSteps;
368 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
369 panels := @gLifts;
370 PANEL_BLOCKMON:
371 panels := @gBlockMon;
372 else
373 Exit;
374 end;
376 len := Length(panels^);
377 SetLength(panels^, len + 1);
379 panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures);
380 panels^[len].ArrIdx := len;
381 if sav then
382 panels^[len].SaveIt := True;
384 Result := len;
386 len := Length(PanelByID);
387 SetLength(PanelByID, len + 1);
388 PanelByID[len].PWhere := panels;
389 PanelByID[len].PArrID := Result;
390 end;
392 function CreateNullTexture(RecName: String): Integer;
393 begin
394 SetLength(Textures, Length(Textures)+1);
395 result := High(Textures);
397 with Textures[High(Textures)] do
398 begin
399 TextureName := RecName;
400 Width := 1;
401 Height := 1;
402 Anim := False;
403 TextureID := TEXTURE_NONE;
404 end;
405 end;
407 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
408 var
409 WAD: TWADFile;
410 TextureData: Pointer;
411 WADName, txname: String;
412 a, ResLength: Integer;
413 begin
414 Result := -1;
416 if Textures <> nil then
417 for a := 0 to High(Textures) do
418 if Textures[a].TextureName = RecName then
419 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
420 Result := a;
421 Exit;
422 end;
424 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
425 if (RecName = TEXTURE_NAME_WATER) or
426 (RecName = TEXTURE_NAME_ACID1) or
427 (RecName = TEXTURE_NAME_ACID2) then
428 begin
429 SetLength(Textures, Length(Textures)+1);
431 with Textures[High(Textures)] do
432 begin
433 TextureName := RecName;
435 if TextureName = TEXTURE_NAME_WATER then
436 TextureID := TEXTURE_SPECIAL_WATER
437 else
438 if TextureName = TEXTURE_NAME_ACID1 then
439 TextureID := TEXTURE_SPECIAL_ACID1
440 else
441 if TextureName = TEXTURE_NAME_ACID2 then
442 TextureID := TEXTURE_SPECIAL_ACID2;
444 Anim := False;
445 end;
447 result := High(Textures);
448 Exit;
449 end;
451 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
452 WADName := g_ExtractWadName(RecName);
454 WAD := TWADFile.Create();
456 if WADName <> '' then
457 WADName := GameDir+'/wads/'+WADName
458 else
459 WADName := Map;
461 WAD.ReadFile(WADName);
463 txname := RecName;
465 if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
466 begin
467 FreeMem(TextureData);
468 RecName := 'COMMON\ALIEN';
469 end;
472 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
473 begin
474 SetLength(Textures, Length(Textures)+1);
475 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
476 Exit;
477 e_GetTextureSize(Textures[High(Textures)].TextureID,
478 @Textures[High(Textures)].Width,
479 @Textures[High(Textures)].Height);
480 FreeMem(TextureData);
481 Textures[High(Textures)].TextureName := {RecName}txname;
482 Textures[High(Textures)].Anim := False;
484 result := High(Textures);
485 end
486 else // Íåò òàêîãî ðåóñðñà â WAD'å
487 begin
488 //e_WriteLog(Format('SHIT! Error loading texture %s : %s : %s', [RecName, txname, g_ExtractFilePathName(RecName)]), MSG_WARNING);
489 if log then
490 begin
491 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
492 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
493 end;
494 end;
496 WAD.Free();
497 end;
499 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
500 var
501 WAD: TWADFile;
502 TextureWAD: PChar = nil;
503 TextData: Pointer = nil;
504 TextureData: Pointer = nil;
505 cfg: TConfig = nil;
506 WADName: String;
507 ResLength: Integer;
508 TextureResource: String;
509 _width, _height, _framecount, _speed: Integer;
510 _backanimation: Boolean;
511 //imgfmt: string;
512 ia: TDynImageDataArray = nil;
513 f, c, frdelay, frloop: Integer;
514 begin
515 result := -1;
517 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
519 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
520 WADName := g_ExtractWadName(RecName);
522 WAD := TWADFile.Create();
523 try
524 if WADName <> '' then
525 WADName := GameDir+'/wads/'+WADName
526 else
527 WADName := Map;
529 WAD.ReadFile(WADName);
531 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
532 begin
533 if log then
534 begin
535 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
536 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
537 end;
538 exit;
539 end;
541 {TEST
542 if WADName = Map then
543 begin
544 //FreeMem(TextureWAD);
545 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
546 end;
549 WAD.FreeWAD();
551 if ResLength < 6 then
552 begin
553 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
554 exit;
555 end;
557 // ýòî ïòèöà? ýòî ñàìîë¸ò?
558 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
559 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
560 begin
561 // íåò, ýòî ñóïåðìåí!
562 if not WAD.ReadMemory(TextureWAD, ResLength) then
563 begin
564 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
565 exit;
566 end;
568 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
569 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
570 begin
571 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
572 exit;
573 end;
575 cfg := TConfig.CreateMem(TextData, ResLength);
577 TextureResource := cfg.ReadStr('', 'resource', '');
578 if TextureResource = '' then
579 begin
580 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
581 exit;
582 end;
584 _width := cfg.ReadInt('', 'framewidth', 0);
585 _height := cfg.ReadInt('', 'frameheight', 0);
586 _framecount := cfg.ReadInt('', 'framecount', 0);
587 _speed := cfg.ReadInt('', 'waitcount', 0);
588 _backanimation := cfg.ReadBool('', 'backanimation', False);
590 cfg.Free();
591 cfg := nil;
593 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
594 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
595 begin
596 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
597 exit;
598 end;
600 WAD.Free();
601 WAD := nil;
603 SetLength(Textures, Length(Textures)+1);
604 with Textures[High(Textures)] do
605 begin
606 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
607 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
608 begin
609 TextureName := RecName;
610 Width := _width;
611 Height := _height;
612 Anim := True;
613 FramesCount := _framecount;
614 Speed := _speed;
615 result := High(Textures);
616 end
617 else
618 begin
619 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
620 end;
621 end;
622 end
623 else
624 begin
625 // try animated image
627 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
628 if length(imgfmt) = 0 then
629 begin
630 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
631 exit;
632 end;
634 GlobalMetadata.ClearMetaItems();
635 GlobalMetadata.ClearMetaItemsForSaving();
636 if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
637 begin
638 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
639 exit;
640 end;
641 if length(ia) = 0 then
642 begin
643 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
644 exit;
645 end;
647 WAD.Free();
648 WAD := nil;
650 _width := ia[0].width;
651 _height := ia[0].height;
652 _framecount := length(ia);
653 _speed := 1;
654 _backanimation := false;
655 frdelay := -1;
656 frloop := -666;
657 if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then
658 begin
659 //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]);
660 try
661 f := GlobalMetadata.MetaItems[SMetaFrameDelay];
662 frdelay := f;
663 if f < 0 then f := 0;
664 // rounding ;-)
665 c := f mod 28;
666 if c < 13 then c := 0 else c := 1;
667 f := (f div 28)+c;
668 if f < 1 then f := 1 else if f > 255 then f := 255;
669 _speed := f;
670 except
671 end;
672 end;
673 if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then
674 begin
675 //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]);
676 try
677 f := GlobalMetadata.MetaItems[SMetaAnimationLoops];
678 frloop := f;
679 if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back
680 except
681 end;
682 end;
683 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
684 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
685 f := ord(_backanimation);
686 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);
688 SetLength(Textures, Length(Textures)+1);
689 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
690 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
691 begin
692 Textures[High(Textures)].TextureName := RecName;
693 Textures[High(Textures)].Width := _width;
694 Textures[High(Textures)].Height := _height;
695 Textures[High(Textures)].Anim := True;
696 Textures[High(Textures)].FramesCount := length(ia);
697 Textures[High(Textures)].Speed := _speed;
698 result := High(Textures);
699 //writeln(' CREATED!');
700 end
701 else
702 begin
703 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
704 end;
705 end;
706 finally
707 for f := 0 to High(ia) do FreeImage(ia[f]);
708 WAD.Free();
709 cfg.Free();
710 if TextureWAD <> nil then FreeMem(TextureWAD);
711 if TextData <> nil then FreeMem(TextData);
712 if TextureData <> nil then FreeMem(TextureData);
713 end;
714 end;
716 procedure CreateItem(Item: TItemRec_1);
717 begin
718 if g_Game_IsClient then Exit;
720 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
721 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
722 Exit;
724 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
725 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
726 end;
728 procedure CreateArea(Area: TAreaRec_1);
729 var
730 a: Integer;
731 id: DWORD;
732 begin
733 case Area.AreaType of
734 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
735 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
736 begin
737 SetLength(RespawnPoints, Length(RespawnPoints)+1);
738 with RespawnPoints[High(RespawnPoints)] do
739 begin
740 X := Area.X;
741 Y := Area.Y;
742 Direction := TDirection(Area.Direction);
744 case Area.AreaType of
745 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
746 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
747 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
748 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
749 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
750 end;
751 end;
752 end;
754 AREA_REDFLAG, AREA_BLUEFLAG:
755 begin
756 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
758 if FlagPoints[a] <> nil then Exit;
760 New(FlagPoints[a]);
762 with FlagPoints[a]^ do
763 begin
764 X := Area.X-FLAGRECT.X;
765 Y := Area.Y-FLAGRECT.Y;
766 Direction := TDirection(Area.Direction);
767 end;
769 with gFlags[a] do
770 begin
771 case a of
772 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
773 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
774 end;
776 Animation := TAnimation.Create(id, True, 8);
777 Obj.Rect := FLAGRECT;
779 g_Map_ResetFlag(a);
780 end;
781 end;
783 AREA_DOMFLAG:
784 begin
785 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
786 with DOMFlagPoints[High(DOMFlagPoints)] do
787 begin
788 X := Area.X;
789 Y := Area.Y;
790 Direction := TDirection(Area.Direction);
791 end;
793 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
794 end;
795 end;
796 end;
798 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
799 var
800 _trigger: TTrigger;
801 begin
802 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
804 with _trigger do
805 begin
806 X := Trigger.X;
807 Y := Trigger.Y;
808 Width := Trigger.Width;
809 Height := Trigger.Height;
810 Enabled := ByteBool(Trigger.Enabled);
811 TexturePanel := Trigger.TexturePanel;
812 TexturePanelType := fTexturePanel1Type;
813 ShotPanelType := fTexturePanel2Type;
814 TriggerType := Trigger.TriggerType;
815 ActivateType := Trigger.ActivateType;
816 Keys := Trigger.Keys;
817 Data.Default := Trigger.DATA;
818 end;
820 g_Triggers_Create(_trigger);
821 end;
823 procedure CreateMonster(monster: TMonsterRec_1);
824 var
825 a, i: Integer;
826 begin
827 if g_Game_IsClient then Exit;
829 if (gGameSettings.GameType = GT_SINGLE)
830 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
831 begin
832 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
833 TDirection(monster.Direction));
835 if gTriggers <> nil then
836 for a := 0 to High(gTriggers) do
837 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
838 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
839 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
840 gMonsters[i].AddTrigger(a);
842 if monster.MonsterType <> MONSTER_BARREL then
843 Inc(gTotalMonsters);
844 end;
845 end;
847 procedure g_Map_ReAdd_DieTriggers();
848 var
849 i, a: Integer;
850 begin
851 if g_Game_IsClient then Exit;
853 for i := 0 to High(gMonsters) do
854 if gMonsters[i] <> nil then
855 begin
856 gMonsters[i].ClearTriggers();
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);
863 end;
864 end;
866 function extractWadName(resourceName: string): string;
867 var
868 posN: Integer;
869 begin
870 posN := Pos(':', resourceName);
871 if posN > 0 then
872 Result:= Copy(resourceName, 0, posN-1)
873 else
874 Result := '';
875 end;
877 procedure addResToExternalResList(res: string);
878 begin
879 res := extractWadName(res);
880 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
881 gExternalResources.Add(res);
882 end;
884 procedure generateExternalResourcesList(mapReader: TMapReader_1);
885 var
886 textures: TTexturesRec1Array;
887 mapHeader: TMapHeaderRec_1;
888 i: integer;
889 resFile: String = '';
890 begin
891 if gExternalResources = nil then
892 gExternalResources := TStringList.Create;
894 gExternalResources.Clear;
895 textures := mapReader.GetTextures();
896 for i := 0 to High(textures) do
897 begin
898 addResToExternalResList(resFile);
899 end;
901 textures := nil;
903 mapHeader := mapReader.GetMapHeader;
905 addResToExternalResList(mapHeader.MusicName);
906 addResToExternalResList(mapHeader.SkyName);
907 end;
909 function g_Map_Load(Res: String): Boolean;
910 const
911 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
912 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
913 var
914 WAD: TWADFile;
915 MapReader: TMapReader_1;
916 Header: TMapHeaderRec_1;
917 _textures: TTexturesRec1Array;
918 _texnummap: array of Integer; // `_textures` -> `Textures`
919 panels: TPanelsRec1Array;
920 items: TItemsRec1Array;
921 monsters: TMonsterRec1Array;
922 areas: TAreasRec1Array;
923 triggers: TTriggersRec1Array;
924 a, b, c, k: Integer;
925 PanelID: DWORD;
926 AddTextures: TAddTextureArray;
927 texture: TTextureRec_1;
928 TriggersTable: Array of record
929 TexturePanel: Integer;
930 LiftPanel: Integer;
931 DoorPanel: Integer;
932 ShotPanel: Integer;
933 end;
934 FileName, mapResName, s, TexName: String;
935 Data: Pointer;
936 Len: Integer;
937 ok, isAnim, trigRef: Boolean;
938 CurTex, ntn: Integer;
940 mapX0: Integer = $3fffffff;
941 mapY0: Integer = $3fffffff;
942 mapX1: Integer = -$3fffffff;
943 mapY1: Integer = -$3fffffff;
945 procedure fixMinMax (var panels: TPanelArray);
946 var
947 idx: Integer;
948 begin
949 for idx := 0 to High(panels) do
950 begin
951 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
952 if mapX0 > panels[idx].X then mapX0 := panels[idx].X;
953 if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y;
954 if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1;
955 if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1;
956 end;
957 end;
959 procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer);
960 var
961 idx: Integer;
962 begin
963 for idx := High(panels) downto 0 do
964 begin
965 gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
966 end;
967 end;
969 begin
970 gMapGrid.Free();
971 gMapGrid := nil;
973 Result := False;
974 gMapInfo.Map := Res;
975 TriggersTable := nil;
976 FillChar(texture, SizeOf(texture), 0);
978 sfsGCDisable(); // temporary disable removing of temporary volumes
979 try
980 // Çàãðóçêà WAD:
981 FileName := g_ExtractWadName(Res);
982 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
983 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
985 WAD := TWADFile.Create();
986 if not WAD.ReadFile(FileName) then
987 begin
988 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
989 WAD.Free();
990 Exit;
991 end;
992 //k8: why loader ignores path here?
993 mapResName := g_ExtractFileName(Res);
994 if not WAD.GetMapResource(mapResName, Data, Len) then
995 begin
996 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
997 WAD.Free();
998 Exit;
999 end;
1001 WAD.Free();
1003 // Çàãðóçêà êàðòû:
1004 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
1005 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
1006 MapReader := TMapReader_1.Create();
1008 if not MapReader.LoadMap(Data) then
1009 begin
1010 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
1011 FreeMem(Data);
1012 MapReader.Free();
1013 Exit;
1014 end;
1016 FreeMem(Data);
1017 generateExternalResourcesList(MapReader);
1018 // Çàãðóçêà òåêñòóð:
1019 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
1020 _textures := MapReader.GetTextures();
1021 _texnummap := nil;
1023 // Äîáàâëåíèå òåêñòóð â Textures[]:
1024 if _textures <> nil then
1025 begin
1026 e_WriteLog(' Loading textures:', MSG_NOTIFY);
1027 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
1028 SetLength(_texnummap, length(_textures));
1030 for a := 0 to High(_textures) do
1031 begin
1032 SetLength(s, 64);
1033 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
1034 for b := 1 to Length(s) do
1035 if s[b] = #0 then
1036 begin
1037 SetLength(s, b-1);
1038 Break;
1039 end;
1040 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
1041 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
1042 // Àíèìèðîâàííàÿ òåêñòóðà:
1043 if ByteBool(_textures[a].Anim) then
1044 begin
1045 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1046 if ntn < 0 then
1047 begin
1048 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1049 ntn := CreateNullTexture(_textures[a].Resource);
1050 end;
1051 end
1052 else // Îáû÷íàÿ òåêñòóðà:
1053 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1054 if ntn < 0 then
1055 begin
1056 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1057 ntn := CreateNullTexture(_textures[a].Resource);
1058 end;
1060 _texnummap[a] := ntn; // fix texture number
1061 g_Game_StepLoading();
1062 end;
1063 end;
1065 // Çàãðóçêà òðèããåðîâ:
1066 gTriggerClientID := 0;
1067 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1068 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1069 triggers := MapReader.GetTriggers();
1071 // Çàãðóçêà ïàíåëåé:
1072 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1073 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1074 panels := MapReader.GetPanels();
1076 // check texture numbers for panels
1077 for a := 0 to High(panels) do
1078 begin
1079 if panels[a].TextureNum > High(_textures) then
1080 begin
1081 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1082 result := false;
1083 exit;
1084 end;
1085 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1086 end;
1088 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1089 if triggers <> nil then
1090 begin
1091 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1092 SetLength(TriggersTable, Length(triggers));
1093 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1095 for a := 0 to High(TriggersTable) do
1096 begin
1097 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1098 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1099 // Ëèôòû:
1100 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1101 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1102 else
1103 TriggersTable[a].LiftPanel := -1;
1104 // Äâåðè:
1105 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1106 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1107 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1108 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1109 else
1110 TriggersTable[a].DoorPanel := -1;
1111 // Òóðåëü:
1112 if triggers[a].TriggerType = TRIGGER_SHOT then
1113 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1114 else
1115 TriggersTable[a].ShotPanel := -1;
1117 g_Game_StepLoading();
1118 end;
1119 end;
1121 // Ñîçäàåì ïàíåëè:
1122 if panels <> nil then
1123 begin
1124 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1125 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1127 for a := 0 to High(panels) do
1128 begin
1129 SetLength(AddTextures, 0);
1130 trigRef := False;
1131 CurTex := -1;
1132 if _textures <> nil then
1133 begin
1134 texture := _textures[panels[a].TextureNum];
1135 ok := True;
1136 end
1137 else
1138 ok := False;
1140 if ok then
1141 begin
1142 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1143 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1144 ok := False;
1145 if (TriggersTable <> nil) and (_textures <> nil) then
1146 for b := 0 to High(TriggersTable) do
1147 if (TriggersTable[b].TexturePanel = a)
1148 or (TriggersTable[b].ShotPanel = a) then
1149 begin
1150 trigRef := True;
1151 ok := True;
1152 Break;
1153 end;
1154 end;
1156 if ok then
1157 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1158 SetLength(s, 64);
1159 CopyMemory(@s[1], @texture.Resource[0], 64);
1160 // Èçìåðÿåì äëèíó:
1161 Len := Length(s);
1162 for c := Len downto 1 do
1163 if s[c] <> #0 then
1164 begin
1165 Len := c;
1166 Break;
1167 end;
1168 SetLength(s, Len);
1170 // Ñïåö-òåêñòóðû çàïðåùåíû:
1171 if g_Map_IsSpecialTexture(s) then
1172 ok := False
1173 else
1174 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1175 ok := g_Texture_NumNameFindStart(s);
1177 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1178 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1179 if ok then
1180 begin
1181 k := NNF_NAME_BEFORE;
1182 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1183 while ok or (k = NNF_NAME_BEFORE) or
1184 (k = NNF_NAME_EQUALS) do
1185 begin
1186 k := g_Texture_NumNameFindNext(TexName);
1188 if (k = NNF_NAME_BEFORE) or
1189 (k = NNF_NAME_AFTER) then
1190 begin
1191 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1192 if ByteBool(texture.Anim) then
1193 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1194 isAnim := True;
1195 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1196 if not ok then
1197 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1198 isAnim := False;
1199 ok := CreateTexture(TexName, FileName, False) >= 0;
1200 end;
1201 end
1202 else
1203 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1204 isAnim := False;
1205 ok := CreateTexture(TexName, FileName, False) >= 0;
1206 if not ok then
1207 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1208 isAnim := True;
1209 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1210 end;
1211 end;
1213 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1214 if ok then
1215 begin
1216 for c := 0 to High(Textures) do
1217 if Textures[c].TextureName = TexName then
1218 begin
1219 SetLength(AddTextures, Length(AddTextures)+1);
1220 AddTextures[High(AddTextures)].Texture := c;
1221 AddTextures[High(AddTextures)].Anim := isAnim;
1222 Break;
1223 end;
1224 end;
1225 end
1226 else
1227 if k = NNF_NAME_EQUALS then
1228 begin
1229 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1230 SetLength(AddTextures, Length(AddTextures)+1);
1231 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1232 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1233 CurTex := High(AddTextures);
1234 ok := True;
1235 end
1236 else // NNF_NO_NAME
1237 ok := False;
1238 end; // while ok...
1240 ok := True;
1241 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1242 end; // if ok - ññûëàþòñÿ òðèããåðû
1244 if not ok then
1245 begin
1246 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1247 SetLength(AddTextures, 1);
1248 AddTextures[0].Texture := panels[a].TextureNum;
1249 AddTextures[0].Anim := ByteBool(texture.Anim);
1250 CurTex := 0;
1251 end;
1253 //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);
1255 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1256 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1258 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1259 if TriggersTable <> nil then
1260 for b := 0 to High(TriggersTable) do
1261 begin
1262 // Òðèããåð äâåðè/ëèôòà:
1263 if (TriggersTable[b].LiftPanel = a) or
1264 (TriggersTable[b].DoorPanel = a) then
1265 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1266 // Òðèããåð ñìåíû òåêñòóðû:
1267 if TriggersTable[b].TexturePanel = a then
1268 triggers[b].TexturePanel := PanelID;
1269 // Òðèããåð "Òóðåëü":
1270 if TriggersTable[b].ShotPanel = a then
1271 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1272 end;
1274 g_Game_StepLoading();
1275 end;
1276 end;
1278 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1279 if (triggers <> nil) and not gLoadGameMode then
1280 begin
1281 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1282 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1283 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1284 for a := 0 to High(triggers) do
1285 begin
1286 if triggers[a].TexturePanel <> -1 then
1287 b := panels[TriggersTable[a].TexturePanel].PanelType
1288 else
1289 b := 0;
1290 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1291 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1292 c := panels[TriggersTable[a].ShotPanel].PanelType
1293 else
1294 c := 0;
1295 CreateTrigger(triggers[a], b, c);
1296 end;
1297 end;
1299 // Çàãðóçêà ïðåäìåòîâ:
1300 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1301 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1302 items := MapReader.GetItems();
1304 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1305 if (items <> nil) and not gLoadGameMode then
1306 begin
1307 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1308 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1309 for a := 0 to High(items) do
1310 CreateItem(Items[a]);
1311 end;
1313 // Çàãðóçêà îáëàñòåé:
1314 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1315 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1316 areas := MapReader.GetAreas();
1318 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1319 if areas <> nil then
1320 begin
1321 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1322 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1323 for a := 0 to High(areas) do
1324 CreateArea(areas[a]);
1325 end;
1327 // Çàãðóçêà ìîíñòðîâ:
1328 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1329 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1330 monsters := MapReader.GetMonsters();
1332 gTotalMonsters := 0;
1334 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1335 if (monsters <> nil) and not gLoadGameMode then
1336 begin
1337 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1338 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1339 for a := 0 to High(monsters) do
1340 CreateMonster(monsters[a]);
1341 end;
1343 // Çàãðóçêà îïèñàíèÿ êàðòû:
1344 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1345 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1346 Header := MapReader.GetMapHeader();
1348 MapReader.Free();
1350 with gMapInfo do
1351 begin
1352 Name := Header.MapName;
1353 Description := Header.MapDescription;
1354 Author := Header.MapAuthor;
1355 MusicName := Header.MusicName;
1356 SkyName := Header.SkyName;
1357 Height := Header.Height;
1358 Width := Header.Width;
1359 end;
1361 // Çàãðóçêà íåáà:
1362 if gMapInfo.SkyName <> '' then
1363 begin
1364 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1365 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1366 FileName := g_ExtractWadName(gMapInfo.SkyName);
1368 if FileName <> '' then
1369 FileName := GameDir+'/wads/'+FileName
1370 else
1371 begin
1372 FileName := g_ExtractWadName(Res);
1373 end;
1375 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1376 if g_Texture_CreateWAD(BackID, s) then
1377 begin
1378 g_Game_SetupScreenSize();
1379 end
1380 else
1381 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1382 end;
1384 // Çàãðóçêà ìóçûêè:
1385 ok := False;
1386 if gMapInfo.MusicName <> '' then
1387 begin
1388 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1389 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1390 FileName := g_ExtractWadName(gMapInfo.MusicName);
1392 if FileName <> '' then
1393 FileName := GameDir+'/wads/'+FileName
1394 else
1395 begin
1396 FileName := g_ExtractWadName(Res);
1397 end;
1399 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1400 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1401 ok := True
1402 else
1403 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1404 end;
1406 // Îñòàëüíûå óñòàíâêè:
1407 CreateDoorMap();
1408 CreateLiftMap();
1410 g_Items_Init();
1411 g_Weapon_Init();
1412 g_Monsters_Init();
1414 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1415 if not gLoadGameMode then
1416 g_GFX_Init();
1418 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1419 _textures := nil;
1420 panels := nil;
1421 items := nil;
1422 areas := nil;
1423 triggers := nil;
1424 TriggersTable := nil;
1425 AddTextures := nil;
1427 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1428 if ok and (not gLoadGameMode) then
1429 begin
1430 gMusic.SetByName(gMapInfo.MusicName);
1431 gMusic.Play();
1432 end
1433 else
1434 gMusic.SetByName('');
1435 finally
1436 sfsGCEnable(); // enable releasing unused volumes
1437 end;
1439 e_WriteLog('Creating map grid', MSG_NOTIFY);
1441 fixMinMax(gWalls);
1442 fixMinMax(gRenderBackgrounds);
1443 fixMinMax(gRenderForegrounds);
1444 fixMinMax(gWater);
1445 fixMinMax(gAcid1);
1446 fixMinMax(gAcid2);
1447 fixMinMax(gSteps);
1449 gMapGrid := TBodyGrid.Create(mapX1+1, mapY1+1);
1451 addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR
1452 addPanelsToGrid(gRenderBackgrounds, PANEL_BACK);
1453 addPanelsToGrid(gRenderForegrounds, PANEL_FORE);
1454 addPanelsToGrid(gWater, PANEL_WATER);
1455 addPanelsToGrid(gAcid1, PANEL_ACID1);
1456 addPanelsToGrid(gAcid2, PANEL_ACID2);
1457 addPanelsToGrid(gSteps, PANEL_STEP);
1459 gMapGrid.dumpStats();
1461 e_WriteLog('Done loading map.', MSG_NOTIFY);
1462 Result := True;
1463 end;
1465 function g_Map_GetMapInfo(Res: String): TMapInfo;
1466 var
1467 WAD: TWADFile;
1468 MapReader: TMapReader_1;
1469 Header: TMapHeaderRec_1;
1470 FileName: String;
1471 Data: Pointer;
1472 Len: Integer;
1473 begin
1474 FillChar(Result, SizeOf(Result), 0);
1475 FileName := g_ExtractWadName(Res);
1477 WAD := TWADFile.Create();
1478 if not WAD.ReadFile(FileName) then
1479 begin
1480 WAD.Free();
1481 Exit;
1482 end;
1484 //k8: it ignores path again
1485 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1486 begin
1487 WAD.Free();
1488 Exit;
1489 end;
1491 WAD.Free();
1493 MapReader := TMapReader_1.Create();
1495 if not MapReader.LoadMap(Data) then
1496 begin
1497 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1498 ZeroMemory(@Header, SizeOf(Header));
1499 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1500 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1501 end
1502 else
1503 begin
1504 Header := MapReader.GetMapHeader();
1505 Result.Name := Header.MapName;
1506 Result.Description := Header.MapDescription;
1507 end;
1509 FreeMem(Data);
1510 MapReader.Free();
1512 Result.Map := Res;
1513 Result.Author := Header.MapAuthor;
1514 Result.Height := Header.Height;
1515 Result.Width := Header.Width;
1516 end;
1518 function g_Map_GetMapsList(WADName: string): SArray;
1519 var
1520 WAD: TWADFile;
1521 a: Integer;
1522 ResList: SArray;
1523 begin
1524 Result := nil;
1525 WAD := TWADFile.Create();
1526 if not WAD.ReadFile(WADName) then
1527 begin
1528 WAD.Free();
1529 Exit;
1530 end;
1531 ResList := WAD.GetMapResources();
1532 if ResList <> nil then
1533 begin
1534 for a := 0 to High(ResList) do
1535 begin
1536 SetLength(Result, Length(Result)+1);
1537 Result[High(Result)] := ResList[a];
1538 end;
1539 end;
1540 WAD.Free();
1541 end;
1543 function g_Map_Exist(Res: string): Boolean;
1544 var
1545 WAD: TWADFile;
1546 FileName, mnn: string;
1547 ResList: SArray;
1548 a: Integer;
1549 begin
1550 Result := False;
1552 FileName := addWadExtension(g_ExtractWadName(Res));
1554 WAD := TWADFile.Create;
1555 if not WAD.ReadFile(FileName) then
1556 begin
1557 WAD.Free();
1558 Exit;
1559 end;
1561 ResList := WAD.GetMapResources();
1562 WAD.Free();
1564 mnn := g_ExtractFileName(Res);
1565 if ResList <> nil then
1566 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1567 begin
1568 Result := True;
1569 Exit;
1570 end;
1571 end;
1573 procedure g_Map_Free();
1574 var
1575 a: Integer;
1577 procedure FreePanelArray(var panels: TPanelArray);
1578 var
1579 i: Integer;
1581 begin
1582 if panels <> nil then
1583 begin
1584 for i := 0 to High(panels) do
1585 panels[i].Free();
1586 panels := nil;
1587 end;
1588 end;
1590 begin
1591 g_GFX_Free();
1592 g_Weapon_Free();
1593 g_Items_Free();
1594 g_Triggers_Free();
1595 g_Monsters_Free();
1597 RespawnPoints := nil;
1598 if FlagPoints[FLAG_RED] <> nil then
1599 begin
1600 Dispose(FlagPoints[FLAG_RED]);
1601 FlagPoints[FLAG_RED] := nil;
1602 end;
1603 if FlagPoints[FLAG_BLUE] <> nil then
1604 begin
1605 Dispose(FlagPoints[FLAG_BLUE]);
1606 FlagPoints[FLAG_BLUE] := nil;
1607 end;
1608 //DOMFlagPoints := nil;
1610 //gDOMFlags := nil;
1612 if Textures <> nil then
1613 begin
1614 for a := 0 to High(Textures) do
1615 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1616 if Textures[a].Anim then
1617 g_Frames_DeleteByID(Textures[a].FramesID)
1618 else
1619 if Textures[a].TextureID <> TEXTURE_NONE then
1620 e_DeleteTexture(Textures[a].TextureID);
1622 Textures := nil;
1623 end;
1625 FreePanelArray(gWalls);
1626 FreePanelArray(gRenderBackgrounds);
1627 FreePanelArray(gRenderForegrounds);
1628 FreePanelArray(gWater);
1629 FreePanelArray(gAcid1);
1630 FreePanelArray(gAcid2);
1631 FreePanelArray(gSteps);
1632 FreePanelArray(gLifts);
1633 FreePanelArray(gBlockMon);
1635 if BackID <> DWORD(-1) then
1636 begin
1637 gBackSize.X := 0;
1638 gBackSize.Y := 0;
1639 e_DeleteTexture(BackID);
1640 BackID := DWORD(-1);
1641 end;
1643 g_Game_StopAllSounds(False);
1644 gMusic.FreeSound();
1645 g_Sound_Delete(gMapInfo.MusicName);
1647 gMapInfo.Name := '';
1648 gMapInfo.Description := '';
1649 gMapInfo.MusicName := '';
1650 gMapInfo.Height := 0;
1651 gMapInfo.Width := 0;
1653 gDoorMap := nil;
1654 gLiftMap := nil;
1656 PanelByID := nil;
1657 end;
1659 procedure g_Map_Update();
1660 var
1661 a, d, j: Integer;
1662 m: Word;
1663 s: String;
1665 procedure UpdatePanelArray(var panels: TPanelArray);
1666 var
1667 i: Integer;
1669 begin
1670 if panels <> nil then
1671 for i := 0 to High(panels) do
1672 panels[i].Update();
1673 end;
1675 begin
1676 UpdatePanelArray(gWalls);
1677 UpdatePanelArray(gRenderBackgrounds);
1678 UpdatePanelArray(gRenderForegrounds);
1679 UpdatePanelArray(gWater);
1680 UpdatePanelArray(gAcid1);
1681 UpdatePanelArray(gAcid2);
1682 UpdatePanelArray(gSteps);
1684 if gGameSettings.GameMode = GM_CTF then
1685 begin
1686 for a := FLAG_RED to FLAG_BLUE do
1687 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1688 with gFlags[a] do
1689 begin
1690 if gFlags[a].Animation <> nil then
1691 gFlags[a].Animation.Update();
1693 m := g_Obj_Move(@Obj, True, True);
1695 if gTime mod (GAME_TICK*2) <> 0 then
1696 Continue;
1698 // Ñîïðîòèâëåíèå âîçäóõà:
1699 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1701 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1702 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1703 begin
1704 g_Map_ResetFlag(a);
1705 gFlags[a].CaptureTime := 0;
1706 if a = FLAG_RED then
1707 s := _lc[I_PLAYER_FLAG_RED]
1708 else
1709 s := _lc[I_PLAYER_FLAG_BLUE];
1710 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1712 if g_Game_IsNet then
1713 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1714 Continue;
1715 end;
1717 if Count > 0 then
1718 Count := Count - 1;
1720 // Èãðîê áåðåò ôëàã:
1721 if gPlayers <> nil then
1722 begin
1723 j := Random(Length(gPlayers)) - 1;
1725 for d := 0 to High(gPlayers) do
1726 begin
1727 Inc(j);
1728 if j > High(gPlayers) then
1729 j := 0;
1731 if gPlayers[j] <> nil then
1732 if gPlayers[j].Live and
1733 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1734 begin
1735 if gPlayers[j].GetFlag(a) then
1736 Break;
1737 end;
1738 end;
1739 end;
1740 end;
1741 end;
1742 end;
1745 var
1746 pvpset: array of TPanel = nil; // potentially lit panels
1747 pvpb, pvpe: array [0..7] of Integer; // start/end (inclusive) of the correspoinding type panels in pvpset
1748 pvpcount: Integer = -1; // to avoid constant reallocations
1750 function pvpType (panelType: Word): Integer;
1751 begin
1752 case panelType of
1753 PANEL_WALL, PANEL_CLOSEDOOR: result := 0; // gWalls
1754 PANEL_BACK: result := 1; // gRenderBackgrounds
1755 PANEL_FORE: result := 2; // gRenderForegrounds
1756 PANEL_WATER: result := 3; // gWater
1757 PANEL_ACID1: result := 4; // gAcid1
1758 PANEL_ACID2: result := 5; // gAcid2
1759 PANEL_STEP: result := 6; // gSteps
1760 else result := -1;
1761 end;
1762 end;
1764 procedure g_Map_ResetPVP ();
1765 begin
1766 pvpcount := -1; // special
1767 end;
1769 procedure g_Map_BuildPVP (minx, miny, maxx, maxy: Integer);
1770 var
1771 idx: Integer;
1772 tpc: Integer;
1774 procedure checkPanels (var panels: TPanelArray; stp: Integer);
1775 var
1776 idx, x, y, w, h: Integer;
1777 begin
1778 if panels = nil then exit;
1779 tpc := tpc+Length(panels);
1780 if (stp < 0) or (stp > 6) then exit;
1781 pvpb[stp] := pvpcount;
1782 for idx := 0 to High(panels) do
1783 begin
1784 w := panels[idx].Width;
1785 h := panels[idx].Height;
1786 if (w < 1) or (h < 1) then continue;
1787 x := panels[idx].X;
1788 y := panels[idx].Y;
1789 if (x > maxx) or (y > maxy) then continue;
1790 if (x+w <= minx) or (y+h <= miny) then continue;
1791 if pvpcount = length(pvpset) then SetLength(pvpset, pvpcount+32768);
1792 pvpset[pvpcount] := panels[idx];
1793 Inc(pvpcount);
1794 end;
1795 pvpe[stp] := pvpcount-1;
1796 end;
1798 begin
1799 //e_WriteLog(Format('visible rect: (%d,%d)-(%d,%d)', [minx, miny, maxx, maxy]), MSG_NOTIFY);
1800 pvpcount := 0;
1801 for idx := 0 to High(pvpb) do begin pvpb[idx] := 0; pvpe[idx] := -1; end;
1802 tpc := 0;
1803 checkPanels(gWalls, 0);
1804 checkPanels(gRenderBackgrounds, 1);
1805 checkPanels(gRenderForegrounds, 2);
1806 checkPanels(gWater, 3);
1807 checkPanels(gAcid1, 4);
1808 checkPanels(gAcid2, 5);
1809 checkPanels(gSteps, 6);
1810 //e_WriteLog(Format('total panels: %d; visible panels: %d', [tpc, pvpcount]), MSG_NOTIFY);
1811 end;
1813 procedure g_Map_DrawPanelsOld(PanelType: Word);
1815 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1816 var
1817 idx: Integer;
1818 begin
1819 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1820 begin
1821 if pvpcount < 0 then
1822 begin
1823 // alas, no visible set
1824 for idx := 0 to High(panels) do
1825 begin
1826 if not (drawDoors xor panels[idx].Door) then panels[idx].Draw();
1827 end;
1828 end
1829 else
1830 begin
1831 // wow, use visible set
1832 if pvpb[stp] <= pvpe[stp] then
1833 begin
1834 for idx := pvpb[stp] to pvpe[stp] do
1835 begin
1836 if not (drawDoors xor pvpset[idx].Door) then pvpset[idx].Draw();
1837 end;
1838 end;
1839 end;
1840 end;
1841 end;
1843 begin
1844 case PanelType of
1845 PANEL_WALL: DrawPanels(0, gWalls);
1846 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1847 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1848 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1849 PANEL_WATER: DrawPanels(3, gWater);
1850 PANEL_ACID1: DrawPanels(4, gAcid1);
1851 PANEL_ACID2: DrawPanels(5, gAcid2);
1852 PANEL_STEP: DrawPanels(6, gSteps);
1853 end;
1854 end;
1857 var
1858 gDrawPanelList: TBinaryHeapObj = nil;
1860 function dplLess (a, b: TObject): Boolean;
1861 begin
1862 result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx);
1863 end;
1865 procedure dplClear ();
1866 begin
1867 if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear();
1868 end;
1870 procedure dplAddPanel (pan: TPanel);
1871 begin
1872 if pan = nil then exit;
1873 gDrawPanelList.insert(pan);
1874 end;
1877 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
1879 function qq (obj: TObject; tag: Integer): Boolean;
1880 var
1881 pan: TPanel;
1882 begin
1883 result := false; // don't stop, ever
1885 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1887 if obj = nil then
1888 begin
1889 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1890 end;
1891 if not (obj is TPanel) then
1892 begin
1893 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1894 exit;
1895 end;
1896 //pan := (obj as TPanel);
1897 //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1899 if (tag = PANEL_WALL) then
1900 begin
1901 if (PanelType = PANEL_WALL) then
1902 begin
1903 pan := (obj as TPanel);
1904 if not pan.Door then
1905 begin
1906 //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);
1907 dplAddPanel(pan);
1908 end;
1909 end
1910 else if (PanelType = PANEL_CLOSEDOOR) then
1911 begin
1912 pan := (obj as TPanel);
1913 if pan.Door then
1914 begin
1915 //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);
1916 dplAddPanel(pan);
1917 end;
1918 end
1919 end
1920 else if (PanelType = tag) then
1921 begin
1922 pan := (obj as TPanel);
1923 if not pan.Door then
1924 begin
1925 //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);
1926 dplAddPanel(pan);
1927 end;
1928 end;
1929 end;
1931 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1932 var
1933 idx: Integer;
1934 pan: TPanel;
1935 begin
1936 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1937 begin
1938 if pvpcount < 0 then
1939 begin
1940 // alas, no visible set
1941 for idx := 0 to High(panels) do
1942 begin
1943 if not (drawDoors xor panels[idx].Door) then
1944 begin
1945 pan := panels[idx];
1946 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);
1947 end;
1948 end;
1949 end
1950 else
1951 begin
1952 // wow, use visible set
1953 if pvpb[stp] <= pvpe[stp] then
1954 begin
1955 for idx := pvpb[stp] to pvpe[stp] do
1956 begin
1957 if not (drawDoors xor pvpset[idx].Door) then
1958 begin
1959 pan := pvpset[idx];
1960 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);
1961 end;
1962 end;
1963 end;
1964 end;
1965 end;
1966 end;
1968 begin
1969 //g_Map_DrawPanelsOld(PanelType); exit;
1970 //e_WriteLog('==================', MSG_NOTIFY);
1971 //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1972 dplClear();
1973 gMapGrid.forEachInAABB(x0, y0, wdt, hgt, qq);
1975 // debug
1977 e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1978 case PanelType of
1979 PANEL_WALL: DrawPanels(0, gWalls);
1980 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1981 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1982 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1983 PANEL_WATER: DrawPanels(3, gWater);
1984 PANEL_ACID1: DrawPanels(4, gAcid1);
1985 PANEL_ACID2: DrawPanels(5, gAcid2);
1986 PANEL_STEP: DrawPanels(6, gSteps);
1987 end;
1988 e_WriteLog('==================', MSG_NOTIFY);
1991 // sort and draw the list (we need to sort it, or rendering is fucked)
1992 while gDrawPanelList.count > 0 do
1993 begin
1994 (gDrawPanelList.front() as TPanel).Draw();
1995 gDrawPanelList.popFront();
1996 end;
1997 end;
1999 var
2000 plpset: array of Integer = nil; // potentially lit panels
2001 plpcount: Integer; // to avoid constant reallocations
2003 function g_Map_BuildPLP (ltminx, ltminy, ltmaxx, ltmaxy: Integer): Boolean;
2004 var
2005 idx: Integer;
2006 panels: TPanelArray;
2007 begin
2008 panels := gWalls;
2009 plpcount := 0;
2010 if (ltminx < ltmaxx) and (ltminy < ltmaxy) then
2011 begin
2012 if panels <> nil then
2013 begin
2014 for idx := 0 to High(panels) do
2015 begin
2016 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
2017 if (panels[idx].X+panels[idx].Width <= ltminx) then continue;
2018 if (panels[idx].Y+panels[idx].Height <= ltminy) then continue;
2019 if (panels[idx].X > ltmaxx) then continue;
2020 if (panels[idx].Y > ltmaxy) then continue;
2021 if plpcount = length(plpset) then SetLength(plpset, plpcount+32768);
2022 plpset[plpcount] := idx;
2023 Inc(plpcount);
2024 end;
2025 //e_WriteLog(Format('%d panels left out of %d', [plpcount, Length(panels)]), MSG_NOTIFY);
2026 end;
2027 end;
2028 result := (plpcount > 0);
2029 end;
2031 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
2033 (* old
2034 procedure drawPanels (var panels: TPanelArray);
2035 var
2036 a: Integer;
2037 begin
2038 if panels <> nil then
2039 begin
2040 for a := 0 to High(panels) do
2041 begin
2042 panels[a].DrawShadowVolume(lightX, lightY, radius);
2043 end;
2044 end;
2045 end;
2046 *)
2047 var
2048 idx: Integer;
2049 begin
2050 (*
2051 drawPanels(gWalls);
2052 //drawPanels(gRenderForegrounds);
2053 *)
2054 for idx := 0 to plpcount-1 do
2055 begin
2056 gWalls[plpset[idx]].DrawShadowVolume(lightX, lightY, radius);
2057 end;
2058 end;
2060 procedure g_Map_DrawBack(dx, dy: Integer);
2061 begin
2062 if gDrawBackGround and (BackID <> DWORD(-1)) then
2063 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
2064 else
2065 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2066 end;
2068 function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word;
2069 PanelType: Word; b1x3: Boolean): Boolean;
2070 var
2071 a, h: Integer;
2072 begin
2073 Result := False;
2075 if WordBool(PanelType and PANEL_WALL) then
2076 if gWalls <> nil then
2077 begin
2078 h := High(gWalls);
2080 for a := 0 to h do
2081 if gWalls[a].Enabled and
2082 g_Collide(X, Y, Width, Height,
2083 gWalls[a].X, gWalls[a].Y,
2084 gWalls[a].Width, gWalls[a].Height) then
2085 begin
2086 Result := True;
2087 Exit;
2088 end;
2089 end;
2091 if WordBool(PanelType and PANEL_WATER) then
2092 if gWater <> nil then
2093 begin
2094 h := High(gWater);
2096 for a := 0 to h do
2097 if g_Collide(X, Y, Width, Height,
2098 gWater[a].X, gWater[a].Y,
2099 gWater[a].Width, gWater[a].Height) then
2100 begin
2101 Result := True;
2102 Exit;
2103 end;
2104 end;
2106 if WordBool(PanelType and PANEL_ACID1) then
2107 if gAcid1 <> nil then
2108 begin
2109 h := High(gAcid1);
2111 for a := 0 to h do
2112 if g_Collide(X, Y, Width, Height,
2113 gAcid1[a].X, gAcid1[a].Y,
2114 gAcid1[a].Width, gAcid1[a].Height) then
2115 begin
2116 Result := True;
2117 Exit;
2118 end;
2119 end;
2121 if WordBool(PanelType and PANEL_ACID2) then
2122 if gAcid2 <> nil then
2123 begin
2124 h := High(gAcid2);
2126 for a := 0 to h do
2127 if g_Collide(X, Y, Width, Height,
2128 gAcid2[a].X, gAcid2[a].Y,
2129 gAcid2[a].Width, gAcid2[a].Height) then
2130 begin
2131 Result := True;
2132 Exit;
2133 end;
2134 end;
2136 if WordBool(PanelType and PANEL_STEP) then
2137 if gSteps <> nil then
2138 begin
2139 h := High(gSteps);
2141 for a := 0 to h do
2142 if g_Collide(X, Y, Width, Height,
2143 gSteps[a].X, gSteps[a].Y,
2144 gSteps[a].Width, gSteps[a].Height) then
2145 begin
2146 Result := True;
2147 Exit;
2148 end;
2149 end;
2151 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
2152 if gLifts <> nil then
2153 begin
2154 h := High(gLifts);
2156 for a := 0 to h do
2157 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2158 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2159 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2160 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2161 g_Collide(X, Y, Width, Height,
2162 gLifts[a].X, gLifts[a].Y,
2163 gLifts[a].Width, gLifts[a].Height) then
2164 begin
2165 Result := True;
2166 Exit;
2167 end;
2168 end;
2170 if WordBool(PanelType and PANEL_BLOCKMON) then
2171 if gBlockMon <> nil then
2172 begin
2173 h := High(gBlockMon);
2175 for a := 0 to h do
2176 if ( (not b1x3) or
2177 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2178 g_Collide(X, Y, Width, Height,
2179 gBlockMon[a].X, gBlockMon[a].Y,
2180 gBlockMon[a].Width, gBlockMon[a].Height) then
2181 begin
2182 Result := True;
2183 Exit;
2184 end;
2185 end;
2186 end;
2188 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean;
2190 function qq (obj: TObject; tag: Integer): Boolean;
2191 var
2192 pan: TPanel;
2193 a: Integer;
2194 begin
2195 result := false; // don't stop, ever
2197 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2199 if obj = nil then
2200 begin
2201 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2202 end;
2203 if not (obj is TPanel) then
2204 begin
2205 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2206 exit;
2207 end;
2209 pan := (obj as TPanel);
2210 a := pan.ArrIdx;
2212 if WordBool(PanelType and PANEL_WALL) and WordBool(tag and PANEL_WALL) then
2213 begin
2214 if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then
2215 begin
2216 result := true;
2217 exit;
2218 end;
2219 end;
2221 if WordBool(PanelType and PANEL_WATER) and WordBool(tag and PANEL_WATER) then
2222 begin
2223 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2224 begin
2225 result := True;
2226 exit;
2227 end;
2228 end;
2230 if WordBool(PanelType and PANEL_ACID1) and WordBool(tag and PANEL_ACID1) then
2231 begin
2232 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2233 begin
2234 result := True;
2235 exit;
2236 end;
2237 end;
2239 if WordBool(PanelType and PANEL_ACID2) and WordBool(tag and PANEL_ACID2) then
2240 begin
2241 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2242 begin
2243 result := True;
2244 exit;
2245 end;
2246 end;
2248 if WordBool(PanelType and PANEL_STEP) and WordBool(tag and PANEL_STEP) then
2249 begin
2250 if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then
2251 begin
2252 result := True;
2253 exit;
2254 end;
2255 end;
2256 end;
2258 var
2259 a, h: Integer;
2260 begin
2261 result := gMapGrid.forEachInAABB(X, Y, Width, Height, qq);
2262 if not result then
2263 begin
2264 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (gLifts <> nil) then
2265 begin
2266 h := High(gLifts);
2267 for a := 0 to h do
2268 begin
2269 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2270 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2271 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2272 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2273 g_Collide(X, Y, Width, Height,
2274 gLifts[a].X, gLifts[a].Y,
2275 gLifts[a].Width, gLifts[a].Height) then
2276 begin
2277 Result := True;
2278 Exit;
2279 end;
2280 end;
2281 end;
2283 if WordBool(PanelType and PANEL_BLOCKMON) and (gBlockMon <> nil) then
2284 begin
2285 h := High(gBlockMon);
2286 for a := 0 to h do
2287 begin
2288 if ( (not b1x3) or
2289 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2290 g_Collide(X, Y, Width, Height,
2291 gBlockMon[a].X, gBlockMon[a].Y,
2292 gBlockMon[a].Width, gBlockMon[a].Height) then
2293 begin
2294 Result := True;
2295 Exit;
2296 end;
2297 end;
2298 end;
2299 end;
2300 end;
2303 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
2304 var
2305 a, h: Integer;
2306 begin
2307 Result := TEXTURE_NONE;
2309 if gWater <> nil then
2310 begin
2311 h := High(gWater);
2313 for a := 0 to h do
2314 if g_Collide(X, Y, Width, Height,
2315 gWater[a].X, gWater[a].Y,
2316 gWater[a].Width, gWater[a].Height) then
2317 begin
2318 Result := gWater[a].GetTextureID();
2319 Exit;
2320 end;
2321 end;
2323 if gAcid1 <> nil then
2324 begin
2325 h := High(gAcid1);
2327 for a := 0 to h do
2328 if g_Collide(X, Y, Width, Height,
2329 gAcid1[a].X, gAcid1[a].Y,
2330 gAcid1[a].Width, gAcid1[a].Height) then
2331 begin
2332 Result := gAcid1[a].GetTextureID();
2333 Exit;
2334 end;
2335 end;
2337 if gAcid2 <> nil then
2338 begin
2339 h := High(gAcid2);
2341 for a := 0 to h do
2342 if g_Collide(X, Y, Width, Height,
2343 gAcid2[a].X, gAcid2[a].Y,
2344 gAcid2[a].Width, gAcid2[a].Height) then
2345 begin
2346 Result := gAcid2[a].GetTextureID();
2347 Exit;
2348 end;
2349 end;
2350 end;
2352 procedure g_Map_EnableWall(ID: DWORD);
2353 begin
2354 with gWalls[ID] do
2355 begin
2356 Enabled := True;
2357 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
2359 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2360 end;
2361 end;
2363 procedure g_Map_DisableWall(ID: DWORD);
2364 begin
2365 with gWalls[ID] do
2366 begin
2367 Enabled := False;
2368 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
2370 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2371 end;
2372 end;
2374 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
2375 var
2376 tp: TPanel;
2377 begin
2378 case PanelType of
2379 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2380 tp := gWalls[ID];
2381 PANEL_FORE:
2382 tp := gRenderForegrounds[ID];
2383 PANEL_BACK:
2384 tp := gRenderBackgrounds[ID];
2385 PANEL_WATER:
2386 tp := gWater[ID];
2387 PANEL_ACID1:
2388 tp := gAcid1[ID];
2389 PANEL_ACID2:
2390 tp := gAcid2[ID];
2391 PANEL_STEP:
2392 tp := gSteps[ID];
2393 else
2394 Exit;
2395 end;
2397 tp.NextTexture(AnimLoop);
2398 if g_Game_IsServer and g_Game_IsNet then
2399 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
2400 end;
2402 procedure g_Map_SetLift(ID: DWORD; t: Integer);
2403 begin
2404 if gLifts[ID].LiftType = t then
2405 Exit;
2407 with gLifts[ID] do
2408 begin
2409 LiftType := t;
2411 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
2413 if LiftType = 0 then
2414 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
2415 else if LiftType = 1 then
2416 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
2417 else if LiftType = 2 then
2418 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
2419 else if LiftType = 3 then
2420 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
2422 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2423 end;
2424 end;
2426 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
2427 var
2428 a: Integer;
2429 PointsArray: Array of TRespawnPoint;
2430 begin
2431 Result := False;
2432 SetLength(PointsArray, 0);
2434 if RespawnPoints = nil then
2435 Exit;
2437 for a := 0 to High(RespawnPoints) do
2438 if RespawnPoints[a].PointType = PointType then
2439 begin
2440 SetLength(PointsArray, Length(PointsArray)+1);
2441 PointsArray[High(PointsArray)] := RespawnPoints[a];
2442 end;
2444 if PointsArray = nil then
2445 Exit;
2447 RespawnPoint := PointsArray[Random(Length(PointsArray))];
2448 Result := True;
2449 end;
2451 function g_Map_GetPointCount(PointType: Byte): Word;
2452 var
2453 a: Integer;
2454 begin
2455 Result := 0;
2457 if RespawnPoints = nil then
2458 Exit;
2460 for a := 0 to High(RespawnPoints) do
2461 if RespawnPoints[a].PointType = PointType then
2462 Result := Result + 1;
2463 end;
2465 function g_Map_HaveFlagPoints(): Boolean;
2466 begin
2467 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
2468 end;
2470 procedure g_Map_ResetFlag(Flag: Byte);
2471 begin
2472 with gFlags[Flag] do
2473 begin
2474 Obj.X := -1000;
2475 Obj.Y := -1000;
2476 Obj.Vel.X := 0;
2477 Obj.Vel.Y := 0;
2478 Direction := D_LEFT;
2479 State := FLAG_STATE_NONE;
2480 if FlagPoints[Flag] <> nil then
2481 begin
2482 Obj.X := FlagPoints[Flag]^.X;
2483 Obj.Y := FlagPoints[Flag]^.Y;
2484 Direction := FlagPoints[Flag]^.Direction;
2485 State := FLAG_STATE_NORMAL;
2486 end;
2487 Count := -1;
2488 end;
2489 end;
2491 procedure g_Map_DrawFlags();
2492 var
2493 i, dx: Integer;
2494 Mirror: TMirrorType;
2495 begin
2496 if gGameSettings.GameMode <> GM_CTF then
2497 Exit;
2499 for i := FLAG_RED to FLAG_BLUE do
2500 with gFlags[i] do
2501 if State <> FLAG_STATE_CAPTURED then
2502 begin
2503 if State = FLAG_STATE_NONE then
2504 continue;
2506 if Direction = D_LEFT then
2507 begin
2508 Mirror := M_HORIZONTAL;
2509 dx := -1;
2510 end
2511 else
2512 begin
2513 Mirror := M_NONE;
2514 dx := 1;
2515 end;
2517 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2519 if g_debug_Frames then
2520 begin
2521 e_DrawQuad(Obj.X+Obj.Rect.X,
2522 Obj.Y+Obj.Rect.Y,
2523 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2524 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2525 0, 255, 0);
2526 end;
2527 end;
2528 end;
2530 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2531 var
2532 dw: DWORD;
2533 b: Byte;
2534 str: String;
2535 boo: Boolean;
2537 procedure SavePanelArray(var panels: TPanelArray);
2538 var
2539 PAMem: TBinMemoryWriter;
2540 i: Integer;
2541 begin
2542 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2543 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2545 i := 0;
2546 while i < Length(panels) do
2547 begin
2548 if panels[i].SaveIt then
2549 begin
2550 // ID ïàíåëè:
2551 PAMem.WriteInt(i);
2552 // Ñîõðàíÿåì ïàíåëü:
2553 panels[i].SaveState(PAMem);
2554 end;
2555 Inc(i);
2556 end;
2558 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2559 PAMem.SaveToMemory(Mem);
2560 PAMem.Free();
2561 end;
2563 procedure SaveFlag(flag: PFlag);
2564 begin
2565 // Ñèãíàòóðà ôëàãà:
2566 dw := FLAG_SIGNATURE; // 'FLAG'
2567 Mem.WriteDWORD(dw);
2568 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2569 Mem.WriteByte(flag^.RespawnType);
2570 // Ñîñòîÿíèå ôëàãà:
2571 Mem.WriteByte(flag^.State);
2572 // Íàïðàâëåíèå ôëàãà:
2573 if flag^.Direction = D_LEFT then
2574 b := 1
2575 else // D_RIGHT
2576 b := 2;
2577 Mem.WriteByte(b);
2578 // Îáúåêò ôëàãà:
2579 Obj_SaveState(@flag^.Obj, Mem);
2580 end;
2582 begin
2583 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2585 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2586 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2587 SavePanelArray(gWalls);
2588 // Ñîõðàíÿåì ïàíåëè ôîíà:
2589 SavePanelArray(gRenderBackgrounds);
2590 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2591 SavePanelArray(gRenderForegrounds);
2592 // Ñîõðàíÿåì ïàíåëè âîäû:
2593 SavePanelArray(gWater);
2594 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2595 SavePanelArray(gAcid1);
2596 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2597 SavePanelArray(gAcid2);
2598 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2599 SavePanelArray(gSteps);
2600 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2601 SavePanelArray(gLifts);
2602 ///// /////
2604 ///// Ñîõðàíÿåì ìóçûêó: /////
2605 // Ñèãíàòóðà ìóçûêè:
2606 dw := MUSIC_SIGNATURE; // 'MUSI'
2607 Mem.WriteDWORD(dw);
2608 // Íàçâàíèå ìóçûêè:
2609 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2610 if gMusic.NoMusic then
2611 str := ''
2612 else
2613 str := gMusic.Name;
2614 Mem.WriteString(str, 64);
2615 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2616 dw := gMusic.GetPosition();
2617 Mem.WriteDWORD(dw);
2618 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2619 boo := gMusic.SpecPause;
2620 Mem.WriteBoolean(boo);
2621 ///// /////
2623 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2624 Mem.WriteInt(gTotalMonsters);
2625 ///// /////
2627 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2628 if gGameSettings.GameMode = GM_CTF then
2629 begin
2630 // Ôëàã Êðàñíîé êîìàíäû:
2631 SaveFlag(@gFlags[FLAG_RED]);
2632 // Ôëàã Ñèíåé êîìàíäû:
2633 SaveFlag(@gFlags[FLAG_BLUE]);
2634 end;
2635 ///// /////
2637 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2638 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2639 begin
2640 // Î÷êè Êðàñíîé êîìàíäû:
2641 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2642 // Î÷êè Ñèíåé êîìàíäû:
2643 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2644 end;
2645 ///// /////
2646 end;
2648 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2649 var
2650 dw: DWORD;
2651 b: Byte;
2652 str: String;
2653 boo: Boolean;
2655 procedure LoadPanelArray(var panels: TPanelArray);
2656 var
2657 PAMem: TBinMemoryReader;
2658 i, id: Integer;
2659 begin
2660 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2661 PAMem := TBinMemoryReader.Create();
2662 PAMem.LoadFromMemory(Mem);
2664 for i := 0 to Length(panels)-1 do
2665 if panels[i].SaveIt then
2666 begin
2667 // ID ïàíåëè:
2668 PAMem.ReadInt(id);
2669 if id <> i then
2670 begin
2671 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2672 end;
2673 // Çàãðóæàåì ïàíåëü:
2674 panels[i].LoadState(PAMem);
2675 end;
2677 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2678 PAMem.Free();
2679 end;
2681 procedure LoadFlag(flag: PFlag);
2682 begin
2683 // Ñèãíàòóðà ôëàãà:
2684 Mem.ReadDWORD(dw);
2685 if dw <> FLAG_SIGNATURE then // 'FLAG'
2686 begin
2687 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2688 end;
2689 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2690 Mem.ReadByte(flag^.RespawnType);
2691 // Ñîñòîÿíèå ôëàãà:
2692 Mem.ReadByte(flag^.State);
2693 // Íàïðàâëåíèå ôëàãà:
2694 Mem.ReadByte(b);
2695 if b = 1 then
2696 flag^.Direction := D_LEFT
2697 else // b = 2
2698 flag^.Direction := D_RIGHT;
2699 // Îáúåêò ôëàãà:
2700 Obj_LoadState(@flag^.Obj, Mem);
2701 end;
2703 begin
2704 if Mem = nil then
2705 Exit;
2707 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2708 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2709 LoadPanelArray(gWalls);
2710 // Çàãðóæàåì ïàíåëè ôîíà:
2711 LoadPanelArray(gRenderBackgrounds);
2712 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2713 LoadPanelArray(gRenderForegrounds);
2714 // Çàãðóæàåì ïàíåëè âîäû:
2715 LoadPanelArray(gWater);
2716 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2717 LoadPanelArray(gAcid1);
2718 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2719 LoadPanelArray(gAcid2);
2720 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2721 LoadPanelArray(gSteps);
2722 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2723 LoadPanelArray(gLifts);
2724 ///// /////
2726 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2727 g_GFX_Init();
2729 ///// Çàãðóæàåì ìóçûêó: /////
2730 // Ñèãíàòóðà ìóçûêè:
2731 Mem.ReadDWORD(dw);
2732 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2733 begin
2734 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2735 end;
2736 // Íàçâàíèå ìóçûêè:
2737 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2738 Mem.ReadString(str);
2739 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2740 Mem.ReadDWORD(dw);
2741 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2742 Mem.ReadBoolean(boo);
2743 // Çàïóñêàåì ýòó ìóçûêó:
2744 gMusic.SetByName(str);
2745 gMusic.SpecPause := boo;
2746 gMusic.Play();
2747 gMusic.Pause(True);
2748 gMusic.SetPosition(dw);
2749 ///// /////
2751 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2752 Mem.ReadInt(gTotalMonsters);
2753 ///// /////
2755 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2756 if gGameSettings.GameMode = GM_CTF then
2757 begin
2758 // Ôëàã Êðàñíîé êîìàíäû:
2759 LoadFlag(@gFlags[FLAG_RED]);
2760 // Ôëàã Ñèíåé êîìàíäû:
2761 LoadFlag(@gFlags[FLAG_BLUE]);
2762 end;
2763 ///// /////
2765 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2766 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2767 begin
2768 // Î÷êè Êðàñíîé êîìàíäû:
2769 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2770 // Î÷êè Ñèíåé êîìàíäû:
2771 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2772 end;
2773 ///// /////
2774 end;
2776 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
2777 var
2778 Arr: TPanelArray;
2779 begin
2780 Result := nil;
2781 if (PanelID < 0) or (PanelID > High(PanelByID)) then Exit;
2782 Arr := PanelByID[PanelID].PWhere^;
2783 PanelArrayID := PanelByID[PanelID].PArrID;
2784 Result := Addr(Arr[PanelByID[PanelID].PArrID]);
2785 end;
2787 end.