~sebsite/generic-tetromino-game

add option for input delay v3 SUPERSEDED

Lorenz (xha): 1
 add option for input delay

 2 files changed, 43 insertions(+), 7 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sebsite/generic-tetromino-game/patches/41960/mbox | git am -3
Learn more about email & git

[PATCH v3] add option for input delay Export this patch

---
:)
 main.c                          | 41 +++++++++++++++++++++++++++------
 website/docs/options/index.html |  9 ++++++++
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/main.c b/main.c
index 1c8dfe3..b00ddae 100644
--- a/main.c
+++ b/main.c
@@ -115,6 +115,7 @@ enum option {
	OPT_COLORS,
	OPT_GARBAGE_PILING,
	OPT_HARD_DROP,
	OPT_INPUT_DELAY,
	OPT_INPUT_HANDLER,
	OPT_LINES_PER_LEVEL,
	OPT_MUSIC,
@@ -2249,6 +2250,11 @@ option_string_values(enum option opt, const char *const **restrict values,
		valbuf[2] = "with lock";
		*nvalues = 3;
		break;
	case OPT_INPUT_DELAY:
		valbuf[0] = "off";
		valbuf[1] = "on";
		*nvalues = 2;
		break;
	case OPT_INPUT_HANDLER:
		valbuf[0] = "vanilla";
		*nvalues = 1;
@@ -2830,6 +2836,8 @@ set_option_string(const char *key, const char *val, const char **restrict err)
		*err = parse_config_string(key, val, OPT_GARBAGE_PILING);
	} else if (strcmp(key, "hard_drop") == 0) {
		*err = parse_config_string(key, val, OPT_HARD_DROP);
	} else if (strcmp(key, "input_delay") == 0) {
		*err = parse_config_string(key, val, OPT_INPUT_DELAY);
	} else if (strcmp(key, "input_handler") == 0) {
		*err = parse_config_string(key, val, OPT_INPUT_HANDLER);
	} else if (strcmp(key, "lines_per_level") == 0) {
@@ -2859,6 +2867,7 @@ parse_config(void)
	options[OPT_COLORS] = xstrdup("classic");
	options[OPT_GARBAGE_PILING] = xstrdup("on");
	options[OPT_HARD_DROP] = xstrdup("off");
	options[OPT_INPUT_DELAY] = xstrdup("off");
	options[OPT_INPUT_HANDLER] = xstrdup("vanilla");
	options[OPT_LINES_PER_LEVEL] = xstrdup("vanilla");
	options[OPT_MUSIC] = xstrdup("random");
@@ -3041,6 +3050,8 @@ save_config(void)
		goto close_and_unlink;
	if (write_config_string(f, "hard_drop", options[OPT_HARD_DROP]) == -1)
		goto close_and_unlink;
	if (write_config_string(f, "input_delay", options[OPT_INPUT_DELAY]) == -1)
		goto close_and_unlink;
	if (write_config_string(f, "input_handler", options[OPT_INPUT_HANDLER]) == -1)
		goto close_and_unlink;
	if (write_config_string(f, "lines_per_level", options[OPT_LINES_PER_LEVEL]) == -1)
@@ -3166,6 +3177,7 @@ draw_core_option(void)
	case OPT_COLORS:
	case OPT_GARBAGE_PILING:
	case OPT_HARD_DROP:
	case OPT_INPUT_DELAY:
	case OPT_PAUSE:
	case OPT_SAVE_HIGHSCORES:
	case OPT_SFX:
@@ -3288,6 +3300,7 @@ draw_options_page(void)
		writefg("COLORS", 2, y++, WHITE);
		writefg("GARBAGE PILING", 2, y++, WHITE);
		writefg("HARD DROP", 2, y++, WHITE);
		writefg("INPUT DELAY", 2, y++, WHITE);
		writefg("INPUT HANDLER", 2, y++, WHITE);
		writefg("LINES PER LEVEL", 2, y++, WHITE);
		writefg("MUSIC", 2, y++, WHITE);
@@ -4070,6 +4083,7 @@ read_replay_metadata(FILE *f)
{
	/* TODO: most likely a memory leak here */
	options[OPT_HARD_DROP] = xstrdup("off");
	options[OPT_INPUT_DELAY] = xstrdup("off");
	options[OPT_LINES_PER_LEVEL] = xstrdup("vanilla");
	options[OPT_RNG] = xstrdup("classic");

@@ -4094,6 +4108,8 @@ read_replay_metadata(FILE *f)

		if (strcmp(line, "hard_drop") == 0) {
			err = parse_config_string(line, val, OPT_HARD_DROP);
		} else if (strcmp(line, "input_delay") == 0) {
			err = parse_config_string(line, val, OPT_INPUT_DELAY);
		} else if (strcmp(line, "lines_per_level") == 0) {
			err = parse_config_string(line, val, OPT_LINES_PER_LEVEL);
		} else if (strcmp(line, "rng") == 0) {
@@ -7789,9 +7805,12 @@ static int
gameinput(const uint8_t inputs[static 4][2], uint8_t i)
{
	struct game_state *g = &state.game.players[i];
	uint8_t pressed = inputs[0][i] & ~inputs[1][i];
	uint8_t held = inputs[0][i] & inputs[1][i];
	uint8_t released = ~inputs[0][i] & inputs[1][i];

	uint8_t delay = strcmp(options[OPT_INPUT_DELAY], "on") == 0 ? 2 : 0;
	uint8_t pressed = inputs[delay][i] & ~inputs[delay + 1][i];
	uint8_t held = inputs[delay][i] & inputs[delay + 1][i];
	uint8_t released = ~inputs[delay][i] & inputs[delay + 1][i];

	if (g->over) {
		if (pressed == INPUT_MASK_START) {
			/* only start pressed; no other buttons */
@@ -7821,11 +7840,11 @@ gameinput(const uint8_t inputs[static 4][2], uint8_t i)
				/* only if not pushing down (and not pressed up) */
				if (pressed & (INPUT_MASK_RIGHT | INPUT_MASK_LEFT)) {
					g->das = 0;
					shift(g, inputs[0][i]);
					shift(g, inputs[delay][i]);
				} else if (held & (INPUT_MASK_RIGHT | INPUT_MASK_LEFT)) {
					++g->das;
					if (g->das >= 16)
						shift(g, inputs[0][i]);
						shift(g, inputs[delay][i]);
				}
			}
			if (released & INPUT_MASK_UP) {
@@ -7887,6 +7906,10 @@ save_replay(void)
		if (write_config_string(f, "hard_drop", options[OPT_HARD_DROP]) == -1)
			goto write_err;
	}
	if (strcmp(options[OPT_INPUT_DELAY], "off") != 0) {
		if (write_config_string(f, "input_delay", options[OPT_INPUT_DELAY]) == -1)
			goto write_err;
	}
	if (strcmp(options[OPT_LINES_PER_LEVEL], "vanilla") != 0) {
		if (write_config_string(f, "lines_per_level", options[OPT_LINES_PER_LEVEL]) == -1)
			goto write_err;
@@ -8558,7 +8581,8 @@ read_inputs(void))[2]
static void
handle_inputs(const uint8_t inputs[static 4][2])
{
	uint8_t pressed = inputs[0][0] & ~inputs[1][0];
	uint8_t delay = strcmp(options[OPT_INPUT_DELAY], "on") == 0 ? 2 : 0;
	uint8_t pressed = inputs[delay][0] & ~inputs[delay + 1][0];
	switch (state.scr) {
	case TITLE:
		titleinput(pressed);
@@ -8591,7 +8615,10 @@ handle_inputs(const uint8_t inputs[static 4][2])
		onlineinput(pressed);
		break;
	case OPTIONS:
		optionsinput(pressed);
		/* input delay might get enabled in the options: to avoid
		 * disabling it again with the same key press, disable input
		 * delay for the options */
		optionsinput(inputs[0][0] & ~inputs[1][0]);
		break;
	case INPUT:
		inputinput(pressed);
diff --git a/website/docs/options/index.html b/website/docs/options/index.html
index 0f6749b..aca0012 100644
--- a/website/docs/options/index.html
+++ b/website/docs/options/index.html
@@ -61,6 +61,15 @@
            <dd>Pressing the up button will snap the tetromino to the bottom of the board and immediately lock it.</dd>
          </dl>
        </section>
        <section>
          <h3 class="option">Input Delay</h3>
          <dl>
            <dt class="optval">On</dt>
            <dd><span class="i">(default)</span>The input delay of NES Tetris (2 frames) will be emulated. Note that the options screen doesn't have input delay, regardless of this setting.</dd>
            <dt class="optval">Off</dt>
            <dd>The inputs will be processed as soon as they are available.</dd>
          </dl>
        </section>
        <!-- TODO: finish me -->
        <section>
          <h3 class="option">Lines per level</h3>
-- 
2.41.0
Mostly looks good, the one issue I found is that you can't exit the
options screen when input delay is enabled, since the start button press
is read twice.