1 /*
2 ** intermission_parser.cpp
3 ** Parser for intermission definitions in MAPINFO
4 ** (both new style and old style 'ENDGAME' blocks)
5 **
6 **---------------------------------------------------------------------------
7 ** Copyright 2010 Christoph Oelckers
8 ** All rights reserved.
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions
12 ** are met:
13 **
14 ** 1. Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** 2. Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in the
18 ** documentation and/or other materials provided with the distribution.
19 ** 3. The name of the author may not be used to endorse or promote products
20 ** derived from this software without specific prior written permission.
21 **
22 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 **---------------------------------------------------------------------------
33 **
34 */
35
36
37 #include "intermission/intermission.h"
38 #include "g_level.h"
39 #include "w_wad.h"
40 #include "gi.h"
41
42
ReplaceIntermission(FName intname,FIntermissionDescriptor * desc)43 static void ReplaceIntermission(FName intname,FIntermissionDescriptor *desc)
44 {
45 FIntermissionDescriptor ** pDesc = IntermissionDescriptors.CheckKey(intname);
46 if (pDesc != NULL && *pDesc != NULL) delete *pDesc;
47 IntermissionDescriptors[intname] = desc;
48 }
49
DeinitIntermissions()50 void DeinitIntermissions()
51 {
52 FIntermissionDescriptorList::Iterator it(IntermissionDescriptors);
53
54 FIntermissionDescriptorList::Pair *pair;
55
56 while (it.NextPair(pair))
57 {
58 delete pair->Value;
59 pair->Value = NULL;
60 }
61 IntermissionDescriptors.Clear();
62 }
63
64 //==========================================================================
65 //
66 // FIntermissionAction
67 //
68 //==========================================================================
69
FIntermissionAction()70 FIntermissionAction::FIntermissionAction()
71 {
72 mSize = sizeof(FIntermissionAction);
73 mClass = RUNTIME_CLASS(DIntermissionScreen);
74 mMusicOrder =
75 mCdId =
76 mCdTrack =
77 mDuration = 0;
78 mFlatfill = false;
79 mMusicLooping = true;
80 }
81
ParseKey(FScanner & sc)82 bool FIntermissionAction::ParseKey(FScanner &sc)
83 {
84 if (sc.Compare("music"))
85 {
86 sc.MustGetToken('=');
87 sc.MustGetToken(TK_StringConst);
88 mMusic = sc.String;
89 mMusicOrder = 0;
90 if (sc.CheckToken(','))
91 {
92 sc.MustGetToken(TK_IntConst);
93 mMusicOrder = sc.Number;
94 }
95 return true;
96 }
97 else if (sc.Compare("cdmusic"))
98 {
99 sc.MustGetToken('=');
100 sc.MustGetToken(TK_IntConst);
101 mCdTrack = sc.Number;
102 mCdId = 0;
103 if (sc.CheckToken(','))
104 {
105 sc.MustGetToken(TK_IntConst);
106 mCdId = sc.Number;
107 }
108 return true;
109 }
110 else if (sc.Compare("Time"))
111 {
112 sc.MustGetToken('=');
113 if (!sc.CheckToken('-'))
114 {
115 sc.MustGetFloat();
116 mDuration = xs_RoundToInt(sc.Float*TICRATE);
117 }
118 else
119 {
120 sc.MustGetToken(TK_IntConst);
121 mDuration = sc.Number;
122 }
123 return true;
124 }
125 else if (sc.Compare("Background"))
126 {
127 sc.MustGetToken('=');
128 sc.MustGetToken(TK_StringConst);
129 mBackground = sc.String;
130 mFlatfill = 0;
131 if (sc.CheckToken(','))
132 {
133 sc.MustGetToken(TK_IntConst);
134 mFlatfill = !!sc.Number;
135 if (sc.CheckToken(','))
136 {
137 sc.MustGetToken(TK_StringConst);
138 mPalette = sc.String;
139 }
140 }
141 return true;
142 }
143 else if (sc.Compare("Sound"))
144 {
145 sc.MustGetToken('=');
146 sc.MustGetToken(TK_StringConst);
147 mSound = sc.String;
148 return true;
149 }
150 else if (sc.Compare("Draw"))
151 {
152 FIntermissionPatch *pat = &mOverlays[mOverlays.Reserve(1)];
153 sc.MustGetToken('=');
154 sc.MustGetToken(TK_StringConst);
155 pat->mName = sc.String;
156 sc.MustGetToken(',');
157 sc.MustGetToken(TK_IntConst);
158 pat->x = sc.Number;
159 sc.MustGetToken(',');
160 sc.MustGetToken(TK_IntConst);
161 pat->y = sc.Number;
162 pat->mCondition = NAME_None;
163 return true;
164 }
165 else if (sc.Compare("DrawConditional"))
166 {
167 FIntermissionPatch *pat = &mOverlays[mOverlays.Reserve(1)];
168 sc.MustGetToken('=');
169 sc.MustGetToken(TK_StringConst);
170 pat->mCondition = sc.String;
171 sc.MustGetToken(',');
172 sc.MustGetToken(TK_StringConst);
173 pat->mName = sc.String;
174 sc.MustGetToken(',');
175 sc.MustGetToken(TK_IntConst);
176 pat->x = sc.Number;
177 sc.MustGetToken(',');
178 sc.MustGetToken(TK_IntConst);
179 pat->y = sc.Number;
180 return true;
181 }
182 else return false;
183 }
184
185 //==========================================================================
186 //
187 // FIntermissionActionFader
188 //
189 //==========================================================================
190
FIntermissionActionFader()191 FIntermissionActionFader::FIntermissionActionFader()
192 {
193 mSize = sizeof(FIntermissionActionFader);
194 mClass = RUNTIME_CLASS(DIntermissionScreenFader);
195 mFadeType = FADE_In;
196 }
197
ParseKey(FScanner & sc)198 bool FIntermissionActionFader::ParseKey(FScanner &sc)
199 {
200 struct FadeType
201 {
202 const char *Name;
203 EFadeType Type;
204 }
205 const FT[] = {
206 { "FadeIn", FADE_In },
207 { "FadeOut", FADE_Out },
208 { NULL, FADE_In }
209 };
210
211 if (sc.Compare("FadeType"))
212 {
213 sc.MustGetToken('=');
214 sc.MustGetToken(TK_Identifier);
215 int v = sc.MatchString(&FT[0].Name, sizeof(FT[0]));
216 if (v != -1) mFadeType = FT[v].Type;
217 return true;
218 }
219 else return Super::ParseKey(sc);
220 }
221
222 //==========================================================================
223 //
224 // FIntermissionActionWiper
225 //
226 //==========================================================================
227
FIntermissionActionWiper()228 FIntermissionActionWiper::FIntermissionActionWiper()
229 {
230 mSize = sizeof(FIntermissionActionWiper);
231 mClass = WIPER_ID;
232 mWipeType = GS_FORCEWIPE;
233 }
234
ParseKey(FScanner & sc)235 bool FIntermissionActionWiper::ParseKey(FScanner &sc)
236 {
237 struct WipeType
238 {
239 const char *Name;
240 gamestate_t Type;
241 }
242 const FT[] = {
243 { "Crossfade", GS_FORCEWIPEFADE },
244 { "Melt", GS_FORCEWIPEMELT },
245 { "Burn", GS_FORCEWIPEBURN },
246 { "Default", GS_FORCEWIPE },
247 { NULL, GS_FORCEWIPE }
248 };
249
250 if (sc.Compare("WipeType"))
251 {
252 sc.MustGetToken('=');
253 sc.MustGetToken(TK_Identifier);
254 int v = sc.MatchString(&FT[0].Name, sizeof(FT[0]));
255 if (v != -1) mWipeType = FT[v].Type;
256 return true;
257 }
258 else return Super::ParseKey(sc);
259 }
260
261 //==========================================================================
262 //
263 // FIntermissionActionFader
264 //
265 //==========================================================================
266
FIntermissionActionTextscreen()267 FIntermissionActionTextscreen::FIntermissionActionTextscreen()
268 {
269 mSize = sizeof(FIntermissionActionTextscreen);
270 mClass = RUNTIME_CLASS(DIntermissionScreenText);
271 mTextSpeed = 2;
272 mTextX = -1; // use gameinfo defaults
273 mTextY = -1;
274 mTextColor = CR_UNTRANSLATED;
275 mTextDelay = 10;
276 }
277
ParseKey(FScanner & sc)278 bool FIntermissionActionTextscreen::ParseKey(FScanner &sc)
279 {
280 if (sc.Compare("Position"))
281 {
282 sc.MustGetToken('=');
283 sc.MustGetToken(TK_IntConst);
284 mTextX = sc.Number;
285 sc.MustGetToken(',');
286 sc.MustGetToken(TK_IntConst);
287 mTextY = sc.Number;
288 return true;
289 }
290 else if (sc.Compare("TextLump"))
291 {
292 sc.MustGetToken('=');
293 sc.MustGetToken(TK_StringConst);
294 int lump = Wads.CheckNumForFullName(sc.String, true);
295 if (lump > 0)
296 {
297 mText = Wads.ReadLump(lump).GetString();
298 }
299 else
300 {
301 // only print an error if coming from a PWAD
302 if (Wads.GetLumpFile(sc.LumpNum) > 1)
303 sc.ScriptMessage("Unknown text lump '%s'", sc.String);
304 mText.Format("Unknown text lump '%s'", sc.String);
305 }
306 return true;
307 }
308 else if (sc.Compare("Text"))
309 {
310 sc.MustGetToken('=');
311 do
312 {
313 sc.MustGetToken(TK_StringConst);
314 mText << sc.String << '\n';
315 }
316 while (sc.CheckToken(','));
317 return true;
318 }
319 else if (sc.Compare("TextColor"))
320 {
321 sc.MustGetToken('=');
322 sc.MustGetToken(TK_StringConst);
323 mTextColor = V_FindFontColor(sc.String);
324 return true;
325 }
326 else if (sc.Compare("TextDelay"))
327 {
328 sc.MustGetToken('=');
329 if (!sc.CheckToken('-'))
330 {
331 sc.MustGetFloat();
332 mTextDelay = xs_RoundToInt(sc.Float*TICRATE);
333 }
334 else
335 {
336 sc.MustGetToken(TK_IntConst);
337 mTextDelay = sc.Number;
338 }
339 return true;
340 }
341 else if (sc.Compare("textspeed"))
342 {
343 sc.MustGetToken('=');
344 sc.MustGetToken(TK_IntConst);
345 mTextSpeed = sc.Number;
346 return true;
347 }
348 else return Super::ParseKey(sc);
349 }
350
351 //==========================================================================
352 //
353 // FIntermissionAction
354 //
355 //==========================================================================
356
FIntermissionActionCast()357 FIntermissionActionCast::FIntermissionActionCast()
358 {
359 mSize = sizeof(FIntermissionActionCast);
360 mClass = RUNTIME_CLASS(DIntermissionScreenCast);
361 }
362
ParseKey(FScanner & sc)363 bool FIntermissionActionCast::ParseKey(FScanner &sc)
364 {
365 if (sc.Compare("CastName"))
366 {
367 sc.MustGetToken('=');
368 sc.MustGetToken(TK_StringConst);
369 mName = sc.String;
370 return true;
371 }
372 else if (sc.Compare("CastClass"))
373 {
374 sc.MustGetToken('=');
375 sc.MustGetToken(TK_StringConst);
376 mCastClass = sc.String;
377 return true;
378 }
379 else if (sc.Compare("AttackSound"))
380 {
381 static const char *const seqs[] = {"Missile", "Melee", NULL};
382 FCastSound *cs = &mCastSounds[mCastSounds.Reserve(1)];
383 sc.MustGetToken('=');
384 sc.MustGetToken(TK_StringConst);
385 cs->mSequence = (BYTE)sc.MatchString(seqs);
386 sc.MustGetToken(',');
387 sc.MustGetToken(TK_IntConst);
388 cs->mIndex = (BYTE)sc.Number;
389 sc.MustGetToken(',');
390 sc.MustGetToken(TK_StringConst);
391 cs->mSound = sc.String;
392 return true;
393 }
394 else return Super::ParseKey(sc);
395 }
396
397 //==========================================================================
398 //
399 // FIntermissionActionScroller
400 //
401 //==========================================================================
402
FIntermissionActionScroller()403 FIntermissionActionScroller::FIntermissionActionScroller()
404 {
405 mSize = sizeof(FIntermissionActionScroller);
406 mClass = RUNTIME_CLASS(DIntermissionScreenScroller);
407 mScrollDelay = 0;
408 mScrollTime = 640;
409 mScrollDir = SCROLL_Right;
410 }
411
ParseKey(FScanner & sc)412 bool FIntermissionActionScroller::ParseKey(FScanner &sc)
413 {
414 struct ScrollType
415 {
416 const char *Name;
417 EScrollDir Type;
418 }
419 const ST[] = {
420 { "Left", SCROLL_Left },
421 { "Right", SCROLL_Right },
422 { "Up", SCROLL_Up },
423 { "Down", SCROLL_Down },
424 { NULL, SCROLL_Left }
425 };
426
427 if (sc.Compare("ScrollDirection"))
428 {
429 sc.MustGetToken('=');
430 sc.MustGetToken(TK_Identifier);
431 int v = sc.MatchString(&ST[0].Name, sizeof(ST[0]));
432 if (v != -1) mScrollDir = ST[v].Type;
433 return true;
434 }
435 else if (sc.Compare("InitialDelay"))
436 {
437 sc.MustGetToken('=');
438 if (!sc.CheckToken('-'))
439 {
440 sc.MustGetFloat();
441 mScrollDelay = xs_RoundToInt(sc.Float*TICRATE);
442 }
443 else
444 {
445 sc.MustGetToken(TK_IntConst);
446 mScrollDelay = sc.Number;
447 }
448 return true;
449 }
450 else if (sc.Compare("ScrollTime"))
451 {
452 sc.MustGetToken('=');
453 if (!sc.CheckToken('-'))
454 {
455 sc.MustGetFloat();
456 mScrollTime = xs_RoundToInt(sc.Float*TICRATE);
457 }
458 else
459 {
460 sc.MustGetToken(TK_IntConst);
461 mScrollTime = sc.Number;
462 }
463 return true;
464 }
465 else if (sc.Compare("Background2"))
466 {
467 sc.MustGetToken('=');
468 sc.MustGetToken(TK_StringConst);
469 mSecondPic = sc.String;
470 return true;
471 }
472 else return Super::ParseKey(sc);
473 }
474
475 //==========================================================================
476 //
477 // ParseIntermission
478 //
479 //==========================================================================
480
ParseIntermissionAction(FIntermissionDescriptor * desc)481 void FMapInfoParser::ParseIntermissionAction(FIntermissionDescriptor *desc)
482 {
483 FIntermissionAction *ac = NULL;
484
485 sc.MustGetToken(TK_Identifier);
486 if (sc.Compare("image"))
487 {
488 ac = new FIntermissionAction;
489 }
490 else if (sc.Compare("scroller"))
491 {
492 ac = new FIntermissionActionScroller;
493 }
494 else if (sc.Compare("cast"))
495 {
496 ac = new FIntermissionActionCast;
497 }
498 else if (sc.Compare("Fader"))
499 {
500 ac = new FIntermissionActionFader;
501 }
502 else if (sc.Compare("Wiper"))
503 {
504 ac = new FIntermissionActionWiper;
505 }
506 else if (sc.Compare("TextScreen"))
507 {
508 ac = new FIntermissionActionTextscreen;
509 }
510 else if (sc.Compare("GotoTitle"))
511 {
512 ac = new FIntermissionAction;
513 ac->mClass = TITLE_ID;
514 }
515 else if (sc.Compare("Link"))
516 {
517 sc.MustGetToken('=');
518 sc.MustGetToken(TK_Identifier);
519 desc->mLink = sc.String;
520 return;
521 }
522 else
523 {
524 sc.ScriptMessage("Unknown intermission type '%s'", sc.String);
525 }
526
527 sc.MustGetToken('{');
528 while (!sc.CheckToken('}'))
529 {
530 bool success = false;
531 if (!sc.CheckToken(TK_Sound))
532 {
533 sc.MustGetToken(TK_Identifier);
534 }
535 if (ac != NULL)
536 {
537 success = ac->ParseKey(sc);
538 if (!success)
539 {
540 sc.ScriptMessage("Unknown key name '%s'\n", sc.String);
541 }
542 }
543 if (!success) SkipToNext();
544 }
545 if (ac != NULL) desc->mActions.Push(ac);
546 }
547
548 //==========================================================================
549 //
550 // ParseIntermission
551 //
552 //==========================================================================
553
ParseIntermission()554 void FMapInfoParser::ParseIntermission()
555 {
556 sc.MustGetString();
557 FName intname = sc.String;
558 FIntermissionDescriptor *desc = new FIntermissionDescriptor();
559
560 ReplaceIntermission(intname, desc);
561 sc.MustGetToken('{');
562 while (!sc.CheckToken('}'))
563 {
564 ParseIntermissionAction(desc);
565 }
566 }
567
568 //==========================================================================
569 //
570 // Parse old style endsequence
571 //
572 //==========================================================================
573
574 struct EndSequence
575 {
576 SBYTE EndType;
577 bool MusicLooping;
578 bool PlayTheEnd;
579 FString PicName;
580 FString PicName2;
581 FString Music;
582 };
583
584 enum EndTypes
585 {
586 END_Pic,
587 END_Bunny,
588 END_Cast,
589 END_Demon
590 };
591
ParseEndGame()592 FName FMapInfoParser::ParseEndGame()
593 {
594 EndSequence newSeq;
595 static int generated = 0;
596
597 newSeq.EndType = -1;
598 newSeq.PlayTheEnd = false;
599 newSeq.MusicLooping = true;
600 while (!sc.CheckString("}"))
601 {
602 sc.MustGetString();
603 if (sc.Compare("pic"))
604 {
605 ParseAssign();
606 sc.MustGetString();
607 newSeq.EndType = END_Pic;
608 newSeq.PicName = sc.String;
609 }
610 else if (sc.Compare("hscroll"))
611 {
612 ParseAssign();
613 newSeq.EndType = END_Bunny;
614 sc.MustGetString();
615 newSeq.PicName = sc.String;
616 ParseComma();
617 sc.MustGetString();
618 newSeq.PicName2 = sc.String;
619 if (CheckNumber())
620 newSeq.PlayTheEnd = !!sc.Number;
621 }
622 else if (sc.Compare("vscroll"))
623 {
624 ParseAssign();
625 newSeq.EndType = END_Demon;
626 sc.MustGetString();
627 newSeq.PicName = sc.String;
628 ParseComma();
629 sc.MustGetString();
630 newSeq.PicName2 = sc.String;
631 }
632 else if (sc.Compare("cast"))
633 {
634 newSeq.EndType = END_Cast;
635 if (newSeq.PicName.IsEmpty()) newSeq.PicName = "$bgcastcall";
636 }
637 else if (sc.Compare("music"))
638 {
639 ParseAssign();
640 sc.MustGetString();
641 newSeq.Music = sc.String;
642 if (CheckNumber())
643 {
644 newSeq.MusicLooping = !!sc.Number;
645 }
646 }
647 else
648 {
649 if (format_type == FMT_New)
650 {
651 // Unknown
652 sc.ScriptMessage("Unknown property '%s' found in endgame definition\n", sc.String);
653 SkipToNext();
654 }
655 else
656 {
657 sc.ScriptError("Unknown property '%s' found in endgame definition\n", sc.String);
658 }
659
660 }
661 }
662 FIntermissionDescriptor *desc = new FIntermissionDescriptor;
663 FIntermissionAction *action = NULL;
664
665 switch (newSeq.EndType)
666 {
667 case END_Pic:
668 action = new FIntermissionAction;
669 break;
670
671 case END_Bunny:
672 {
673 FIntermissionActionScroller *bunny = new FIntermissionActionScroller;
674 bunny->mSecondPic = newSeq.PicName2;
675 bunny->mScrollDir = SCROLL_Left;
676 bunny->mScrollDelay = 230;
677 bunny->mScrollTime = 640;
678 bunny->mDuration = 1130;
679 action = bunny;
680 if (newSeq.PlayTheEnd) desc->mLink = "TheEnd";
681 break;
682 }
683
684 case END_Demon:
685 {
686 FIntermissionActionScroller *demon = new FIntermissionActionScroller;
687 demon->mSecondPic = newSeq.PicName2;
688 demon->mScrollDir = SCROLL_Up;
689 demon->mScrollDelay = 70;
690 demon->mScrollTime = 600;
691 action = demon;
692 break;
693 }
694
695 case END_Cast:
696 action = new FIntermissionAction;
697 action->mDuration = 1;
698 desc->mLink = "Doom2Cast";
699 break;
700 }
701
702 if (action == NULL)
703 {
704 sc.ScriptError("Endgame type was not defined");
705 return NAME_None; // We won't really get here.
706 }
707 else
708 {
709 action->mBackground = newSeq.PicName;
710 action->mMusic = newSeq.Music;
711 action->mMusicLooping = newSeq.MusicLooping;
712 desc->mActions.Push(action);
713
714 FString seq;
715 seq.Format("@EndSequence_%d_", generated++);
716 ReplaceIntermission(seq, desc);
717 return FName(seq);
718 }
719 }
720
721 //==========================================================================
722 //
723 // Checks map name for end sequence
724 //
725 //==========================================================================
726
CheckEndSequence()727 FName FMapInfoParser::CheckEndSequence()
728 {
729 const char *seqname = NULL;
730
731 if (sc.Compare("endgame"))
732 {
733 if (!sc.CheckString("{"))
734 {
735 // Make Demon Eclipse work again
736 sc.UnGet();
737 goto standard_endgame;
738 }
739 return ParseEndGame();
740 }
741 else if (strnicmp (sc.String, "EndGame", 7) == 0)
742 {
743 switch (sc.String[7])
744 {
745 case '1': seqname = "Inter_Pic1"; break;
746 case '2': seqname = "Inter_Pic2"; break;
747 case '3': seqname = "Inter_Bunny"; break;
748 case 'C': seqname = "Inter_Cast"; break;
749 case 'W': seqname = "Inter_Underwater"; break;
750 case 'S': seqname = "Inter_Strife"; break;
751 standard_endgame:
752 default: seqname = "Inter_Pic3"; break;
753 }
754 }
755 else if (sc.Compare("endpic"))
756 {
757 ParseComma();
758 sc.MustGetString ();
759 FString seqname;
760 seqname << "@EndPic_" << sc.String;
761 FIntermissionDescriptor *desc = new FIntermissionDescriptor;
762 FIntermissionAction *action = new FIntermissionAction;
763 action->mBackground = sc.String;
764 desc->mActions.Push(action);
765 ReplaceIntermission(seqname, desc);
766 return FName(seqname);
767 }
768 else if (sc.Compare("endbunny"))
769 {
770 seqname = "Inter_Bunny";
771 }
772 else if (sc.Compare("endcast"))
773 {
774 seqname = "Inter_Cast";
775 }
776 else if (sc.Compare("enddemon"))
777 {
778 seqname = "Inter_Demonscroll";
779 }
780 else if (sc.Compare("endchess"))
781 {
782 seqname = "Inter_Chess";
783 }
784 else if (sc.Compare("endunderwater"))
785 {
786 seqname = "Inter_Underwater";
787 }
788 else if (sc.Compare("endbuystrife"))
789 {
790 seqname = "Inter_BuyStrife";
791 }
792 else if (sc.Compare("endtitle"))
793 {
794 seqname = "Inter_Titlescreen";
795 }
796 else if (sc.Compare("endsequence"))
797 {
798 ParseComma();
799 sc.MustGetString();
800 seqname = sc.String;
801 }
802
803 if (seqname != NULL)
804 {
805 return FName(seqname);
806 }
807 return NAME_None;
808 }
809
810
811 //==========================================================================
812 //
813 // Creates an intermission from the cluster's finale info
814 //
815 //==========================================================================
816
F_StartFinale(const char * music,int musicorder,int cdtrack,unsigned int cdid,const char * flat,const char * text,INTBOOL textInLump,INTBOOL finalePic,INTBOOL lookupText,bool ending,FName endsequence)817 void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat,
818 const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText,
819 bool ending, FName endsequence)
820 {
821 // Hexen's chess ending doesn't have a text screen, even if the cluster has a message defined.
822 if (text != NULL && *text != 0 && endsequence != NAME_Inter_Chess)
823 {
824 FIntermissionActionTextscreen *textscreen = new FIntermissionActionTextscreen;
825 if (textInLump)
826 {
827 int lump = Wads.CheckNumForFullName(text, true);
828 if (lump > 0)
829 {
830 textscreen->mText = Wads.ReadLump(lump).GetString();
831 }
832 else
833 {
834 textscreen->mText.Format("Unknown text lump '%s'", text);
835 }
836 }
837 else if (!lookupText)
838 {
839 textscreen->mText = text;
840 }
841 else
842 {
843 textscreen->mText << '$' << text;
844 }
845 textscreen->mTextDelay = 10;
846 if (flat != NULL && *flat != 0)
847 {
848 textscreen->mBackground = flat;
849 }
850 else
851 {
852 // force a black screen if no texture is set.
853 textscreen->mBackground = "-";
854 }
855 textscreen->mFlatfill = !finalePic;
856
857 if (music != NULL && *music != 0)
858 {
859 textscreen->mMusic = music;
860 textscreen->mMusicOrder = musicorder;
861 }
862 if (cdtrack > 0)
863 {
864 textscreen->mCdTrack = cdtrack;
865 textscreen->mCdId = cdid;
866 }
867 FIntermissionDescriptor *desc = new FIntermissionDescriptor;
868 desc->mActions.Push(textscreen);
869
870 if (ending)
871 {
872 desc->mLink = endsequence;
873 FIntermissionActionWiper *wiper = new FIntermissionActionWiper;
874 desc->mActions.Push(wiper);
875 }
876
877 F_StartIntermission(desc, true, ending? FSTATE_EndingGame : FSTATE_ChangingLevel);
878 }
879 else if (ending)
880 {
881 FIntermissionDescriptor **pdesc = IntermissionDescriptors.CheckKey(endsequence);
882 if (pdesc != NULL)
883 {
884 F_StartIntermission(*pdesc, false, ending? FSTATE_EndingGame : FSTATE_ChangingLevel);
885 }
886 }
887 }
888