2 #include "framebuffer.hpp"
4 #include "messages.hpp"
5 #include "romimage.hpp"
7 #include "instance.hpp"
8 #include "core/messages.hpp"
9 #include "library/zip.hpp"
11 #define DEMO_WAIT 1080
15 const uint8_t hash1
[32] = {
16 66,234,24,74,51,217,34,32,61,153,253,130,17,157,160,183,62,231,155,167,135,216,249,116,41,95,216,
19 const uint8_t hash2
[32] = {
20 68,57,232,117,27,127,113,87,161,78,208,193,235,97,13,131,227,152,229,127,31,114,47,235,97,248,103,
24 void reload_song(struct instance
& inst
, bool menu
, uint32_t num
)
27 inst
.mplayer
.set_song(NULL
);
31 std::string filename
= inst
.rom_filename
+ "/menu.opus";
32 std::istream
* s
= NULL
;
34 s
= &zip::openrel(filename
, "");
35 messages
<< "Selected song: " << filename
<< std::endl
;
36 inst
.bsong
= new song_buffer(*s
);
37 inst
.mplayer
.set_song(inst
.bsong
);
39 } catch(std::exception
& e
) {
41 messages
<< "Unable to load song: " << e
.what() << std::endl
;
46 inst
.mplayer
.set_song(NULL
);
50 std::istream
* s
= NULL
;
52 zip::reader
r(inst
.rom_filename
);
54 std::vector
<std::string
> inames
;
56 if(regex_match("music.+\\.opus", i
))
60 iname
= inames
[num
% inames
.size()];
62 messages
<< "Selected song: " << iname
<< std::endl
;
63 inst
.bsong
= new song_buffer(*s
);
64 inst
.mplayer
.set_song(inst
.bsong
);
66 } catch(std::exception
& e
) {
67 messages
<< "Unable to load song: " << e
.what() << std::endl
;
74 void faded_framebuffer(struct instance
& inst
, uint16_t alpha
)
76 inst
.indirect_flag
= true;
77 for(unsigned i
= 0; i
< sizeof(inst
.framebuffer
) / sizeof(inst
.framebuffer
[0]); i
++) {
78 uint32_t L
= (((inst
.framebuffer
[i
] & 0x00FF00FF) * alpha
) >> 8) & 0x00FF00FF;
79 uint32_t H
= (((inst
.framebuffer
[i
] & 0xFF00FF00U
) >> 8) * alpha
) & 0xFF00FF00U
;
80 inst
.fadeffect_buffer
[i
] = L
| H
;
84 uint16_t stage_to_xpos(uint8_t stage
)
86 return (stage
> 15) ? 224 : 64;
89 uint16_t stage_to_ypos(uint8_t stage
)
91 return 13 + (((stage
- 1) % 15) / 3) * 39 + ((stage
- 1) % 3) * 9;;
94 uint8_t do_menu_fadein(struct instance
& inst
, uint16_t b
)
96 faded_framebuffer(inst
, 8 * inst
.state
.fadecount
);
97 return (++inst
.state
.fadecount
== 32) ? state_menu
: state_menu_fadein
;
100 uint8_t do_menu_fadeout(struct instance
& inst
, uint16_t b
)
102 faded_framebuffer(inst
, 256 - 8 * inst
.state
.fadecount
);
103 return (++inst
.state
.fadecount
== 32) ? state_load_level
: state_menu_fadeout
;
106 uint8_t do_level_fadein(struct instance
& inst
, uint16_t b
)
108 uint8_t fadelimit
= inst
.state
.timeattack
? 144 : 32;
109 faded_framebuffer(inst
, 256 * inst
.state
.fadecount
/ fadelimit
);
110 return (++inst
.state
.fadecount
== fadelimit
) ? state_level_play
: state_level_fadein
;
113 uint8_t do_level_fadeout(struct instance
& inst
, uint16_t b
)
115 faded_framebuffer(inst
, 256 - 8 * inst
.state
.fadecount
);
116 return (++inst
.state
.fadecount
== 32) ? state_load_menu
: state_level_fadeout
;
119 uint8_t do_level_fadeout_retry(struct instance
& inst
, uint16_t b
)
121 faded_framebuffer(inst
, 256 - 8 * inst
.state
.fadecount
);
122 return (++inst
.state
.fadecount
== 32) ? state_load_level_nomus
: state_level_fadeout_retry
;
125 uint8_t do_level_unavail(struct instance
& inst
, uint16_t b
)
127 inst
.indirect_flag
= false;
128 if(!inst
.state
.fadecount
) {
129 memset(inst
.framebuffer
, 0, sizeof(inst
.framebuffer
));
130 memset(inst
.origbuffer
, 0, sizeof(inst
.origbuffer
));
131 draw_message(inst
, _lvlunavail_g
, 0xFFFFFF, 0);
133 inst
.state
.fadecount
= 1;
134 return ((b
& ~inst
.state
.lastkeys
) & 0x30) ? state_load_menu
: state_level_unavail
;
137 uint8_t do_demo_unavail(struct instance
& inst
, uint16_t b
)
139 inst
.indirect_flag
= false;
140 if(!inst
.state
.fadecount
) {
141 memset(inst
.framebuffer
, 0, sizeof(inst
.framebuffer
));
142 memset(inst
.origbuffer
, 0, sizeof(inst
.origbuffer
));
143 draw_message(inst
, _demounavail_g
, 0xFFFFFF, 0);
145 inst
.state
.fadecount
= 1;
146 return ((b
& ~inst
.state
.lastkeys
) & 0x30) ? state_load_menu
: state_demo_unavail
;
149 uint8_t do_level_complete(struct instance
& inst
, uint16_t b
)
151 inst
.indirect_flag
= false;
152 if(!inst
.state
.fadecount
) {
153 if(inst
.state
.secret
== 0x81 && !inst
.state
.demo_flag
)
154 draw_message(inst
, _lvlcomplete2_g
, 0xFFFFFF, 0);
155 else if(inst
.state
.secret
== 0x82 && !inst
.state
.demo_flag
)
156 draw_message(inst
, _lvlcomplete3_g
, 0xFFFFFF, 0);
158 draw_message(inst
, _lvlcomplete_g
, 0xFFFFFF, 0);
159 if(inst
.state
.timeattack
|| inst
.state
.demo_flag
)
160 draw_timeattack_time(inst
, inst
.state
.waited
);
161 if(!inst
.state
.demo_flag
&& inst
.state
.stage
> 0 && inst
.state
.sram
[inst
.state
.stage
]
163 inst
.state
.sram
[inst
.state
.stage
]++;
164 if(!inst
.state
.demo_flag
&& inst
.state
.stage
> 0 && inst
.state
.stage
< 30)
167 ++inst
.state
.fadecount
;
168 //In timeattack mode, only start clears the screen.
169 if(inst
.state
.timeattack
)
170 return (b
& 32) ? state_level_fadeout
: state_level_complete
;
172 return state_level_fadeout
;
173 return (inst
.state
.fadecount
== 48) ? state_level_fadeout
: state_level_complete
;
176 uint8_t do_menu(struct instance
& inst
, uint16_t b
)
178 inst
.indirect_flag
= false;
179 if(inst
.state
.savestage
) {
180 inst
.state
.stage
= inst
.state
.savestage
;
181 inst
.state
.savestage
= 0;
183 if(inst
.state
.stage
== 0)
184 inst
.state
.stage
= 1;
185 if(inst
.state
.oldstage
!= inst
.state
.stage
) {
186 if(inst
.state
.oldstage
) {
188 uint16_t txpos
= stage_to_xpos(inst
.state
.oldstage
);
189 uint16_t typos
= stage_to_ypos(inst
.state
.oldstage
);
190 render_framebuffer_update(inst
, txpos
, typos
, 45, 7);
192 inst
.state
.oldstage
= inst
.state
.stage
;
193 uint16_t txpos
= stage_to_xpos(inst
.state
.stage
);
194 uint16_t typos
= stage_to_ypos(inst
.state
.stage
);
195 uint32_t color
= inst
.origbuffer
[320 * typos
+ txpos
];
196 for(unsigned i
= 0; i
< FB_SCALE
* 7; i
++)
197 for(unsigned j
= 0; j
< FB_SCALE
* 45; j
++) {
198 size_t p
= (i
+ FB_SCALE
* typos
) * FB_WIDTH
+ (j
+ FB_SCALE
* txpos
);
199 if(inst
.framebuffer
[p
] == color
)
200 inst
.framebuffer
[p
] = 0xFFC080;
203 uint16_t rising
= b
& ~inst
.state
.lastkeys
;
204 if(rising
& 1) //Left.
205 inst
.state
.stage
= (inst
.state
.stage
> 15) ? (inst
.state
.stage
- 15) :
206 (inst
.state
.stage
+ 15);
207 if(rising
& 2) //Right.
208 inst
.state
.stage
= (inst
.state
.stage
> 15) ? (inst
.state
.stage
- 15) :
209 (inst
.state
.stage
+ 15);
211 inst
.state
.stage
= ((inst
.state
.stage
% 15) == 1) ? (inst
.state
.stage
+ 14) :
212 (inst
.state
.stage
- 1);
213 if(rising
& 8) //Down.
214 inst
.state
.stage
= ((inst
.state
.stage
% 15) == 0) ? (inst
.state
.stage
- 14) :
215 (inst
.state
.stage
+ 1);
216 if(rising
& 48) { //A or Start.
218 inst
.state
.savestage
= inst
.state
.stage
;
219 inst
.state
.stage
= 0;
221 inst
.state
.demo_flag
= ((b
& 64) != 0);
222 return state_menu_fadeout
;
224 if(b
!= inst
.state
.lastkeys
)
225 inst
.state
.waited
= 0;
227 if(++inst
.state
.waited
== DEMO_WAIT
) {
228 inst
.state
.savestage
= inst
.state
.stage
;
229 inst
.state
.stage
= 0;
230 inst
.state
.demo_flag
= 2;
231 return state_menu_fadeout
;
236 uint8_t do_load_menu(struct instance
& inst
, uint16_t b
)
238 inst
.state
.cursong
= inst
.state
.rng
.pull();
239 reload_song(inst
, true, inst
.state
.cursong
);
240 inst
.mplayer
.rewind();
241 inst
.state
.oldstage
= 0;
242 for(unsigned i
= 0; i
< 64000; i
++)
243 inst
.origbuffer
[i
] = inst
.levelselect
[i
];
244 render_backbuffer(inst
);
245 for(unsigned i
= 1; i
< 31; i
++)
246 for(unsigned j
= 0; j
< inst
.state
.sram
[i
] && j
< 7; j
++)
247 draw_bitmap(inst
, complete_mark
, 3 * stage_to_xpos(i
) + 21 * j
+ 141,
248 3 * stage_to_ypos(i
) + 3);
249 inst
.indirect_flag
= true;
250 memset(inst
.fadeffect_buffer
, 0, sizeof(inst
.fadeffect_buffer
));
251 inst
.state
.waited
= 0;
252 return state_menu_fadein
;
255 uint8_t do_load_level(struct instance
& inst
, uint16_t b
)
257 inst
.state
.waited
= 0;
258 inst
.state
.secret
= 0;
259 if(inst
.state
.state
== state_load_level
) {
260 inst
.state
.timeattack
= (!inst
.state
.demo_flag
&& b
& 64) ? 1 : 0;
261 inst
.state
.cursong
= inst
.state
.rng
.pull();
262 reload_song(inst
, false, inst
.state
.cursong
);
263 inst
.mplayer
.rewind();
265 inst
.indirect_flag
= true;
266 memset(inst
.fadeffect_buffer
, 0, sizeof(inst
.fadeffect_buffer
));
267 if(!inst
.levels
.present(inst
.state
.stage
)) {
268 return state_level_unavail
;
270 inst
.state
.curlevel
= level(inst
.levels
[inst
.state
.stage
]);
271 if((inst
.state
.curlevel
.get_o2_amount() * 36) % 65536 == 0 ||
272 inst
.state
.curlevel
.get_fuel_amount() == 0)
274 inst
.state
.level_init(inst
.state
.stage
);
275 combine_background(inst
, inst
.state
.stage
? (inst
.state
.stage
- 1) / 3 : 0);
277 inst
.levels
[inst
.state
.stage
].sha256_hash(hash
);
278 if(!memcmp(hash
, hash1
, 32)) inst
.state
.secret
= 1;
279 if(!memcmp(hash
, hash2
, 32)) inst
.state
.secret
= 2;
281 if(inst
.state
.demo_flag
== 2) {
282 inst
.state
.curdemo
= inst
.builtin_demo
;
283 } else if(inst
.state
.demo_flag
) {
284 inst
.state
.curdemo
= lookup_demo(inst
, hash
);
286 inst
.state
.curdemo
= demo();
289 return state_demo_unavail
;
291 rebuild_pipe_quad_caches(inst
, inst
.state
.curlevel
.get_palette_color(68),
292 inst
.state
.curlevel
.get_palette_color(69), inst
.state
.curlevel
.get_palette_color(70),
293 inst
.state
.curlevel
.get_palette_color(71));
294 draw_grav_g_meter(inst
);
296 return state_level_fadein
;
299 uint8_t do_level_play(struct instance
& inst
, uint16_t b
)
301 inst
.indirect_flag
= false;
303 b
= inst
.state
.curdemo
.fetchkeys(b
, inst
.state
.p
.lpos
, inst
.state
.p
.framecounter
);
305 inst
.state
.p
.death
= physics::death_escaped
;
306 return state_level_fadeout
;
308 if((b
& ~inst
.state
.lastkeys
) & 32)
309 inst
.state
.paused
= inst
.state
.paused
? 0 : 1;
310 if(inst
.state
.paused
)
311 return state_level_play
;
313 bool jump
= ((b
& 16) != 0);
314 if((b
& 1) != 0) lr
--;
315 if((b
& 2) != 0) lr
++;
316 if((b
& 4) != 0) ad
++;
317 if((b
& 8) != 0) ad
--;
318 if((b
& 256) != 0) lr
= 2; //Cheat for demo.
319 if((b
& 512) != 0) ad
= 2; //Cheat for demo.
320 uint8_t death
= inst
.state
.simulate_frame(inst
.gsfx
, lr
, ad
, jump
);
321 if(!inst
.state
.p
.death
&& inst
.state
.waited
< 65535)
324 if(inst
.state
.timeattack
)
325 draw_timeattack_time(inst
, inst
.state
.waited
);
327 if(death
== physics::death_finished
)
328 return state_level_complete
;
330 return state_level_fadeout_retry
;
332 return state_level_play
;
335 uint8_t do_lockup(struct instance
& inst
, uint16_t b
)
337 inst
.mplayer
.set_song(NULL
);
341 void lstate_lockup(struct instance
& inst
)
343 inst
.mplayer
.set_song(NULL
);
344 memset(inst
.framebuffer
, 0, sizeof(inst
.framebuffer
));
345 memset(inst
.origbuffer
, 0, sizeof(inst
.origbuffer
));
348 void lstate_demo_unavail(struct instance
& inst
)
350 inst
.mplayer
.set_song(NULL
);
351 memset(inst
.framebuffer
, 0, sizeof(inst
.framebuffer
));
352 memset(inst
.origbuffer
, 0, sizeof(inst
.origbuffer
));
353 draw_message(inst
, _demounavail_g
, 0xFFFFFF, 0);
356 void lstate_level_unavail(struct instance
& inst
)
358 inst
.mplayer
.set_song(NULL
);
359 memset(inst
.framebuffer
, 0, sizeof(inst
.framebuffer
));
360 memset(inst
.origbuffer
, 0, sizeof(inst
.origbuffer
));
361 draw_message(inst
, _lvlunavail_g
, 0xFFFFFF, 0);
364 void lstate_level(struct instance
& inst
)
366 reload_song(inst
, false, inst
.state
.cursong
);
367 inst
.mplayer
.do_preroll();
368 combine_background(inst
, inst
.state
.stage
? (inst
.state
.stage
- 1) / 3 : 0);
369 inst
.state
.speedind
= 0;
370 inst
.state
.fuelind
= 0;
371 inst
.state
.o2ind
= 0;
372 inst
.state
.distind
= 0;
373 inst
.state
.lockind
= 0;
374 level
& c
= inst
.state
.curlevel
;
375 rebuild_pipe_quad_caches(inst
, c
.get_palette_color(68), c
.get_palette_color(69),
376 c
.get_palette_color(70), c
.get_palette_color(71));
377 draw_grav_g_meter(inst
);
382 void lstate_menu(struct instance
& inst
)
384 reload_song(inst
, true, inst
.state
.cursong
);
385 inst
.mplayer
.do_preroll();
386 for(unsigned i
= 0; i
< 64000; i
++)
387 inst
.origbuffer
[i
] = inst
.levelselect
[i
];
388 render_backbuffer(inst
);
389 for(unsigned i
= 1; i
< 31; i
++)
390 for(unsigned j
= 0; j
< inst
.state
.sram
[i
] && j
< 7; j
++)
391 draw_bitmap(inst
, complete_mark
, FB_SCALE
* stage_to_xpos(i
) + 21 * j
+ FB_SCALE
* 47,
392 FB_SCALE
* stage_to_ypos(i
) + FB_SCALE
);
393 if(inst
.state
.state
== state_menu
|| inst
.state
.state
== state_menu_fadeout
) {
394 uint16_t txpos
= stage_to_xpos(inst
.state
.stage
);
395 uint16_t typos
= stage_to_ypos(inst
.state
.stage
);
396 uint32_t color
= inst
.origbuffer
[320 * typos
+ txpos
];
397 for(unsigned i
= 0; i
< FB_SCALE
* 7; i
++)
398 for(unsigned j
= 0; j
< FB_SCALE
* 45; j
++) {
399 size_t p
= (i
+ FB_SCALE
* typos
) * FB_WIDTH
+ (j
+ FB_SCALE
* txpos
);
400 if(inst
.framebuffer
[p
] == color
)
401 inst
.framebuffer
[p
] = 0xFFC080;
406 typedef uint8_t (*do_state_t
)(struct instance
& inst
, uint16_t b
);
407 const do_state_t statefn
[] = {
408 do_menu_fadein
,do_menu
,do_menu_fadeout
,do_load_level
,do_level_fadein
,do_level_play
,
409 do_level_complete
, do_level_fadeout
,do_load_menu
,do_level_unavail
,do_demo_unavail
,
410 do_level_fadeout_retry
, do_load_level
, do_lockup
413 typedef void (*do_lstate_t
)(struct instance
& inst
);
414 const do_lstate_t lstatefn
[] = {
415 lstate_menu
,lstate_menu
,lstate_menu
,NULL
,lstate_level
,lstate_level
,
416 lstate_level
,lstate_level
,NULL
,lstate_level_unavail
,lstate_demo_unavail
,
417 lstate_level
, lstate_level
, lstate_lockup
420 bool state_needs_input
[] = {
422 true, //Menu needs input for selections.
423 false, //Menu fadeout.
424 true, //Level load needs input for timeattack mode.
425 false, //Level fadein.
426 true, //Level play needs input for actual playing.
427 true, //Level complete needs input to break out before time.
428 false, //Level fadeout.
429 false, //Loading the menu (initial boot vector):
430 true, //Level unavailable needs input to break out of it.
431 true, //Demo unavailable needs input to break out of it.
432 false, //Level fadeout for retry.
433 false, //Load level for retry. Unlike primary load, this does not need input.
437 void rom_boot_vector(struct instance
& inst
)
439 inst
.state
.stage
= inst
.state
.savestage
= inst
.state
.oldstage
= 0;
440 inst
.state
.change_state(state_load_menu
);
443 void simulate_frame(struct instance
& inst
, uint16_t b
)
446 inst
.state
.rng
.push(b
);
447 inst
.state
.frames_ran
++;
448 if(inst
.state
.state
> state_lockup
) {
449 messages
<< "Invalid state in simulate: " << (int)inst
.state
.state
<< std::endl
;
450 inst
.state
.change_state(state_load_menu
); //Reboot.
452 retstate
= statefn
[inst
.state
.state
](inst
, b
);
453 if(retstate
!= inst
.state
.state
)
454 inst
.state
.change_state(retstate
);
455 inst
.state
.lastkeys
= b
;
458 bool simulate_needs_input(struct instance
& inst
)
460 if(inst
.state
.state
> state_lockup
)
462 return state_needs_input
[inst
.state
.state
];
465 void handle_loadstate(struct instance
& inst
)
467 messages
<< "Loadstate status: " << (int)inst
.state
.state
<< std::endl
;
468 if(inst
.state
.state
> state_lockup
) {
469 messages
<< "Invalid state in loadstate: " << (int)inst
.state
.state
<< std::endl
;
470 inst
.state
.change_state(state_load_menu
); //Reboot.
472 if(lstatefn
[inst
.state
.state
])
473 lstatefn
[inst
.state
.state
](inst
);