Updates to match changes to JoeyLib. Some AGI fixes as well.
This commit is contained in:
parent
45a82bef2f
commit
f9ef3e99c2
12 changed files with 111 additions and 84 deletions
|
|
@ -4,12 +4,12 @@ An interpreter for Sierra's Adventure Game Interpreter (AGI) v2 games --
|
|||
King's Quest III and its contemporaries -- written from the public AGI
|
||||
format descriptions on [JoeyLib](../joeylib), so it runs on every machine
|
||||
JoeyLib targets: the Apple IIgs, Commodore Amiga, Atari ST, MS-DOS, Sharp
|
||||
X68000 and DVX. It decodes the games' own resource files (LOGIC, PICTURE,
|
||||
X68000, and DVX. It decodes the games' own resource files (LOGIC, PICTURE,
|
||||
VIEW, SOUND, OBJECT, WORDS.TOK); it ships no game.
|
||||
|
||||
## Setting up
|
||||
|
||||
JoeyAGI builds with JoeyLib, which owns the cross compilers, the library
|
||||
JoeyAGI builds with JoeyLib, which owns the cross compilers, the library,
|
||||
and every machine's build rules. Check JoeyLib out beside this repository
|
||||
and install its toolchains (its README covers the installer):
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ $ scripts/verify.sh host # or name the ones to run
|
|||
| Gate | What it proves |
|
||||
|------|----------------|
|
||||
| `host` | The whole interpreter, built for the build machine on JoeyLib's headless port, plays scripted sessions and every frame asked for must hash as expected: every resource of every game in `games/` loads and decodes (KQ3's pictures hash as Sierra's interpreter draws them); twenty probe games built from scratch by `tests/probes.py` (pictures, windows, motion, control lines, priority, the parser, menus, inventory, sound timing, ...); and, with `games/kq3`, four KQ3 sessions (the opening, play, save/restore/restart, debug teleports) (`scripts/test-agi.sh`) |
|
||||
| `disk` | `AGI.2mg` with King's Quest III boots on a IIgs, launches the interpreter and draws |
|
||||
| `disk` | `AGI.2mg` with King's Quest III boots on a IIgs, launches the interpreter, and draws |
|
||||
|
||||
`scripts/verify.sh` exits 0 when every gate passed, 1 when one failed, and 3
|
||||
when none failed but one was skipped (no game in `games/`, or the IIgs
|
||||
|
|
|
|||
3
agi.c
3
agi.c
|
|
@ -92,9 +92,6 @@ static void changeRoom(void) {
|
|||
gAgi->vars[VAR_BAD_WORD] = 0u;
|
||||
ego = &gAgi->objects[AGI_EGO];
|
||||
gAgi->vars[VAR_EGO_VIEW] = ego->viewId;
|
||||
ego->direction = AGI_DIR_NONE;
|
||||
ego->motion = AGI_MOTION_NORMAL;
|
||||
gAgi->vars[VAR_EGO_DIR] = AGI_DIR_NONE;
|
||||
switch (gAgi->vars[VAR_EGO_EDGE]) {
|
||||
case AGI_EDGE_TOP:
|
||||
ego->y = AGI_MAX_Y;
|
||||
|
|
|
|||
3
agi.h
3
agi.h
|
|
@ -495,10 +495,11 @@ void gfxPresentDirty(void);
|
|||
void gfxRedrawAll(void);
|
||||
void gfxRedrawUpdating(void);
|
||||
void gfxRestorePicture(void);
|
||||
void gfxShakeScreen(uint8_t times);
|
||||
void gfxShowObjectCel(uint8_t viewId);
|
||||
void gfxShowPic(void);
|
||||
void gfxShakeScreen(uint8_t times);
|
||||
void gfxShowPriority(void);
|
||||
void gfxStampObject(uint8_t n);
|
||||
|
||||
|
||||
// ----- agiObj.c -----
|
||||
|
|
|
|||
39
agiGfx.c
39
agiGfx.c
|
|
@ -49,7 +49,7 @@
|
|||
#define SHAKE_BEATS_PER_UNIT 4u
|
||||
#define MS_PER_SECOND 1000u
|
||||
// A chunky surface's byte holds two pixels.
|
||||
#define CHUNKY_PX_PER_BYTE (SURFACE_WIDTH / SURFACE_BYTES_PER_ROW)
|
||||
#define CHUNKY_PX_PER_BYTE (JL_SURFACE_WIDTH / JL_SURFACE_BYTES_PER_ROW)
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -150,14 +150,14 @@ static void buildShifted(jlSurfaceT *shifted, const jlSurfaceT *normal) {
|
|||
jlSurfaceCopy(shifted, normal);
|
||||
jlSurfaceClear(shifted, AGI_COLOR_BLACK);
|
||||
if (shifted->pixels != NULL && normal->pixels != NULL) {
|
||||
for (y = SHAKE_DY; y < SURFACE_HEIGHT; y++) {
|
||||
memcpy(&shifted->pixels[y * SURFACE_BYTES_PER_ROW + SHAKE_DX / CHUNKY_PX_PER_BYTE],
|
||||
&normal->pixels[(uint16_t)(y - SHAKE_DY) * SURFACE_BYTES_PER_ROW],
|
||||
SURFACE_BYTES_PER_ROW - SHAKE_DX / CHUNKY_PX_PER_BYTE);
|
||||
for (y = SHAKE_DY; y < JL_SURFACE_HEIGHT; y++) {
|
||||
memcpy(&shifted->pixels[y * JL_SURFACE_BYTES_PER_ROW + SHAKE_DX / CHUNKY_PX_PER_BYTE],
|
||||
&normal->pixels[(uint16_t)(y - SHAKE_DY) * JL_SURFACE_BYTES_PER_ROW],
|
||||
JL_SURFACE_BYTES_PER_ROW - SHAKE_DX / CHUNKY_PX_PER_BYTE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sprite = jlSpriteCreateFromSurface(normal, 0, 0, TILE_BLOCKS_PER_ROW, TILE_BLOCKS_PER_COL);
|
||||
sprite = jlSpriteCreateFromSurface(normal, 0, 0, JL_TILE_BLOCKS_PER_ROW, JL_TILE_BLOCKS_PER_COL);
|
||||
if (sprite != NULL) {
|
||||
jlSpriteDraw(shifted, sprite, SHAKE_DX, SHAKE_DY);
|
||||
jlSpriteDestroy(sprite);
|
||||
|
|
@ -332,7 +332,7 @@ static void pushRect(const GfxRectT *r) {
|
|||
}
|
||||
for (y = y0; y < y1; y++) {
|
||||
const uint8_t *src = &gVis[(uint16_t)y * AGI_WIDTH];
|
||||
uint8_t *dst = &stage->pixels[(uint16_t)(screenY + y) * SURFACE_BYTES_PER_ROW];
|
||||
uint8_t *dst = &stage->pixels[(uint16_t)(screenY + y) * JL_SURFACE_BYTES_PER_ROW];
|
||||
|
||||
for (x = x0; x < x1; x++) {
|
||||
c = src[x];
|
||||
|
|
@ -694,3 +694,28 @@ void gfxShowPriority(void) {
|
|||
(void)inputWaitKey();
|
||||
gfxRestorePicture();
|
||||
}
|
||||
|
||||
|
||||
// draw on an object never animated (measured on Sierra's interpreter): its
|
||||
// cel goes into the picture once, at its baseline's priority, with the
|
||||
// objects off. It is in neither blit list, so nothing erases it and it
|
||||
// never moves; animate.obj leaves the image where it is.
|
||||
void gfxStampObject(uint8_t n) {
|
||||
AgiObjectT *o;
|
||||
const AgiCelT *cel;
|
||||
bool mirror;
|
||||
int16_t top;
|
||||
|
||||
o = &gAgi->objects[n];
|
||||
cel = agiViewCel(o->view, o->loop, o->cel, &mirror);
|
||||
if (cel == NULL || cel->width == 0u || cel->height == 0u) {
|
||||
return;
|
||||
}
|
||||
if ((o->flags & OBJ_FIX_PRIORITY) == 0u) {
|
||||
o->priority = agiPriorityForY(o->y);
|
||||
}
|
||||
gfxEraseAll();
|
||||
top = (int16_t)(o->y - (int16_t)cel->height + 1);
|
||||
drawCel(cel, mirror, o->x, top, o->priority, false);
|
||||
markDirty(o->x, top, cel->width, cel->height);
|
||||
}
|
||||
|
|
|
|||
26
agiInput.c
26
agiInput.c
|
|
@ -59,7 +59,7 @@ static const uint8_t kLetterScan[LETTER_COUNT] = {
|
|||
};
|
||||
|
||||
static const jlKeyE kFunctionKeys[FKEY_COUNT] = {
|
||||
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10
|
||||
JL_KEY_F1, JL_KEY_F2, JL_KEY_F3, JL_KEY_F4, JL_KEY_F5, JL_KEY_F6, JL_KEY_F7, JL_KEY_F8, JL_KEY_F9, JL_KEY_F10
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ static void handleKey(uint16_t key) {
|
|||
|
||||
// The joystick, read as one of the eight directions.
|
||||
static uint8_t joystickDirection(void) {
|
||||
return objDirectionTo(0, 0, jlJoystickX(JOYSTICK_0), jlJoystickY(JOYSTICK_0), JOY_DEADZONE);
|
||||
return objDirectionTo(0, 0, jlJoystickX(JL_JOYSTICK_0), jlJoystickY(JL_JOYSTICK_0), JOY_DEADZONE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -372,8 +372,8 @@ void inputPoll(void) {
|
|||
uint8_t dir;
|
||||
|
||||
jlInputPoll();
|
||||
alt = jlKeyDown(KEY_LALT);
|
||||
ctrl = jlKeyDown(KEY_LCTRL);
|
||||
alt = jlKeyDown(JL_KEY_LALT);
|
||||
ctrl = jlKeyDown(JL_KEY_LCTRL);
|
||||
// A Ctrl or Alt chord is a command, not typing, whatever the port
|
||||
// delivers as a character.
|
||||
while ((ch = jlInputGetChar()) >= 0) {
|
||||
|
|
@ -381,8 +381,8 @@ void inputPoll(void) {
|
|||
enqueue((uint16_t)ch);
|
||||
}
|
||||
}
|
||||
for (i = 0u; i < (uint8_t)(KEY_Z - KEY_A + 1); i++) {
|
||||
if (jlKeyPressed((jlKeyE)(KEY_A + i))) {
|
||||
for (i = 0u; i < (uint8_t)(JL_KEY_Z - JL_KEY_A + 1); i++) {
|
||||
if (jlKeyPressed((jlKeyE)(JL_KEY_A + i))) {
|
||||
if (alt) {
|
||||
enqueue((uint16_t)((uint16_t)kLetterScan[i] << SCAN_SHIFT));
|
||||
} else if (ctrl) {
|
||||
|
|
@ -395,23 +395,23 @@ void inputPoll(void) {
|
|||
enqueue((uint16_t)((uint16_t)(FKEY_SCAN_FIRST + i) << SCAN_SHIFT));
|
||||
}
|
||||
}
|
||||
if (jlKeyPressed(KEY_UP)) {
|
||||
if (jlKeyPressed(JL_KEY_UP)) {
|
||||
enqueue(AGI_KEY_UP);
|
||||
}
|
||||
if (jlKeyPressed(KEY_DOWN)) {
|
||||
if (jlKeyPressed(JL_KEY_DOWN)) {
|
||||
enqueue(AGI_KEY_DOWN);
|
||||
}
|
||||
if (jlKeyPressed(KEY_LEFT)) {
|
||||
if (jlKeyPressed(JL_KEY_LEFT)) {
|
||||
enqueue(AGI_KEY_LEFT);
|
||||
}
|
||||
if (jlKeyPressed(KEY_RIGHT)) {
|
||||
if (jlKeyPressed(JL_KEY_RIGHT)) {
|
||||
enqueue(AGI_KEY_RIGHT);
|
||||
}
|
||||
if (jlJoystickConnected(JOYSTICK_0)) {
|
||||
if (jlJoyPressed(JOYSTICK_0, JOY_BUTTON_0)) {
|
||||
if (jlJoystickConnected(JL_JOYSTICK_0)) {
|
||||
if (jlJoyPressed(JL_JOYSTICK_0, JL_JOY_BUTTON_0)) {
|
||||
enqueue(AGI_KEY_JOY_BUTTON_1);
|
||||
}
|
||||
if (jlJoyPressed(JOYSTICK_0, JOY_BUTTON_1)) {
|
||||
if (jlJoyPressed(JL_JOYSTICK_0, JL_JOY_BUTTON_1)) {
|
||||
enqueue(AGI_KEY_JOY_BUTTON_2);
|
||||
}
|
||||
dir = joystickDirection();
|
||||
|
|
|
|||
4
agiObj.c
4
agiObj.c
|
|
@ -543,7 +543,8 @@ bool objSetView(uint8_t n, uint8_t viewId) {
|
|||
|
||||
// unanimate.all (and new.room): every object off the screen and out of
|
||||
// the interpreter's hands, with the default step and cycle settings. Its
|
||||
// view, loop, cel and position stay (new.room places ego from them).
|
||||
// view, loop, cel, position and direction stay (new.room places ego from
|
||||
// them; measured: ego keeps walking the way it went once animated again).
|
||||
void objUnanimateAll(void) {
|
||||
uint8_t i;
|
||||
AgiObjectT *o;
|
||||
|
|
@ -552,7 +553,6 @@ void objUnanimateAll(void) {
|
|||
for (i = 0u; i < AGI_MAX_OBJECTS; i++) {
|
||||
o = &gAgi->objects[i];
|
||||
o->flags = OBJ_SKIP_STEP;
|
||||
o->direction = AGI_DIR_NONE;
|
||||
o->motion = AGI_MOTION_NORMAL;
|
||||
o->cycleMode = AGI_CYCLE_NORMAL;
|
||||
o->stepSize = STEP_DEFAULT;
|
||||
|
|
|
|||
|
|
@ -142,8 +142,8 @@ static void silence(void) {
|
|||
|
||||
// ----- Public API (alphabetical) -----
|
||||
|
||||
// jlInit has started audio.
|
||||
void soundInit(void) {
|
||||
(void)jlAudioInit();
|
||||
silence();
|
||||
}
|
||||
|
||||
|
|
@ -218,9 +218,9 @@ void soundPump(void) {
|
|||
}
|
||||
|
||||
|
||||
// jlShutdown stops audio.
|
||||
void soundShutdown(void) {
|
||||
release();
|
||||
jlAudioShutdown();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ static void copySpan(jlSurfaceT *dst, const jlSurfaceT *src, int16_t col, int16_
|
|||
x = (int16_t)(col * AGI_SCREEN_PX_PER_AGI);
|
||||
xEnd = (int16_t)(x + run * AGI_SCREEN_PX_PER_AGI);
|
||||
if (dst->pixels != NULL && src->pixels != NULL) {
|
||||
at = (uint16_t)((uint16_t)row * SURFACE_BYTES_PER_ROW + (uint16_t)col);
|
||||
at = (uint16_t)((uint16_t)row * JL_SURFACE_BYTES_PER_ROW + (uint16_t)col);
|
||||
memcpy(&dst->pixels[at], &src->pixels[at], (size_t)run);
|
||||
surfaceMarkDirtyRect(dst, x, row, (int16_t)(xEnd - x), 1);
|
||||
return;
|
||||
|
|
|
|||
4
agiVm.c
4
agiVm.c
|
|
@ -480,10 +480,12 @@ static void cmdObject(VmFrameT *f, uint8_t op, const uint8_t *a) {
|
|||
break;
|
||||
case CMD_DRAW:
|
||||
if (o != NULL && (o->flags & OBJ_DRAWN) == 0u && o->view != NULL) {
|
||||
o->flags = (uint16_t)(o->flags | OBJ_ANIMATED);
|
||||
objFixPosition(a[0]);
|
||||
o->prevX = o->x;
|
||||
o->prevY = o->y;
|
||||
if ((o->flags & OBJ_ANIMATED) == 0u) {
|
||||
gfxStampObject(a[0]);
|
||||
}
|
||||
redrawObjects(a[0], (uint16_t)(OBJ_DRAWN | OBJ_UPDATE), 0u);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
1
tests/expected/probes/edgewalk.txt
Normal file
1
tests/expected/probes/edgewalk.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
a 101c0a8c
|
||||
102
tests/hostPort.c
102
tests/hostPort.c
|
|
@ -183,34 +183,34 @@ static void hostWritePpm(const char *path);
|
|||
// ----- Module state -----
|
||||
|
||||
static const HostKeyNameT kKeyNames[] = {
|
||||
{ "Return", KEY_RETURN, JL_CHAR_RETURN },
|
||||
{ "Escape", KEY_ESCAPE, JL_CHAR_ESCAPE },
|
||||
{ "Tab", KEY_TAB, JL_CHAR_TAB },
|
||||
{ "BackSpace", KEY_BACKSPACE, JL_CHAR_BACKSPACE },
|
||||
{ "space", KEY_SPACE, ' ' },
|
||||
{ "Up", KEY_UP, 0u },
|
||||
{ "Down", KEY_DOWN, 0u },
|
||||
{ "Left", KEY_LEFT, 0u },
|
||||
{ "Right", KEY_RIGHT, 0u },
|
||||
{ "F1", KEY_F1, 0u },
|
||||
{ "F2", KEY_F2, 0u },
|
||||
{ "F3", KEY_F3, 0u },
|
||||
{ "F4", KEY_F4, 0u },
|
||||
{ "F5", KEY_F5, 0u },
|
||||
{ "F6", KEY_F6, 0u },
|
||||
{ "F7", KEY_F7, 0u },
|
||||
{ "F8", KEY_F8, 0u },
|
||||
{ "F9", KEY_F9, 0u },
|
||||
{ "F10", KEY_F10, 0u },
|
||||
{ "ctrl", KEY_LCTRL, 0u },
|
||||
{ "alt", KEY_LALT, 0u },
|
||||
{ "shift", KEY_LSHIFT, 0u },
|
||||
{ "period", KEY_NONE, '.' },
|
||||
{ "comma", KEY_NONE, ',' },
|
||||
{ "apostrophe", KEY_NONE, '\'' },
|
||||
{ "minus", KEY_NONE, '-' },
|
||||
{ "question", KEY_NONE, '?' },
|
||||
{ "exclam", KEY_NONE, '!' }
|
||||
{ "Return", JL_KEY_RETURN, JL_CHAR_RETURN },
|
||||
{ "Escape", JL_KEY_ESCAPE, JL_CHAR_ESCAPE },
|
||||
{ "Tab", JL_KEY_TAB, JL_CHAR_TAB },
|
||||
{ "BackSpace", JL_KEY_BACKSPACE, JL_CHAR_BACKSPACE },
|
||||
{ "space", JL_KEY_SPACE, ' ' },
|
||||
{ "Up", JL_KEY_UP, 0u },
|
||||
{ "Down", JL_KEY_DOWN, 0u },
|
||||
{ "Left", JL_KEY_LEFT, 0u },
|
||||
{ "Right", JL_KEY_RIGHT, 0u },
|
||||
{ "F1", JL_KEY_F1, 0u },
|
||||
{ "F2", JL_KEY_F2, 0u },
|
||||
{ "F3", JL_KEY_F3, 0u },
|
||||
{ "F4", JL_KEY_F4, 0u },
|
||||
{ "F5", JL_KEY_F5, 0u },
|
||||
{ "F6", JL_KEY_F6, 0u },
|
||||
{ "F7", JL_KEY_F7, 0u },
|
||||
{ "F8", JL_KEY_F8, 0u },
|
||||
{ "F9", JL_KEY_F9, 0u },
|
||||
{ "F10", JL_KEY_F10, 0u },
|
||||
{ "ctrl", JL_KEY_LCTRL, 0u },
|
||||
{ "alt", JL_KEY_LALT, 0u },
|
||||
{ "shift", JL_KEY_LSHIFT, 0u },
|
||||
{ "period", JL_KEY_NONE, '.' },
|
||||
{ "comma", JL_KEY_NONE, ',' },
|
||||
{ "apostrophe", JL_KEY_NONE, '\'' },
|
||||
{ "minus", JL_KEY_NONE, '-' },
|
||||
{ "question", JL_KEY_NONE, '?' },
|
||||
{ "exclam", JL_KEY_NONE, '!' }
|
||||
};
|
||||
|
||||
// The comparison operators of a condition, in HostOpE order.
|
||||
|
|
@ -220,9 +220,9 @@ static FILE *gScript;
|
|||
static char gOutDir[HOST_PATH_MAX];
|
||||
static uint32_t gFrame;
|
||||
static uint32_t gResumeFrame;
|
||||
static uint32_t gHoldUntil[KEY_COUNT];
|
||||
static bool gHeld[KEY_COUNT];
|
||||
static uint8_t gDisplay[SURFACE_HEIGHT][SURFACE_WIDTH][3];
|
||||
static uint32_t gHoldUntil[JL_KEY_COUNT];
|
||||
static bool gHeld[JL_KEY_COUNT];
|
||||
static uint8_t gDisplay[JL_SURFACE_HEIGHT][JL_SURFACE_WIDTH][3];
|
||||
// Characters still to type for the current 'type' line, one per press.
|
||||
static char gTypeBuf[HOST_LINE_MAX];
|
||||
static long gLinePos;
|
||||
|
|
@ -282,7 +282,7 @@ static uint16_t gGotoCount;
|
|||
static bool hostClearStep(void) {
|
||||
if (gAgi != NULL && gAgi->windowOpen && gClearTries < HOST_CLEAR_TRIES) {
|
||||
gClearTries++;
|
||||
hostPress(KEY_RETURN, JL_CHAR_RETURN, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
hostPress(JL_KEY_RETURN, JL_CHAR_RETURN, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
gResumeFrame = gFrame + HOST_CLEAR_GAP_FRAMES;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -417,13 +417,13 @@ static void hostGoto(const char *label) {
|
|||
static jlKeyE hostEgoKey(uint8_t dir) {
|
||||
switch (dir) {
|
||||
case AGI_DIR_E:
|
||||
return KEY_RIGHT;
|
||||
return JL_KEY_RIGHT;
|
||||
case AGI_DIR_S:
|
||||
return KEY_DOWN;
|
||||
return JL_KEY_DOWN;
|
||||
case AGI_DIR_W:
|
||||
return KEY_LEFT;
|
||||
return JL_KEY_LEFT;
|
||||
default:
|
||||
return KEY_UP;
|
||||
return JL_KEY_UP;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -470,32 +470,32 @@ static bool hostKeyLookup(const char *name, jlKeyE *outKey, uint8_t *outCh) {
|
|||
}
|
||||
c = name[0];
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
*outKey = (jlKeyE)(KEY_A + (c - 'a'));
|
||||
*outKey = (jlKeyE)(JL_KEY_A + (c - 'a'));
|
||||
*outCh = (uint8_t)c;
|
||||
return true;
|
||||
}
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
*outKey = (jlKeyE)(KEY_A + (c - 'A'));
|
||||
*outKey = (jlKeyE)(JL_KEY_A + (c - 'A'));
|
||||
*outCh = (uint8_t)c;
|
||||
return true;
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
*outKey = (jlKeyE)(KEY_0 + (c - '0'));
|
||||
*outKey = (jlKeyE)(JL_KEY_0 + (c - '0'));
|
||||
*outCh = (uint8_t)c;
|
||||
return true;
|
||||
}
|
||||
*outKey = KEY_NONE;
|
||||
*outKey = JL_KEY_NONE;
|
||||
*outCh = (uint8_t)c;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void hostPress(jlKeyE key, uint8_t ch, uint32_t holdFrames, uint32_t gapFrames) {
|
||||
if (key != KEY_NONE) {
|
||||
if (key != JL_KEY_NONE) {
|
||||
gHoldUntil[key] = gFrame + holdFrames;
|
||||
}
|
||||
// Like the real keyboards, a Ctrl or Alt chord types no character.
|
||||
if (ch != 0u && !gHeld[KEY_LALT] && !gHeld[KEY_LCTRL]) {
|
||||
if (ch != 0u && !gHeld[JL_KEY_LALT] && !gHeld[JL_KEY_LCTRL]) {
|
||||
jlInputCharPush(ch);
|
||||
}
|
||||
gResumeFrame = gFrame + holdFrames + gapFrames;
|
||||
|
|
@ -635,14 +635,14 @@ static void hostStep(void) {
|
|||
one[1] = '\0';
|
||||
gTypePos++;
|
||||
if (one[0] == ' ') {
|
||||
hostPress(KEY_SPACE, ' ', HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
hostPress(JL_KEY_SPACE, ' ', HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
} else if (hostKeyLookup(one, &key, &ch)) {
|
||||
hostPress(key, ch, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (gSay == HOST_SAY_TYPING) {
|
||||
hostPress(KEY_RETURN, JL_CHAR_RETURN, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
hostPress(JL_KEY_RETURN, JL_CHAR_RETURN, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
gSay = HOST_SAY_SETTLE;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -708,7 +708,7 @@ static void hostStep(void) {
|
|||
}
|
||||
hostPress(key, ch, (hold > 0.0) ? (uint32_t)(hold * HOST_FRAME_HZ + 0.5) : HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
} else if (strcmp(op, "down") == 0 || strcmp(op, "up") == 0) {
|
||||
if (!hostKeyLookup(arg, &key, &ch) || key == KEY_NONE) {
|
||||
if (!hostKeyLookup(arg, &key, &ch) || key == JL_KEY_NONE) {
|
||||
fprintf(stderr, "agiHost: unknown key '%s'\n", arg);
|
||||
exit(2);
|
||||
}
|
||||
|
|
@ -895,7 +895,7 @@ static bool hostWaitStep(void) {
|
|||
hostWritePpm(path);
|
||||
}
|
||||
gWindowSeen = false;
|
||||
hostPress(KEY_RETURN, JL_CHAR_RETURN, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
hostPress(JL_KEY_RETURN, JL_CHAR_RETURN, HOST_KEY_HOLD_FRAMES, HOST_KEY_GAP_FRAMES);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1046,7 +1046,7 @@ static void hostWritePpm(const char *path) {
|
|||
fprintf(stderr, "agiHost: cannot write %s\n", path);
|
||||
return;
|
||||
}
|
||||
fprintf(fp, "P6\n%d %d\n%u\n", SURFACE_WIDTH, SURFACE_HEIGHT, HOST_CHANNEL_MAX);
|
||||
fprintf(fp, "P6\n%d %d\n%u\n", JL_SURFACE_WIDTH, JL_SURFACE_HEIGHT, HOST_CHANNEL_MAX);
|
||||
fwrite(gDisplay, 1, sizeof(gDisplay), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
@ -1077,7 +1077,7 @@ void jlpInputInit(void) {
|
|||
void jlpInputPoll(void) {
|
||||
uint16_t k;
|
||||
|
||||
for (k = 0u; k < (uint16_t)KEY_COUNT; k++) {
|
||||
for (k = 0u; k < (uint16_t)JL_KEY_COUNT; k++) {
|
||||
gKeyState[k] = (uint8_t)((gHeld[k] || gFrame < gHoldUntil[k]) ? 1u : 0u);
|
||||
}
|
||||
}
|
||||
|
|
@ -1100,10 +1100,10 @@ void jlpPresent(const jlSurfaceT *src) {
|
|||
uint8_t nib;
|
||||
uint16_t rgb;
|
||||
|
||||
for (y = 0u; y < SURFACE_HEIGHT; y++) {
|
||||
for (y = 0u; y < JL_SURFACE_HEIGHT; y++) {
|
||||
pal = src->palette[src->scb[y]];
|
||||
for (x = 0u; x < SURFACE_WIDTH; x++) {
|
||||
byte = src->pixels[(uint32_t)y * SURFACE_BYTES_PER_ROW + x / HOST_PIXELS_PER_BYTE];
|
||||
for (x = 0u; x < JL_SURFACE_WIDTH; x++) {
|
||||
byte = src->pixels[(uint32_t)y * JL_SURFACE_BYTES_PER_ROW + x / HOST_PIXELS_PER_BYTE];
|
||||
nib = (uint8_t)((x & 1u) ? (byte & 0x0Fu) : (byte >> 4));
|
||||
rgb = pal[nib];
|
||||
gDisplay[y][x][0] = (uint8_t)(((rgb >> 8) & 0x0Fu) * HOST_NIBBLE_SCALE);
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ int main(void) {
|
|||
bool ok;
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.noAudio = true;
|
||||
if (!jlInit(&cfg)) {
|
||||
fprintf(stderr, "jlInit failed\n");
|
||||
return 1;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue