DEADSOFTWARE

730812cdd2e16113909fb57d2e888277aef0a807
[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 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
68 procedure g_Map_DrawBack(dx, dy: Integer);
69 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word;
70 PanelType: Word; b1x3: Boolean): Boolean;
71 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
72 procedure g_Map_EnableWall(ID: DWORD);
73 procedure g_Map_DisableWall(ID: DWORD);
74 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
75 procedure g_Map_SetLift(ID: DWORD; t: Integer);
76 procedure g_Map_ReAdd_DieTriggers();
77 function g_Map_IsSpecialTexture(Texture: String): Boolean;
79 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
80 function g_Map_GetPointCount(PointType: Byte): Word;
82 function g_Map_HaveFlagPoints(): Boolean;
84 procedure g_Map_ResetFlag(Flag: Byte);
85 procedure g_Map_DrawFlags();
87 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
89 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
90 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
92 // build "possibly lit panels" index, so we can avoid looping over all level panels again and again
93 function g_Map_BuildPLP (ltminx, ltminy, ltmaxx, ltmaxy: Integer): Boolean; // returns `false` if no patels lit
94 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
96 const
97 RESPAWNPOINT_PLAYER1 = 1;
98 RESPAWNPOINT_PLAYER2 = 2;
99 RESPAWNPOINT_DM = 3;
100 RESPAWNPOINT_RED = 4;
101 RESPAWNPOINT_BLUE = 5;
103 FLAG_NONE = 0;
104 FLAG_RED = 1;
105 FLAG_BLUE = 2;
106 FLAG_DOM = 3;
108 FLAG_STATE_NONE = 0;
109 FLAG_STATE_NORMAL = 1;
110 FLAG_STATE_DROPPED = 2;
111 FLAG_STATE_CAPTURED = 3;
112 FLAG_STATE_SCORED = 4; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
113 FLAG_STATE_RETURNED = 5; // Äëÿ ýâåíòîâ ÷åðåç ñåòêó.
115 FLAG_TIME = 720; // 20 seconds
117 SKY_STRETCH: Single = 1.5;
119 var
120 gWalls: TPanelArray;
121 gRenderBackgrounds: TPanelArray;
122 gRenderForegrounds: TPanelArray;
123 gWater, gAcid1, gAcid2: TPanelArray;
124 gSteps: TPanelArray;
125 gLifts: TPanelArray;
126 gBlockMon: TPanelArray;
127 gFlags: array [FLAG_RED..FLAG_BLUE] of TFlag;
128 //gDOMFlags: array of TFlag;
129 gMapInfo: TMapInfo;
130 gBackSize: TPoint;
131 gDoorMap: array of array of DWORD;
132 gLiftMap: array of array of DWORD;
133 gWADHash: TMD5Digest;
134 BackID: DWORD = DWORD(-1);
135 gExternalResources: TStringList;
136 gMapGrid: TBodyGrid = nil;
138 implementation
140 uses
141 g_main, e_log, SysUtils, g_items, g_gfx, g_console,
142 GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
143 g_options, MAPREADER, g_triggers, g_player, MAPDEF,
144 Math, g_monsters, g_saveload, g_language, g_netmsg,
145 utils, sfs,
146 ImagingTypes, Imaging, ImagingUtility,
147 ImagingGif, ImagingNetworkGraphics;
149 const
150 FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52);
151 MUSIC_SIGNATURE = $4953554D; // 'MUSI'
152 FLAG_SIGNATURE = $47414C46; // 'FLAG'
154 type
155 TPanelID = record
156 PWhere: ^TPanelArray;
157 PArrID: Integer;
158 end;
160 var
161 PanelById: array of TPanelID;
162 Textures: TLevelTextureArray;
163 RespawnPoints: Array of TRespawnPoint;
164 FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
165 //DOMFlagPoints: Array of TFlagPoint;
168 function g_Map_IsSpecialTexture(Texture: String): Boolean;
169 begin
170 Result := (Texture = TEXTURE_NAME_WATER) or
171 (Texture = TEXTURE_NAME_ACID1) or
172 (Texture = TEXTURE_NAME_ACID2);
173 end;
175 procedure CreateDoorMap();
176 var
177 PanelArray: Array of record
178 X, Y: Integer;
179 Width, Height: Word;
180 Active: Boolean;
181 PanelID: DWORD;
182 end;
183 a, b, c, m, i, len: Integer;
184 ok: Boolean;
185 begin
186 if gWalls = nil then
187 Exit;
189 i := 0;
190 len := 128;
191 SetLength(PanelArray, len);
193 for a := 0 to High(gWalls) do
194 if gWalls[a].Door then
195 begin
196 PanelArray[i].X := gWalls[a].X;
197 PanelArray[i].Y := gWalls[a].Y;
198 PanelArray[i].Width := gWalls[a].Width;
199 PanelArray[i].Height := gWalls[a].Height;
200 PanelArray[i].Active := True;
201 PanelArray[i].PanelID := a;
203 i := i + 1;
204 if i = len then
205 begin
206 len := len + 128;
207 SetLength(PanelArray, len);
208 end;
209 end;
211 // Íåò äâåðåé:
212 if i = 0 then
213 begin
214 PanelArray := nil;
215 Exit;
216 end;
218 SetLength(gDoorMap, 0);
220 g_Game_SetLoadingText(_lc[I_LOAD_DOOR_MAP], i-1, False);
222 for a := 0 to i-1 do
223 if PanelArray[a].Active then
224 begin
225 PanelArray[a].Active := False;
226 m := Length(gDoorMap);
227 SetLength(gDoorMap, m+1);
228 SetLength(gDoorMap[m], 1);
229 gDoorMap[m, 0] := PanelArray[a].PanelID;
230 ok := True;
232 while ok do
233 begin
234 ok := False;
236 for b := 0 to i-1 do
237 if PanelArray[b].Active then
238 for c := 0 to High(gDoorMap[m]) do
239 if {((gRenderWalls[PanelArray[b].RenderPanelID].TextureID = gRenderWalls[gDoorMap[m, c]].TextureID) or
240 gRenderWalls[PanelArray[b].RenderPanelID].Hide or gRenderWalls[gDoorMap[m, c]].Hide) and}
241 g_CollideAround(PanelArray[b].X, PanelArray[b].Y,
242 PanelArray[b].Width, PanelArray[b].Height,
243 gWalls[gDoorMap[m, c]].X,
244 gWalls[gDoorMap[m, c]].Y,
245 gWalls[gDoorMap[m, c]].Width,
246 gWalls[gDoorMap[m, c]].Height) then
247 begin
248 PanelArray[b].Active := False;
249 SetLength(gDoorMap[m],
250 Length(gDoorMap[m])+1);
251 gDoorMap[m, High(gDoorMap[m])] := PanelArray[b].PanelID;
252 ok := True;
253 Break;
254 end;
255 end;
257 g_Game_StepLoading();
258 end;
260 PanelArray := nil;
261 end;
263 procedure CreateLiftMap();
264 var
265 PanelArray: Array of record
266 X, Y: Integer;
267 Width, Height: Word;
268 Active: Boolean;
269 end;
270 a, b, c, len, i, j: Integer;
271 ok: Boolean;
272 begin
273 if gLifts = nil then
274 Exit;
276 len := Length(gLifts);
277 SetLength(PanelArray, len);
279 for a := 0 to len-1 do
280 begin
281 PanelArray[a].X := gLifts[a].X;
282 PanelArray[a].Y := gLifts[a].Y;
283 PanelArray[a].Width := gLifts[a].Width;
284 PanelArray[a].Height := gLifts[a].Height;
285 PanelArray[a].Active := True;
286 end;
288 SetLength(gLiftMap, len);
289 i := 0;
291 g_Game_SetLoadingText(_lc[I_LOAD_LIFT_MAP], len-1, False);
293 for a := 0 to len-1 do
294 if PanelArray[a].Active then
295 begin
296 PanelArray[a].Active := False;
297 SetLength(gLiftMap[i], 32);
298 j := 0;
299 gLiftMap[i, j] := a;
300 ok := True;
302 while ok do
303 begin
304 ok := False;
305 for b := 0 to len-1 do
306 if PanelArray[b].Active then
307 for c := 0 to j do
308 if g_CollideAround(PanelArray[b].X,
309 PanelArray[b].Y,
310 PanelArray[b].Width,
311 PanelArray[b].Height,
312 PanelArray[gLiftMap[i, c]].X,
313 PanelArray[gLiftMap[i, c]].Y,
314 PanelArray[gLiftMap[i, c]].Width,
315 PanelArray[gLiftMap[i, c]].Height) then
316 begin
317 PanelArray[b].Active := False;
318 j := j+1;
319 if j > High(gLiftMap[i]) then
320 SetLength(gLiftMap[i],
321 Length(gLiftMap[i])+32);
323 gLiftMap[i, j] := b;
324 ok := True;
326 Break;
327 end;
328 end;
330 SetLength(gLiftMap[i], j+1);
331 i := i+1;
333 g_Game_StepLoading();
334 end;
336 SetLength(gLiftMap, i);
338 PanelArray := nil;
339 end;
341 function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
342 CurTex: Integer; sav: Boolean): Integer;
343 var
344 len: Integer;
345 panels: ^TPanelArray;
346 begin
347 Result := -1;
349 case PanelRec.PanelType of
350 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
351 panels := @gWalls;
352 PANEL_BACK:
353 panels := @gRenderBackgrounds;
354 PANEL_FORE:
355 panels := @gRenderForegrounds;
356 PANEL_WATER:
357 panels := @gWater;
358 PANEL_ACID1:
359 panels := @gAcid1;
360 PANEL_ACID2:
361 panels := @gAcid2;
362 PANEL_STEP:
363 panels := @gSteps;
364 PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT:
365 panels := @gLifts;
366 PANEL_BLOCKMON:
367 panels := @gBlockMon;
368 else
369 Exit;
370 end;
372 len := Length(panels^);
373 SetLength(panels^, len + 1);
375 panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures);
376 panels^[len].ArrIdx := len;
377 if sav then
378 panels^[len].SaveIt := True;
380 Result := len;
382 len := Length(PanelByID);
383 SetLength(PanelByID, len + 1);
384 PanelByID[len].PWhere := panels;
385 PanelByID[len].PArrID := Result;
386 end;
388 function CreateNullTexture(RecName: String): Integer;
389 begin
390 SetLength(Textures, Length(Textures)+1);
391 result := High(Textures);
393 with Textures[High(Textures)] do
394 begin
395 TextureName := RecName;
396 Width := 1;
397 Height := 1;
398 Anim := False;
399 TextureID := TEXTURE_NONE;
400 end;
401 end;
403 function CreateTexture(RecName: String; Map: string; log: Boolean): Integer;
404 var
405 WAD: TWADFile;
406 TextureData: Pointer;
407 WADName, txname: String;
408 a, ResLength: Integer;
409 begin
410 Result := -1;
412 if Textures <> nil then
413 for a := 0 to High(Textures) do
414 if Textures[a].TextureName = RecName then
415 begin // Òåêñòóðà ñ òàêèì èìåíåì óæå åñòü
416 Result := a;
417 Exit;
418 end;
420 // Òåêñòóðû ñî ñïåöèàëüíûìè èìåíàìè (âîäà, ëàâà, êèñëîòà):
421 if (RecName = TEXTURE_NAME_WATER) or
422 (RecName = TEXTURE_NAME_ACID1) or
423 (RecName = TEXTURE_NAME_ACID2) then
424 begin
425 SetLength(Textures, Length(Textures)+1);
427 with Textures[High(Textures)] do
428 begin
429 TextureName := RecName;
431 if TextureName = TEXTURE_NAME_WATER then
432 TextureID := TEXTURE_SPECIAL_WATER
433 else
434 if TextureName = TEXTURE_NAME_ACID1 then
435 TextureID := TEXTURE_SPECIAL_ACID1
436 else
437 if TextureName = TEXTURE_NAME_ACID2 then
438 TextureID := TEXTURE_SPECIAL_ACID2;
440 Anim := False;
441 end;
443 result := High(Textures);
444 Exit;
445 end;
447 // Çàãðóæàåì ðåñóðñ òåêñòóðû â ïàìÿòü èç WAD'à:
448 WADName := g_ExtractWadName(RecName);
450 WAD := TWADFile.Create();
452 if WADName <> '' then
453 WADName := GameDir+'/wads/'+WADName
454 else
455 WADName := Map;
457 WAD.ReadFile(WADName);
459 txname := RecName;
461 if (WADName = Map) and WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
462 begin
463 FreeMem(TextureData);
464 RecName := 'COMMON\ALIEN';
465 end;
468 if WAD.GetResource(g_ExtractFilePathName(RecName), TextureData, ResLength) then
469 begin
470 SetLength(Textures, Length(Textures)+1);
471 if not e_CreateTextureMem(TextureData, ResLength, Textures[High(Textures)].TextureID) then
472 Exit;
473 e_GetTextureSize(Textures[High(Textures)].TextureID,
474 @Textures[High(Textures)].Width,
475 @Textures[High(Textures)].Height);
476 FreeMem(TextureData);
477 Textures[High(Textures)].TextureName := {RecName}txname;
478 Textures[High(Textures)].Anim := False;
480 result := High(Textures);
481 end
482 else // Íåò òàêîãî ðåóñðñà â WAD'å
483 begin
484 //e_WriteLog(Format('SHIT! Error loading texture %s : %s : %s', [RecName, txname, g_ExtractFilePathName(RecName)]), MSG_WARNING);
485 if log then
486 begin
487 e_WriteLog(Format('Error loading texture %s', [RecName]), MSG_WARNING);
488 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
489 end;
490 end;
492 WAD.Free();
493 end;
495 function CreateAnimTexture(RecName: String; Map: string; log: Boolean): Integer;
496 var
497 WAD: TWADFile;
498 TextureWAD: PChar = nil;
499 TextData: Pointer = nil;
500 TextureData: Pointer = nil;
501 cfg: TConfig = nil;
502 WADName: String;
503 ResLength: Integer;
504 TextureResource: String;
505 _width, _height, _framecount, _speed: Integer;
506 _backanimation: Boolean;
507 //imgfmt: string;
508 ia: TDynImageDataArray = nil;
509 f, c, frdelay, frloop: Integer;
510 begin
511 result := -1;
513 //e_WriteLog(Format('*** Loading animated texture "%s"', [RecName]), MSG_NOTIFY);
515 // ×èòàåì WAD-ðåñóðñ àíèì.òåêñòóðû èç WAD'à â ïàìÿòü:
516 WADName := g_ExtractWadName(RecName);
518 WAD := TWADFile.Create();
519 try
520 if WADName <> '' then
521 WADName := GameDir+'/wads/'+WADName
522 else
523 WADName := Map;
525 WAD.ReadFile(WADName);
527 if not WAD.GetResource(g_ExtractFilePathName(RecName), TextureWAD, ResLength) then
528 begin
529 if log then
530 begin
531 e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
532 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
533 end;
534 exit;
535 end;
537 {TEST
538 if WADName = Map then
539 begin
540 //FreeMem(TextureWAD);
541 if not WAD.GetResource('COMMON/animation', TextureWAD, ResLength) then Halt(1);
542 end;
545 WAD.FreeWAD();
547 if ResLength < 6 then
548 begin
549 e_WriteLog(Format('Animated texture file "%s" too short', [RecName]), MSG_WARNING);
550 exit;
551 end;
553 // ýòî ïòèöà? ýòî ñàìîë¸ò?
554 if (TextureWAD[0] = 'D') and (TextureWAD[1] = 'F') and
555 (TextureWAD[2] = 'W') and (TextureWAD[3] = 'A') and (TextureWAD[4] = 'D') then
556 begin
557 // íåò, ýòî ñóïåðìåí!
558 if not WAD.ReadMemory(TextureWAD, ResLength) then
559 begin
560 e_WriteLog(Format('Animated texture WAD file "%s" is invalid', [RecName]), MSG_WARNING);
561 exit;
562 end;
564 // ×èòàåì INI-ðåñóðñ àíèì. òåêñòóðû è çàïîìèíàåì åãî óñòàíîâêè:
565 if not WAD.GetResource('TEXT/ANIM', TextData, ResLength) then
566 begin
567 e_WriteLog(Format('Animated texture file "%s" has invalid INI', [RecName]), MSG_WARNING);
568 exit;
569 end;
571 cfg := TConfig.CreateMem(TextData, ResLength);
573 TextureResource := cfg.ReadStr('', 'resource', '');
574 if TextureResource = '' then
575 begin
576 e_WriteLog(Format('Animated texture WAD file "%s" has no "resource"', [RecName]), MSG_WARNING);
577 exit;
578 end;
580 _width := cfg.ReadInt('', 'framewidth', 0);
581 _height := cfg.ReadInt('', 'frameheight', 0);
582 _framecount := cfg.ReadInt('', 'framecount', 0);
583 _speed := cfg.ReadInt('', 'waitcount', 0);
584 _backanimation := cfg.ReadBool('', 'backanimation', False);
586 cfg.Free();
587 cfg := nil;
589 // ×èòàåì ðåñóðñ òåêñòóð (êàäðîâ) àíèì. òåêñòóðû â ïàìÿòü:
590 if not WAD.GetResource('TEXTURES/'+TextureResource, TextureData, ResLength) then
591 begin
592 e_WriteLog(Format('Animated texture WAD file "%s" has no texture "%s"', [RecName, 'TEXTURES/'+TextureResource]), MSG_WARNING);
593 exit;
594 end;
596 WAD.Free();
597 WAD := nil;
599 SetLength(Textures, Length(Textures)+1);
600 with Textures[High(Textures)] do
601 begin
602 // Ñîçäàåì êàäðû àíèì. òåêñòóðû èç ïàìÿòè:
603 if g_Frames_CreateMemory(@FramesID, '', TextureData, ResLength, _width, _height, _framecount, _backanimation) then
604 begin
605 TextureName := RecName;
606 Width := _width;
607 Height := _height;
608 Anim := True;
609 FramesCount := _framecount;
610 Speed := _speed;
611 result := High(Textures);
612 end
613 else
614 begin
615 if log then e_WriteLog(Format('Error loading animation texture %s', [RecName]), MSG_WARNING);
616 end;
617 end;
618 end
619 else
620 begin
621 // try animated image
623 imgfmt := DetermineMemoryFormat(TextureWAD, ResLength);
624 if length(imgfmt) = 0 then
625 begin
626 e_WriteLog(Format('Animated texture file "%s" has unknown format', [RecName]), MSG_WARNING);
627 exit;
628 end;
630 GlobalMetadata.ClearMetaItems();
631 GlobalMetadata.ClearMetaItemsForSaving();
632 if not LoadMultiImageFromMemory(TextureWAD, ResLength, ia) then
633 begin
634 e_WriteLog(Format('Animated texture file "%s" cannot be loaded', [RecName]), MSG_WARNING);
635 exit;
636 end;
637 if length(ia) = 0 then
638 begin
639 e_WriteLog(Format('Animated texture file "%s" has no frames', [RecName]), MSG_WARNING);
640 exit;
641 end;
643 WAD.Free();
644 WAD := nil;
646 _width := ia[0].width;
647 _height := ia[0].height;
648 _framecount := length(ia);
649 _speed := 1;
650 _backanimation := false;
651 frdelay := -1;
652 frloop := -666;
653 if GlobalMetadata.HasMetaItem(SMetaFrameDelay) then
654 begin
655 //writeln(' frame delay: ', GlobalMetadata.MetaItems[SMetaFrameDelay]);
656 try
657 f := GlobalMetadata.MetaItems[SMetaFrameDelay];
658 frdelay := f;
659 if f < 0 then f := 0;
660 // rounding ;-)
661 c := f mod 28;
662 if c < 13 then c := 0 else c := 1;
663 f := (f div 28)+c;
664 if f < 1 then f := 1 else if f > 255 then f := 255;
665 _speed := f;
666 except
667 end;
668 end;
669 if GlobalMetadata.HasMetaItem(SMetaAnimationLoops) then
670 begin
671 //writeln(' frame loop : ', GlobalMetadata.MetaItems[SMetaAnimationLoops]);
672 try
673 f := GlobalMetadata.MetaItems[SMetaAnimationLoops];
674 frloop := f;
675 if f <> 0 then _backanimation := true; // non-infinite looping == forth-and-back
676 except
677 end;
678 end;
679 //writeln(' creating animated texture with ', length(ia), ' frames (delay:', _speed, '; backloop:', _backanimation, ') from "', RecName, '"...');
680 //for f := 0 to high(ia) do writeln(' frame #', f, ': ', ia[f].width, 'x', ia[f].height);
681 f := ord(_backanimation);
682 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);
684 SetLength(Textures, Length(Textures)+1);
685 // cîçäàåì êàäðû àíèì. òåêñòóðû èç êàðòèíîê
686 if g_CreateFramesImg(ia, @Textures[High(Textures)].FramesID, '', _backanimation) then
687 begin
688 Textures[High(Textures)].TextureName := RecName;
689 Textures[High(Textures)].Width := _width;
690 Textures[High(Textures)].Height := _height;
691 Textures[High(Textures)].Anim := True;
692 Textures[High(Textures)].FramesCount := length(ia);
693 Textures[High(Textures)].Speed := _speed;
694 result := High(Textures);
695 //writeln(' CREATED!');
696 end
697 else
698 begin
699 if log then e_WriteLog(Format('Error loading animation texture "%s" images', [RecName]), MSG_WARNING);
700 end;
701 end;
702 finally
703 for f := 0 to High(ia) do FreeImage(ia[f]);
704 WAD.Free();
705 cfg.Free();
706 if TextureWAD <> nil then FreeMem(TextureWAD);
707 if TextData <> nil then FreeMem(TextData);
708 if TextureData <> nil then FreeMem(TextureData);
709 end;
710 end;
712 procedure CreateItem(Item: TItemRec_1);
713 begin
714 if g_Game_IsClient then Exit;
716 if (not (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF])) and
717 ByteBool(Item.Options and ITEM_OPTION_ONLYDM) then
718 Exit;
720 g_Items_Create(Item.X, Item.Y, Item.ItemType, ByteBool(Item.Options and ITEM_OPTION_FALL),
721 gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
722 end;
724 procedure CreateArea(Area: TAreaRec_1);
725 var
726 a: Integer;
727 id: DWORD;
728 begin
729 case Area.AreaType of
730 AREA_DMPOINT, AREA_PLAYERPOINT1, AREA_PLAYERPOINT2,
731 AREA_REDTEAMPOINT, AREA_BLUETEAMPOINT:
732 begin
733 SetLength(RespawnPoints, Length(RespawnPoints)+1);
734 with RespawnPoints[High(RespawnPoints)] do
735 begin
736 X := Area.X;
737 Y := Area.Y;
738 Direction := TDirection(Area.Direction);
740 case Area.AreaType of
741 AREA_DMPOINT: PointType := RESPAWNPOINT_DM;
742 AREA_PLAYERPOINT1: PointType := RESPAWNPOINT_PLAYER1;
743 AREA_PLAYERPOINT2: PointType := RESPAWNPOINT_PLAYER2;
744 AREA_REDTEAMPOINT: PointType := RESPAWNPOINT_RED;
745 AREA_BLUETEAMPOINT: PointType := RESPAWNPOINT_BLUE;
746 end;
747 end;
748 end;
750 AREA_REDFLAG, AREA_BLUEFLAG:
751 begin
752 if Area.AreaType = AREA_REDFLAG then a := FLAG_RED else a := FLAG_BLUE;
754 if FlagPoints[a] <> nil then Exit;
756 New(FlagPoints[a]);
758 with FlagPoints[a]^ do
759 begin
760 X := Area.X-FLAGRECT.X;
761 Y := Area.Y-FLAGRECT.Y;
762 Direction := TDirection(Area.Direction);
763 end;
765 with gFlags[a] do
766 begin
767 case a of
768 FLAG_RED: g_Frames_Get(id, 'FRAMES_FLAG_RED');
769 FLAG_BLUE: g_Frames_Get(id, 'FRAMES_FLAG_BLUE');
770 end;
772 Animation := TAnimation.Create(id, True, 8);
773 Obj.Rect := FLAGRECT;
775 g_Map_ResetFlag(a);
776 end;
777 end;
779 AREA_DOMFLAG:
780 begin
781 {SetLength(DOMFlagPoints, Length(DOMFlagPoints)+1);
782 with DOMFlagPoints[High(DOMFlagPoints)] do
783 begin
784 X := Area.X;
785 Y := Area.Y;
786 Direction := TDirection(Area.Direction);
787 end;
789 g_Map_CreateFlag(DOMFlagPoints[High(DOMFlagPoints)], FLAG_DOM, FLAG_STATE_NORMAL);}
790 end;
791 end;
792 end;
794 procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
795 var
796 _trigger: TTrigger;
797 begin
798 if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
800 with _trigger do
801 begin
802 X := Trigger.X;
803 Y := Trigger.Y;
804 Width := Trigger.Width;
805 Height := Trigger.Height;
806 Enabled := ByteBool(Trigger.Enabled);
807 TexturePanel := Trigger.TexturePanel;
808 TexturePanelType := fTexturePanel1Type;
809 ShotPanelType := fTexturePanel2Type;
810 TriggerType := Trigger.TriggerType;
811 ActivateType := Trigger.ActivateType;
812 Keys := Trigger.Keys;
813 Data.Default := Trigger.DATA;
814 end;
816 g_Triggers_Create(_trigger);
817 end;
819 procedure CreateMonster(monster: TMonsterRec_1);
820 var
821 a, i: Integer;
822 begin
823 if g_Game_IsClient then Exit;
825 if (gGameSettings.GameType = GT_SINGLE)
826 or LongBool(gGameSettings.Options and GAME_OPTION_MONSTERS) then
827 begin
828 i := g_Monsters_Create(monster.MonsterType, monster.X, monster.Y,
829 TDirection(monster.Direction));
831 if gTriggers <> nil then
832 for a := 0 to High(gTriggers) do
833 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
834 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
835 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
836 gMonsters[i].AddTrigger(a);
838 if monster.MonsterType <> MONSTER_BARREL then
839 Inc(gTotalMonsters);
840 end;
841 end;
843 procedure g_Map_ReAdd_DieTriggers();
844 var
845 i, a: Integer;
846 begin
847 if g_Game_IsClient then Exit;
849 for i := 0 to High(gMonsters) do
850 if gMonsters[i] <> nil then
851 begin
852 gMonsters[i].ClearTriggers();
854 for a := 0 to High(gTriggers) do
855 if gTriggers[a].TriggerType in [TRIGGER_PRESS,
856 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
857 if (gTriggers[a].Data.MonsterID-1) = gMonsters[i].StartID then
858 gMonsters[i].AddTrigger(a);
859 end;
860 end;
862 function extractWadName(resourceName: string): string;
863 var
864 posN: Integer;
865 begin
866 posN := Pos(':', resourceName);
867 if posN > 0 then
868 Result:= Copy(resourceName, 0, posN-1)
869 else
870 Result := '';
871 end;
873 procedure addResToExternalResList(res: string);
874 begin
875 res := extractWadName(res);
876 if (res <> '') and (gExternalResources.IndexOf(res) = -1) then
877 gExternalResources.Add(res);
878 end;
880 procedure generateExternalResourcesList(mapReader: TMapReader_1);
881 var
882 textures: TTexturesRec1Array;
883 mapHeader: TMapHeaderRec_1;
884 i: integer;
885 resFile: String = '';
886 begin
887 if gExternalResources = nil then
888 gExternalResources := TStringList.Create;
890 gExternalResources.Clear;
891 textures := mapReader.GetTextures();
892 for i := 0 to High(textures) do
893 begin
894 addResToExternalResList(resFile);
895 end;
897 textures := nil;
899 mapHeader := mapReader.GetMapHeader;
901 addResToExternalResList(mapHeader.MusicName);
902 addResToExternalResList(mapHeader.SkyName);
903 end;
905 function g_Map_Load(Res: String): Boolean;
906 const
907 DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
908 DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
909 var
910 WAD: TWADFile;
911 MapReader: TMapReader_1;
912 Header: TMapHeaderRec_1;
913 _textures: TTexturesRec1Array;
914 _texnummap: array of Integer; // `_textures` -> `Textures`
915 panels: TPanelsRec1Array;
916 items: TItemsRec1Array;
917 monsters: TMonsterRec1Array;
918 areas: TAreasRec1Array;
919 triggers: TTriggersRec1Array;
920 a, b, c, k: Integer;
921 PanelID: DWORD;
922 AddTextures: TAddTextureArray;
923 texture: TTextureRec_1;
924 TriggersTable: Array of record
925 TexturePanel: Integer;
926 LiftPanel: Integer;
927 DoorPanel: Integer;
928 ShotPanel: Integer;
929 end;
930 FileName, mapResName, s, TexName: String;
931 Data: Pointer;
932 Len: Integer;
933 ok, isAnim, trigRef: Boolean;
934 CurTex, ntn: Integer;
936 mapX0: Integer = $3fffffff;
937 mapY0: Integer = $3fffffff;
938 mapX1: Integer = -$3fffffff;
939 mapY1: Integer = -$3fffffff;
941 procedure fixMinMax (var panels: TPanelArray);
942 var
943 idx: Integer;
944 begin
945 for idx := 0 to High(panels) do
946 begin
947 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
948 if mapX0 > panels[idx].X then mapX0 := panels[idx].X;
949 if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y;
950 if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1;
951 if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1;
952 end;
953 end;
955 procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer);
956 var
957 idx: Integer;
958 begin
959 for idx := High(panels) downto 0 do
960 begin
961 gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
962 end;
963 end;
965 begin
966 gMapGrid.Free();
967 gMapGrid := nil;
969 Result := False;
970 gMapInfo.Map := Res;
971 TriggersTable := nil;
972 FillChar(texture, SizeOf(texture), 0);
974 sfsGCDisable(); // temporary disable removing of temporary volumes
975 try
976 // Çàãðóçêà WAD:
977 FileName := g_ExtractWadName(Res);
978 e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
979 g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
981 WAD := TWADFile.Create();
982 if not WAD.ReadFile(FileName) then
983 begin
984 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [FileName]));
985 WAD.Free();
986 Exit;
987 end;
988 //k8: why loader ignores path here?
989 mapResName := g_ExtractFileName(Res);
990 if not WAD.GetMapResource(mapResName, Data, Len) then
991 begin
992 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName]));
993 WAD.Free();
994 Exit;
995 end;
997 WAD.Free();
999 // Çàãðóçêà êàðòû:
1000 e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
1001 g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
1002 MapReader := TMapReader_1.Create();
1004 if not MapReader.LoadMap(Data) then
1005 begin
1006 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
1007 FreeMem(Data);
1008 MapReader.Free();
1009 Exit;
1010 end;
1012 FreeMem(Data);
1013 generateExternalResourcesList(MapReader);
1014 // Çàãðóçêà òåêñòóð:
1015 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
1016 _textures := MapReader.GetTextures();
1017 _texnummap := nil;
1019 // Äîáàâëåíèå òåêñòóð â Textures[]:
1020 if _textures <> nil then
1021 begin
1022 e_WriteLog(' Loading textures:', MSG_NOTIFY);
1023 g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
1024 SetLength(_texnummap, length(_textures));
1026 for a := 0 to High(_textures) do
1027 begin
1028 SetLength(s, 64);
1029 CopyMemory(@s[1], @_textures[a].Resource[0], 64);
1030 for b := 1 to Length(s) do
1031 if s[b] = #0 then
1032 begin
1033 SetLength(s, b-1);
1034 Break;
1035 end;
1036 e_WriteLog(Format(' Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
1037 //if g_Map_IsSpecialTexture(s) then e_WriteLog(' SPECIAL!', MSG_NOTIFY);
1038 // Àíèìèðîâàííàÿ òåêñòóðà:
1039 if ByteBool(_textures[a].Anim) then
1040 begin
1041 ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
1042 if ntn < 0 then
1043 begin
1044 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
1045 ntn := CreateNullTexture(_textures[a].Resource);
1046 end;
1047 end
1048 else // Îáû÷íàÿ òåêñòóðà:
1049 ntn := CreateTexture(_textures[a].Resource, FileName, True);
1050 if ntn < 0 then
1051 begin
1052 g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
1053 ntn := CreateNullTexture(_textures[a].Resource);
1054 end;
1056 _texnummap[a] := ntn; // fix texture number
1057 g_Game_StepLoading();
1058 end;
1059 end;
1061 // Çàãðóçêà òðèããåðîâ:
1062 gTriggerClientID := 0;
1063 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1064 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
1065 triggers := MapReader.GetTriggers();
1067 // Çàãðóçêà ïàíåëåé:
1068 e_WriteLog(' Loading panels...', MSG_NOTIFY);
1069 g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
1070 panels := MapReader.GetPanels();
1072 // check texture numbers for panels
1073 for a := 0 to High(panels) do
1074 begin
1075 if panels[a].TextureNum > High(_textures) then
1076 begin
1077 e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
1078 result := false;
1079 exit;
1080 end;
1081 panels[a].TextureNum := _texnummap[panels[a].TextureNum];
1082 end;
1084 // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
1085 if triggers <> nil then
1086 begin
1087 e_WriteLog(' Setting up trigger table...', MSG_NOTIFY);
1088 SetLength(TriggersTable, Length(triggers));
1089 g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
1091 for a := 0 to High(TriggersTable) do
1092 begin
1093 // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
1094 TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
1095 // Ëèôòû:
1096 if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
1097 TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
1098 else
1099 TriggersTable[a].LiftPanel := -1;
1100 // Äâåðè:
1101 if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
1102 TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
1103 TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
1104 TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
1105 else
1106 TriggersTable[a].DoorPanel := -1;
1107 // Òóðåëü:
1108 if triggers[a].TriggerType = TRIGGER_SHOT then
1109 TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
1110 else
1111 TriggersTable[a].ShotPanel := -1;
1113 g_Game_StepLoading();
1114 end;
1115 end;
1117 // Ñîçäàåì ïàíåëè:
1118 if panels <> nil then
1119 begin
1120 e_WriteLog(' Setting up trigger links...', MSG_NOTIFY);
1121 g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
1123 for a := 0 to High(panels) do
1124 begin
1125 SetLength(AddTextures, 0);
1126 trigRef := False;
1127 CurTex := -1;
1128 if _textures <> nil then
1129 begin
1130 texture := _textures[panels[a].TextureNum];
1131 ok := True;
1132 end
1133 else
1134 ok := False;
1136 if ok then
1137 begin
1138 // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
1139 // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
1140 ok := False;
1141 if (TriggersTable <> nil) and (_textures <> nil) then
1142 for b := 0 to High(TriggersTable) do
1143 if (TriggersTable[b].TexturePanel = a)
1144 or (TriggersTable[b].ShotPanel = a) then
1145 begin
1146 trigRef := True;
1147 ok := True;
1148 Break;
1149 end;
1150 end;
1152 if ok then
1153 begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
1154 SetLength(s, 64);
1155 CopyMemory(@s[1], @texture.Resource[0], 64);
1156 // Èçìåðÿåì äëèíó:
1157 Len := Length(s);
1158 for c := Len downto 1 do
1159 if s[c] <> #0 then
1160 begin
1161 Len := c;
1162 Break;
1163 end;
1164 SetLength(s, Len);
1166 // Ñïåö-òåêñòóðû çàïðåùåíû:
1167 if g_Map_IsSpecialTexture(s) then
1168 ok := False
1169 else
1170 // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
1171 ok := g_Texture_NumNameFindStart(s);
1173 // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
1174 // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
1175 if ok then
1176 begin
1177 k := NNF_NAME_BEFORE;
1178 // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
1179 while ok or (k = NNF_NAME_BEFORE) or
1180 (k = NNF_NAME_EQUALS) do
1181 begin
1182 k := g_Texture_NumNameFindNext(TexName);
1184 if (k = NNF_NAME_BEFORE) or
1185 (k = NNF_NAME_AFTER) then
1186 begin
1187 // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
1188 if ByteBool(texture.Anim) then
1189 begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
1190 isAnim := True;
1191 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1192 if not ok then
1193 begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
1194 isAnim := False;
1195 ok := CreateTexture(TexName, FileName, False) >= 0;
1196 end;
1197 end
1198 else
1199 begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
1200 isAnim := False;
1201 ok := CreateTexture(TexName, FileName, False) >= 0;
1202 if not ok then
1203 begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
1204 isAnim := True;
1205 ok := CreateAnimTexture(TexName, FileName, False) >= 0;
1206 end;
1207 end;
1209 // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
1210 if ok then
1211 begin
1212 for c := 0 to High(Textures) do
1213 if Textures[c].TextureName = TexName then
1214 begin
1215 SetLength(AddTextures, Length(AddTextures)+1);
1216 AddTextures[High(AddTextures)].Texture := c;
1217 AddTextures[High(AddTextures)].Anim := isAnim;
1218 Break;
1219 end;
1220 end;
1221 end
1222 else
1223 if k = NNF_NAME_EQUALS then
1224 begin
1225 // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
1226 SetLength(AddTextures, Length(AddTextures)+1);
1227 AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
1228 AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
1229 CurTex := High(AddTextures);
1230 ok := True;
1231 end
1232 else // NNF_NO_NAME
1233 ok := False;
1234 end; // while ok...
1236 ok := True;
1237 end; // if ok - åñòü ñìåæíûå òåêñòóðû
1238 end; // if ok - ññûëàþòñÿ òðèããåðû
1240 if not ok then
1241 begin
1242 // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
1243 SetLength(AddTextures, 1);
1244 AddTextures[0].Texture := panels[a].TextureNum;
1245 AddTextures[0].Anim := ByteBool(texture.Anim);
1246 CurTex := 0;
1247 end;
1249 //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);
1251 // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
1252 PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
1254 // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
1255 if TriggersTable <> nil then
1256 for b := 0 to High(TriggersTable) do
1257 begin
1258 // Òðèããåð äâåðè/ëèôòà:
1259 if (TriggersTable[b].LiftPanel = a) or
1260 (TriggersTable[b].DoorPanel = a) then
1261 TTriggerData(triggers[b].DATA).PanelID := PanelID;
1262 // Òðèããåð ñìåíû òåêñòóðû:
1263 if TriggersTable[b].TexturePanel = a then
1264 triggers[b].TexturePanel := PanelID;
1265 // Òðèããåð "Òóðåëü":
1266 if TriggersTable[b].ShotPanel = a then
1267 TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
1268 end;
1270 g_Game_StepLoading();
1271 end;
1272 end;
1274 // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
1275 if (triggers <> nil) and not gLoadGameMode then
1276 begin
1277 e_WriteLog(' Creating triggers...', MSG_NOTIFY);
1278 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
1279 // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
1280 for a := 0 to High(triggers) do
1281 begin
1282 if triggers[a].TexturePanel <> -1 then
1283 b := panels[TriggersTable[a].TexturePanel].PanelType
1284 else
1285 b := 0;
1286 if (triggers[a].TriggerType = TRIGGER_SHOT) and
1287 (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
1288 c := panels[TriggersTable[a].ShotPanel].PanelType
1289 else
1290 c := 0;
1291 CreateTrigger(triggers[a], b, c);
1292 end;
1293 end;
1295 // Çàãðóçêà ïðåäìåòîâ:
1296 e_WriteLog(' Loading triggers...', MSG_NOTIFY);
1297 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
1298 items := MapReader.GetItems();
1300 // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
1301 if (items <> nil) and not gLoadGameMode then
1302 begin
1303 e_WriteLog(' Spawning items...', MSG_NOTIFY);
1304 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
1305 for a := 0 to High(items) do
1306 CreateItem(Items[a]);
1307 end;
1309 // Çàãðóçêà îáëàñòåé:
1310 e_WriteLog(' Loading areas...', MSG_NOTIFY);
1311 g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
1312 areas := MapReader.GetAreas();
1314 // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
1315 if areas <> nil then
1316 begin
1317 e_WriteLog(' Creating areas...', MSG_NOTIFY);
1318 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
1319 for a := 0 to High(areas) do
1320 CreateArea(areas[a]);
1321 end;
1323 // Çàãðóçêà ìîíñòðîâ:
1324 e_WriteLog(' Loading monsters...', MSG_NOTIFY);
1325 g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
1326 monsters := MapReader.GetMonsters();
1328 gTotalMonsters := 0;
1330 // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
1331 if (monsters <> nil) and not gLoadGameMode then
1332 begin
1333 e_WriteLog(' Spawning monsters...', MSG_NOTIFY);
1334 g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
1335 for a := 0 to High(monsters) do
1336 CreateMonster(monsters[a]);
1337 end;
1339 // Çàãðóçêà îïèñàíèÿ êàðòû:
1340 e_WriteLog(' Reading map info...', MSG_NOTIFY);
1341 g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
1342 Header := MapReader.GetMapHeader();
1344 MapReader.Free();
1346 with gMapInfo do
1347 begin
1348 Name := Header.MapName;
1349 Description := Header.MapDescription;
1350 Author := Header.MapAuthor;
1351 MusicName := Header.MusicName;
1352 SkyName := Header.SkyName;
1353 Height := Header.Height;
1354 Width := Header.Width;
1355 end;
1357 // Çàãðóçêà íåáà:
1358 if gMapInfo.SkyName <> '' then
1359 begin
1360 e_WriteLog(' Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
1361 g_Game_SetLoadingText(_lc[I_LOAD_SKY], 0, False);
1362 FileName := g_ExtractWadName(gMapInfo.SkyName);
1364 if FileName <> '' then
1365 FileName := GameDir+'/wads/'+FileName
1366 else
1367 begin
1368 FileName := g_ExtractWadName(Res);
1369 end;
1371 s := FileName+':'+g_ExtractFilePathName(gMapInfo.SkyName);
1372 if g_Texture_CreateWAD(BackID, s) then
1373 begin
1374 g_Game_SetupScreenSize();
1375 end
1376 else
1377 g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
1378 end;
1380 // Çàãðóçêà ìóçûêè:
1381 ok := False;
1382 if gMapInfo.MusicName <> '' then
1383 begin
1384 e_WriteLog(' Loading music: ' + gMapInfo.MusicName, MSG_NOTIFY);
1385 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1386 FileName := g_ExtractWadName(gMapInfo.MusicName);
1388 if FileName <> '' then
1389 FileName := GameDir+'/wads/'+FileName
1390 else
1391 begin
1392 FileName := g_ExtractWadName(Res);
1393 end;
1395 s := FileName+':'+g_ExtractFilePathName(gMapInfo.MusicName);
1396 if g_Sound_CreateWADEx(gMapInfo.MusicName, s, True) then
1397 ok := True
1398 else
1399 g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
1400 end;
1402 // Îñòàëüíûå óñòàíâêè:
1403 CreateDoorMap();
1404 CreateLiftMap();
1406 g_Items_Init();
1407 g_Weapon_Init();
1408 g_Monsters_Init();
1410 // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
1411 if not gLoadGameMode then
1412 g_GFX_Init();
1414 // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
1415 _textures := nil;
1416 panels := nil;
1417 items := nil;
1418 areas := nil;
1419 triggers := nil;
1420 TriggersTable := nil;
1421 AddTextures := nil;
1423 // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
1424 if ok and (not gLoadGameMode) then
1425 begin
1426 gMusic.SetByName(gMapInfo.MusicName);
1427 gMusic.Play();
1428 end
1429 else
1430 gMusic.SetByName('');
1431 finally
1432 sfsGCEnable(); // enable releasing unused volumes
1433 end;
1435 e_WriteLog('Creating map grid', MSG_NOTIFY);
1437 fixMinMax(gWalls);
1438 fixMinMax(gRenderBackgrounds);
1439 fixMinMax(gRenderForegrounds);
1440 fixMinMax(gWater);
1441 fixMinMax(gAcid1);
1442 fixMinMax(gAcid2);
1443 fixMinMax(gSteps);
1445 gMapGrid := TBodyGrid.Create(mapX1+1, mapY1+1);
1447 addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR
1448 addPanelsToGrid(gRenderBackgrounds, PANEL_BACK);
1449 addPanelsToGrid(gRenderForegrounds, PANEL_FORE);
1450 addPanelsToGrid(gWater, PANEL_WATER);
1451 addPanelsToGrid(gAcid1, PANEL_ACID1);
1452 addPanelsToGrid(gAcid2, PANEL_ACID2);
1453 addPanelsToGrid(gSteps, PANEL_STEP);
1455 gMapGrid.dumpStats();
1457 e_WriteLog('Done loading map.', MSG_NOTIFY);
1458 Result := True;
1459 end;
1461 function g_Map_GetMapInfo(Res: String): TMapInfo;
1462 var
1463 WAD: TWADFile;
1464 MapReader: TMapReader_1;
1465 Header: TMapHeaderRec_1;
1466 FileName: String;
1467 Data: Pointer;
1468 Len: Integer;
1469 begin
1470 FillChar(Result, SizeOf(Result), 0);
1471 FileName := g_ExtractWadName(Res);
1473 WAD := TWADFile.Create();
1474 if not WAD.ReadFile(FileName) then
1475 begin
1476 WAD.Free();
1477 Exit;
1478 end;
1480 //k8: it ignores path again
1481 if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then
1482 begin
1483 WAD.Free();
1484 Exit;
1485 end;
1487 WAD.Free();
1489 MapReader := TMapReader_1.Create();
1491 if not MapReader.LoadMap(Data) then
1492 begin
1493 g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
1494 ZeroMemory(@Header, SizeOf(Header));
1495 Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
1496 Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
1497 end
1498 else
1499 begin
1500 Header := MapReader.GetMapHeader();
1501 Result.Name := Header.MapName;
1502 Result.Description := Header.MapDescription;
1503 end;
1505 FreeMem(Data);
1506 MapReader.Free();
1508 Result.Map := Res;
1509 Result.Author := Header.MapAuthor;
1510 Result.Height := Header.Height;
1511 Result.Width := Header.Width;
1512 end;
1514 function g_Map_GetMapsList(WADName: string): SArray;
1515 var
1516 WAD: TWADFile;
1517 a: Integer;
1518 ResList: SArray;
1519 begin
1520 Result := nil;
1521 WAD := TWADFile.Create();
1522 if not WAD.ReadFile(WADName) then
1523 begin
1524 WAD.Free();
1525 Exit;
1526 end;
1527 ResList := WAD.GetMapResources();
1528 if ResList <> nil then
1529 begin
1530 for a := 0 to High(ResList) do
1531 begin
1532 SetLength(Result, Length(Result)+1);
1533 Result[High(Result)] := ResList[a];
1534 end;
1535 end;
1536 WAD.Free();
1537 end;
1539 function g_Map_Exist(Res: string): Boolean;
1540 var
1541 WAD: TWADFile;
1542 FileName, mnn: string;
1543 ResList: SArray;
1544 a: Integer;
1545 begin
1546 Result := False;
1548 FileName := addWadExtension(g_ExtractWadName(Res));
1550 WAD := TWADFile.Create;
1551 if not WAD.ReadFile(FileName) then
1552 begin
1553 WAD.Free();
1554 Exit;
1555 end;
1557 ResList := WAD.GetMapResources();
1558 WAD.Free();
1560 mnn := g_ExtractFileName(Res);
1561 if ResList <> nil then
1562 for a := 0 to High(ResList) do if StrEquCI1251(ResList[a], mnn) then
1563 begin
1564 Result := True;
1565 Exit;
1566 end;
1567 end;
1569 procedure g_Map_Free();
1570 var
1571 a: Integer;
1573 procedure FreePanelArray(var panels: TPanelArray);
1574 var
1575 i: Integer;
1577 begin
1578 if panels <> nil then
1579 begin
1580 for i := 0 to High(panels) do
1581 panels[i].Free();
1582 panels := nil;
1583 end;
1584 end;
1586 begin
1587 g_GFX_Free();
1588 g_Weapon_Free();
1589 g_Items_Free();
1590 g_Triggers_Free();
1591 g_Monsters_Free();
1593 RespawnPoints := nil;
1594 if FlagPoints[FLAG_RED] <> nil then
1595 begin
1596 Dispose(FlagPoints[FLAG_RED]);
1597 FlagPoints[FLAG_RED] := nil;
1598 end;
1599 if FlagPoints[FLAG_BLUE] <> nil then
1600 begin
1601 Dispose(FlagPoints[FLAG_BLUE]);
1602 FlagPoints[FLAG_BLUE] := nil;
1603 end;
1604 //DOMFlagPoints := nil;
1606 //gDOMFlags := nil;
1608 if Textures <> nil then
1609 begin
1610 for a := 0 to High(Textures) do
1611 if not g_Map_IsSpecialTexture(Textures[a].TextureName) then
1612 if Textures[a].Anim then
1613 g_Frames_DeleteByID(Textures[a].FramesID)
1614 else
1615 if Textures[a].TextureID <> TEXTURE_NONE then
1616 e_DeleteTexture(Textures[a].TextureID);
1618 Textures := nil;
1619 end;
1621 FreePanelArray(gWalls);
1622 FreePanelArray(gRenderBackgrounds);
1623 FreePanelArray(gRenderForegrounds);
1624 FreePanelArray(gWater);
1625 FreePanelArray(gAcid1);
1626 FreePanelArray(gAcid2);
1627 FreePanelArray(gSteps);
1628 FreePanelArray(gLifts);
1629 FreePanelArray(gBlockMon);
1631 if BackID <> DWORD(-1) then
1632 begin
1633 gBackSize.X := 0;
1634 gBackSize.Y := 0;
1635 e_DeleteTexture(BackID);
1636 BackID := DWORD(-1);
1637 end;
1639 g_Game_StopAllSounds(False);
1640 gMusic.FreeSound();
1641 g_Sound_Delete(gMapInfo.MusicName);
1643 gMapInfo.Name := '';
1644 gMapInfo.Description := '';
1645 gMapInfo.MusicName := '';
1646 gMapInfo.Height := 0;
1647 gMapInfo.Width := 0;
1649 gDoorMap := nil;
1650 gLiftMap := nil;
1652 PanelByID := nil;
1653 end;
1655 procedure g_Map_Update();
1656 var
1657 a, d, j: Integer;
1658 m: Word;
1659 s: String;
1661 procedure UpdatePanelArray(var panels: TPanelArray);
1662 var
1663 i: Integer;
1665 begin
1666 if panels <> nil then
1667 for i := 0 to High(panels) do
1668 panels[i].Update();
1669 end;
1671 begin
1672 UpdatePanelArray(gWalls);
1673 UpdatePanelArray(gRenderBackgrounds);
1674 UpdatePanelArray(gRenderForegrounds);
1675 UpdatePanelArray(gWater);
1676 UpdatePanelArray(gAcid1);
1677 UpdatePanelArray(gAcid2);
1678 UpdatePanelArray(gSteps);
1680 if gGameSettings.GameMode = GM_CTF then
1681 begin
1682 for a := FLAG_RED to FLAG_BLUE do
1683 if not (gFlags[a].State in [FLAG_STATE_NONE, FLAG_STATE_CAPTURED]) then
1684 with gFlags[a] do
1685 begin
1686 if gFlags[a].Animation <> nil then
1687 gFlags[a].Animation.Update();
1689 m := g_Obj_Move(@Obj, True, True);
1691 if gTime mod (GAME_TICK*2) <> 0 then
1692 Continue;
1694 // Ñîïðîòèâëåíèå âîçäóõà:
1695 Obj.Vel.X := z_dec(Obj.Vel.X, 1);
1697 // Òàéìàóò ïîòåðÿííîãî ôëàãà, ëèáî îí âûïàë çà êàðòó:
1698 if ((Count = 0) or ByteBool(m and MOVE_FALLOUT)) and g_Game_IsServer then
1699 begin
1700 g_Map_ResetFlag(a);
1701 gFlags[a].CaptureTime := 0;
1702 if a = FLAG_RED then
1703 s := _lc[I_PLAYER_FLAG_RED]
1704 else
1705 s := _lc[I_PLAYER_FLAG_BLUE];
1706 g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
1708 if g_Game_IsNet then
1709 MH_SEND_FlagEvent(FLAG_STATE_RETURNED, a, 0);
1710 Continue;
1711 end;
1713 if Count > 0 then
1714 Count := Count - 1;
1716 // Èãðîê áåðåò ôëàã:
1717 if gPlayers <> nil then
1718 begin
1719 j := Random(Length(gPlayers)) - 1;
1721 for d := 0 to High(gPlayers) do
1722 begin
1723 Inc(j);
1724 if j > High(gPlayers) then
1725 j := 0;
1727 if gPlayers[j] <> nil then
1728 if gPlayers[j].Live and
1729 g_Obj_Collide(@Obj, @gPlayers[j].Obj) then
1730 begin
1731 if gPlayers[j].GetFlag(a) then
1732 Break;
1733 end;
1734 end;
1735 end;
1736 end;
1737 end;
1738 end;
1742 function pvpType (panelType: Word): Integer;
1743 begin
1744 case panelType of
1745 PANEL_WALL, PANEL_CLOSEDOOR: result := 0; // gWalls
1746 PANEL_BACK: result := 1; // gRenderBackgrounds
1747 PANEL_FORE: result := 2; // gRenderForegrounds
1748 PANEL_WATER: result := 3; // gWater
1749 PANEL_ACID1: result := 4; // gAcid1
1750 PANEL_ACID2: result := 5; // gAcid2
1751 PANEL_STEP: result := 6; // gSteps
1752 else result := -1;
1753 end;
1754 end;
1758 procedure g_Map_DrawPanelsOld(PanelType: Word);
1760 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1761 var
1762 idx: Integer;
1763 begin
1764 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1765 begin
1766 // alas, no visible set
1767 for idx := 0 to High(panels) do
1768 begin
1769 if not (drawDoors xor panels[idx].Door) then panels[idx].Draw();
1770 end;
1771 end;
1772 end;
1774 begin
1775 case PanelType of
1776 PANEL_WALL: DrawPanels(0, gWalls);
1777 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1778 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1779 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1780 PANEL_WATER: DrawPanels(3, gWater);
1781 PANEL_ACID1: DrawPanels(4, gAcid1);
1782 PANEL_ACID2: DrawPanels(5, gAcid2);
1783 PANEL_STEP: DrawPanels(6, gSteps);
1784 end;
1785 end;
1788 var
1789 gDrawPanelList: TBinaryHeapObj = nil;
1791 function dplLess (a, b: TObject): Boolean;
1792 begin
1793 result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx);
1794 end;
1796 procedure dplClear ();
1797 begin
1798 if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear();
1799 end;
1801 procedure dplAddPanel (pan: TPanel);
1802 begin
1803 if pan = nil then exit;
1804 gDrawPanelList.insert(pan);
1805 end;
1808 procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word);
1810 function qq (obj: TObject; tag: Integer): Boolean;
1811 var
1812 pan: TPanel;
1813 begin
1814 result := false; // don't stop, ever
1816 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1818 if obj = nil then
1819 begin
1820 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1821 end;
1822 if not (obj is TPanel) then
1823 begin
1824 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
1825 exit;
1826 end;
1827 //pan := (obj as TPanel);
1828 //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
1830 if (tag = PANEL_WALL) then
1831 begin
1832 if (PanelType = PANEL_WALL) then
1833 begin
1834 pan := (obj as TPanel);
1835 if not pan.Door then
1836 begin
1837 //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);
1838 dplAddPanel(pan);
1839 end;
1840 end
1841 else if (PanelType = PANEL_CLOSEDOOR) then
1842 begin
1843 pan := (obj as TPanel);
1844 if pan.Door then
1845 begin
1846 //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);
1847 dplAddPanel(pan);
1848 end;
1849 end
1850 end
1851 else if (PanelType = tag) then
1852 begin
1853 pan := (obj as TPanel);
1854 if not pan.Door then
1855 begin
1856 //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);
1857 dplAddPanel(pan);
1858 end;
1859 end;
1860 end;
1862 procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
1863 var
1864 idx: Integer;
1865 pan: TPanel;
1866 begin
1867 if (panels <> nil) and (stp >= 0) and (stp <= 6) then
1868 begin
1869 // alas, no visible set
1870 for idx := 0 to High(panels) do
1871 begin
1872 if not (drawDoors xor panels[idx].Door) then
1873 begin
1874 pan := panels[idx];
1875 if (pan.Width < 1) or (pan.Height < 1) then continue;
1876 if (pan.X+pan.Width <= x0) or (pan.Y+pan.Height <= y0) then continue;
1877 if (pan.X >= x0+wdt) or (pan.Y >= y0+hgt) then continue;
1878 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);
1879 end;
1880 end;
1881 end;
1882 end;
1884 begin
1885 //g_Map_DrawPanelsOld(PanelType); exit;
1886 //e_WriteLog('==================', MSG_NOTIFY);
1887 //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1888 dplClear();
1889 gMapGrid.forEachInAABB(x0, y0, wdt, hgt, qq);
1891 // debug
1893 e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY);
1894 case PanelType of
1895 PANEL_WALL: DrawPanels(0, gWalls);
1896 PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True);
1897 PANEL_BACK: DrawPanels(1, gRenderBackgrounds);
1898 PANEL_FORE: DrawPanels(2, gRenderForegrounds);
1899 PANEL_WATER: DrawPanels(3, gWater);
1900 PANEL_ACID1: DrawPanels(4, gAcid1);
1901 PANEL_ACID2: DrawPanels(5, gAcid2);
1902 PANEL_STEP: DrawPanels(6, gSteps);
1903 end;
1904 e_WriteLog('==================', MSG_NOTIFY);
1907 // sort and draw the list (we need to sort it, or rendering is fucked)
1908 while gDrawPanelList.count > 0 do
1909 begin
1910 (gDrawPanelList.front() as TPanel).Draw();
1911 gDrawPanelList.popFront();
1912 end;
1913 end;
1915 var
1916 plpset: array of Integer = nil; // potentially lit panels
1917 plpcount: Integer; // to avoid constant reallocations
1919 function g_Map_BuildPLP (ltminx, ltminy, ltmaxx, ltmaxy: Integer): Boolean;
1920 var
1921 idx: Integer;
1922 panels: TPanelArray;
1923 begin
1924 panels := gWalls;
1925 plpcount := 0;
1926 if (ltminx < ltmaxx) and (ltminy < ltmaxy) then
1927 begin
1928 if panels <> nil then
1929 begin
1930 for idx := 0 to High(panels) do
1931 begin
1932 if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue;
1933 if (panels[idx].X+panels[idx].Width <= ltminx) then continue;
1934 if (panels[idx].Y+panels[idx].Height <= ltminy) then continue;
1935 if (panels[idx].X > ltmaxx) then continue;
1936 if (panels[idx].Y > ltmaxy) then continue;
1937 if plpcount = length(plpset) then SetLength(plpset, plpcount+32768);
1938 plpset[plpcount] := idx;
1939 Inc(plpcount);
1940 end;
1941 //e_WriteLog(Format('%d panels left out of %d', [plpcount, Length(panels)]), MSG_NOTIFY);
1942 end;
1943 end;
1944 result := (plpcount > 0);
1945 end;
1947 procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer);
1949 (* old
1950 procedure drawPanels (var panels: TPanelArray);
1951 var
1952 a: Integer;
1953 begin
1954 if panels <> nil then
1955 begin
1956 for a := 0 to High(panels) do
1957 begin
1958 panels[a].DrawShadowVolume(lightX, lightY, radius);
1959 end;
1960 end;
1961 end;
1962 *)
1963 var
1964 idx: Integer;
1965 begin
1966 (*
1967 drawPanels(gWalls);
1968 //drawPanels(gRenderForegrounds);
1969 *)
1970 for idx := 0 to plpcount-1 do
1971 begin
1972 gWalls[plpset[idx]].DrawShadowVolume(lightX, lightY, radius);
1973 end;
1974 end;
1976 procedure g_Map_DrawBack(dx, dy: Integer);
1977 begin
1978 if gDrawBackGround and (BackID <> DWORD(-1)) then
1979 e_DrawSize(BackID, dx, dy, 0, False, False, gBackSize.X, gBackSize.Y)
1980 else
1981 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
1982 end;
1984 function g_Map_CollidePanelOld(X, Y: Integer; Width, Height: Word;
1985 PanelType: Word; b1x3: Boolean): Boolean;
1986 var
1987 a, h: Integer;
1988 begin
1989 Result := False;
1991 if WordBool(PanelType and PANEL_WALL) then
1992 if gWalls <> nil then
1993 begin
1994 h := High(gWalls);
1996 for a := 0 to h do
1997 if gWalls[a].Enabled and
1998 g_Collide(X, Y, Width, Height,
1999 gWalls[a].X, gWalls[a].Y,
2000 gWalls[a].Width, gWalls[a].Height) then
2001 begin
2002 Result := True;
2003 Exit;
2004 end;
2005 end;
2007 if WordBool(PanelType and PANEL_WATER) then
2008 if gWater <> nil then
2009 begin
2010 h := High(gWater);
2012 for a := 0 to h do
2013 if g_Collide(X, Y, Width, Height,
2014 gWater[a].X, gWater[a].Y,
2015 gWater[a].Width, gWater[a].Height) then
2016 begin
2017 Result := True;
2018 Exit;
2019 end;
2020 end;
2022 if WordBool(PanelType and PANEL_ACID1) then
2023 if gAcid1 <> nil then
2024 begin
2025 h := High(gAcid1);
2027 for a := 0 to h do
2028 if g_Collide(X, Y, Width, Height,
2029 gAcid1[a].X, gAcid1[a].Y,
2030 gAcid1[a].Width, gAcid1[a].Height) then
2031 begin
2032 Result := True;
2033 Exit;
2034 end;
2035 end;
2037 if WordBool(PanelType and PANEL_ACID2) then
2038 if gAcid2 <> nil then
2039 begin
2040 h := High(gAcid2);
2042 for a := 0 to h do
2043 if g_Collide(X, Y, Width, Height,
2044 gAcid2[a].X, gAcid2[a].Y,
2045 gAcid2[a].Width, gAcid2[a].Height) then
2046 begin
2047 Result := True;
2048 Exit;
2049 end;
2050 end;
2052 if WordBool(PanelType and PANEL_STEP) then
2053 if gSteps <> nil then
2054 begin
2055 h := High(gSteps);
2057 for a := 0 to h do
2058 if g_Collide(X, Y, Width, Height,
2059 gSteps[a].X, gSteps[a].Y,
2060 gSteps[a].Width, gSteps[a].Height) then
2061 begin
2062 Result := True;
2063 Exit;
2064 end;
2065 end;
2067 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
2068 if gLifts <> nil then
2069 begin
2070 h := High(gLifts);
2072 for a := 0 to h do
2073 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2074 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2075 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2076 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2077 g_Collide(X, Y, Width, Height,
2078 gLifts[a].X, gLifts[a].Y,
2079 gLifts[a].Width, gLifts[a].Height) then
2080 begin
2081 Result := True;
2082 Exit;
2083 end;
2084 end;
2086 if WordBool(PanelType and PANEL_BLOCKMON) then
2087 if gBlockMon <> nil then
2088 begin
2089 h := High(gBlockMon);
2091 for a := 0 to h do
2092 if ( (not b1x3) or
2093 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2094 g_Collide(X, Y, Width, Height,
2095 gBlockMon[a].X, gBlockMon[a].Y,
2096 gBlockMon[a].Width, gBlockMon[a].Height) then
2097 begin
2098 Result := True;
2099 Exit;
2100 end;
2101 end;
2102 end;
2104 function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean;
2106 function qq (obj: TObject; tag: Integer): Boolean;
2107 var
2108 pan: TPanel;
2109 a: Integer;
2110 begin
2111 result := false; // don't stop, ever
2113 //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2115 if obj = nil then
2116 begin
2117 e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2118 end;
2119 if not (obj is TPanel) then
2120 begin
2121 e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
2122 exit;
2123 end;
2125 pan := (obj as TPanel);
2126 a := pan.ArrIdx;
2128 if WordBool(PanelType and PANEL_WALL) and WordBool(tag and PANEL_WALL) then
2129 begin
2130 if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then
2131 begin
2132 result := true;
2133 exit;
2134 end;
2135 end;
2137 if WordBool(PanelType and PANEL_WATER) and WordBool(tag and PANEL_WATER) then
2138 begin
2139 if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then
2140 begin
2141 result := True;
2142 exit;
2143 end;
2144 end;
2146 if WordBool(PanelType and PANEL_ACID1) and WordBool(tag and PANEL_ACID1) then
2147 begin
2148 if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then
2149 begin
2150 result := True;
2151 exit;
2152 end;
2153 end;
2155 if WordBool(PanelType and PANEL_ACID2) and WordBool(tag and PANEL_ACID2) then
2156 begin
2157 if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then
2158 begin
2159 result := True;
2160 exit;
2161 end;
2162 end;
2164 if WordBool(PanelType and PANEL_STEP) and WordBool(tag and PANEL_STEP) then
2165 begin
2166 if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then
2167 begin
2168 result := True;
2169 exit;
2170 end;
2171 end;
2172 end;
2174 var
2175 a, h: Integer;
2176 begin
2177 result := gMapGrid.forEachInAABB(X, Y, Width, Height, qq);
2178 if not result then
2179 begin
2180 if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (gLifts <> nil) then
2181 begin
2182 h := High(gLifts);
2183 for a := 0 to h do
2184 begin
2185 if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or
2186 (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or
2187 (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or
2188 (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and
2189 g_Collide(X, Y, Width, Height,
2190 gLifts[a].X, gLifts[a].Y,
2191 gLifts[a].Width, gLifts[a].Height) then
2192 begin
2193 Result := True;
2194 Exit;
2195 end;
2196 end;
2197 end;
2199 if WordBool(PanelType and PANEL_BLOCKMON) and (gBlockMon <> nil) then
2200 begin
2201 h := High(gBlockMon);
2202 for a := 0 to h do
2203 begin
2204 if ( (not b1x3) or
2205 ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and
2206 g_Collide(X, Y, Width, Height,
2207 gBlockMon[a].X, gBlockMon[a].Y,
2208 gBlockMon[a].Width, gBlockMon[a].Height) then
2209 begin
2210 Result := True;
2211 Exit;
2212 end;
2213 end;
2214 end;
2215 end;
2216 end;
2219 function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD;
2220 var
2221 a, h: Integer;
2222 begin
2223 Result := TEXTURE_NONE;
2225 if gWater <> nil then
2226 begin
2227 h := High(gWater);
2229 for a := 0 to h do
2230 if g_Collide(X, Y, Width, Height,
2231 gWater[a].X, gWater[a].Y,
2232 gWater[a].Width, gWater[a].Height) then
2233 begin
2234 Result := gWater[a].GetTextureID();
2235 Exit;
2236 end;
2237 end;
2239 if gAcid1 <> nil then
2240 begin
2241 h := High(gAcid1);
2243 for a := 0 to h do
2244 if g_Collide(X, Y, Width, Height,
2245 gAcid1[a].X, gAcid1[a].Y,
2246 gAcid1[a].Width, gAcid1[a].Height) then
2247 begin
2248 Result := gAcid1[a].GetTextureID();
2249 Exit;
2250 end;
2251 end;
2253 if gAcid2 <> nil then
2254 begin
2255 h := High(gAcid2);
2257 for a := 0 to h do
2258 if g_Collide(X, Y, Width, Height,
2259 gAcid2[a].X, gAcid2[a].Y,
2260 gAcid2[a].Width, gAcid2[a].Height) then
2261 begin
2262 Result := gAcid2[a].GetTextureID();
2263 Exit;
2264 end;
2265 end;
2266 end;
2268 procedure g_Map_EnableWall(ID: DWORD);
2269 begin
2270 with gWalls[ID] do
2271 begin
2272 Enabled := True;
2273 g_Mark(X, Y, Width, Height, MARK_DOOR, True);
2275 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2276 end;
2277 end;
2279 procedure g_Map_DisableWall(ID: DWORD);
2280 begin
2281 with gWalls[ID] do
2282 begin
2283 Enabled := False;
2284 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
2286 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2287 end;
2288 end;
2290 procedure g_Map_SwitchTexture(PanelType: Word; ID: DWORD; AnimLoop: Byte = 0);
2291 var
2292 tp: TPanel;
2293 begin
2294 case PanelType of
2295 PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2296 tp := gWalls[ID];
2297 PANEL_FORE:
2298 tp := gRenderForegrounds[ID];
2299 PANEL_BACK:
2300 tp := gRenderBackgrounds[ID];
2301 PANEL_WATER:
2302 tp := gWater[ID];
2303 PANEL_ACID1:
2304 tp := gAcid1[ID];
2305 PANEL_ACID2:
2306 tp := gAcid2[ID];
2307 PANEL_STEP:
2308 tp := gSteps[ID];
2309 else
2310 Exit;
2311 end;
2313 tp.NextTexture(AnimLoop);
2314 if g_Game_IsServer and g_Game_IsNet then
2315 MH_SEND_PanelTexture(PanelType, ID, AnimLoop);
2316 end;
2318 procedure g_Map_SetLift(ID: DWORD; t: Integer);
2319 begin
2320 if gLifts[ID].LiftType = t then
2321 Exit;
2323 with gLifts[ID] do
2324 begin
2325 LiftType := t;
2327 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
2329 if LiftType = 0 then
2330 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
2331 else if LiftType = 1 then
2332 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
2333 else if LiftType = 2 then
2334 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
2335 else if LiftType = 3 then
2336 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True);
2338 if g_Game_IsServer and g_Game_IsNet then MH_SEND_PanelState(PanelType, ID);
2339 end;
2340 end;
2342 function g_Map_GetPoint(PointType: Byte; var RespawnPoint: TRespawnPoint): Boolean;
2343 var
2344 a: Integer;
2345 PointsArray: Array of TRespawnPoint;
2346 begin
2347 Result := False;
2348 SetLength(PointsArray, 0);
2350 if RespawnPoints = nil then
2351 Exit;
2353 for a := 0 to High(RespawnPoints) do
2354 if RespawnPoints[a].PointType = PointType then
2355 begin
2356 SetLength(PointsArray, Length(PointsArray)+1);
2357 PointsArray[High(PointsArray)] := RespawnPoints[a];
2358 end;
2360 if PointsArray = nil then
2361 Exit;
2363 RespawnPoint := PointsArray[Random(Length(PointsArray))];
2364 Result := True;
2365 end;
2367 function g_Map_GetPointCount(PointType: Byte): Word;
2368 var
2369 a: Integer;
2370 begin
2371 Result := 0;
2373 if RespawnPoints = nil then
2374 Exit;
2376 for a := 0 to High(RespawnPoints) do
2377 if RespawnPoints[a].PointType = PointType then
2378 Result := Result + 1;
2379 end;
2381 function g_Map_HaveFlagPoints(): Boolean;
2382 begin
2383 Result := (FlagPoints[FLAG_RED] <> nil) and (FlagPoints[FLAG_BLUE] <> nil);
2384 end;
2386 procedure g_Map_ResetFlag(Flag: Byte);
2387 begin
2388 with gFlags[Flag] do
2389 begin
2390 Obj.X := -1000;
2391 Obj.Y := -1000;
2392 Obj.Vel.X := 0;
2393 Obj.Vel.Y := 0;
2394 Direction := D_LEFT;
2395 State := FLAG_STATE_NONE;
2396 if FlagPoints[Flag] <> nil then
2397 begin
2398 Obj.X := FlagPoints[Flag]^.X;
2399 Obj.Y := FlagPoints[Flag]^.Y;
2400 Direction := FlagPoints[Flag]^.Direction;
2401 State := FLAG_STATE_NORMAL;
2402 end;
2403 Count := -1;
2404 end;
2405 end;
2407 procedure g_Map_DrawFlags();
2408 var
2409 i, dx: Integer;
2410 Mirror: TMirrorType;
2411 begin
2412 if gGameSettings.GameMode <> GM_CTF then
2413 Exit;
2415 for i := FLAG_RED to FLAG_BLUE do
2416 with gFlags[i] do
2417 if State <> FLAG_STATE_CAPTURED then
2418 begin
2419 if State = FLAG_STATE_NONE then
2420 continue;
2422 if Direction = D_LEFT then
2423 begin
2424 Mirror := M_HORIZONTAL;
2425 dx := -1;
2426 end
2427 else
2428 begin
2429 Mirror := M_NONE;
2430 dx := 1;
2431 end;
2433 Animation.Draw(Obj.X+dx, Obj.Y+1, Mirror);
2435 if g_debug_Frames then
2436 begin
2437 e_DrawQuad(Obj.X+Obj.Rect.X,
2438 Obj.Y+Obj.Rect.Y,
2439 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2440 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2441 0, 255, 0);
2442 end;
2443 end;
2444 end;
2446 procedure g_Map_SaveState(Var Mem: TBinMemoryWriter);
2447 var
2448 dw: DWORD;
2449 b: Byte;
2450 str: String;
2451 boo: Boolean;
2453 procedure SavePanelArray(var panels: TPanelArray);
2454 var
2455 PAMem: TBinMemoryWriter;
2456 i: Integer;
2457 begin
2458 // Ñîçäàåì íîâûé ñïèñîê ñîõðàíÿåìûõ ïàíåëåé:
2459 PAMem := TBinMemoryWriter.Create((Length(panels)+1) * 40);
2461 i := 0;
2462 while i < Length(panels) do
2463 begin
2464 if panels[i].SaveIt then
2465 begin
2466 // ID ïàíåëè:
2467 PAMem.WriteInt(i);
2468 // Ñîõðàíÿåì ïàíåëü:
2469 panels[i].SaveState(PAMem);
2470 end;
2471 Inc(i);
2472 end;
2474 // Ñîõðàíÿåì ýòîò ñïèñîê ïàíåëåé:
2475 PAMem.SaveToMemory(Mem);
2476 PAMem.Free();
2477 end;
2479 procedure SaveFlag(flag: PFlag);
2480 begin
2481 // Ñèãíàòóðà ôëàãà:
2482 dw := FLAG_SIGNATURE; // 'FLAG'
2483 Mem.WriteDWORD(dw);
2484 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2485 Mem.WriteByte(flag^.RespawnType);
2486 // Ñîñòîÿíèå ôëàãà:
2487 Mem.WriteByte(flag^.State);
2488 // Íàïðàâëåíèå ôëàãà:
2489 if flag^.Direction = D_LEFT then
2490 b := 1
2491 else // D_RIGHT
2492 b := 2;
2493 Mem.WriteByte(b);
2494 // Îáúåêò ôëàãà:
2495 Obj_SaveState(@flag^.Obj, Mem);
2496 end;
2498 begin
2499 Mem := TBinMemoryWriter.Create(1024 * 1024); // 1 MB
2501 ///// Ñîõðàíÿåì ñïèñêè ïàíåëåé: /////
2502 // Ñîõðàíÿåì ïàíåëè ñòåí è äâåðåé:
2503 SavePanelArray(gWalls);
2504 // Ñîõðàíÿåì ïàíåëè ôîíà:
2505 SavePanelArray(gRenderBackgrounds);
2506 // Ñîõðàíÿåì ïàíåëè ïåðåäíåãî ïëàíà:
2507 SavePanelArray(gRenderForegrounds);
2508 // Ñîõðàíÿåì ïàíåëè âîäû:
2509 SavePanelArray(gWater);
2510 // Ñîõðàíÿåì ïàíåëè êèñëîòû-1:
2511 SavePanelArray(gAcid1);
2512 // Ñîõðàíÿåì ïàíåëè êèñëîòû-2:
2513 SavePanelArray(gAcid2);
2514 // Ñîõðàíÿåì ïàíåëè ñòóïåíåé:
2515 SavePanelArray(gSteps);
2516 // Ñîõðàíÿåì ïàíåëè ëèôòîâ:
2517 SavePanelArray(gLifts);
2518 ///// /////
2520 ///// Ñîõðàíÿåì ìóçûêó: /////
2521 // Ñèãíàòóðà ìóçûêè:
2522 dw := MUSIC_SIGNATURE; // 'MUSI'
2523 Mem.WriteDWORD(dw);
2524 // Íàçâàíèå ìóçûêè:
2525 Assert(gMusic <> nil, 'g_Map_SaveState: gMusic = nil');
2526 if gMusic.NoMusic then
2527 str := ''
2528 else
2529 str := gMusic.Name;
2530 Mem.WriteString(str, 64);
2531 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2532 dw := gMusic.GetPosition();
2533 Mem.WriteDWORD(dw);
2534 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2535 boo := gMusic.SpecPause;
2536 Mem.WriteBoolean(boo);
2537 ///// /////
2539 ///// Ñîõðàíÿåì êîëè÷åñòâî ìîíñòðîâ: /////
2540 Mem.WriteInt(gTotalMonsters);
2541 ///// /////
2543 //// Ñîõðàíÿåì ôëàãè, åñëè ýòî CTF: /////
2544 if gGameSettings.GameMode = GM_CTF then
2545 begin
2546 // Ôëàã Êðàñíîé êîìàíäû:
2547 SaveFlag(@gFlags[FLAG_RED]);
2548 // Ôëàã Ñèíåé êîìàíäû:
2549 SaveFlag(@gFlags[FLAG_BLUE]);
2550 end;
2551 ///// /////
2553 ///// Ñîõðàíÿåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2554 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2555 begin
2556 // Î÷êè Êðàñíîé êîìàíäû:
2557 Mem.WriteSmallInt(gTeamStat[TEAM_RED].Goals);
2558 // Î÷êè Ñèíåé êîìàíäû:
2559 Mem.WriteSmallInt(gTeamStat[TEAM_BLUE].Goals);
2560 end;
2561 ///// /////
2562 end;
2564 procedure g_Map_LoadState(Var Mem: TBinMemoryReader);
2565 var
2566 dw: DWORD;
2567 b: Byte;
2568 str: String;
2569 boo: Boolean;
2571 procedure LoadPanelArray(var panels: TPanelArray);
2572 var
2573 PAMem: TBinMemoryReader;
2574 i, id: Integer;
2575 begin
2576 // Çàãðóæàåì òåêóùèé ñïèñîê ïàíåëåé:
2577 PAMem := TBinMemoryReader.Create();
2578 PAMem.LoadFromMemory(Mem);
2580 for i := 0 to Length(panels)-1 do
2581 if panels[i].SaveIt then
2582 begin
2583 // ID ïàíåëè:
2584 PAMem.ReadInt(id);
2585 if id <> i then
2586 begin
2587 raise EBinSizeError.Create('g_Map_LoadState: LoadPanelArray: Wrong Panel ID');
2588 end;
2589 // Çàãðóæàåì ïàíåëü:
2590 panels[i].LoadState(PAMem);
2591 end;
2593 // Ýòîò ñïèñîê ïàíåëåé çàãðóæåí:
2594 PAMem.Free();
2595 end;
2597 procedure LoadFlag(flag: PFlag);
2598 begin
2599 // Ñèãíàòóðà ôëàãà:
2600 Mem.ReadDWORD(dw);
2601 if dw <> FLAG_SIGNATURE then // 'FLAG'
2602 begin
2603 raise EBinSizeError.Create('g_Map_LoadState: LoadFlag: Wrong Flag Signature');
2604 end;
2605 // Âðåìÿ ïåðåïîÿâëåíèÿ ôëàãà:
2606 Mem.ReadByte(flag^.RespawnType);
2607 // Ñîñòîÿíèå ôëàãà:
2608 Mem.ReadByte(flag^.State);
2609 // Íàïðàâëåíèå ôëàãà:
2610 Mem.ReadByte(b);
2611 if b = 1 then
2612 flag^.Direction := D_LEFT
2613 else // b = 2
2614 flag^.Direction := D_RIGHT;
2615 // Îáúåêò ôëàãà:
2616 Obj_LoadState(@flag^.Obj, Mem);
2617 end;
2619 begin
2620 if Mem = nil then
2621 Exit;
2623 ///// Çàãðóæàåì ñïèñêè ïàíåëåé: /////
2624 // Çàãðóæàåì ïàíåëè ñòåí è äâåðåé:
2625 LoadPanelArray(gWalls);
2626 // Çàãðóæàåì ïàíåëè ôîíà:
2627 LoadPanelArray(gRenderBackgrounds);
2628 // Çàãðóæàåì ïàíåëè ïåðåäíåãî ïëàíà:
2629 LoadPanelArray(gRenderForegrounds);
2630 // Çàãðóæàåì ïàíåëè âîäû:
2631 LoadPanelArray(gWater);
2632 // Çàãðóæàåì ïàíåëè êèñëîòû-1:
2633 LoadPanelArray(gAcid1);
2634 // Çàãðóæàåì ïàíåëè êèñëîòû-2:
2635 LoadPanelArray(gAcid2);
2636 // Çàãðóæàåì ïàíåëè ñòóïåíåé:
2637 LoadPanelArray(gSteps);
2638 // Çàãðóæàåì ïàíåëè ëèôòîâ:
2639 LoadPanelArray(gLifts);
2640 ///// /////
2642 // Îáíîâëÿåì êàðòó ñòîëêíîâåíèé:
2643 g_GFX_Init();
2645 ///// Çàãðóæàåì ìóçûêó: /////
2646 // Ñèãíàòóðà ìóçûêè:
2647 Mem.ReadDWORD(dw);
2648 if dw <> MUSIC_SIGNATURE then // 'MUSI'
2649 begin
2650 raise EBinSizeError.Create('g_Map_LoadState: Wrong Music Signature');
2651 end;
2652 // Íàçâàíèå ìóçûêè:
2653 Assert(gMusic <> nil, 'g_Map_LoadState: gMusic = nil');
2654 Mem.ReadString(str);
2655 // Ïîçèöèÿ ïðîèãðûâàíèÿ ìóçûêè:
2656 Mem.ReadDWORD(dw);
2657 // Ñòîèò ëè ìóçûêà íà ñïåö-ïàóçå:
2658 Mem.ReadBoolean(boo);
2659 // Çàïóñêàåì ýòó ìóçûêó:
2660 gMusic.SetByName(str);
2661 gMusic.SpecPause := boo;
2662 gMusic.Play();
2663 gMusic.Pause(True);
2664 gMusic.SetPosition(dw);
2665 ///// /////
2667 ///// Çàãðóæàåì êîëè÷åñòâî ìîíñòðîâ: /////
2668 Mem.ReadInt(gTotalMonsters);
2669 ///// /////
2671 //// Çàãðóæàåì ôëàãè, åñëè ýòî CTF: /////
2672 if gGameSettings.GameMode = GM_CTF then
2673 begin
2674 // Ôëàã Êðàñíîé êîìàíäû:
2675 LoadFlag(@gFlags[FLAG_RED]);
2676 // Ôëàã Ñèíåé êîìàíäû:
2677 LoadFlag(@gFlags[FLAG_BLUE]);
2678 end;
2679 ///// /////
2681 ///// Çàãðóæàåì êîëè÷åñòâî ïîáåä, åñëè ýòî TDM/CTF: /////
2682 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
2683 begin
2684 // Î÷êè Êðàñíîé êîìàíäû:
2685 Mem.ReadSmallInt(gTeamStat[TEAM_RED].Goals);
2686 // Î÷êè Ñèíåé êîìàíäû:
2687 Mem.ReadSmallInt(gTeamStat[TEAM_BLUE].Goals);
2688 end;
2689 ///// /////
2690 end;
2692 function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel;
2693 var
2694 Arr: TPanelArray;
2695 begin
2696 Result := nil;
2697 if (PanelID < 0) or (PanelID > High(PanelByID)) then Exit;
2698 Arr := PanelByID[PanelID].PWhere^;
2699 PanelArrayID := PanelByID[PanelID].PArrID;
2700 Result := Addr(Arr[PanelByID[PanelID].PArrID]);
2701 end;
2703 end.