ReC98/th02/th02.h

324 lines
7.1 KiB
C

/* ReC98
* -----
* Include file for TH02
*/
#include "ReC98.h"
#include "th01\ranks.h"
// Formats
// -------
typedef struct {
char magic[4]; // = "MPTN"
char count;
char unused;
} mptn_header_t;
#define MPTN_SIZE (8 * 16)
extern char mptn_show_palette_on_load;
extern unsigned char mptn_count;
extern int *mptn_buffer;
extern char mptn_palette[16 * 3];
int pascal mptn_load(const char *fn);
void pascal mptn_palette_show(void);
void pascal mptn_free(void);
#define PI_SLOTS 6
extern void far *pi_slot_buffers[PI_SLOTS];
extern PiHeader pi_slot_headers[PI_SLOTS];
int pi_slot_load(int slot, const char *fn);
void pi_slot_palette_apply(int slot);
void pi_slot_put(int x, int y, int slot);
#define pi_load_put_free(slot, fn) \
pi_slot_load(slot, (fn)); \
pi_slot_palette_apply(slot); \
pi_slot_put(0, 0, slot); \
graph_pi_free(&pi_slot_headers[slot], pi_slot_buffers[slot]);
// "東方封魔.録" in Shift-JIS
#define PF_FN "\x93\x8C\x95\xFB\x95\x95\x96\x82\x2E\x98\x5E"
#define PF_KEY 0x12
// -------
// Hardware
// -------
#define graph_clear_both() \
graph_accesspage(1); graph_clear(); \
graph_accesspage(0); graph_clear(); \
graph_accesspage(0); graph_showpage(0);
#define FX(color, weight, spacing) \
(color | (weight & 3) << 4 | (spacing & 7) << 6)
void graph_putsa_fx(int x, int y, int fx, const unsigned char *str);
void pascal graph_copy_rect_1_to_0(int x, int y, int w, int h);
// -------
// Gaiji characters
// ----------------
/* ZUN messed up and swapped M and N in MIKOFT.BFT for both regular and bold
* fonts. Therefore, other code shouldn't really use the straightforward
* solution of just adding char literals to a defined start offset, as it may
* suggest that this also works for M and N (which it doesn't). So...
*/
typedef enum {
GB_DIGITS = 160,
gb_0_ = GB_DIGITS,
gb_1_,
gb_2_,
gb_3_,
gb_4_,
gb_5_,
gb_6_,
gb_7_,
gb_8_,
gb_9_,
GB_LETTERS = 105,
gb_A_ = GB_LETTERS + 'A',
gb_B_,
gb_C_,
gb_D_,
gb_E_,
gb_F_,
gb_G_,
gb_H_,
gb_I_,
gb_J_,
gb_K_,
gb_L_,
gb_M_ = GB_LETTERS + 'N',
gb_N_ = GB_LETTERS + 'M',
gb_O_ = GB_LETTERS + 'O',
gb_P_,
gb_Q_,
gb_R_,
gb_S_,
gb_T_,
gb_U_,
gb_V_,
gb_W_,
gb_X_,
gb_Y_,
gb_Z_,
gb_SP = 207,
} gaiji_bold_t;
typedef enum {
gs_YINYANG = 2, // ☯
gs_BOMB, // ◉? ⦿? 🎯? 🖸? Or simply 💣?
gs_BULLET = 218, // •
gs_PERIOD, // .
gs_EXCLAMATION, // !
gs_QUESTION, // ?
gs_ELLIPSIS, // …
gs_COPYRIGHT, // ©
gs_HEART, // 🎔
gs_SKULL, // 💀
gs_GHOST, // 👻
gs_SIDDHAM_HAM, // Siddhaṃ seed syllable HĀṂ (I don't even)
gs_SPACE, // ␠
gs_ARROW_LEFT, // ←
gs_ARROW_RIGHT, // →
gs_END, // "End"
// Unused 32x16 rank sprites
gs_EA, gs_SY, // "Ea", "sy"
gs_NOR, gs_MAL, // "Nor, "mal"
gs_HA, gs_RD, // "Ha, "rd"
gs_LUN, gs_ATIC, // "Lun", "atic"
gs_ALL, // "All"
} gaiji_symbols_t;
// ----------------
typedef enum {
INPUT_UP = 0x1,
INPUT_DOWN = 0x2,
INPUT_LEFT = 0x4,
INPUT_RIGHT = 0x8,
INPUT_SHOT = 0x10,
INPUT_BOMB = 0x20,
INPUT_CANCEL = 0x40,
INPUT_OK = 0x80,
INPUT_Q = 0x100,
INPUT_UP_LEFT = 0x1000,
INPUT_UP_RIGHT = 0x2000,
INPUT_DOWN_LEFT = 0x4000,
INPUT_DOWN_RIGHT = 0x8000
} input_t;
extern input_t input;
void input_sense(void);
void pascal frame_delay(int frames);
void pascal frame_delay_2(int frames);
void key_delay(void);
// Sound
// -----
typedef enum {
SND_BGM_OFF,
SND_BGM_FM,
SND_BGM_MIDI
} snd_bgm_mode_t;
#include "libs\kaja\kaja.h"
extern char snd_active;
extern char snd_interrupt_if_midi;
extern unsigned char snd_midi_active;
extern char snd_midi_possible;
extern char snd_fm_possible;
int snd_pmd_resident(void);
int snd_mmd_resident(void);
int snd_determine_mode(void);
int snd_kaja_interrupt(int ax);
#define snd_kaja_func(func, param) snd_kaja_interrupt((func) << 8 | (param))
#define SND_LOAD_SONG (KAJA_GET_SONG_ADDRESS << 8)
#define SND_LOAD_SE (PMD_GET_SE_ADDRESS << 8)
void snd_load(const char *fn, kaja_func_t func);
void snd_se_reset(void);
void snd_se_play(int new_se);
void snd_se_update(void);
// -----
// Music Room
#define MUSIC_CMT_FILE "MUSIC.TXT"
#define MUSIC_CMT_LINE_LEN 42
#define MUSIC_CMT_LINE_COUNT 20
// Configuration file
// ------------------
#define CFG_FN "huuma.cfg"
#pragma option -a1
typedef struct {
char rank;
char bgm_mode;
char bombs;
char lives;
char perf;
} huuma_options_t;
typedef struct {
huuma_options_t opts;
int resident_sgm;
char debug;
} huuma_cfg_t;
#pragma option -a.
// ------------------
// Resident structure
// ------------------
#define RES_ID "MIKOConfig"
typedef struct {
char id[11]; // = RES_ID
char stage;
char debug;
long score;
int continues_used;
char rem_bombs;
char rem_lives;
char rank;
char start_power;
char bgm_mode;
char start_bombs;
char start_lives;
long frame;
int unused_1;
char unused_2;
unsigned char op_main_retval;
unsigned char perf;
char unused_3;
char shottype;
char demo_num;
int skill;
int unused_4;
long score_highest;
} resident_t;
extern resident_t *mikoconfig;
extern char rank;
extern char bombs;
extern char lives;
// ------------------
#define SHOTTYPE_COUNT 3
// Highscores
// ---------
#define SCORE_PLACES 10
#define SCORE_NAME_LEN 6 /* excluding the terminating 0 */
#define EXTRA_CLEAR_FLAGS {1, 2, 4}
#define GAME_CLEAR_CONSTANTS {318, 118, 218}
#define STAGE_ALL 127
typedef struct {
/* For ranks (and therefore, structure instances) #0, #1 and #2 (Easy,
* Normal and Hard), this is either GAME_CLEAR_CONSTANTS[rank] or 0,
* and indicates whether the main 5 stages have been cleared with the
* *shot type* associated with the rank's index, in any difficulty.
* Yes, ZUN uses a field in a rank-specific structure to store a
* shot type-specific value.
*
* For rank #3, this is instead interpreted as a bit field using the
* EXTRA_CLEAR_FLAGS to indicate whether the Extra Stage has been
* cleared with the respective shot type.
* Yes, ZUN stores what is technically information about the Extra
* rank in the structure of the Lunatic rank.
*
* For rank #4, this field is unused.
*/
int cleared;
long points[SCORE_PLACES];
long points_sum;
unsigned char g_name[SCORE_PLACES][SCORE_NAME_LEN + 1];
unsigned char g_name_first_sum;
unsigned char stage[SCORE_PLACES];
unsigned char stage_sum;
struct date date[SCORE_PLACES];
unsigned char shottype[SCORE_PLACES];
} score_t;
typedef struct {
score_t score;
long score_sum; // Sum of all bytes in score, pre-encraption
} score_file_t;
extern char cleared_game_with[SHOTTYPE_COUNT];
extern char cleared_extra_with[SHOTTYPE_COUNT];
int pascal score_cleared_load(void);
// ---------
// Debugging
// ---------
// Calls ZUN's interrupt vector set up in ZUNINIT.COM to display an error
// message.
typedef enum {
ERROR_FILE_NOT_FOUND = 2,
ERROR_OUT_OF_MEMORY = 3,
ERROR_MISSING_DRIVER = 4,
ERROR_HISCORE_CORRUPT = 5
} zun_error_t;
void pascal zun_error(zun_error_t err);
// ---------
void game_exit(void);