lsnes rr2-β24
[lsnes.git] / src / emulation / sky / logic.cpp
blobf47fa2cac7f18991c6edc46ef2ed20312a87a9ae
1 #include "logic.hpp"
2 #include "framebuffer.hpp"
3 #include "music.hpp"
4 #include "messages.hpp"
5 #include "romimage.hpp"
6 #include "draw.hpp"
7 #include "instance.hpp"
8 #include "core/messages.hpp"
9 #include "library/zip.hpp"
11 #define DEMO_WAIT 1080
13 namespace sky
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,
17 97,168,163,129,23
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,
21 11,159,217,129,136
24 void reload_song(struct instance& inst, bool menu, uint32_t num)
26 if(menu) {
27 inst.mplayer.set_song(NULL);
28 if(inst.bsong)
29 delete inst.bsong;
30 inst.bsong = NULL;
31 std::string filename = inst.rom_filename + "/menu.opus";
32 std::istream* s = NULL;
33 try {
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);
38 delete s;
39 } catch(std::exception& e) {
40 if(s) {
41 messages << "Unable to load song: " << e.what() << std::endl;
42 delete s;
45 } else {
46 inst.mplayer.set_song(NULL);
47 if(inst.bsong)
48 delete inst.bsong;
49 inst.bsong = NULL;
50 std::istream* s = NULL;
51 try {
52 zip::reader r(inst.rom_filename);
53 std::string iname;
54 std::vector<std::string> inames;
55 for(auto i : r)
56 if(regex_match("music.+\\.opus", i))
57 inames.push_back(i);
58 if(inames.empty())
59 return;
60 iname = inames[num % inames.size()];
61 s = &r[iname];
62 messages << "Selected song: " << iname << std::endl;
63 inst.bsong = new song_buffer(*s);
64 inst.mplayer.set_song(inst.bsong);
65 delete s;
66 } catch(std::exception& e) {
67 messages << "Unable to load song: " << e.what() << std::endl;
68 if(s)
69 delete s;
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);
157 else
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]
162 < 255)
163 inst.state.sram[inst.state.stage]++;
164 if(!inst.state.demo_flag && inst.state.stage > 0 && inst.state.stage < 30)
165 inst.state.stage++;
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;
171 if(b & 112)
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) {
187 //Erase old mark.
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);
210 if(rising & 4) //Up.
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.
217 if((b & 3) == 3) {
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;
226 else
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;
233 return state_menu;
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)
273 return state_lockup;
274 inst.state.level_init(inst.state.stage);
275 combine_background(inst, inst.state.stage ? (inst.state.stage - 1) / 3 : 0);
276 uint8_t hash[32];
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;
280 try {
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);
285 } else {
286 inst.state.curdemo = demo();
288 } catch(...) {
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);
295 draw_level(inst);
296 return state_level_fadein;
299 uint8_t do_level_play(struct instance& inst, uint16_t b)
301 inst.indirect_flag = false;
302 //Handle demo.
303 b = inst.state.curdemo.fetchkeys(b, inst.state.p.lpos, inst.state.p.framecounter);
304 if((b & 96) == 96) {
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;
312 int lr = 0, ad = 0;
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)
322 inst.state.waited++;
323 draw_level(inst);
324 if(inst.state.timeattack)
325 draw_timeattack_time(inst, inst.state.waited);
326 draw_gauges(inst);
327 if(death == physics::death_finished)
328 return state_level_complete;
329 else if(death)
330 return state_level_fadeout_retry;
331 else
332 return state_level_play;
335 uint8_t do_lockup(struct instance& inst, uint16_t b)
337 inst.mplayer.set_song(NULL);
338 return state_lockup;
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);
378 draw_gauges(inst);
379 draw_level(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[] = {
421 false, //Menu fadein
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.
434 false, //Lockup.
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)
445 uint8_t retstate;
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)
461 return false;
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);