1 /*
2 ** g_intermission.cpp
3 **
4 **---------------------------------------------------------------------------
5 ** Copyright 2012 Braden Obrzut
6 ** All rights reserved.
7 **
8 ** Redistribution and use in source and binary forms, with or without
9 ** modification, are permitted provided that the following conditions
10 ** are met:
11 **
12 ** 1. Redistributions of source code must retain the above copyright
13 ** notice, this list of conditions and the following disclaimer.
14 ** 2. Redistributions in binary form must reproduce the above copyright
15 ** notice, this list of conditions and the following disclaimer in the
16 ** documentation and/or other materials provided with the distribution.
17 ** 3. The name of the author may not be used to endorse or promote products
18 ** derived from this software without specific prior written permission.
19 **
20 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 **---------------------------------------------------------------------------
31 **
32 **
33 */
34
35 #include "wl_def.h"
36 #include "id_ca.h"
37 #include "id_in.h"
38 #include "id_sd.h"
39 #include "id_vh.h"
40 #include "g_intermission.h"
41 #include "language.h"
42 #include "r_sprites.h"
43 #include "tarray.h"
44 #include "wl_agent.h"
45 #include "wl_draw.h"
46 #include "wl_game.h"
47 #include "wl_inter.h"
48 #include "wl_menu.h"
49 #include "wl_play.h"
50 #include "thingdef/thingdef.h"
51
52 static TMap<FName, IntermissionInfo> intermissions;
53
Find(const FName & name)54 IntermissionInfo *IntermissionInfo::Find(const FName &name)
55 {
56 return &intermissions[name];
57 }
58
Clear()59 void IntermissionInfo::Clear()
60 {
61 for(unsigned int i = 0;i < Actions.Size();++i)
62 delete Actions[i].action;
63 Actions.Clear();
64 }
65
66 ////////////////////////////////////////////////////////////////////////////////
67
68 void StartTravel ();
69 void FinishTravel ();
70
71 static bool intermissionMapLoaded = false;
72 static bool exitOnAck;
73
ClearStatusbar()74 static void ClearStatusbar()
75 {
76 DrawPlayScreen();
77
78 FTexture *borderTex = TexMan(levelInfo->GetBorderTexture());
79 VWB_DrawFill(borderTex, statusbarx, statusbary2+CleanYfac, screenWidth-statusbarx, screenHeight);
80 }
81
WaitIntermission(unsigned int time)82 static bool WaitIntermission(unsigned int time)
83 {
84 if(time)
85 {
86 return IN_UserInput(time);
87 }
88 else
89 {
90 IN_ClearKeysDown ();
91 IN_Ack ();
92 return true;
93 }
94 }
95
ShowImage(IntermissionAction * image,bool drawonly)96 static bool ShowImage(IntermissionAction *image, bool drawonly)
97 {
98 if(!image->Music.IsEmpty())
99 StartCPMusic(image->Music);
100
101 if(!image->Palette.IsEmpty())
102 {
103 if(image->Palette.CompareNoCase("$GamePalette") == 0)
104 VL_ReadPalette(gameinfo.GamePalette);
105 else
106 VL_ReadPalette(image->Palette);
107 }
108
109 static FTextureID background;
110 static bool tileBackground = false;
111 static IntermissionAction::BackgroundType type = IntermissionAction::NORMAL;
112
113 // High Scores and such need special handling
114 if(image->Type != IntermissionAction::UNSET)
115 {
116 type = image->Type;
117 }
118 if(type == IntermissionAction::NORMAL && image->Background.isValid())
119 {
120 background = image->Background;
121 tileBackground = image->BackgroundTile;
122 }
123
124 intermissionMapLoaded = false;
125 switch(type)
126 {
127 default:
128 if(!tileBackground)
129 CA_CacheScreen(TexMan(background));
130 else
131 VWB_DrawFill(TexMan(background), 0, 0, screenWidth, screenHeight);
132 break;
133 case IntermissionAction::HIGHSCORES:
134 DrawHighScores();
135 break;
136 case IntermissionAction::TITLEPAGE:
137 background = TexMan.CheckForTexture(gameinfo.TitlePage, FTexture::TEX_Any);
138 if(!gameinfo.TitlePalette.IsEmpty())
139 VL_ReadPalette(gameinfo.TitlePalette);
140 CA_CacheScreen(TexMan(background));
141 break;
142 case IntermissionAction::LOADMAP:
143 if(image->MapName.IsNotEmpty())
144 {
145 strncpy(gamestate.mapname, image->MapName, 8);
146 StartTravel();
147 SetupGameLevel();
148 FinishTravel();
149 // Drop weapon
150 players[0].SetPSprite(NULL, player_t::ps_weapon);
151 PreloadGraphics(true);
152 gamestate.victoryflag = true;
153 }
154 intermissionMapLoaded = true;
155 ThreeDRefresh();
156 ClearStatusbar();
157 break;
158 }
159
160 for(unsigned int i = 0;i < image->Draw.Size();++i)
161 {
162 VWB_DrawGraphic(TexMan(image->Draw[i].Image), image->Draw[i].X, image->Draw[i].Y);
163 }
164
165 if(!drawonly)
166 {
167 VW_UpdateScreen();
168 return WaitIntermission(image->Time);
169 }
170 return false;
171 }
172
173
DrawCastName(CastIntermissionAction * cast)174 static void DrawCastName(CastIntermissionAction *cast)
175 {
176 int width = BigFont->StringWidth(cast->Name);
177 screen->DrawText(BigFont, gameinfo.FontColors[GameInfo::DIALOG],
178 (screenWidth - width*CleanXfac)/2, statusbary2 + (screenHeight - statusbary2 - BigFont->GetHeight())/2,
179 cast->Name,
180 DTA_CleanNoMove, true,
181 TAG_DONE
182 );
183 }
R_CastZoomer(const Frame * frame,CastIntermissionAction * cast)184 static bool R_CastZoomer(const Frame *frame, CastIntermissionAction *cast)
185 {
186 // This may appear to animate faster than vanilla, but I'm fairly sure
187 // that's because while the time on screen is adaptive, the frame durations
188 // were decremented by one each frame.
189 TObjPtr<SpriteZoomer> zoomer = new SpriteZoomer(frame, 224);
190 do
191 {
192 for(unsigned int t = tics;zoomer && t-- > 0;)
193 zoomer->Tick();
194 if(!zoomer)
195 break;
196
197 if(intermissionMapLoaded)
198 ThreeDRefresh();
199 else
200 {
201 // Unlike a 3D view, we will overwrite the whole screen here
202 ShowImage(cast, true);
203 DrawCastName(cast);
204 }
205 zoomer->Draw();
206 VH_UpdateScreen();
207 IN_ProcessEvents();
208 if(Keyboard[sc_Space] || Keyboard[sc_Escape] || Keyboard[sc_Enter])
209 {
210 bool done = Keyboard[sc_Escape] || Keyboard[sc_Enter];
211 Keyboard[sc_Space] = Keyboard[sc_Escape] = Keyboard[sc_Enter] = false;
212 zoomer->Destroy();
213 if(done)
214 return true;
215 break;
216 }
217 CalcTics();
218 }
219 while(true);
220 return false;
221 }
ShowCast(CastIntermissionAction * cast)222 static bool ShowCast(CastIntermissionAction *cast)
223 {
224 ClearStatusbar();
225 DrawCastName(cast);
226
227 SD_PlaySound(cast->Class->GetDefault()->seesound);
228 const Frame *frame = cast->Class->FindState(NAME_See);
229 return R_CastZoomer(frame, cast);
230 }
231
ShowFader(FaderIntermissionAction * fader)232 static void ShowFader(FaderIntermissionAction *fader)
233 {
234 switch(fader->Fade)
235 {
236 case FaderIntermissionAction::FADEIN:
237 ShowImage(fader, true);
238 VL_FadeIn(0, 255, fader->Time);
239 break;
240 case FaderIntermissionAction::FADEOUT:
241 // We want to hold whatever may have been drawn in the previous page during the fade, so we don't need to draw.
242 VL_FadeOut(0, 255, 0, 0, 0, fader->Time);
243 break;
244 }
245 }
246
ShowTextScreen(TextScreenIntermissionAction * textscreen,bool demoMode)247 static bool ShowTextScreen(TextScreenIntermissionAction *textscreen, bool demoMode)
248 {
249 if(textscreen->TextSpeed)
250 Printf("Warning: Text screen has a non-zero textspeed which isn't supported at this time.\n");
251
252 ShowImage(textscreen, true);
253
254 if(textscreen->TextDelay)
255 {
256 if(WaitIntermission(textscreen->TextDelay) && demoMode)
257 return true;
258 }
259
260 py = textscreen->PrintY;
261 for(unsigned int i = 0;i < textscreen->Text.Size();++i)
262 {
263 px = textscreen->PrintX;
264
265 FString str = textscreen->Text[i];
266 if(str[0] == '$')
267 str = language[str.Mid(1)];
268
269 DrawMultiLineText(str, textscreen->TextFont, textscreen->TextColor, textscreen->Alignment, textscreen->Anchor);
270 }
271
272 // This really only makes sense to use if trying to display text immediately.
273 if(textscreen->FadeTime)
274 {
275 VL_FadeIn(0, 255, textscreen->FadeTime);
276 }
277
278 VW_UpdateScreen();
279 return WaitIntermission(textscreen->Time);
280 }
281
ShowIntermission(const IntermissionInfo * intermission,bool demoMode)282 bool ShowIntermission(const IntermissionInfo *intermission, bool demoMode)
283 {
284 exitOnAck = demoMode;
285 bool gototitle = false;
286 bool acked = false;
287
288 // For a cast call we want the bar area to display the names
289 if(viewsize > 20)
290 {
291 const int oldviewsize = viewsize;
292 NewViewSize(20);
293 viewsize = oldviewsize;
294 }
295
296 do
297 {
298 for(unsigned int i = 0;i < intermission->Actions.Size();++i)
299 {
300 switch(intermission->Actions[i].type)
301 {
302 default:
303 case IntermissionInfo::IMAGE:
304 acked = ShowImage(intermission->Actions[i].action, false);
305 break;
306 case IntermissionInfo::CAST:
307 acked = gototitle = ShowCast((CastIntermissionAction*)intermission->Actions[i].action);
308 break;
309 case IntermissionInfo::FADER:
310 ShowFader((FaderIntermissionAction*)intermission->Actions[i].action);
311 break;
312 case IntermissionInfo::GOTOTITLE:
313 gototitle = true;
314 break;
315 case IntermissionInfo::TEXTSCREEN:
316 acked = ShowTextScreen((TextScreenIntermissionAction*)intermission->Actions[i].action, demoMode);
317 break;
318 case IntermissionInfo::VICTORYSTATS:
319 Victory(true);
320 break;
321 }
322
323 if(demoMode ? acked : gototitle)
324 goto EscSequence;
325 }
326 if(intermission->Link != NAME_None)
327 intermission = IntermissionInfo::Find(intermission->Link);
328 else
329 break;
330 }
331 while(intermission);
332 EscSequence:
333
334 // If we changed the view size, we should reset it now.
335 if(viewsize > 20)
336 NewViewSize(viewsize);
337
338 if(!gototitle && !demoMode)
339 {
340 // Hold at the final page until esc is pressed
341 IN_ClearKeysDown();
342
343 ControlInfo ci;
344 do
345 {
346 LastScan = 0;
347 ReadAnyControl(&ci);
348 }
349 while(LastScan != sc_Escape && LastScan != sc_Enter && !ci.button1);
350 }
351
352 if(demoMode)
353 {
354 if(acked)
355 {
356 VW_FadeOut();
357 VL_ReadPalette(gameinfo.GamePalette);
358 return false;
359 }
360 else
361 return true;
362 }
363 else
364 {
365 VL_ReadPalette(gameinfo.GamePalette);
366 return !gototitle;
367 }
368 }
369