some more edits
This commit is contained in:
parent
1884df3f1e
commit
cc60012f85
|
@ -1,2 +1,3 @@
|
|||
build-fx
|
||||
*.g1a
|
||||
__pycache__
|
||||
|
|
2
Makefile
2
Makefile
|
@ -3,6 +3,8 @@
|
|||
# the [fxsdk] program.
|
||||
#---
|
||||
|
||||
PATH := .:$(PATH)
|
||||
|
||||
#
|
||||
# Configuration
|
||||
#
|
||||
|
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
129
converters.py
129
converters.py
|
@ -1,17 +1,138 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import fxconv
|
||||
from itertools import product
|
||||
|
||||
def convert(input, output, params, target):
|
||||
if params["type"] != "map":
|
||||
raise fxconv.FxconvError(f"unknown conversion type {params["type"]}")
|
||||
raise fxconv.FxconvError(f"unknown conversion type {params['type']}")
|
||||
|
||||
# Convert the map into binary.
|
||||
# coordinate system start from (0, 0), positive to right and bottom
|
||||
# okay for now we just hardcode 18x10 (16x8 + borders).
|
||||
#
|
||||
# Format of the map:
|
||||
#
|
||||
# - width (1 byte)
|
||||
# - height (1 byte)
|
||||
# - camera_x (1 byte)
|
||||
# - camera_y (1 byte)
|
||||
# - spawn_x (1 byte), where to spawn enemies
|
||||
# - spawn_y (1 byte), where to spawn enemies
|
||||
# - number of enemy path elements (1 byte)
|
||||
# - unused (9 bytes)
|
||||
#
|
||||
# - offset of grid data from file start (2 bytes, big endian)
|
||||
# - offset of enemy path data from file start (2 bytes, big endian)
|
||||
# - unused (12 bytes)
|
||||
# - grid data (variable)
|
||||
# - enemy path (variable)
|
||||
#
|
||||
# every element of grid data is:
|
||||
# - type (1 byte), amongst:
|
||||
# 0x00: basic placement tile
|
||||
# 0x01: basic enemy path
|
||||
# 0x02: castle
|
||||
#
|
||||
# every element of enemy path is:
|
||||
# - delta (1 byte):
|
||||
# 0x00: up
|
||||
# 0x01: right
|
||||
# 0x02: down
|
||||
# 0x03: left
|
||||
|
||||
data = open(input, "r").read()
|
||||
print(data)
|
||||
lines = open(input, "r").read().splitlines()
|
||||
|
||||
w, h = 18, 10
|
||||
spawn_x, spawn_y = None, None
|
||||
arr_x, arr_y = None, None
|
||||
grid_data = b''
|
||||
|
||||
if len(lines) != h:
|
||||
raise fxconv.FxconvError(f"should have 10 lines, has {len(lines)}")
|
||||
|
||||
for line_no, line in enumerate(lines):
|
||||
line = line.strip()
|
||||
if len(line) != w:
|
||||
raise fxconv.FxconvError(f"line no. {line_no + 1} "
|
||||
f"should have 18 columns, has {len(line)}")
|
||||
|
||||
for car_no, c in enumerate(line):
|
||||
if c == '#':
|
||||
grid_data += b'\0'
|
||||
elif c == ' ':
|
||||
grid_data += b'\1'
|
||||
elif c == '>':
|
||||
if spawn_x is not None:
|
||||
raise fxconv.FxconvError("multiple spawn points, please "
|
||||
"choose, you dumbass")
|
||||
spawn_x, spawn_y = car_no, line_no
|
||||
grid_data += b'\1'
|
||||
elif c == 'x':
|
||||
if arr_x is not None:
|
||||
raise fxconv.FxconvError("multiple castles, please "
|
||||
"choose, you dumbass")
|
||||
arr_x, arr_y = car_no, line_no
|
||||
grid_data += b'\2'
|
||||
else:
|
||||
raise fxconv.FxconvError(f"invalid character at "
|
||||
f"line {line_no + 1}, column {car_no + 1}")
|
||||
|
||||
if spawn_x is None:
|
||||
raise fxconv.FxconvError("no spawn point, is that some kind of "
|
||||
"sick joke")
|
||||
if arr_x is None:
|
||||
raise fxconv.FxconvError("no castle, are you kidding me")
|
||||
|
||||
def find_path(previous):
|
||||
for delta_x, delta_y in ((0, -1), (1, 0), (0, 1), (-1, 0)):
|
||||
x, y = previous[-1]
|
||||
x += delta_x
|
||||
y += delta_y
|
||||
|
||||
if (x, y) == (arr_x, arr_y):
|
||||
return previous + ((x, y),)
|
||||
elif grid_data[y * w + x] != 1:
|
||||
pass
|
||||
elif (x, y) not in previous:
|
||||
result = find_path(previous + ((x, y),))
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
path_to_arr = find_path(((spawn_x, spawn_y),))
|
||||
if path_to_arr is None:
|
||||
raise fxconv.FxconvError(f"no path from spawn to castle")
|
||||
|
||||
path_data = b''
|
||||
for (ax, ay), (bx, by) in zip(path_to_arr, path_to_arr[1:]):
|
||||
path_data += int({
|
||||
(0, -1): 0,
|
||||
(1, 0): 1,
|
||||
(0, 1): 2,
|
||||
(-1, 0): 3
|
||||
}[(bx - ax, by - ay)]).to_bytes(1, 'big')
|
||||
|
||||
def round4len(x):
|
||||
x = len(x)
|
||||
result = (x // 4) * 4 + (x % 4 != 0) * 4
|
||||
return result
|
||||
def round4data(x):
|
||||
return x + b'\0' * (round4len(x) - len(x))
|
||||
|
||||
data = int(w).to_bytes(1, 'big') + int(h).to_bytes(1, 'big')
|
||||
data += int(1).to_bytes(1, 'big') + int(1).to_bytes(1, 'big')
|
||||
data += int(spawn_x).to_bytes(1, 'big')
|
||||
data += int(spawn_y).to_bytes(1, 'big')
|
||||
data += int(len(path_data)).to_bytes(1, 'big')
|
||||
data += b'\0' * 9
|
||||
data += int(32).to_bytes(2, 'big')
|
||||
data += int(32 + round4len(grid_data)).to_bytes(2, 'big')
|
||||
data += b'\0' * 12
|
||||
data += round4data(grid_data)
|
||||
data += round4data(path_data)
|
||||
|
||||
data = b'placeholder'
|
||||
fxconv.elf(data, output, "_" + params["name"], **target)
|
||||
|
||||
# End of file.
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import getopt
|
||||
import sys
|
||||
import os
|
||||
import fxconv
|
||||
import subprocess
|
||||
|
||||
# Note: this line is edited at compile time to insert the install folder
|
||||
PREFIX="""\
|
||||
/usr
|
||||
""".strip()
|
||||
|
||||
help_string = f"""
|
||||
usage: fxconv [-s] <python script> [files...]
|
||||
fxconv -b <bin file> -o <object file> [parameters...]
|
||||
fxconv -i <png file> -o <object file> (--fx|--cg) [parameters...]
|
||||
fxconv -f <png file> -o <object file> [parameters...]
|
||||
|
||||
fxconv converts data files such as images and fonts into gint formats
|
||||
optimized for fast execution, or into object files.
|
||||
|
||||
Operating modes:
|
||||
-s, --script Expose the fxconv module and run this Python script
|
||||
-b, --binary Turn data into an object file, no conversion
|
||||
-i, --image Convert to gint's bopti image format
|
||||
-f, --font Convert to gint's topti font format
|
||||
--libimg-image Convert to the libimg image format
|
||||
|
||||
When using -s, additional arguments are stored in the [fxconv.args] variable of
|
||||
the module. This is intended to be a restricted list of file names specified by
|
||||
a Makefile, used to convert only a subset of the files in the script.
|
||||
|
||||
The operating mode options are shortcuts to convert single files without a
|
||||
script. They accept parameters with a "category.key:value" syntax, for example:
|
||||
fxconv -f myfont.png -o myfont.o charset:ascii grid.padding:1 height:7
|
||||
|
||||
When converting images, use --fx (black-and-white calculators) or --cg (16-bit
|
||||
color calculators) to specify the target machine.
|
||||
|
||||
Install PREFIX is set to '{PREFIX}'.
|
||||
""".strip()
|
||||
|
||||
# Simple error-warnings system
|
||||
def err(msg):
|
||||
print("\x1b[31;1merror:\x1b[0m", msg, file=sys.stderr)
|
||||
def warn(msg):
|
||||
print("\x1b[33;1mwarning:\x1b[0m", msg, file=sys.stderr)
|
||||
|
||||
# "converters" module from the user project
|
||||
try:
|
||||
import converters
|
||||
except ImportError:
|
||||
converters = None
|
||||
|
||||
def main():
|
||||
# Default execution mode is to run a Python script for conversion
|
||||
modes = "script binary image font bopti-image libimg-image"
|
||||
mode = "s"
|
||||
output = None
|
||||
model = None
|
||||
target = { 'toolchain': None, 'arch': None, 'section': None }
|
||||
use_custom = False
|
||||
|
||||
# Parse command-line arguments
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print(help_string, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
longs = "help output= fx cg toolchain= arch= section= custom " + modes
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:], "hsbifo:", longs.split())
|
||||
except getopt.GetoptError as error:
|
||||
err(error)
|
||||
sys.exit(1)
|
||||
|
||||
for name, value in opts:
|
||||
# Print usage
|
||||
if name == "--help":
|
||||
err(help_string, file=sys.stderr)
|
||||
sys.exit(0)
|
||||
# TODO: fxconv: verbose mode
|
||||
elif name == "--verbose":
|
||||
pass
|
||||
elif name in [ "-o", "--output" ]:
|
||||
output = value
|
||||
elif name in [ "--fx", "--cg" ]:
|
||||
model = name[2:]
|
||||
elif name == "--toolchain":
|
||||
target['toolchain'] = value
|
||||
elif name == "--arch":
|
||||
target['arch'] = value
|
||||
elif name == "--section":
|
||||
target['section'] = value
|
||||
elif name == "--custom":
|
||||
use_custom = True
|
||||
mode = "custom"
|
||||
# Other names are modes
|
||||
else:
|
||||
mode = name[1] if len(name)==2 else name[2:]
|
||||
|
||||
# Remaining arguments
|
||||
if args == []:
|
||||
err(f"execution mode -{mode} expects an input file")
|
||||
sys.exit(1)
|
||||
input = args.pop(0)
|
||||
|
||||
# In --script mode, run the Python script with an augmented PYTHONPATH
|
||||
|
||||
if mode == "s":
|
||||
if output is not None:
|
||||
warn("option --output is ignored in script mode")
|
||||
|
||||
if PREFIX == "":
|
||||
err("unknown or invalid install path x_x")
|
||||
sys.exit(1)
|
||||
|
||||
env = os.environ.copy()
|
||||
if "PYTHONPATH" in env:
|
||||
env["PYTHONPATH"] += f":{PREFIX}/bin"
|
||||
else:
|
||||
env["PYTHONPATH"] = f"{PREFIX}/bin"
|
||||
|
||||
p = subprocess.run([ sys.executable, input ], env=env)
|
||||
if p.returncode != 0:
|
||||
sys.exit(1)
|
||||
|
||||
# In shortcut conversion modes, read parameters from the command-line
|
||||
|
||||
else:
|
||||
def check(arg):
|
||||
if ':' not in arg:
|
||||
warn(f"argument {arg} is not a valid parameter (ignored)")
|
||||
return ':' in arg
|
||||
|
||||
def insert(params, path, value):
|
||||
if len(path) == 1:
|
||||
params[path[0]] = value
|
||||
return
|
||||
if not path[0] in params:
|
||||
params[path[0]] = {}
|
||||
insert(params[path[0]], path[1:], value)
|
||||
|
||||
args = [ arg.split(':', 1) for arg in args if check(arg) ]
|
||||
params = {}
|
||||
for (name, value) in args:
|
||||
insert(params, name.split("."), value)
|
||||
|
||||
if "type" in params:
|
||||
pass
|
||||
elif(len(mode) == 1):
|
||||
params["type"] = { "b": "binary", "i": "image", "f": "font" }[mode]
|
||||
else:
|
||||
params["type"] = mode
|
||||
|
||||
# Will be deprecated in the future
|
||||
if params["type"] == "image":
|
||||
warn("type 'image' is deprecated, use 'bopti-image' instead")
|
||||
params["type"] = "bopti-image"
|
||||
|
||||
# Use the custom module
|
||||
custom = None
|
||||
if use_custom:
|
||||
if converters is None:
|
||||
err("--custom specified but no [converters] module in wd")
|
||||
sys.exit(1)
|
||||
custom = converters.convert
|
||||
|
||||
try:
|
||||
fxconv.convert(input, params, target, output, model, custom)
|
||||
except fxconv.FxconvError as e:
|
||||
err(e)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
302
src/game.c
302
src/game.c
|
@ -1,25 +1,313 @@
|
|||
#include "main.h"
|
||||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
#define NENEMIES 64
|
||||
|
||||
/* Map definition.
|
||||
* This defines how we'll naviguate through the map. */
|
||||
/* State definition, as used throughout the main game.
|
||||
*
|
||||
* For each enemy, the data is:
|
||||
* - alive: if the enemy is alive or dead.
|
||||
*
|
||||
* - nstepf: number of frames for one step, defines the speed of the
|
||||
* enemy.
|
||||
*
|
||||
* - x, y: calculated only for display and collision.
|
||||
* - step, substep: where the AI is at. `step` is the index starting at zero
|
||||
* of the path where is at, `substep` is the substep from 0 to 7, looping
|
||||
* when 8 (augmenting step, except when at the castle).
|
||||
* - nfwait: number of frames to be waited.
|
||||
* - pdr: the enemy that spawned previously or is the next further on the
|
||||
* path. Simple chain list that could evolve later if some enemies are
|
||||
* slowed down or have various speeds, allowing some enemies to overtake
|
||||
* others. */
|
||||
|
||||
void dmap(void *map)
|
||||
struct enemy {
|
||||
int alive;
|
||||
|
||||
int nstepf;
|
||||
|
||||
int x, y;
|
||||
int step, substep;
|
||||
int nfwait;
|
||||
struct enemy **ndrp; /* pointer on the pointer to this enemy structure */
|
||||
struct enemy *pdr; /* previous enemy to be drawn */
|
||||
};
|
||||
|
||||
struct state {
|
||||
/* Map information:
|
||||
*
|
||||
* - w, h: dimensions
|
||||
* - sp_x, sp_y: enemy spawn coordinates
|
||||
* - nep: number of enemy path */
|
||||
|
||||
int w, h;
|
||||
int sp_x, sp_y;
|
||||
int nep; /* number of enemies path. */
|
||||
uint8_t *grid;
|
||||
uint8_t *ep;
|
||||
|
||||
/* AI information:
|
||||
*
|
||||
* - tbsp: time between enemy spawns.
|
||||
* - tnsp: time to next spawn (as a number of ticks).
|
||||
* - nae: number of currently alive enemies.
|
||||
* - first_enemy: pointer to the last enemy to have spawned,
|
||||
* to draw first */
|
||||
|
||||
int tbsp, tnsp;
|
||||
int nae;
|
||||
struct enemy *first_enemy;
|
||||
|
||||
/* Camera, cursor and display information:
|
||||
*
|
||||
* - cam_x, cam_y: camera coordinates, always displays 16x8 tiles
|
||||
* - cur_x, cur_y: map coordinate for the cursor.
|
||||
* - drf: draw frame. */
|
||||
|
||||
int cam_x, cam_y;
|
||||
int cur_x, cur_y;
|
||||
int drf; /* draw frame, varies from 0 to 255 and looping */
|
||||
|
||||
/* Raw data */
|
||||
|
||||
struct enemy enemies[NENEMIES];
|
||||
};
|
||||
|
||||
static struct state state;
|
||||
|
||||
/* init(raw): initialize the state with the given raw map data. */
|
||||
|
||||
static void init(uint8_t *raw)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize map information */
|
||||
|
||||
state.w = raw[0];
|
||||
state.h = raw[1];
|
||||
state.sp_x = raw[4];
|
||||
state.sp_y = raw[5];
|
||||
state.nep = raw[6];
|
||||
state.grid = &raw[(raw[16] << 8) | raw[17]];
|
||||
state.ep = &raw[(raw[18] << 8) | raw[19]];
|
||||
|
||||
/* Initialize AI information */
|
||||
|
||||
state.tbsp = 50;
|
||||
state.tnsp = state.tbsp;
|
||||
state.nae = 0;
|
||||
state.first_enemy = NULL;
|
||||
|
||||
for (i = 0; i < NENEMIES; i++)
|
||||
state.enemies[i].alive = 0;
|
||||
|
||||
/* Initialize display information */
|
||||
|
||||
state.cam_x = raw[2];
|
||||
state.cam_y = raw[3];
|
||||
state.cur_x = 1;
|
||||
state.cur_y = 1;
|
||||
state.drf = 0;
|
||||
}
|
||||
|
||||
/* tick(): tick the game engine. */
|
||||
|
||||
static void tick()
|
||||
{
|
||||
struct enemy *ep;
|
||||
int i;
|
||||
|
||||
for (ep = state.first_enemy; ep; ep = ep->pdr) {
|
||||
if (!--ep->nfwait) {
|
||||
ep->nfwait = ep->nstepf;
|
||||
|
||||
switch (state.ep[ep->step]) {
|
||||
case 0:
|
||||
ep->y--;
|
||||
break;
|
||||
case 1:
|
||||
ep->x++;
|
||||
break;
|
||||
case 2:
|
||||
ep->y++;
|
||||
break;
|
||||
case 3:
|
||||
ep->x--;
|
||||
break;
|
||||
}
|
||||
|
||||
ep->substep++;
|
||||
if (ep->substep == 8) {
|
||||
ep->step++;
|
||||
ep->substep = 0;
|
||||
|
||||
if (ep->step == state.nep) {
|
||||
ep->alive = 0;
|
||||
if (ep->ndrp)
|
||||
(*ep->ndrp) = ep->pdr;
|
||||
|
||||
state.nae--;
|
||||
|
||||
/* TODO: remove one life to the castle */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Spawn enemies if required */
|
||||
|
||||
if (!--state.tnsp) {
|
||||
state.tnsp = state.tbsp;
|
||||
|
||||
if (state.nae < NENEMIES) {
|
||||
for (i = 0, ep = &state.enemies[0]; i < NENEMIES; i++, ep++);
|
||||
ep->pdr = state.first_enemy;
|
||||
ep->pdr->ndrp = &ep->pdr;
|
||||
state.first_enemy = ep;
|
||||
ep->ndrp = &state.first_enemy;
|
||||
|
||||
ep->alive = 1;
|
||||
ep->x = state.sp_x << 3;
|
||||
ep->y = state.sp_y << 3;
|
||||
ep->step = 0;
|
||||
ep->substep = 0;
|
||||
|
||||
/* TODO: use a given type of enemy? */
|
||||
|
||||
ep->nstepf = 10;
|
||||
ep->nfwait = ep->nstepf;
|
||||
|
||||
state.nae++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* tile_cam(x, y): return the type of the tile at coordinates (x, y) relative
|
||||
* to the current camera position.
|
||||
*
|
||||
* If out of bounds, a basic placement tile (id. 0) will be returned */
|
||||
|
||||
static inline int tile_cam(int x, int y)
|
||||
{
|
||||
x += state.cam_x;
|
||||
y += state.cam_y;
|
||||
|
||||
if (x < 0 || x >= state.w || y < 0 || y >= state.h)
|
||||
return 0;
|
||||
return state.grid[y * state.w + x];
|
||||
}
|
||||
|
||||
/* draw(): basically the drawing function for everything. */
|
||||
|
||||
static void draw()
|
||||
{
|
||||
int x, y;
|
||||
|
||||
dclear(C_WHITE);
|
||||
|
||||
/* draw the grid */
|
||||
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 16; x++) {
|
||||
int tile = tile_cam(x, y);
|
||||
int ox = x * 8, oy = y * 8;
|
||||
|
||||
if (tile == 1 || tile == 2) {
|
||||
/* above, below, left, right */
|
||||
if (tile_cam(x, y - 1) == 0)
|
||||
dline(ox, oy, ox + 7, oy, C_BLACK);
|
||||
if (tile_cam(x, y + 1) == 0)
|
||||
dline(ox, oy + 7, ox + 7, oy + 7, C_BLACK);
|
||||
if (tile_cam(x - 1, y) == 0)
|
||||
dline(ox, oy, ox, oy + 7, C_BLACK);
|
||||
if (tile_cam(x + 1, y) == 0)
|
||||
dline(ox + 7, oy, ox + 7, oy + 7, C_BLACK);
|
||||
|
||||
/* top left, top right, bottom left, bottom right */
|
||||
if (tile_cam(x - 1, y - 1) == 0)
|
||||
dpixel(ox, oy, C_BLACK);
|
||||
if (tile_cam(x + 1, y - 1) == 0)
|
||||
dpixel(ox + 7, oy, C_BLACK);
|
||||
if (tile_cam(x - 1, y + 1) == 0)
|
||||
dpixel(ox, oy + 7, C_BLACK);
|
||||
if (tile_cam(x + 1, y + 1) == 0)
|
||||
dpixel(ox + 7, oy + 7, C_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the enemies. */
|
||||
|
||||
{
|
||||
struct enemy *ep;
|
||||
extern bopti_image_t img_enemy;
|
||||
|
||||
for (ep = state.first_enemy; ep; ep = ep->pdr)
|
||||
dimage(ep->x, ep->y, &img_enemy);
|
||||
}
|
||||
|
||||
/* Draw the cursor */
|
||||
|
||||
{
|
||||
int d = state.drf & 128 ? 2 : 0;
|
||||
int ox = state.cur_x - state.cam_x + 1;
|
||||
int oy = state.cur_y - state.cam_y + 1;
|
||||
|
||||
dline(ox + d, oy, ox + d + 1, oy, C_BLACK);
|
||||
dline(ox + d + 4, oy, ox + d + 5, oy, C_BLACK);
|
||||
dline(ox, oy + d, ox, oy + d + 1, C_BLACK);
|
||||
dline(ox, oy + d + 4, ox, oy + d + 5, C_BLACK);
|
||||
|
||||
dline(ox + d, oy + 7, ox + d + 1, oy + 7, C_BLACK);
|
||||
dline(ox + d + 4, oy + 7, ox + d + 5, oy + 7, C_BLACK);
|
||||
dline(ox + 7, oy + d, ox + 7, oy + d + 1, C_BLACK);
|
||||
dline(ox + 7, oy + d + 4, ox + 7, oy + d + 5, C_BLACK);
|
||||
}
|
||||
|
||||
/* okay we can update now */
|
||||
|
||||
dprint(16, 96, C_BLACK, "state.tnsp = 0x%08X", state.tnsp);
|
||||
dupdate();
|
||||
}
|
||||
|
||||
/* Main game function. */
|
||||
|
||||
menu_t *game(menu_t *last_menu)
|
||||
{
|
||||
int timeout = 1 /* a non-zero value just in case */;
|
||||
extern uint8_t map_basic[];
|
||||
|
||||
(void)last_menu;
|
||||
|
||||
dclear(C_WHITE);
|
||||
dtext(1, 1, C_BLACK, "Sample fxSDK add-in.");
|
||||
dupdate();
|
||||
getkey();
|
||||
init(map_basic);
|
||||
while (1) {
|
||||
int should_draw = 0;
|
||||
key_event_t event = getkey_opt(GETKEY_MOD_SHIFT | GETKEY_BACKLIGHT,
|
||||
&timeout);
|
||||
|
||||
/* TODO: find a way to creatively deduce the time it takes to
|
||||
* go from here to the `if (should_draw)`, in order to keep
|
||||
* an as-constant-as-possible draw time */
|
||||
|
||||
switch (event.type) {
|
||||
case KEYEV_NONE:
|
||||
/* timeout event */
|
||||
should_draw = 1;
|
||||
break;
|
||||
case KEYEV_DOWN:
|
||||
if (event.key == KEY_EXE)
|
||||
return no_menu;
|
||||
}
|
||||
|
||||
if (timeout < 0 || should_draw) {
|
||||
timeout = 65;
|
||||
state.drf = (state.drf + 1) & 255;
|
||||
|
||||
/* Here, we should draw. */
|
||||
tick(); /* TODO: perhaps a better placement somewhere */
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
return no_menu;
|
||||
}
|
||||
|
|
Reference in New Issue