1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: mapinfo.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "sv_local.h"
30
31 // MACROS ------------------------------------------------------------------
32
33 enum
34 {
35 CD_STARTTRACK,
36 CD_END1TRACK,
37 CD_END2TRACK,
38 CD_END3TRACK,
39 CD_INTERTRACK,
40 CD_TITLETRACK,
41 };
42
43 // TYPES -------------------------------------------------------------------
44
45 struct FMapSongInfo
46 {
47 VName MapName;
48 VName SongName;
49 };
50
51 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
52
53 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
54
55 VName P_TranslateMap(int map);
56
57 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
58
59 static void ParseMapInfo(VScriptParser* sc);
60
61 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
62
63 // PUBLIC DATA DEFINITIONS -------------------------------------------------
64
65 // PRIVATE DATA DEFINITIONS ------------------------------------------------
66
67 static mapInfo_t DefaultMap;
68 static TArray<mapInfo_t> MapInfo;
69 static TArray<FMapSongInfo> MapSongList;
70 static VClusterDef DefaultClusterDef;
71 static TArray<VClusterDef> ClusterDefs;
72 static TArray<VEpisodeDef> EpisodeDefs;
73 static TArray<VSkillDef> SkillDefs;
74 // Non-level specific song cd track numbers
75 static int cd_NonLevelTracks[6];
76
77 // CODE --------------------------------------------------------------------
78
79 //==========================================================================
80 //
81 // InitMapInfo
82 //
83 //==========================================================================
84
InitMapInfo()85 void InitMapInfo()
86 {
87 guard(InitMapInfo);
88 for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
89 Lump = W_IterateNS(Lump, WADNS_Global))
90 {
91 if (W_LumpName(Lump) == NAME_mapinfo)
92 {
93 ParseMapInfo(new VScriptParser(*W_LumpName(Lump),
94 W_CreateLumpReaderNum(Lump)));
95 }
96 }
97 // Optionally parse script file.
98 if (fl_devmode && FL_FileExists("scripts/mapinfo.txt"))
99 {
100 ParseMapInfo(new VScriptParser("scripts/mapinfo.txt",
101 FL_OpenFileRead("scripts/mapinfo.txt")));
102 }
103
104 for (int i = 0; i < MapInfo.Num(); i++)
105 {
106 if (VStr(MapInfo[i].NextMap).StartsWith("&wt@"))
107 {
108 MapInfo[i].NextMap = P_TranslateMap(atoi(
109 *MapInfo[i].NextMap + 4));
110 }
111 if (VStr(MapInfo[i].SecretMap).StartsWith("&wt@"))
112 {
113 MapInfo[i].SecretMap = P_TranslateMap(atoi(
114 *MapInfo[i].SecretMap + 4));
115 }
116 }
117 for (int i = 0; i < EpisodeDefs.Num(); i++)
118 {
119 if (VStr(EpisodeDefs[i].Name).StartsWith("&wt@"))
120 {
121 EpisodeDefs[i].Name = P_TranslateMap(atoi(
122 *EpisodeDefs[i].Name + 4));
123 }
124 if (VStr(EpisodeDefs[i].TeaserName).StartsWith("&wt@"))
125 {
126 EpisodeDefs[i].TeaserName = P_TranslateMap(atoi(
127 *EpisodeDefs[i].TeaserName + 4));
128 }
129 }
130
131 // Set up default map info returned for maps that have not defined in
132 // MAPINFO
133 DefaultMap.Name = "Unnamed";
134 DefaultMap.Sky1Texture = GTextureManager.CheckNumForName("sky1",
135 TEXTYPE_Wall, true, true);
136 DefaultMap.Sky2Texture = DefaultMap.Sky1Texture;
137 DefaultMap.FadeTable = NAME_colormap;
138 DefaultMap.HorizWallShade = -8;
139 DefaultMap.VertWallShade = 8;
140 unguard;
141 }
142
143 //==========================================================================
144 //
145 // SetMapDefaults
146 //
147 //==========================================================================
148
SetMapDefaults(mapInfo_t & Info)149 static void SetMapDefaults(mapInfo_t& Info)
150 {
151 guard(SetMapDefaults);
152 Info.LumpName = NAME_None;
153 Info.Name = VStr();
154 Info.LevelNum = 0;
155 Info.Cluster = 0;
156 Info.WarpTrans = 0;
157 Info.NextMap = NAME_None;
158 Info.SecretMap = NAME_None;
159 Info.SongLump = NAME_None;
160 Info.CDTrack = 0;
161 Info.Sky1Texture = GTextureManager.DefaultTexture;
162 Info.Sky2Texture = GTextureManager.DefaultTexture;
163 Info.Sky1ScrollDelta = 0;
164 Info.Sky2ScrollDelta = 0;
165 Info.SkyBox = NAME_None;
166 Info.FadeTable = NAME_colormap;
167 Info.Fade = 0;
168 Info.OutsideFog = 0;
169 Info.Gravity = 0;
170 Info.AirControl = 0;
171 Info.Flags = 0;
172 Info.Flags2 = 0;
173 Info.TitlePatch = NAME_None;
174 Info.ParTime = 0;
175 Info.SuckTime = 0;
176 Info.HorizWallShade = -8;
177 Info.VertWallShade = 8;
178 Info.Infighting = 0;
179 Info.SpecialActions.Clear();
180 Info.RedirectType = NAME_None;
181 Info.RedirectMap = NAME_None;
182 Info.ExitPic = NAME_None;
183 Info.EnterPic = NAME_None;
184 Info.InterMusic = NAME_None;
185
186 if (GGameInfo->Flags & VGameInfo::GIF_DefaultLaxMonsterActivation)
187 {
188 Info.Flags2 |= MAPINFOF2_LaxMonsterActivation;
189 }
190 unguard;
191 }
192
193 //==========================================================================
194 //
195 // ParseNextMapName
196 //
197 //==========================================================================
198
ParseNextMapName(VScriptParser * sc,bool HexenMode)199 static VName ParseNextMapName(VScriptParser* sc, bool HexenMode)
200 {
201 guard(ParseNextMapName);
202 if (sc->CheckNumber())
203 {
204 if (HexenMode)
205 return va("&wt@%02d", sc->Number);
206 else
207 return va("map%02d", sc->Number);
208 }
209 else if (sc->Check("endbunny"))
210 {
211 return "EndGameBunny";
212 }
213 else if (sc->Check("endcast"))
214 {
215 return "EndGameCast";
216 }
217 else if (sc->Check("enddemon"))
218 {
219 return "EndGameDemon";
220 }
221 else if (sc->Check("endchess"))
222 {
223 return "EndGameChess";
224 }
225 else if (sc->Check("endunderwater"))
226 {
227 return "EndGameUnderwater";
228 }
229 else if (sc->Check("endbuystrife"))
230 {
231 return "EndGameBuyStrife";
232 }
233 else if (sc->Check("endpic"))
234 {
235 sc->ExpectName8();
236 return va("EndGameCustomPic%s", *sc->Name8);
237 }
238 else
239 {
240 sc->ExpectString();
241 if (sc->String.ToLower().StartsWith("endgame"))
242 {
243 switch (sc->String[7])
244 {
245 case '1':
246 return "EndGamePic1";
247 case '2':
248 return "EndGamePic2";
249 case '3':
250 return "EndGameBunny";
251 case 'c':
252 case 'C':
253 return "EndGameCast";
254 case 'w':
255 case 'W':
256 return "EndGameUnderwater";
257 case 's':
258 case 'S':
259 return "EndGameStrife";
260 default:
261 return "EndGamePic3";
262 }
263 }
264 else
265 {
266 return VName(*sc->String, VName::AddLower8);
267 }
268 }
269 unguard;
270 }
271
272 //==========================================================================
273 //
274 // DoCompatFlag
275 //
276 //==========================================================================
277
DoCompatFlag(VScriptParser * sc,mapInfo_t * info,int Flag)278 static void DoCompatFlag(VScriptParser* sc, mapInfo_t* info, int Flag)
279 {
280 guard(DoCompatFlag);
281 int Set = 1;
282 if (sc->CheckNumber())
283 {
284 Set = sc->Number;
285 }
286 if (Set)
287 {
288 info->Flags2 |= Flag;
289 }
290 else
291 {
292 info->Flags2 &= ~Flag;
293 }
294 unguard;
295 }
296
297 //==========================================================================
298 //
299 // ParseMapCommon
300 //
301 //==========================================================================
302
ParseMapCommon(VScriptParser * sc,mapInfo_t * info,bool & HexenMode)303 static void ParseMapCommon(VScriptParser* sc, mapInfo_t* info, bool& HexenMode)
304 {
305 guard(ParseMapCommon);
306 // Process optional tokens
307 while (1)
308 {
309 if (sc->Check("levelnum"))
310 {
311 sc->ExpectNumber();
312 info->LevelNum = sc->Number;
313 }
314 else if (sc->Check("cluster"))
315 {
316 sc->ExpectNumber();
317 info->Cluster = sc->Number;
318 if (P_GetClusterDef(info->Cluster) == &DefaultClusterDef)
319 {
320 // Add empty cluster def if it doesn't exist yet.
321 VClusterDef& C = ClusterDefs.Alloc();
322 C.Cluster = info->Cluster;
323 C.Flags = 0;
324 C.EnterText = VStr();
325 C.ExitText = VStr();
326 C.Flat = NAME_None;
327 C.Music = NAME_None;
328 C.CDTrack = 0;
329 C.CDId = 0;
330 if (HexenMode)
331 {
332 C.Flags |= CLUSTERF_Hub;
333 }
334 }
335 }
336 else if (sc->Check("warptrans"))
337 {
338 sc->ExpectNumber();
339 info->WarpTrans = sc->Number;
340 }
341 else if (sc->Check("next"))
342 {
343 info->NextMap = ParseNextMapName(sc, HexenMode);
344 }
345 else if (sc->Check("secret") || sc->Check("secretnext"))
346 {
347 info->SecretMap = ParseNextMapName(sc, HexenMode);
348 }
349 else if (sc->Check("sky1"))
350 {
351 sc->ExpectName8();
352 info->Sky1Texture = GTextureManager.NumForName(
353 sc->Name8, TEXTYPE_Wall, true, false);
354 sc->ExpectFloat();
355 if (HexenMode)
356 {
357 sc->Float /= 256.0;
358 }
359 info->Sky1ScrollDelta = sc->Float * 35.0;
360 }
361 else if (sc->Check("sky2"))
362 {
363 sc->ExpectName8();
364 info->Sky2Texture = GTextureManager.NumForName(
365 sc->Name8, TEXTYPE_Wall, true, false);
366 sc->ExpectFloat();
367 if (HexenMode)
368 {
369 sc->Float /= 256.0;
370 }
371 info->Sky2ScrollDelta = sc->Float * 35.0;
372 }
373 else if (sc->Check("skybox"))
374 {
375 sc->ExpectString();
376 info->SkyBox = *sc->String;
377 }
378 else if (sc->Check("doublesky"))
379 {
380 info->Flags |= MAPINFOF_DoubleSky;
381 }
382 else if (sc->Check("lightning"))
383 {
384 info->Flags |= MAPINFOF_Lightning;
385 }
386 else if (sc->Check("forcenoskystretch"))
387 {
388 info->Flags |= MAPINFOF_ForceNoSkyStretch;
389 }
390 else if (sc->Check("fadetable"))
391 {
392 sc->ExpectName8();
393 info->FadeTable = sc->Name8;
394 }
395 else if (sc->Check("fade"))
396 {
397 sc->ExpectString();
398 info->Fade = M_ParseColour(sc->String);
399 }
400 else if (sc->Check("outsidefog"))
401 {
402 sc->ExpectString();
403 info->OutsideFog = M_ParseColour(sc->String);
404 }
405 else if (sc->Check("music"))
406 {
407 sc->ExpectName8();
408 info->SongLump = sc->Name8;
409 }
410 else if (sc->Check("cdtrack"))
411 {
412 sc->ExpectNumber();
413 info->CDTrack = sc->Number;
414 }
415 else if (sc->Check("gravity"))
416 {
417 sc->ExpectNumber();
418 info->Gravity = (float)sc->Number;
419 }
420 else if (sc->Check("aircontrol"))
421 {
422 sc->ExpectFloat();
423 info->AirControl = sc->Float;
424 }
425 else if (sc->Check("map07special"))
426 {
427 info->Flags |= MAPINFOF_Map07Special;
428 }
429 else if (sc->Check("baronspecial"))
430 {
431 info->Flags |= MAPINFOF_BaronSpecial;
432 }
433 else if (sc->Check("cyberdemonspecial"))
434 {
435 info->Flags |= MAPINFOF_CyberDemonSpecial;
436 }
437 else if (sc->Check("spidermastermindspecial"))
438 {
439 info->Flags |= MAPINFOF_SpiderMastermindSpecial;
440 }
441 else if (sc->Check("minotaurspecial"))
442 {
443 info->Flags |= MAPINFOF_MinotaurSpecial;
444 }
445 else if (sc->Check("dsparilspecial"))
446 {
447 info->Flags |= MAPINFOF_DSparilSpecial;
448 }
449 else if (sc->Check("ironlichspecial"))
450 {
451 info->Flags |= MAPINFOF_IronLichSpecial;
452 }
453 else if (sc->Check("specialaction_exitlevel"))
454 {
455 info->Flags &= ~(MAPINFOF_SpecialActionOpenDoor |
456 MAPINFOF_SpecialActionLowerFloor);
457 }
458 else if (sc->Check("specialaction_opendoor"))
459 {
460 info->Flags &= ~MAPINFOF_SpecialActionLowerFloor;
461 info->Flags |= MAPINFOF_SpecialActionOpenDoor;
462 }
463 else if (sc->Check("specialaction_lowerfloor"))
464 {
465 info->Flags |= MAPINFOF_SpecialActionLowerFloor;
466 info->Flags &= ~MAPINFOF_SpecialActionOpenDoor;
467 }
468 else if (sc->Check("specialaction_killmonsters"))
469 {
470 info->Flags |= MAPINFOF_SpecialActionKillMonsters;
471 }
472 else if (sc->Check("intermission"))
473 {
474 info->Flags &= ~MAPINFOF_NoIntermission;
475 }
476 else if (sc->Check("nointermission"))
477 {
478 info->Flags |= MAPINFOF_NoIntermission;
479 }
480 else if (sc->Check("titlepatch"))
481 {
482 sc->ExpectName8();
483 info->TitlePatch = sc->Name8;
484 }
485 else if (sc->Check("par"))
486 {
487 sc->ExpectNumber();
488 info->ParTime = sc->Number;
489 }
490 else if (sc->Check("sucktime"))
491 {
492 sc->ExpectNumber();
493 info->SuckTime = sc->Number;
494 }
495 else if (sc->Check("nosoundclipping"))
496 {
497 // Ignored
498 }
499 else if (sc->Check("allowmonstertelefrags"))
500 {
501 info->Flags |= MAPINFOF_AllowMonsterTelefrags;
502 }
503 else if (sc->Check("noallies"))
504 {
505 info->Flags |= MAPINFOF_NoAllies;
506 }
507 else if (sc->Check("fallingdamage"))
508 {
509 info->Flags &= ~(MAPINFOF_OldFallingDamage |
510 MAPINFOF_StrifeFallingDamage);
511 info->Flags |= MAPINFOF_FallingDamage;
512 }
513 else if (sc->Check("oldfallingdamage") ||
514 sc->Check("forcefallingdamage"))
515 {
516 info->Flags &= ~(MAPINFOF_FallingDamage |
517 MAPINFOF_StrifeFallingDamage);
518 info->Flags |= MAPINFOF_OldFallingDamage;
519 }
520 else if (sc->Check("strifefallingdamage"))
521 {
522 info->Flags &= ~(MAPINFOF_OldFallingDamage |
523 MAPINFOF_FallingDamage);
524 info->Flags |= MAPINFOF_StrifeFallingDamage;
525 }
526 else if (sc->Check("nofallingdamage"))
527 {
528 info->Flags &= ~(MAPINFOF_OldFallingDamage |
529 MAPINFOF_StrifeFallingDamage | MAPINFOF_FallingDamage);
530 }
531 else if (sc->Check("monsterfallingdamage"))
532 {
533 info->Flags |= MAPINFOF_MonsterFallingDamage;
534 }
535 else if (sc->Check("nomonsterfallingdamage"))
536 {
537 info->Flags &= ~MAPINFOF_MonsterFallingDamage;
538 }
539 else if (sc->Check("deathslideshow"))
540 {
541 info->Flags |= MAPINFOF_DeathSlideShow;
542 }
543 else if (sc->Check("allowfreelook"))
544 {
545 info->Flags &= ~MAPINFOF_NoFreelook;
546 }
547 else if (sc->Check("nofreelook"))
548 {
549 info->Flags |= MAPINFOF_NoFreelook;
550 }
551 else if (sc->Check("allowjump"))
552 {
553 info->Flags &= ~MAPINFOF_NoJump;
554 }
555 else if (sc->Check("nojump"))
556 {
557 info->Flags |= MAPINFOF_NoJump;
558 }
559 else if (sc->Check("noautosequences"))
560 {
561 info->Flags |= MAPINFOF_NoAutoSndSeq;
562 }
563 else if (sc->Check("activateowndeathspecials"))
564 {
565 info->Flags |= MAPINFOF_ActivateOwnSpecial;
566 }
567 else if (sc->Check("killeractivatesdeathspecials"))
568 {
569 info->Flags &= ~MAPINFOF_ActivateOwnSpecial;
570 }
571 else if (sc->Check("missilesactivateimpactlines"))
572 {
573 info->Flags |= MAPINFOF_MissilesActivateImpact;
574 }
575 else if (sc->Check("missileshootersactivetimpactlines"))
576 {
577 info->Flags &= ~MAPINFOF_MissilesActivateImpact;
578 }
579 else if (sc->Check("filterstarts"))
580 {
581 info->Flags |= MAPINFOF_FilterStarts;
582 }
583 else if (sc->Check("infiniteflightpowerup"))
584 {
585 info->Flags |= MAPINFOF_InfiniteFlightPowerup;
586 }
587 else if (sc->Check("noinfiniteflightpowerup"))
588 {
589 info->Flags &= ~MAPINFOF_InfiniteFlightPowerup;
590 }
591 else if (sc->Check("clipmidtextures"))
592 {
593 info->Flags |= MAPINFOF_ClipMidTex;
594 }
595 else if (sc->Check("wrapmidtextures"))
596 {
597 info->Flags |= MAPINFOF_WrapMidTex;
598 }
599 else if (sc->Check("keepfullinventory"))
600 {
601 info->Flags |= MAPINFOF_KeepFullInventory;
602 }
603 else if (sc->Check("compat_shorttex"))
604 {
605 DoCompatFlag(sc, info, MAPINFOF2_CompatShortTex);
606 }
607 else if (sc->Check("compat_stairs"))
608 {
609 DoCompatFlag(sc, info, MAPINFOF2_CompatStairs);
610 }
611 else if (sc->Check("compat_limitpain"))
612 {
613 DoCompatFlag(sc, info, MAPINFOF2_CompatLimitPain);
614 }
615 else if (sc->Check("compat_nopassover"))
616 {
617 DoCompatFlag(sc, info, MAPINFOF2_CompatNoPassOver);
618 }
619 else if (sc->Check("compat_notossdrops"))
620 {
621 DoCompatFlag(sc, info, MAPINFOF2_CompatNoTossDrops);
622 }
623 else if (sc->Check("compat_useblocking"))
624 {
625 DoCompatFlag(sc, info, MAPINFOF2_CompatUseBlocking);
626 }
627 else if (sc->Check("compat_nodoorlight"))
628 {
629 DoCompatFlag(sc, info, MAPINFOF2_CompatNoDoorLight);
630 }
631 else if (sc->Check("compat_ravenscroll"))
632 {
633 DoCompatFlag(sc, info, MAPINFOF2_CompatRavenScroll);
634 }
635 else if (sc->Check("compat_soundtarget"))
636 {
637 DoCompatFlag(sc, info, MAPINFOF2_CompatSoundTarget);
638 }
639 else if (sc->Check("compat_dehhealth"))
640 {
641 DoCompatFlag(sc, info, MAPINFOF2_CompatDehHealth);
642 }
643 else if (sc->Check("compat_trace"))
644 {
645 DoCompatFlag(sc, info, MAPINFOF2_CompatTrace);
646 }
647 else if (sc->Check("compat_dropoff"))
648 {
649 DoCompatFlag(sc, info, MAPINFOF2_CompatDropOff);
650 }
651 else if (sc->Check("compat_boomscroll") ||
652 sc->Check("additive_scrollers"))
653 {
654 DoCompatFlag(sc, info, MAPINFOF2_CompatBoomScroll);
655 }
656 else if (sc->Check("compat_invisibility"))
657 {
658 DoCompatFlag(sc, info, MAPINFOF2_CompatInvisibility);
659 }
660 else if (sc->Check("evenlighting"))
661 {
662 info->HorizWallShade = 0;
663 info->VertWallShade = 0;
664 }
665 else if (sc->Check("vertwallshade"))
666 {
667 sc->ExpectNumber();
668 info->VertWallShade = MID(-128, sc->Number, 127);
669 }
670 else if (sc->Check("horizwallshade"))
671 {
672 sc->ExpectNumber();
673 info->HorizWallShade = MID(-128, sc->Number, 127);
674 }
675 else if (sc->Check("noinfighting"))
676 {
677 info->Infighting = -1;
678 }
679 else if (sc->Check("normalinfighting"))
680 {
681 info->Infighting = 0;
682 }
683 else if (sc->Check("totalinfighting"))
684 {
685 info->Infighting = 1;
686 }
687 else if (sc->Check("specialaction"))
688 {
689 VMapSpecialAction& A = info->SpecialActions.Alloc();
690 sc->SetCMode(true);
691 sc->ExpectString();
692 A.TypeName = *sc->String.ToLower();
693 sc->Expect(",");
694 sc->ExpectString();
695 A.Special = 0;
696 for (int i = 0; i < LineSpecialInfos.Num(); i++)
697 {
698 if (!LineSpecialInfos[i].Name.ICmp(sc->String))
699 {
700 A.Special = LineSpecialInfos[i].Number;
701 break;
702 }
703 }
704 if (!A.Special)
705 {
706 GCon->Logf("Unknown action special %s", *sc->String);
707 }
708 memset(A.Args, 0, sizeof(A.Args));
709 for (int i = 0; i < 5 && sc->Check(","); i++)
710 {
711 sc->ExpectNumber();
712 A.Args[i] = sc->Number;
713 }
714 sc->SetCMode(false);
715 }
716 else if (sc->Check("redirect"))
717 {
718 sc->ExpectString();
719 info->RedirectType = *sc->String.ToLower();
720 info->RedirectMap = ParseNextMapName(sc, HexenMode);
721 }
722 else if (sc->Check("strictmonsteractivation"))
723 {
724 info->Flags2 &= ~MAPINFOF2_LaxMonsterActivation;
725 info->Flags2 |= MAPINFOF2_HaveMonsterActivation;
726 }
727 else if (sc->Check("laxmonsteractivation"))
728 {
729 info->Flags2 |= MAPINFOF2_LaxMonsterActivation;
730 info->Flags2 |= MAPINFOF2_HaveMonsterActivation;
731 }
732 else if (sc->Check("interpic") || sc->Check("exitpic"))
733 {
734 sc->ExpectName8();
735 info->ExitPic = *sc->String.ToLower();
736 }
737 else if (sc->Check("enterpic"))
738 {
739 sc->ExpectName8();
740 info->EnterPic = *sc->String.ToLower();
741 }
742 else if (sc->Check("intermusic"))
743 {
744 sc->ExpectString();
745 info->InterMusic = *sc->String.ToLower();
746 }
747 else if (sc->Check("cd_start_track"))
748 {
749 sc->ExpectNumber();
750 cd_NonLevelTracks[CD_STARTTRACK] = sc->Number;
751 }
752 else if (sc->Check("cd_end1_track"))
753 {
754 sc->ExpectNumber();
755 cd_NonLevelTracks[CD_END1TRACK] = sc->Number;
756 }
757 else if (sc->Check("cd_end2_track"))
758 {
759 sc->ExpectNumber();
760 cd_NonLevelTracks[CD_END2TRACK] = sc->Number;
761 }
762 else if (sc->Check("cd_end3_track"))
763 {
764 sc->ExpectNumber();
765 cd_NonLevelTracks[CD_END3TRACK] = sc->Number;
766 }
767 else if (sc->Check("cd_intermission_track"))
768 {
769 sc->ExpectNumber();
770 cd_NonLevelTracks[CD_INTERTRACK] = sc->Number;
771 }
772 else if (sc->Check("cd_title_track"))
773 {
774 sc->ExpectNumber();
775 cd_NonLevelTracks[CD_TITLETRACK] = sc->Number;
776 }
777 // These are stubs for now.
778 else if (sc->Check("cdid"))
779 {
780 GCon->Logf("Unimplemented MAPINFO comand cdid");
781 sc->ExpectString();
782 }
783 else if (sc->Check("noinventorybar"))
784 {
785 GCon->Logf("Unimplemented MAPINFO comand noinventorybar");
786 }
787 else if (sc->Check("airsupply"))
788 {
789 GCon->Logf("Unimplemented MAPINFO comand airsupply");
790 sc->ExpectNumber();
791 }
792 else if (sc->Check("sndseq"))
793 {
794 GCon->Logf("Unimplemented MAPINFO comand sndseq");
795 sc->ExpectName8();
796 }
797 else if (sc->Check("sndinfo"))
798 {
799 GCon->Logf("Unimplemented MAPINFO comand sndinfo");
800 sc->ExpectName8();
801 }
802 else if (sc->Check("soundinfo"))
803 {
804 GCon->Logf("Unimplemented MAPINFO comand soundinfo");
805 sc->ExpectName8();
806 }
807 else if (sc->Check("allowcrouch"))
808 {
809 GCon->Logf("Unimplemented MAPINFO comand allowcrouch");
810 }
811 else if (sc->Check("nocrouch"))
812 {
813 GCon->Logf("Unimplemented MAPINFO comand nocrouch");
814 }
815 else if (sc->Check("pausemusicinmenus"))
816 {
817 GCon->Logf("Unimplemented MAPINFO comand pausemusicinmenus");
818 }
819 else if (sc->Check("bordertexture"))
820 {
821 GCon->Logf("Unimplemented MAPINFO comand bordertexture");
822 sc->ExpectName8();
823 }
824 else if (sc->Check("f1"))
825 {
826 GCon->Logf("Unimplemented MAPINFO comand f1");
827 sc->ExpectString();
828 }
829 else if (sc->Check("allowrespawn"))
830 {
831 GCon->Logf("Unimplemented MAPINFO comand allowrespawn");
832 }
833 else if (sc->Check("teamdamage"))
834 {
835 GCon->Logf("Unimplemented MAPINFO comand teamdamage");
836 sc->ExpectFloat();
837 }
838 else if (sc->Check("fogdensity"))
839 {
840 GCon->Logf("Unimplemented MAPINFO comand fogdensity");
841 sc->ExpectNumber();
842 }
843 else if (sc->Check("outsidefogdensity"))
844 {
845 GCon->Logf("Unimplemented MAPINFO comand outsidefogdensity");
846 sc->ExpectNumber();
847 }
848 else if (sc->Check("skyfog"))
849 {
850 GCon->Logf("Unimplemented MAPINFO comand skyfog");
851 sc->ExpectNumber();
852 }
853 else if (sc->Check("teamplayon"))
854 {
855 GCon->Logf("Unimplemented MAPINFO comand teamplayon");
856 }
857 else if (sc->Check("teamplayoff"))
858 {
859 GCon->Logf("Unimplemented MAPINFO comand teamplayoff");
860 }
861 else if (sc->Check("checkswitchrange"))
862 {
863 GCon->Logf("Unimplemented MAPINFO comand checkswitchrange");
864 }
865 else if (sc->Check("nocheckswitchrange"))
866 {
867 GCon->Logf("Unimplemented MAPINFO comand nocheckswitchrange");
868 }
869 else if (sc->Check("translator"))
870 {
871 GCon->Logf("Unimplemented MAPINFO comand translator");
872 sc->ExpectString();
873 }
874 else if (sc->Check("unfreezesingleplayerconversations"))
875 {
876 GCon->Logf("Unimplemented MAPINFO comand unfreezesingleplayerconversations");
877 }
878 else
879 {
880 break;
881 }
882 }
883
884 // Second sky defaults to first sky
885 if (info->Sky2Texture == GTextureManager.DefaultTexture)
886 {
887 info->Sky2Texture = info->Sky1Texture;
888 }
889
890 if (info->Flags & MAPINFOF_DoubleSky)
891 {
892 GTextureManager.SetFrontSkyLayer(info->Sky1Texture);
893 }
894 unguard;
895 }
896
897 //==========================================================================
898 //
899 // ParseMap
900 //
901 //==========================================================================
902
ParseMap(VScriptParser * sc,bool & HexenMode,mapInfo_t & Default)903 static void ParseMap(VScriptParser* sc, bool& HexenMode, mapInfo_t& Default)
904 {
905 guard(ParseMap);
906 mapInfo_t* info = NULL;
907 VName MapLumpName;
908 if (sc->CheckNumber())
909 {
910 // Map number, for Hexen compatibility
911 HexenMode = true;
912 if (sc->Number < 1 || sc->Number > 99)
913 {
914 sc->Error("Map number out or range");
915 }
916 MapLumpName = va("map%02d", sc->Number);
917 }
918 else
919 {
920 // Map name
921 sc->ExpectName8();
922 MapLumpName = sc->Name8;
923 }
924
925 // Check for replaced map info.
926 for (int i = 0; i < MapInfo.Num(); i++)
927 {
928 if (MapLumpName == MapInfo[i].LumpName)
929 {
930 info = &MapInfo[i];
931 break;
932 }
933 }
934 if (!info)
935 {
936 info = &MapInfo.Alloc();
937 }
938
939 // Copy defaults to current map definition
940 info->LumpName = MapLumpName;
941 info->LevelNum = Default.LevelNum;
942 info->Cluster = Default.Cluster;
943 info->WarpTrans = Default.WarpTrans;
944 info->NextMap = Default.NextMap;
945 info->SecretMap = Default.SecretMap;
946 info->SongLump = Default.SongLump;
947 info->CDTrack = Default.CDTrack;
948 info->Sky1Texture = Default.Sky1Texture;
949 info->Sky2Texture = Default.Sky2Texture;
950 info->Sky1ScrollDelta = Default.Sky1ScrollDelta;
951 info->Sky2ScrollDelta = Default.Sky2ScrollDelta;
952 info->SkyBox = Default.SkyBox;
953 info->FadeTable = Default.FadeTable;
954 info->Fade = Default.Fade;
955 info->OutsideFog = Default.OutsideFog;
956 info->Gravity = Default.Gravity;
957 info->AirControl = Default.AirControl;
958 info->Flags = Default.Flags;
959 info->Flags2 = Default.Flags2;
960 info->TitlePatch = Default.TitlePatch;
961 info->ParTime = Default.ParTime;
962 info->SuckTime = Default.SuckTime;
963 info->HorizWallShade = Default.HorizWallShade;
964 info->VertWallShade = Default.VertWallShade;
965 info->Infighting = Default.Infighting;
966 info->SpecialActions = Default.SpecialActions;
967 info->RedirectType = Default.RedirectType;
968 info->RedirectMap = Default.RedirectMap;
969 info->ExitPic = Default.ExitPic;
970 info->EnterPic = Default.EnterPic;
971 info->InterMusic = Default.InterMusic;
972
973 if (HexenMode)
974 {
975 info->Flags |= MAPINFOF_NoIntermission |
976 MAPINFOF_FallingDamage |
977 MAPINFOF_MonsterFallingDamage |
978 MAPINFOF_NoAutoSndSeq |
979 MAPINFOF_ActivateOwnSpecial |
980 MAPINFOF_MissilesActivateImpact |
981 MAPINFOF_InfiniteFlightPowerup;
982 }
983
984 // Map name must follow the number
985 if (sc->Check("lookup"))
986 {
987 info->Flags |= MAPINFOF_LookupName;
988 sc->ExpectString();
989 info->Name = sc->String.ToLower();
990 }
991 else
992 {
993 info->Flags &= ~MAPINFOF_LookupName;
994 sc->ExpectString();
995 info->Name = sc->String;
996 }
997
998 // Set song lump name from SNDINFO script
999 for (int i = 0; i < MapSongList.Num(); i++)
1000 {
1001 if (MapSongList[i].MapName == info->LumpName)
1002 {
1003 info->SongLump = MapSongList[i].SongName;
1004 }
1005 }
1006
1007 // Set default levelnum for this map.
1008 const char* mn = *MapLumpName;
1009 if (mn[0] == 'm' && mn[1] == 'a' && mn[2] == 'p' && mn[5] == 0)
1010 {
1011 int num = atoi(mn + 3);
1012 if (num >= 1 && num <= 99)
1013 info->LevelNum = num;
1014 }
1015 else if (mn[0] == 'e' && mn[1] >= '0' && mn[1] <= '9' &&
1016 mn[2] == 'm' && mn[3] >= '0' && mn[3] <= '9')
1017 {
1018 info->LevelNum = (mn[1] - '1') * 10 + (mn[3] - '0');
1019 }
1020
1021 ParseMapCommon(sc, info, HexenMode);
1022
1023 // Avoid duplicate levelnums, later one takes precedance.
1024 for (int i = 0; i < MapInfo.Num(); i++)
1025 {
1026 if (MapInfo[i].LevelNum == info->LevelNum &&
1027 &MapInfo[i] != info)
1028 {
1029 MapInfo[i].LevelNum = 0;
1030 }
1031 }
1032 unguard;
1033 }
1034
1035 //==========================================================================
1036 //
1037 // ParseClusterDef
1038 //
1039 //==========================================================================
1040
ParseClusterDef(VScriptParser * sc)1041 static void ParseClusterDef(VScriptParser* sc)
1042 {
1043 guard(ParseClusterDef);
1044 VClusterDef* CDef = NULL;
1045 sc->ExpectNumber();
1046
1047 // Check for replaced cluster def.
1048 for (int i = 0; i < ClusterDefs.Num(); i++)
1049 {
1050 if (sc->Number == ClusterDefs[i].Cluster)
1051 {
1052 CDef = &ClusterDefs[i];
1053 break;
1054 }
1055 }
1056 if (!CDef)
1057 {
1058 CDef = &ClusterDefs.Alloc();
1059 }
1060
1061 // Set defaults.
1062 CDef->Cluster = sc->Number;
1063 CDef->Flags = 0;
1064 CDef->EnterText = VStr();
1065 CDef->ExitText = VStr();
1066 CDef->Flat = NAME_None;
1067 CDef->Music = NAME_None;
1068 CDef->CDTrack = 0;
1069 CDef->CDId = 0;
1070
1071 while (1)
1072 {
1073 if (sc->Check("hub"))
1074 {
1075 CDef->Flags |= CLUSTERF_Hub;
1076 }
1077 else if (sc->Check("entertext"))
1078 {
1079 if (sc->Check("lookup"))
1080 {
1081 CDef->Flags |= CLUSTERF_LookupEnterText;
1082 sc->ExpectString();
1083 CDef->EnterText = sc->String.ToLower();
1084 }
1085 else
1086 {
1087 CDef->Flags &= ~CLUSTERF_LookupEnterText;
1088 sc->ExpectString();
1089 CDef->EnterText = sc->String;
1090 }
1091 }
1092 else if (sc->Check("entertextislump"))
1093 {
1094 CDef->Flags |= CLUSTERF_EnterTextIsLump;
1095 }
1096 else if (sc->Check("exittext"))
1097 {
1098 if (sc->Check("lookup"))
1099 {
1100 CDef->Flags |= CLUSTERF_LookupExitText;
1101 sc->ExpectString();
1102 CDef->ExitText = sc->String.ToLower();
1103 }
1104 else
1105 {
1106 CDef->Flags &= ~CLUSTERF_LookupExitText;
1107 sc->ExpectString();
1108 CDef->ExitText = sc->String;
1109 }
1110 }
1111 else if (sc->Check("exittextislump"))
1112 {
1113 CDef->Flags |= CLUSTERF_ExitTextIsLump;
1114 }
1115 else if (sc->Check("flat"))
1116 {
1117 sc->ExpectName8();
1118 CDef->Flat = sc->Name8;
1119 CDef->Flags &= ~CLUSTERF_FinalePic;
1120 }
1121 else if (sc->Check("pic"))
1122 {
1123 sc->ExpectName8();
1124 CDef->Flat = sc->Name8;
1125 CDef->Flags |= CLUSTERF_FinalePic;
1126 }
1127 else if (sc->Check("music"))
1128 {
1129 sc->ExpectName8();
1130 CDef->Music = sc->Name8;
1131 }
1132 else if (sc->Check("cdtrack"))
1133 {
1134 sc->ExpectNumber();
1135 CDef->CDTrack = sc->Number;
1136 }
1137 else if (sc->Check("cdid"))
1138 {
1139 sc->ExpectNumber();
1140 CDef->CDId = sc->Number;
1141 }
1142 else if (sc->Check("name"))
1143 {
1144 sc->Check("lookup");
1145 sc->ExpectString();
1146 GCon->Logf("Unimplemented MAPINFO cluster comand name");
1147 }
1148 else
1149 {
1150 break;
1151 }
1152 }
1153
1154 // Make sure text lump names are in lower case.
1155 if (CDef->Flags & CLUSTERF_EnterTextIsLump)
1156 {
1157 CDef->EnterText = CDef->EnterText.ToLower();
1158 }
1159 if (CDef->Flags & CLUSTERF_ExitTextIsLump)
1160 {
1161 CDef->ExitText = CDef->ExitText.ToLower();
1162 }
1163 unguard;
1164 }
1165
1166 //==========================================================================
1167 //
1168 // ParseEpisodeDef
1169 //
1170 //==========================================================================
1171
ParseEpisodeDef(VScriptParser * sc)1172 static void ParseEpisodeDef(VScriptParser* sc)
1173 {
1174 guard(ParseEpisodeDef);
1175 VEpisodeDef* EDef = NULL;
1176 int EIdx = 0;
1177 sc->ExpectName8();
1178
1179 // Check for replaced episode.
1180 for (int i = 0; i < EpisodeDefs.Num(); i++)
1181 {
1182 if (sc->Name8 == EpisodeDefs[i].Name)
1183 {
1184 EDef = &EpisodeDefs[i];
1185 EIdx = i;
1186 break;
1187 }
1188 }
1189 if (!EDef)
1190 {
1191 EDef = &EpisodeDefs.Alloc();
1192 EIdx = EpisodeDefs.Num() - 1;
1193 }
1194
1195 // Check for removal of an episode.
1196 if (sc->Check("remove"))
1197 {
1198 EpisodeDefs.RemoveIndex(EIdx);
1199 return;
1200 }
1201
1202 // Set defaults.
1203 EDef->Name = sc->Name8;
1204 EDef->TeaserName = NAME_None;
1205 EDef->Text = VStr();
1206 EDef->PicName = NAME_None;
1207 EDef->Flags = 0;
1208 EDef->Key = VStr();
1209
1210 if (sc->Check("teaser"))
1211 {
1212 sc->ExpectName8();
1213 EDef->TeaserName = sc->Name8;
1214 }
1215
1216 while (1)
1217 {
1218 if (sc->Check("name"))
1219 {
1220 if (sc->Check("lookup"))
1221 {
1222 EDef->Flags |= EPISODEF_LookupText;
1223 sc->ExpectString();
1224 EDef->Text = sc->String.ToLower();
1225 }
1226 else
1227 {
1228 EDef->Flags &= ~EPISODEF_LookupText;
1229 sc->ExpectString();
1230 EDef->Text = sc->String;
1231 }
1232 }
1233 else if (sc->Check("picname"))
1234 {
1235 sc->ExpectName8();
1236 EDef->PicName = sc->Name8;
1237 }
1238 else if (sc->Check("key"))
1239 {
1240 sc->ExpectString();
1241 EDef->Key = sc->String.ToLower();
1242 }
1243 else if (sc->Check("noskillmenu"))
1244 {
1245 EDef->Flags |= EPISODEF_NoSkillMenu;
1246 }
1247 else if (sc->Check("optional"))
1248 {
1249 EDef->Flags |= EPISODEF_Optional;
1250 }
1251 else
1252 {
1253 break;
1254 }
1255 }
1256 unguard;
1257 }
1258
1259 //==========================================================================
1260 //
1261 // ParseSkillDef
1262 //
1263 //==========================================================================
1264
ParseSkillDef(VScriptParser * sc)1265 static void ParseSkillDef(VScriptParser* sc)
1266 {
1267 guard(ParseSkillDef);
1268 VSkillDef* SDef = NULL;
1269 sc->ExpectString();
1270
1271 // Check for replaced skill.
1272 for (int i = 0; i < SkillDefs.Num(); i++)
1273 {
1274 if (!sc->String.ICmp(SkillDefs[i].Name))
1275 {
1276 SDef = &SkillDefs[i];
1277 break;
1278 }
1279 }
1280 if (!SDef)
1281 {
1282 SDef = &SkillDefs.Alloc();
1283 SDef->Name = sc->String;
1284 }
1285
1286 // Set defaults.
1287 SDef->AmmoFactor = 1.0;
1288 SDef->DoubleAmmoFactor = 2.0;
1289 SDef->DamageFactor = 1.0;
1290 SDef->RespawnTime = 0.0;
1291 SDef->RespawnLimit = 0;
1292 SDef->Aggressiveness = 1.0;
1293 SDef->SpawnFilter = 0;
1294 SDef->AcsReturn = SkillDefs.Num() - 1;
1295 SDef->MenuName.Clean();
1296 SDef->PlayerClassNames.Clear();
1297 SDef->ConfirmationText.Clean();
1298 SDef->Key.Clean();
1299 SDef->TextColour.Clean();
1300 SDef->Flags = 0;
1301
1302 while (1)
1303 {
1304 if (sc->Check("AmmoFactor"))
1305 {
1306 sc->ExpectFloat();
1307 SDef->AmmoFactor = sc->Float;
1308 }
1309 else if (sc->Check("DoubleAmmoFactor"))
1310 {
1311 sc->ExpectFloat();
1312 SDef->DoubleAmmoFactor = sc->Float;
1313 }
1314 else if (sc->Check("DamageFactor"))
1315 {
1316 sc->ExpectFloat();
1317 SDef->DamageFactor = sc->Float;
1318 }
1319 else if (sc->Check("FastMonsters"))
1320 {
1321 SDef->Flags |= SKILLF_FastMonsters;
1322 }
1323 else if (sc->Check("DisableCheats"))
1324 {
1325 SDef->Flags |= SKILLF_DisableCheats;
1326 }
1327 else if (sc->Check("EasyBossBrain"))
1328 {
1329 SDef->Flags |= SKILLF_EasyBossBrain;
1330 }
1331 else if (sc->Check("AutoUseHealth"))
1332 {
1333 SDef->Flags |= SKILLF_AutoUseHealth;
1334 }
1335 else if (sc->Check("RespawnTime"))
1336 {
1337 sc->ExpectFloat();
1338 SDef->RespawnTime = sc->Float;
1339 }
1340 else if (sc->Check("RespawnLimit"))
1341 {
1342 sc->ExpectNumber();
1343 SDef->RespawnLimit = sc->Number;
1344 }
1345 else if (sc->Check("Aggressiveness"))
1346 {
1347 sc->ExpectFloat();
1348 SDef->Aggressiveness = 1.0 - MID(0.0, sc->Float, 1.0);
1349 }
1350 else if (sc->Check("SpawnFilter"))
1351 {
1352 if (sc->CheckNumber())
1353 {
1354 if (sc->Number > 0)
1355 {
1356 SDef->SpawnFilter = 1 << (sc->Number - 1);
1357 }
1358 }
1359 else
1360 {
1361 if (sc->Check("Baby"))
1362 {
1363 SDef->SpawnFilter = 1;
1364 }
1365 else if (sc->Check("Easy"))
1366 {
1367 SDef->SpawnFilter = 2;
1368 }
1369 else if (sc->Check("Normal"))
1370 {
1371 SDef->SpawnFilter = 4;
1372 }
1373 else if (sc->Check("Hard"))
1374 {
1375 SDef->SpawnFilter = 8;
1376 }
1377 else if (sc->Check("Nightmare"))
1378 {
1379 SDef->SpawnFilter = 16;
1380 }
1381 else
1382 {
1383 sc->ExpectString();
1384 }
1385 }
1386 }
1387 else if (sc->Check("ACSReturn"))
1388 {
1389 sc->ExpectNumber();
1390 SDef->AcsReturn = sc->Number;
1391 }
1392 else if (sc->Check("Name"))
1393 {
1394 sc->ExpectString();
1395 SDef->MenuName = sc->String;
1396 SDef->Flags &= ~SKILLF_MenuNameIsPic;
1397 }
1398 else if (sc->Check("PlayerClassName"))
1399 {
1400 VSkillPlayerClassName& CN = SDef->PlayerClassNames.Alloc();
1401 sc->ExpectString();
1402 CN.ClassName = sc->String;
1403 sc->ExpectString();
1404 CN.MenuName = sc->String;
1405 }
1406 else if (sc->Check("PicName"))
1407 {
1408 sc->ExpectString();
1409 SDef->MenuName = sc->String.ToLower();
1410 SDef->Flags |= SKILLF_MenuNameIsPic;
1411 }
1412 else if (sc->Check("MustConfirm"))
1413 {
1414 SDef->Flags |= SKILLF_MustConfirm;
1415 if (sc->CheckQuotedString())
1416 {
1417 SDef->ConfirmationText = sc->String;
1418 }
1419 }
1420 else if (sc->Check("Key"))
1421 {
1422 sc->ExpectString();
1423 SDef->Key = sc->String;
1424 }
1425 else if (sc->Check("TextColor"))
1426 {
1427 sc->ExpectString();
1428 SDef->TextColour = sc->String;
1429 }
1430 else
1431 {
1432 break;
1433 }
1434 }
1435 unguard;
1436 }
1437
1438 //==========================================================================
1439 //
1440 // ParseMapInfo
1441 //
1442 //==========================================================================
1443
ParseMapInfo(VScriptParser * sc)1444 static void ParseMapInfo(VScriptParser* sc)
1445 {
1446 guard(ParseMapInfo);
1447 bool HexenMode = false;
1448
1449 // Set up default map info.
1450 mapInfo_t Default;
1451 SetMapDefaults(Default);
1452
1453 while (!sc->AtEnd())
1454 {
1455 if (sc->Check("map"))
1456 {
1457 ParseMap(sc, HexenMode, Default);
1458 }
1459 else if (sc->Check("defaultmap"))
1460 {
1461 SetMapDefaults(Default);
1462 ParseMapCommon(sc, &Default, HexenMode);
1463 }
1464 else if (sc->Check("adddefaultmap"))
1465 {
1466 ParseMapCommon(sc, &Default, HexenMode);
1467 }
1468 else if (sc->Check("clusterdef"))
1469 {
1470 ParseClusterDef(sc);
1471 }
1472 else if (sc->Check("episode"))
1473 {
1474 ParseEpisodeDef(sc);
1475 }
1476 else if (sc->Check("clearepisodes"))
1477 {
1478 EpisodeDefs.Clear();
1479 }
1480 else if (sc->Check("skill"))
1481 {
1482 ParseSkillDef(sc);
1483 }
1484 else if (sc->Check("clearskills"))
1485 {
1486 SkillDefs.Clear();
1487 }
1488 else
1489 {
1490 sc->Error(va("Invalid command %s", *sc->String));
1491 }
1492 }
1493 delete sc;
1494 sc = NULL;
1495 unguard;
1496 }
1497
1498 //==========================================================================
1499 //
1500 // QualifyMap
1501 //
1502 //==========================================================================
1503
QualifyMap(int map)1504 static int QualifyMap(int map)
1505 {
1506 return (map < 0 || map >= MapInfo.Num()) ? 0 : map;
1507 }
1508
1509 //==========================================================================
1510 //
1511 // P_GetMapInfo
1512 //
1513 //==========================================================================
1514
P_GetMapInfo(VName map)1515 const mapInfo_t& P_GetMapInfo(VName map)
1516 {
1517 guard(P_GetMapInfo);
1518 for (int i = 0; i < MapInfo.Num(); i++)
1519 {
1520 if (map == MapInfo[i].LumpName)
1521 {
1522 return MapInfo[i];
1523 }
1524 }
1525 return DefaultMap;
1526 unguard;
1527 }
1528
1529 //==========================================================================
1530 //
1531 // P_GetMapName
1532 //
1533 //==========================================================================
1534
P_GetMapName(int map)1535 const char* P_GetMapName(int map)
1536 {
1537 return *MapInfo[QualifyMap(map)].GetName();
1538 }
1539
1540 //==========================================================================
1541 //
1542 // P_GetMapLumpName
1543 //
1544 //==========================================================================
1545
P_GetMapLumpName(int map)1546 VName P_GetMapLumpName(int map)
1547 {
1548 return MapInfo[QualifyMap(map)].LumpName;
1549 }
1550
1551 //==========================================================================
1552 //
1553 // P_TranslateMap
1554 //
1555 // Returns the actual map number given a warp map number.
1556 //
1557 //==========================================================================
1558
P_TranslateMap(int map)1559 VName P_TranslateMap(int map)
1560 {
1561 guard(P_TranslateMap);
1562 for (int i = MapInfo.Num() - 1; i >= 0; i--)
1563 {
1564 if (MapInfo[i].WarpTrans == map)
1565 {
1566 return MapInfo[i].LumpName;
1567 }
1568 }
1569 // Not found
1570 return MapInfo[0].LumpName;
1571 unguard;
1572 }
1573
1574 //==========================================================================
1575 //
1576 // P_GetMapNameByLevelNum
1577 //
1578 // Returns the actual map name given a level number.
1579 //
1580 //==========================================================================
1581
P_GetMapNameByLevelNum(int map)1582 VName P_GetMapNameByLevelNum(int map)
1583 {
1584 guard(P_GetMapNameByLevelNum);
1585 for (int i = 0; i < MapInfo.Num(); i++)
1586 {
1587 if (MapInfo[i].LevelNum == map)
1588 {
1589 return MapInfo[i].LumpName;
1590 }
1591 }
1592 // Not found, use map##
1593 return va("map%02d", map);
1594 unguard;
1595 }
1596
1597 //==========================================================================
1598 //
1599 // P_PutMapSongLump
1600 //
1601 //==========================================================================
1602
P_PutMapSongLump(int map,VName lumpName)1603 void P_PutMapSongLump(int map, VName lumpName)
1604 {
1605 guard(P_PutMapSongLump);
1606 FMapSongInfo& ms = MapSongList.Alloc();
1607 ms.MapName = va("map%02d", map);
1608 ms.SongName = lumpName;
1609 unguard;
1610 }
1611
1612 //==========================================================================
1613 //
1614 // P_GetClusterDef
1615 //
1616 //==========================================================================
1617
P_GetClusterDef(int Cluster)1618 const VClusterDef* P_GetClusterDef(int Cluster)
1619 {
1620 guard(P_GetClusterDef);
1621 for (int i = 0; i < ClusterDefs.Num(); i++)
1622 {
1623 if (Cluster == ClusterDefs[i].Cluster)
1624 {
1625 return &ClusterDefs[i];
1626 }
1627 }
1628 return &DefaultClusterDef;
1629 unguard;
1630 }
1631
1632 //==========================================================================
1633 //
1634 // P_GetNumEpisodes
1635 //
1636 //==========================================================================
1637
P_GetNumEpisodes()1638 int P_GetNumEpisodes()
1639 {
1640 return EpisodeDefs.Num();
1641 }
1642
1643 //==========================================================================
1644 //
1645 // P_GetEpisodeDef
1646 //
1647 //==========================================================================
1648
P_GetEpisodeDef(int Index)1649 VEpisodeDef* P_GetEpisodeDef(int Index)
1650 {
1651 return &EpisodeDefs[Index];
1652 }
1653
1654 //==========================================================================
1655 //
1656 // P_GetNumSkills
1657 //
1658 //==========================================================================
1659
P_GetNumSkills()1660 int P_GetNumSkills()
1661 {
1662 return SkillDefs.Num();
1663 }
1664
1665 //==========================================================================
1666 //
1667 // P_GetSkillDef
1668 //
1669 //==========================================================================
1670
P_GetSkillDef(int Index)1671 const VSkillDef* P_GetSkillDef(int Index)
1672 {
1673 return &SkillDefs[Index];
1674 }
1675
1676 //==========================================================================
1677 //
1678 // P_GetMusicLumpNames
1679 //
1680 //==========================================================================
1681
P_GetMusicLumpNames(TArray<FReplacedString> & List)1682 void P_GetMusicLumpNames(TArray<FReplacedString>& List)
1683 {
1684 guard(P_GetMusicLumpNames);
1685 for (int i = 0; i < MapInfo.Num(); i++)
1686 {
1687 const char* MName = *MapInfo[i].SongLump;
1688 if (MName[0] == 'd' && MName[1] == '_')
1689 {
1690 FReplacedString& R = List.Alloc();
1691 R.Index = i;
1692 R.Replaced = false;
1693 R.Old = MName + 2;
1694 }
1695 }
1696 unguard;
1697 }
1698
1699 //==========================================================================
1700 //
1701 // P_ReplaceMusicLumpNames
1702 //
1703 //==========================================================================
1704
P_ReplaceMusicLumpNames(TArray<FReplacedString> & List)1705 void P_ReplaceMusicLumpNames(TArray<FReplacedString>& List)
1706 {
1707 guard(P_ReplaceMusicLumpNames);
1708 for (int i = 0; i < List.Num(); i++)
1709 {
1710 if (List[i].Replaced)
1711 {
1712 MapInfo[List[i].Index].SongLump = VName(*(VStr("d_") +
1713 List[i].New), VName::AddLower8);
1714 }
1715 }
1716 unguard;
1717 }
1718
1719 //==========================================================================
1720 //
1721 // P_SetParTime
1722 //
1723 //==========================================================================
1724
P_SetParTime(VName Map,int Par)1725 void P_SetParTime(VName Map, int Par)
1726 {
1727 guard(P_SetParTime);
1728 for (int i = 0; i < MapInfo.Num(); i++)
1729 {
1730 if (MapInfo[i].LumpName == Map)
1731 {
1732 MapInfo[i].ParTime = Par;
1733 return;
1734 }
1735 }
1736 GCon->Logf("WARNING! No such map %s", *Map);
1737 unguard;
1738 }
1739
1740 //==========================================================================
1741 //
1742 // IsMapPresent
1743 //
1744 //==========================================================================
1745
IsMapPresent(VName MapName)1746 bool IsMapPresent(VName MapName)
1747 {
1748 guard(IsMapPresent);
1749 if (W_CheckNumForName(MapName) >= 0)
1750 {
1751 return true;
1752 }
1753 VStr FileName = va("maps/%s.wad", *MapName);
1754 if (FL_FileExists(FileName))
1755 {
1756 return true;
1757 }
1758 return false;
1759 unguard;
1760 }
1761
1762 //==========================================================================
1763 //
1764 // P_GetCDStartTrack
1765 //
1766 //==========================================================================
1767
P_GetCDStartTrack()1768 int P_GetCDStartTrack()
1769 {
1770 return cd_NonLevelTracks[CD_STARTTRACK];
1771 }
1772
1773 //==========================================================================
1774 //
1775 // P_GetCDEnd1Track
1776 //
1777 //==========================================================================
1778
P_GetCDEnd1Track()1779 int P_GetCDEnd1Track()
1780 {
1781 return cd_NonLevelTracks[CD_END1TRACK];
1782 }
1783
1784 //==========================================================================
1785 //
1786 // P_GetCDEnd2Track
1787 //
1788 //==========================================================================
1789
P_GetCDEnd2Track()1790 int P_GetCDEnd2Track()
1791 {
1792 return cd_NonLevelTracks[CD_END2TRACK];
1793 }
1794
1795 //==========================================================================
1796 //
1797 // P_GetCDEnd3Track
1798 //
1799 //==========================================================================
1800
P_GetCDEnd3Track()1801 int P_GetCDEnd3Track()
1802 {
1803 return cd_NonLevelTracks[CD_END3TRACK];
1804 }
1805
1806 //==========================================================================
1807 //
1808 // P_GetCDIntermissionTrack
1809 //
1810 //==========================================================================
1811
P_GetCDIntermissionTrack()1812 int P_GetCDIntermissionTrack()
1813 {
1814 return cd_NonLevelTracks[CD_INTERTRACK];
1815 }
1816
1817 //==========================================================================
1818 //
1819 // P_GetCDTitleTrack
1820 //
1821 //==========================================================================
1822
P_GetCDTitleTrack()1823 int P_GetCDTitleTrack()
1824 {
1825 return cd_NonLevelTracks[CD_TITLETRACK];
1826 }
1827
1828 //==========================================================================
1829 //
1830 // COMMAND MapList
1831 //
1832 //==========================================================================
1833
COMMAND(MapList)1834 COMMAND(MapList)
1835 {
1836 guard(COMMAND MapList);
1837 for (int i = 0; i < MapInfo.Num(); i++)
1838 {
1839 if (IsMapPresent(MapInfo[i].LumpName))
1840 {
1841 GCon->Log(VStr(MapInfo[i].LumpName) + " - " +
1842 ((MapInfo[i].Flags & MAPINFOF_LookupName) ?
1843 GLanguage[*MapInfo[i].Name] : MapInfo[i].Name));
1844 }
1845 }
1846 unguard;
1847 }
1848
1849 //==========================================================================
1850 //
1851 // ShutdownMapInfo
1852 //
1853 //==========================================================================
1854
ShutdownMapInfo()1855 void ShutdownMapInfo()
1856 {
1857 guard(ShutdownMapInfo);
1858 DefaultMap.Name.Clean();
1859 MapInfo.Clear();
1860 MapSongList.Clear();
1861 ClusterDefs.Clear();
1862 EpisodeDefs.Clear();
1863 SkillDefs.Clear();
1864 unguard;
1865 }
1866