ReC98/th02/op_01.c

673 lines
16 KiB
C
Raw Normal View History

2015-03-16 21:35:52 +00:00
/* ReC98
* -----
* Code segment #1 of TH02's OP.EXE
*/
#include <process.h>
#include "libs/kaja/kaja.h"
2015-03-16 21:35:52 +00:00
#include "th02/th02.h"
2019-11-19 14:26:47 +00:00
#include "th02/initexit.h"
#include "th02/formats/cfg.h"
#include "th02/formats/pi.h"
#include "th02/snd/snd.h"
2015-03-16 21:35:52 +00:00
#pragma option -d
typedef void pascal near putfunc_t(int sel, unsigned int atrb);
char menu_sel = 0;
char in_option = 0;
char quit = 0;
char unused_1 = 0;
char snd_bgm_mode;
static int unused_2;
unsigned int idle_frames;
unsigned char demo_num;
void __seg *resident_sgm;
2015-03-16 21:35:52 +00:00
putfunc_t near *putfunc;
// No, we don't want to put these two into th02.h. Apparently, declaring
// variables with extern before definining them for real within the same
// compilation unit causes Turbo C++ to emit *everything* in a different
// order... really, I couldn't make this up.
extern char extra_unlocked;
extern unsigned int score_duration;
void title_flash(void);
void pascal score_menu(void);
void pascal shottype_menu(void);
void pascal musicroom(void);
int cfg_load(void)
{
cfg_t cfg;
2015-03-16 21:35:52 +00:00
const char *cfg_fn = CFG_FN;
if(file_exist(cfg_fn)) {
file_ropen(cfg_fn);
file_read(&cfg, sizeof(cfg));
rank = cfg.opts.rank;
snd_bgm_mode = cfg.opts.bgm_mode;
bombs = cfg.opts.bombs;
lives = cfg.opts.lives;
resident_sgm = cfg.resident;
if(!resident_sgm) {
2015-03-16 21:35:52 +00:00
return 1;
}
resident = MK_FP(resident_sgm, 0);
resident->perf = cfg.opts.perf;
resident->debug = cfg.debug;
2015-03-16 21:35:52 +00:00
file_close();
if(snd_bgm_mode == SND_BGM_OFF) {
snd_fm_possible = 0;
snd_active = 0;
} else if(snd_bgm_mode == SND_BGM_FM) {
snd_midi_active = 0;
snd_determine_mode();
} else {
snd_midi_active = snd_midi_possible;
snd_determine_mode();
}
return 0;
}
return 1;
}
void cfg_save(void)
{
const char *cfg_fn = CFG_FN;
cfg_t cfg;
2015-03-16 21:35:52 +00:00
cfg.debug = 0;
cfg.opts.rank = rank;
cfg.opts.bgm_mode = snd_bgm_mode;
cfg.opts.bombs = bombs;
cfg.opts.lives = lives;
cfg.opts.perf = resident->perf;
2015-03-16 21:35:52 +00:00
file_create(cfg_fn);
file_write(&cfg, offsetof(cfg_t, resident));
file_write(&resident_sgm, sizeof(resident_sgm));
2015-03-16 21:35:52 +00:00
file_write(&cfg.debug, sizeof(cfg.debug));
file_close();
}
void text_wipe(void)
{
text_clear();
text_fillca(' ', TX_BLACK | TX_REVERSE);
}
void pascal near pi_load_put_free_to(const char near *fn, char page)
{
pi_slot_load(0, fn);
graph_accesspage(page);
pi_slot_palette_apply(0);
pi_slot_put(0, 0, 0);
graph_pi_free(&pi_slot_headers[0], pi_slot_buffers[0]);
}
void op_animate(void)
{
int door_x, door_y; // Sony Vegas calls this a "Barn Door" transition.
const char gbZUN[] = {gb_Z_, gb_U_, gb_N_, 0};
text_wipe();
snd_load("huuma.efc", SND_LOAD_SE);
pi_load_put_free_to("op2.pi", 1);
pi_load_put_free_to("op.pi", 0);
pi_slot_load(0, "opa.pi");
pi_slot_load(1, "opb.pi");
pi_slot_load(2, "opc.pi");
palette_white();
for(door_x = 0; door_x < 40; door_x++) {
for(door_y = 0; door_y < 25; door_y++) {
text_putca(39 - door_x, door_y, ' ', TX_WHITE);
text_putca(door_x + 40, door_y, ' ', TX_WHITE);
}
palette_settone(200 - (door_x * 2));
frame_delay(1);
}
for(door_x = 40; door_x < 50; door_x++) {
palette_settone(200 - (door_x * 2));
frame_delay(1);
}
palette_100();
if(resident->demo_num == 0) {
2015-03-16 21:35:52 +00:00
door_x = 0;
if(snd_midi_possible) {
door_x = snd_midi_active;
snd_midi_active = 1;
snd_load("op.m", SND_LOAD_SONG);
}
snd_midi_active = 0;
snd_load("op.m", SND_LOAD_SONG);
snd_midi_active = door_x;
}
frame_delay(18);
title_flash();
palette_white();
graph_accesspage(1);
graph_gaiji_putc(548, 384, gs_COPYRIGHT, 0);
graph_gaiji_puts(564, 384, 16, gbZUN, 0);
graph_gaiji_putc(544, 380, gs_COPYRIGHT, 6);
graph_gaiji_puts(560, 380, 16, gbZUN, 6);
graph_copy_page(0);
if(resident->demo_num == 0) {
2015-03-16 21:35:52 +00:00
snd_kaja_func(KAJA_SONG_PLAY, 0);
}
resident->demo_num = 0;
2015-03-16 21:35:52 +00:00
palette_entry_rgb_show("op.rgb");
palette_white_in(6);
}
void pascal near start_init(void)
{
snd_se_reset();
snd_se_play(13);
snd_se_update();
frame_delay(20);
resident->rem_lives = lives;
resident->rem_bombs = bombs;
resident->start_lives = lives;
resident->start_bombs = bombs;
resident->bgm_mode = snd_bgm_mode;
resident->start_power = 0;
resident->score = 0;
resident->continues_used = 0;
resident->unused_3 = 0;
resident->unused_1 = 0;
resident->demo_num = 0;
resident->score_highest = 0;
2015-03-16 21:35:52 +00:00
}
#define start_exec() \
cfg_save(); \
pi_slot_load(0, "ts1.pi"); \
text_clear(); \
shottype_menu(); \
snd_kaja_func(KAJA_SONG_FADE, 15); \
gaiji_restore(); \
super_free(); \
game_exit(); \
if(resident->debug) { \
2015-03-16 21:35:52 +00:00
execl("select", "select", 0, 0); \
} else { \
execl("main", "main", 0, 0); \
}
void start_game(void)
{
start_init();
resident->rank = rank;
resident->stage = 0;
2015-03-16 21:35:52 +00:00
start_exec();
}
void start_demo(void)
{
resident->rem_lives = 2;
resident->rem_bombs = 3;
resident->start_lives = 2;
resident->start_bombs = 3;
resident->bgm_mode = snd_bgm_mode;
resident->rank = RANK_NORMAL;
resident->continues_used = 0;
resident->unused_3 = 0;
resident->demo_num = demo_num;
resident->shottype = 0;
2015-03-16 21:35:52 +00:00
cfg_save();
text_clear();
graph_pi_free(&pi_slot_headers[0], pi_slot_buffers[0]);
graph_pi_free(&pi_slot_headers[1], pi_slot_buffers[1]);
graph_pi_free(&pi_slot_headers[2], pi_slot_buffers[2]);
gaiji_restore();
super_free();
game_exit();
execl("main", "main", 0, 0);
}
void start_extra(void)
{
start_init();
resident->rank = RANK_EXTRA;
resident->stage = 5;
resident->rem_lives = 2;
resident->rem_bombs = 1;
resident->start_lives = 2;
resident->start_bombs = 1;
2015-03-16 21:35:52 +00:00
start_exec();
}
#pragma option -d-
#include "th02/strings/ranks_c.c"
const unsigned char gbHIT_KEY[] = {
gb_H_, gb_I_, gb_T_, gb_SP, gb_K_, gb_E_, gb_Y_, 0
};
const unsigned char gb7SPACES[] = {
gb_SP, gb_SP, gb_SP, gb_SP, gb_SP, gb_SP, gb_SP, 0
};
const unsigned char gbSTART[] = {
gb_S_,gb_T_,gb_A_,gb_R_,gb_T_, 0, 0, 0, 0, 0
};
const unsigned char gbEXTRA_START[] = {
gb_E_,gb_X_,gb_T_,gb_R_,gb_A_,gb_SP,gb_S_,gb_T_,gb_A_,gb_R_,gb_T_, 0
};
const unsigned char gbHISCORE[] = {
gb_H_,gb_I_,gb_S_,gb_C_,gb_O_,gb_R_,gb_E_, 0, 0, 0
};
const unsigned char gbOPTION[] = {
gb_O_,gb_P_,gb_T_,gb_I_,gb_O_,gb_N_, 0, 0, 0, 0
};
const unsigned char gbQUIT[] = {
gb_Q_,gb_U_,gb_I_,gb_T_, 0, 0, 0, 0, 0, 0
};
const unsigned char gbRANK[] = {
gb_R_,gb_A_,gb_N_,gb_K_, 0, 0, 0, 0, 0, 0
};
const unsigned char gbPLAYER[] = {
gb_P_,gb_L_,gb_A_,gb_Y_,gb_E_,gb_R_, 0, 0, 0, 0
};
const unsigned char gbMUSIC[] = {
gb_M_,gb_U_,gb_S_,gb_I_,gb_C_, 0, 0, 0, 0, 0
};
const unsigned char gbBOMB[] = {
gb_B_,gb_O_,gb_M_,gb_B_, 0, 0, 0, 0, 0, 0
};
const unsigned char gbMUSIC_MODE[] = {
gb_M_,gb_U_,gb_S_,gb_I_,gb_C_,gb_SP,gb_M_,gb_O_,gb_D_,gb_E_, 0
};
const unsigned char gbRESET[] = {
gb_R_,gb_E_,gb_S_,gb_E_,gb_T_, 0, 0, 0, 0, 0
};
const unsigned char gsRANKS[4][3] = {
gs_EA, gs_SY, 0,
gs_NOR, gs_MAL, 0,
gs_HA, gs_RD, 0,
gs_LUN, gs_ATIC, 0
};
const unsigned char gbcBGM_MODE[3][5] = {
gb_O_, gb_F_, gb_F_, gb_SP, 0,
gb_SP, gb_F_, gb_M_, gb_SP, 0,
gb_M_, gb_I_, gb_D_, gb_I_, 0
};
const char *PERF_TITLE = "<EFBFBD><EFBFBD><EFBFBD>o";
const char *PERF_OPTIONS[2] = {"<EFBFBD>@<40>ʏ<EFBFBD> ", "<EFBFBD><EFBFBD>y<EFBFBD><EFBFBD>"};
#pragma option -d
void pascal near main_put_shadow(void)
{
graph_gaiji_puts(284, 260, 16, gbSTART, 0);
graph_gaiji_puts(236, 276, 16, gbEXTRA_START, 0);
graph_gaiji_puts(268, 292, 16, gbHISCORE, 0);
graph_gaiji_puts(276, 308, 16, gbOPTION, 0);
graph_gaiji_puts(244, 324, 16, gbMUSIC_MODE, 0);
graph_gaiji_puts(292, 340, 16, gbQUIT, 0);
graph_gaiji_puts(212, 372, 16, gbRANK, 0);
graph_gaiji_puts(308, 372, 16, gbcRANKS[rank], 0);
}
void pascal near main_put(int sel, unsigned int atrb)
{
if(sel == 0) {
gaiji_putsa(35, 16, gbSTART, atrb);
} else if(sel == 2) {
gaiji_putsa(33, 18, gbHISCORE, atrb);
} else if(sel == 3) {
gaiji_putsa(34, 19, gbOPTION, atrb);
} else if(sel == 4) {
gaiji_putsa(30, 20, gbMUSIC_MODE, atrb);
} else if(sel == 5) {
gaiji_putsa(36, 21, gbQUIT, atrb);
}
if(sel == 1) {
if(extra_unlocked) {
gaiji_putsa(29, 17, gbEXTRA_START, atrb);
} else {
gaiji_putsa(29, 17, gbEXTRA_START, TX_BLUE);
}
}
gaiji_putsa(26, 23, gbRANK, TX_GREEN);
gaiji_putsa(38, 23, gbcRANKS[rank], TX_GREEN);
}
void pascal near menu_sel_move(char sel_count, char direction)
{
putfunc(menu_sel, TX_YELLOW);
menu_sel += direction;
if(!in_option && !extra_unlocked && menu_sel == 1) {
menu_sel += direction;
}
if(menu_sel < 0) {
menu_sel = sel_count;
}
if(menu_sel > sel_count) {
menu_sel = 0;
}
putfunc(menu_sel, TX_WHITE);
}
void main_update_and_render(void)
{
static char input_allowed;
static char initialized = 0;
if(!initialized) {
int i;
input_allowed = 0;
initialized = 1;
text_clear();
graph_showpage(1);
graph_copy_page(0);
main_put_shadow();
graph_showpage(0);
idle_frames = 0;
for(i = 0; i < 6; i++) {
main_put(i, menu_sel == i ? TX_WHITE : TX_YELLOW);
}
putfunc = main_put;
}
if(!key_det) {
2015-03-16 21:35:52 +00:00
input_allowed = 1;
}
if(input_allowed) {
if(key_det & INPUT_UP) {
2015-03-16 21:35:52 +00:00
menu_sel_move(5, -1);
}
if(key_det & INPUT_DOWN) {
2015-03-16 21:35:52 +00:00
menu_sel_move(5, 1);
}
if(key_det & INPUT_SHOT || key_det & INPUT_OK) {
2015-03-16 21:35:52 +00:00
switch(menu_sel) {
case 0:
start_game();
break;
case 1:
start_extra();
break;
case 2:
score_duration = 2000;
text_clear();
score_menu();
graph_accesspage(1);
graph_showpage(0);
pi_load_put_free(0, "op2.pi");
palette_entry_rgb_show("op.rgb");
graph_copy_page(0);
graph_accesspage(0);
initialized = 0;
break;
case 3:
menu_sel = 0;
in_option = 1;
initialized = 0;
break;
case 4:
text_clear();
musicroom();
initialized = 0;
break;
case 5:
quit = 1;
break;
}
}
if(key_det & INPUT_CANCEL) {
2015-03-16 21:35:52 +00:00
quit = 1;
}
if(key_det) {
2015-03-16 21:35:52 +00:00
input_allowed = 0;
idle_frames = 0;
}
}
if(idle_frames > 640) {
start_demo();
}
}
void pascal near option_put_shadow(void)
{
graph_gaiji_puts(196, 260, 16, gbRANK, 0);
graph_gaiji_puts(196, 276, 16, gbMUSIC, 0);
graph_gaiji_puts(196, 292, 16, gbPLAYER, 0);
graph_gaiji_puts(196, 308, 16, gbBOMB, 0);
graph_putsa_fx(196, 324, 0, PERF_TITLE);
graph_gaiji_puts(284, 340, 16, gbRESET, 0);
graph_gaiji_puts(292, 372, 16, gbQUIT, 0);
}
void pascal near option_put(int sel, unsigned int atrb)
{
if(sel == 0) {
gaiji_putsa(24, 16, gbRANK, atrb);
gaiji_putsa(42, 16, gbcRANKS[rank], atrb);
graph_copy_rect_1_to_0(336, 260, 128, 16);
graph_gaiji_puts(340, 260, 16, gbcRANKS[rank], 0);
} else if(sel == 1) {
gaiji_putsa(24, 17, gbMUSIC, atrb);
gaiji_putsa(47, 17, gbcBGM_MODE[snd_bgm_mode], atrb);
graph_copy_rect_1_to_0(376, 276, 64, 16);
graph_gaiji_puts(380, 276, 16, gbcBGM_MODE[snd_bgm_mode], 0);
} else if(sel == 2) {
gaiji_putsa(24, 18, gbPLAYER, atrb);
gaiji_putca(49, 18, lives + 1 + GB_DIGITS, atrb);
graph_copy_rect_1_to_0(392, 292, 32, 16);
graph_gaiji_putc(396, 292, lives + 1 + GB_DIGITS, 0);
} else if(sel == 3) {
gaiji_putsa(24, 19, gbBOMB, atrb);
gaiji_putca(49, 19, bombs + GB_DIGITS, atrb);
graph_copy_rect_1_to_0(392, 308, 32, 16);
graph_gaiji_putc(396, 308, bombs + GB_DIGITS, 0);
} else if(sel == 4) {
text_putsa(24, 20, PERF_TITLE, atrb);
text_putsa(45, 20, PERF_OPTIONS[resident->perf], atrb);
2015-03-16 21:35:52 +00:00
graph_copy_rect_1_to_0(360, 324, 128, 16);
graph_putsa_fx(364, 324, 0, PERF_OPTIONS[resident->perf]);
2015-03-16 21:35:52 +00:00
} else if(sel == 5) {
gaiji_putsa(35, 21, gbRESET, atrb);
} else if(sel == 6) {
gaiji_putsa(36, 23, gbQUIT, atrb);
}
}
void pascal near snd_bgm_restart(void)
{
if(snd_bgm_mode == SND_BGM_OFF) {
snd_fm_possible = 0;
snd_kaja_func(KAJA_SONG_STOP, 0);
snd_active = 0;
return;
} else if(snd_bgm_mode == SND_BGM_FM) {
snd_kaja_func(KAJA_SONG_STOP, 0);
snd_midi_active = 0;
snd_determine_mode();
snd_kaja_func(KAJA_SONG_PLAY, 0);
} else if(snd_bgm_mode == SND_BGM_MIDI) {
snd_kaja_func(KAJA_SONG_STOP, 0);
snd_midi_active = snd_midi_possible;
snd_determine_mode();
snd_kaja_func(KAJA_SONG_PLAY, 0);
}
}
void option_update_and_render(void)
{
static char input_allowed = 0;
static char initialized = 0;
#define OPTION_CHANGE(direction) \
option_put(menu_sel, TX_YELLOW); \
switch(menu_sel) { \
case 0: \
RING_##direction##(rank, RANK_LUNATIC); \
break; \
case 1: \
RING_##direction##(snd_bgm_mode, SND_BGM_MIDI); \
snd_bgm_restart(); \
break; \
case 2: \
RING_##direction##(lives, CFG_LIVES_MAX); \
2015-03-16 21:35:52 +00:00
break; \
case 3: \
RING_##direction##(bombs, CFG_BOMBS_MAX); \
2015-03-16 21:35:52 +00:00
break; \
case 4: \
resident->perf = 1 - resident->perf; \
2015-03-16 21:35:52 +00:00
break; \
} \
option_put(menu_sel, TX_WHITE);
#define OPTION_QUIT \
menu_sel = 3; \
in_option = 0; \
initialized = 0;
if(!initialized) {
int i;
input_allowed = 0;
initialized = 1;
text_clear();
graph_showpage(1);
graph_copy_page(0);
option_put_shadow();
graph_showpage(0);
for(i = 0; i < 7; i++) {
option_put(i, menu_sel == i ? TX_WHITE : TX_YELLOW);
}
putfunc = option_put;
}
if(!key_det) {
2015-03-16 21:35:52 +00:00
input_allowed = 1;
}
if(input_allowed) {
if(key_det & INPUT_UP) {
2015-03-16 21:35:52 +00:00
menu_sel_move(6, -1);
}
if(key_det & INPUT_DOWN) {
2015-03-16 21:35:52 +00:00
menu_sel_move(6, 1);
}
if(key_det & INPUT_RIGHT) {
2015-03-16 21:35:52 +00:00
OPTION_CHANGE(INC);
}
if(key_det & INPUT_LEFT) {
2015-03-16 21:35:52 +00:00
OPTION_CHANGE(DEC);
}
if(key_det & INPUT_SHOT || key_det & INPUT_OK) {
2015-03-16 21:35:52 +00:00
switch(menu_sel) {
case 5:
rank = RANK_NORMAL;
snd_bgm_mode = SND_BGM_FM;
snd_kaja_func(KAJA_SONG_STOP, 0);
snd_midi_active = 0;
snd_determine_mode();
snd_kaja_func(KAJA_SONG_PLAY ,0);
lives = CFG_LIVES_DEFAULT;
bombs = CFG_BOMBS_DEFAULT;
resident->unused_2 = 1;
resident->perf = 0;
2015-03-16 21:35:52 +00:00
option_put(0, TX_YELLOW);
option_put(1, TX_YELLOW);
option_put(2, TX_YELLOW);
option_put(3, TX_YELLOW);
option_put(4, TX_YELLOW);
break;
case 6:
OPTION_QUIT;
break;
}
}
if(key_det & INPUT_CANCEL) {
2015-03-16 21:35:52 +00:00
OPTION_QUIT;
}
if(key_det) {
2015-03-16 21:35:52 +00:00
input_allowed = 0;
}
}
}
int main(void)
{
unsigned char ret;
if(snd_pmd_resident()) {
snd_mmd_resident();
if(game_init_op()) {
zun_error(ERROR_OUT_OF_MEMORY);
return 1;
}
extra_unlocked = scoredat_cleared_load();
2015-03-16 21:35:52 +00:00
if(cfg_load() == 1) {
return 1;
}
} else {
return 1;
}
gaiji_backup();
gaiji_entry_bfnt("MIKOFT.bft");
if(resident->demo_num == 0) {
2015-03-16 21:35:52 +00:00
demo_num = 1;
snd_kaja_func(KAJA_SONG_STOP, 0);
} else {
demo_num = resident->demo_num + 1;
2015-03-16 21:35:52 +00:00
if(demo_num > 3) {
demo_num = 1;
}
score_duration = 350;
score_menu();
graph_showpage(0);
graph_accesspage(0);
}
key_det = 0;
2015-03-16 21:35:52 +00:00
snd_active = snd_bgm_mode;
if(!resident->demo_num && snd_midi_possible) {
2015-03-16 21:35:52 +00:00
char midi_active = snd_midi_active;
snd_midi_active = 1;
snd_load("gminit.m", SND_LOAD_SONG);
snd_kaja_func(KAJA_SONG_PLAY, 0);
snd_midi_active = midi_active;
}
op_animate();
pi_slot_load(2, "ts3.pi");
pi_slot_load(1, "ts2.pi");
key_det = 0;
2015-03-16 21:35:52 +00:00
idle_frames = 0;
while(!quit) {
input_sense();
if(in_option == 0) {
main_update_and_render();
} else if(in_option == 1) {
option_update_and_render();
}
resident->frame++;
2015-03-16 21:35:52 +00:00
idle_frames++;
frame_delay(1);
}
ret = resident->op_main_retval;
resident_sgm = 0;
2015-03-16 21:35:52 +00:00
cfg_save();
text_clear();
graph_clear();
game_exit_to_dos();
gaiji_restore();
return ret;
}