1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include "Intro.h"
11 
12 #include "Context.h"
13 #include "audio/AudioMixer.h"
14 #include "audio/audio.h"
15 #include "drawing/Drawing.h"
16 #include "sprites.h"
17 
18 #define BACKROUND_COLOUR_DARK PALETTE_INDEX_10
19 #define BACKROUND_COLOUR_LOGO PALETTE_INDEX_245
20 #define BORDER_COLOUR_PUBLISHER PALETTE_INDEX_129
21 
22 constexpr int32_t PALETTE_G1_IDX_DEVELOPER = 23217;
23 constexpr int32_t PALETTE_G1_IDX_LOGO = 23224;
24 
25 IntroState gIntroState;
26 
27 // Used mainly for timing but also for Y coordinate and fading.
28 static int32_t _introStateCounter;
29 
30 static void* _soundChannel = nullptr;
31 static bool _chainLiftFinished;
32 
33 static void screen_intro_process_mouse_input();
34 static void screen_intro_process_keyboard_input();
35 static void screen_intro_skip_part();
36 static void screen_intro_draw_logo(rct_drawpixelinfo* dpi);
37 
38 // rct2: 0x0068E966
intro_update()39 void intro_update()
40 {
41     screen_intro_process_mouse_input();
42     screen_intro_process_keyboard_input();
43 
44     switch (gIntroState)
45     {
46         case IntroState::Disclaimer1:
47         case IntroState::Disclaimer2:
48             // Originally used for the disclaimer text
49             gIntroState = IntroState::PublisherBegin;
50             [[fallthrough]];
51         case IntroState::PublisherBegin:
52             load_palette();
53 
54             // Set the Y for the Infogrames logo
55             _introStateCounter = -580;
56 
57             // Play the chain lift sound
58             _soundChannel = Mixer_Play_Effect(
59                 OpenRCT2::Audio::SoundId::LiftBM, MIXER_LOOP_INFINITE, MIXER_VOLUME_MAX, 0.5f, 1, true);
60             _chainLiftFinished = false;
61             gIntroState = IntroState::PublisherScroll;
62             break;
63         case IntroState::PublisherScroll:
64             // Move the Infogrames logo down
65             _introStateCounter += 5;
66 
67             // Check if logo is off the screen...ish
68             if (_introStateCounter > context_get_height() - 120)
69             {
70                 _introStateCounter = -116;
71                 gIntroState = IntroState::DeveloperBegin;
72             }
73 
74             break;
75         case IntroState::DeveloperBegin:
76             // Set the Y for the Chris Sawyer logo
77             _introStateCounter = -116;
78 
79             gIntroState = IntroState::DeveloperScroll;
80             break;
81         case IntroState::DeveloperScroll:
82             _introStateCounter += 5;
83 
84             // Check if logo is almost scrolled to the bottom
85             if (!_chainLiftFinished && _introStateCounter >= context_get_height() + 40 - 421)
86             {
87                 _chainLiftFinished = true;
88 
89                 // Stop the chain lift sound
90                 if (_soundChannel != nullptr)
91                 {
92                     Mixer_Stop_Channel(_soundChannel);
93                     _soundChannel = nullptr;
94                 }
95 
96                 // Play the track friction sound
97                 _soundChannel = Mixer_Play_Effect(
98                     OpenRCT2::Audio::SoundId::TrackFrictionBM, MIXER_LOOP_INFINITE, MIXER_VOLUME_MAX, 0.25f, 0.75, true);
99             }
100 
101             // Check if logo is off the screen...ish
102             if (_introStateCounter >= context_get_height() + 40)
103             {
104                 // Stop the track friction sound
105                 if (_soundChannel != nullptr)
106                 {
107                     Mixer_Stop_Channel(_soundChannel);
108                     _soundChannel = nullptr;
109                 }
110 
111                 // Play long peep scream sound
112                 _soundChannel = Mixer_Play_Effect(
113                     OpenRCT2::Audio::SoundId::Scream1, MIXER_LOOP_NONE, MIXER_VOLUME_MAX, 0.5f, 1, false);
114 
115                 gIntroState = IntroState::LogoFadeIn;
116                 _introStateCounter = 0;
117             }
118             break;
119         case IntroState::LogoFadeIn:
120             // Fade in, add 4 / 256 to fading
121             _introStateCounter += 0x400;
122             if (_introStateCounter > 0xFF00)
123             {
124                 gIntroState = IntroState::LogoWait;
125                 _introStateCounter = 0;
126             }
127             break;
128         case IntroState::LogoWait:
129             // Wait 80 game ticks
130             _introStateCounter++;
131             if (_introStateCounter >= 80)
132             {
133                 // Set fading to 256
134                 _introStateCounter = 0xFF00;
135 
136                 gIntroState = IntroState::LogoFadeOut;
137             }
138             break;
139         case IntroState::LogoFadeOut:
140             // Fade out, subtract 4 / 256 from fading
141             _introStateCounter -= 0x400;
142             if (_introStateCounter < 0)
143             {
144                 gIntroState = IntroState::Clear;
145             }
146             break;
147         case IntroState::Clear:
148             // Stop any playing sound
149             if (_soundChannel != nullptr)
150             {
151                 Mixer_Stop_Channel(_soundChannel);
152                 _soundChannel = nullptr;
153             }
154 
155             // Move to next part
156             gIntroState = IntroState::Finish;
157             _introStateCounter = 0;
158             break;
159         case IntroState::Finish:
160             gIntroState = IntroState::None;
161             load_palette();
162             OpenRCT2::Audio::PlayTitleMusic();
163             break;
164         default:
165             break;
166     }
167 }
168 
intro_draw(rct_drawpixelinfo * dpi)169 void intro_draw(rct_drawpixelinfo* dpi)
170 {
171     int32_t screenWidth = context_get_width();
172 
173     switch (gIntroState)
174     {
175         case IntroState::Disclaimer1:
176         case IntroState::Disclaimer2:
177             break;
178         case IntroState::PublisherBegin:
179             gfx_clear(dpi, BACKROUND_COLOUR_DARK);
180             break;
181         case IntroState::PublisherScroll:
182             gfx_clear(dpi, BACKROUND_COLOUR_DARK);
183 
184             // Draw a white rectangle for the logo background (gives a bit of white margin)
185             gfx_fill_rect(
186                 dpi,
187                 { { (screenWidth / 2) - 320 + 50, _introStateCounter + 50 },
188                   { (screenWidth / 2) - 320 + 50 + 540, _introStateCounter + 50 + 425 } },
189                 BORDER_COLOUR_PUBLISHER);
190 
191             // Draw Infogrames logo
192             gfx_draw_sprite(dpi, ImageId(SPR_INTRO_INFOGRAMES_00), { (screenWidth / 2) - 320 + 69, _introStateCounter + 69 });
193             gfx_draw_sprite(dpi, ImageId(SPR_INTRO_INFOGRAMES_10), { (screenWidth / 2) - 320 + 319, _introStateCounter + 69 });
194             gfx_draw_sprite(dpi, ImageId(SPR_INTRO_INFOGRAMES_01), { (screenWidth / 2) - 320 + 69, _introStateCounter + 319 });
195             gfx_draw_sprite(dpi, ImageId(SPR_INTRO_INFOGRAMES_11), { (screenWidth / 2) - 320 + 319, _introStateCounter + 319 });
196             break;
197         case IntroState::DeveloperBegin:
198             gfx_clear(dpi, BACKROUND_COLOUR_DARK);
199             gfx_transpose_palette(PALETTE_G1_IDX_DEVELOPER, 255);
200             break;
201         case IntroState::DeveloperScroll:
202             gfx_clear(dpi, BACKROUND_COLOUR_DARK);
203 
204             // Draw Chris Sawyer logo
205             gfx_draw_sprite(dpi, ImageId(SPR_INTRO_CHRIS_SAWYER_00), { (screenWidth / 2) - 320 + 70, _introStateCounter });
206             gfx_draw_sprite(dpi, ImageId(SPR_INTRO_CHRIS_SAWYER_10), { (screenWidth / 2) - 320 + 320, _introStateCounter });
207             break;
208         case IntroState::LogoFadeIn:
209             if (_introStateCounter <= 0xFF00)
210             {
211                 gfx_transpose_palette(PALETTE_G1_IDX_LOGO, (_introStateCounter >> 8) & 0xFF);
212             }
213             else
214             {
215                 gfx_transpose_palette(PALETTE_G1_IDX_LOGO, 255);
216             }
217             screen_intro_draw_logo(dpi);
218             break;
219         case IntroState::LogoWait:
220             screen_intro_draw_logo(dpi);
221             break;
222         case IntroState::LogoFadeOut:
223             if (_introStateCounter >= 0)
224             {
225                 gfx_transpose_palette(PALETTE_G1_IDX_LOGO, (_introStateCounter >> 8) & 0xFF);
226             }
227             else
228             {
229                 gfx_transpose_palette(PALETTE_G1_IDX_LOGO, 0);
230             }
231             screen_intro_draw_logo(dpi);
232             break;
233         case IntroState::Clear:
234             gfx_clear(dpi, BACKROUND_COLOUR_DARK);
235             break;
236         default:
237             break;
238     }
239 }
240 
screen_intro_process_mouse_input()241 static void screen_intro_process_mouse_input()
242 {
243     if (context_get_cursor_state()->any == CURSOR_PRESSED)
244     {
245         screen_intro_skip_part();
246     }
247 }
248 
249 /**
250  *
251  *  rct2: 0x006E3AEC
252  */
screen_intro_process_keyboard_input()253 static void screen_intro_process_keyboard_input()
254 {
255     const uint8_t* keys = context_get_keys_state();
256     for (int i = 0; i < 256; i++)
257     {
258         if (keys[i] != 0)
259         {
260             screen_intro_skip_part();
261             break;
262         }
263     }
264 }
265 
screen_intro_skip_part()266 static void screen_intro_skip_part()
267 {
268     switch (gIntroState)
269     {
270         case IntroState::None:
271             break;
272         case IntroState::Disclaimer2:
273             gIntroState = IntroState::PublisherBegin;
274             break;
275         default:
276             gIntroState = IntroState::Clear;
277             break;
278     }
279 }
280 
screen_intro_draw_logo(rct_drawpixelinfo * dpi)281 static void screen_intro_draw_logo(rct_drawpixelinfo* dpi)
282 {
283     int32_t screenWidth = context_get_width();
284     int32_t imageWidth = 640;
285     int32_t imageX = (screenWidth - imageWidth) / 2;
286 
287     drawing_engine_invalidate_image(SPR_INTRO_LOGO_00);
288     drawing_engine_invalidate_image(SPR_INTRO_LOGO_10);
289     drawing_engine_invalidate_image(SPR_INTRO_LOGO_20);
290     drawing_engine_invalidate_image(SPR_INTRO_LOGO_01);
291     drawing_engine_invalidate_image(SPR_INTRO_LOGO_11);
292     drawing_engine_invalidate_image(SPR_INTRO_LOGO_21);
293 
294     gfx_clear(dpi, BACKROUND_COLOUR_LOGO);
295     gfx_draw_sprite(dpi, ImageId(SPR_INTRO_LOGO_00), { imageX + 0, 0 });
296     gfx_draw_sprite(dpi, ImageId(SPR_INTRO_LOGO_10), { imageX + 220, 0 });
297     gfx_draw_sprite(dpi, ImageId(SPR_INTRO_LOGO_20), { imageX + 440, 0 });
298     gfx_draw_sprite(dpi, ImageId(SPR_INTRO_LOGO_01), { imageX + 0, 240 });
299     gfx_draw_sprite(dpi, ImageId(SPR_INTRO_LOGO_11), { imageX + 220, 240 });
300     gfx_draw_sprite(dpi, ImageId(SPR_INTRO_LOGO_21), { imageX + 440, 240 });
301 }
302