ReC98/th03/formats/script.hpp

154 lines
4.5 KiB
C++
Raw Normal View History

/// Common code for plaintext script formats
/// ----------------------------------------
// ZUN bloat: At 257 bytes of static data, [_ctype] might be a rather heavy
// dependency for three digit and control character checks. For digits, it's
// also *technically* wrong, as the <ctype.h> functions are affected by the
// current locale (see section 7.4.2 of the C standard), whereas the subsequent
// conversion is hardcoded as a single subtraction from an ASCII '0'.
//
// In the original binary, "control character" refers to every ASCII codepoint
// < 0x20.
#include <ctype.h>
// Code generation… PORTERS: Remove.
#if defined(__TURBOC__) && defined(__MSDOS__)
#undef _IS_DIG
#undef _IS_CTL
static const unsigned char _IS_DIG = 2;
static const unsigned char _IS_CTL = 32;
#endif
enum script_ret_t {
CONTINUE = 0,
STOP = -1,
};
extern int script_param_number_default;
#define str_sep_control_or_space(c) \
(iscntrl(c) || (c == ' '))
#ifdef script_p
// Reads up to 3 ASCII number digits from [script_p] and writes the
// resulting 3-digit number to [ret]. If [script_p] does not point to any
// digit, [script_param_number_default] is written to [ret] instead.
void pascal near script_param_read_number_first(int& ret)
{
unsigned char c0 = *script_p; script_p++;
unsigned char c1 = *script_p; script_p++;
unsigned char c2 = *script_p; script_p++;
if(!isdigit(c0)) {
ret = script_param_number_default;
script_p -= 3;
} else if(!isdigit(c1)) {
ret = (c0 - '0');
script_p -= 2;
} else if(!isdigit(c2)) {
ret = (((c0 - '0') * 10) + c1 - '0');
script_p -= 1;
} else {
ret = (((c0 - '0') * 100) + ((c1 - '0') * 10) + (c2 - '0'));
}
}
inline void script_param_read_number_first(int& ret, int default_value) {
script_param_number_default = default_value;
script_param_read_number_first(ret);
}
void pascal near script_param_read_number_second(int& ret)
{
if(*script_p == ',') {
script_p++;
script_param_read_number_first(ret);
} else {
ret = script_param_number_default;
}
}
// Reads a filename parameter into [ret] i.e., as many characters from
// [script_p] until either
// • encountering a control or ' ' character (leaving [script_p] pointing to
// the character after this sentinel one),
// • or until up to a maximum of (PF_FN_LEN - 1) characters have beed read
// (leaving [script_p] pointing to the character after the last one read).
// The resulting string is \0-terminated, and [temp_len] receives the
// amount of characters before the \0 terminator.
#define script_param_read_fn(ret, temp_len, temp_c) { \
for(temp_len = 0; temp_len < (PF_FN_LEN - 1); temp_len++) { \
temp_c = *script_p; \
script_p++; \
if(str_sep_control_or_space(temp_c)) { \
break; \
} \
ret[temp_len] = temp_c; \
} \
ret[temp_len] = '\0'; \
}
// Commands shared between the cutscene and dialog systems
// -------------------------------------------------------
// The ternary trick in script_op_bgm() is innovative enough, we *really*
// don't want to also work around the resulting warning now. Besides,
// [fast_forward] is an rvalue in the TH04/TH05 dialog code and an lvalue
// in the TH03/TH04/TH05 cutscene code.
#if defined(__TURBOC__) && defined(__MSDOS__)
#pragma warn -rch
#pragma warn -ccc
#endif
#define script_op_bgm(stop_before_load, temp_c, temp_fn, temp_len) { \
c = *script_p; \
if(c == '$') { \
script_p++; \
snd_kaja_func(KAJA_SONG_STOP, 0); \
if(stop_before_load) { /* ZUN bloat */ \
return CONTINUE; \
} \
} else if(c == '*') { \
script_p++; \
snd_kaja_func(KAJA_SONG_PLAY, 0); \
if(stop_before_load) { /* ZUN bloat */ \
return CONTINUE; \
} \
} else if(c == ',') { \
script_p++; \
script_param_read_fn(fn, p1, c); \
(stop_before_load \
? snd_kaja_func(KAJA_SONG_STOP, 0) \
: optimization_barrier() \
); \
snd_load(fn, SND_LOAD_SONG); \
snd_kaja_func(KAJA_SONG_PLAY, 0); \
} \
}
#define script_op_fade(c, func_in, func_out, temp_p1) { \
script_p++; \
script_param_read_number_first(temp_p1, 1); \
if(c == 'i') { \
func_in(p1); \
} else { \
func_out(p1); \
} \
}
#define script_op_shake(fast_forward, temp_i, temp_p1) { \
script_param_read_number_first(temp_p1, 8); \
for(temp_i = 0; temp_i <= temp_p1; temp_i++) { \
if(temp_i & 1) { \
graph_scrollup(4); \
} else { \
graph_scrollup(RES_Y - 4); \
} \
if(!fast_forward) { \
frame_delay(1); \
} \
} \
graph_scrollup(0); \
}
// -------------------------------------------------------
#endif