Many, many, untested opcodes added.

This commit is contained in:
Scott Duensing 2024-01-30 21:12:23 -06:00
parent af33bd6865
commit 389592fc12
25 changed files with 676 additions and 65 deletions

View file

@ -41,7 +41,7 @@
#define MSG_INT_V12_SHIFT "Add V1/V2 shifting."
#define MSG_INT_V12_SHIFT_LOCK "Add V1/V2 shift locking."
#define MSG_MEM_BUFFER "Unable to allocate memory buffer."
#define MSG_OP_VAR_MISSING_PROPERTY "Missing object property."
#define MSG_OP_OBJ_MISSING_PROPERTY "Missing object property."
#define MSG_OP_VAR_TOO_MANY_LOCALS "Too many local variables!"
#define MSG_OP_VAR_STACK_OVERFLOW "Stack overflow!"
#else // DEBUGGING

View file

@ -29,7 +29,11 @@
uint32_t objectPointerGet(uint16_t objectId);
uint32_t objectPointerParentGet(uint32_t objectPointer);
uint16_t objectPropertyDefaultGet(uint32_t propertyId);
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size);
uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship);
void objectUnparent(uint16_t objectId);
#endif // OBJECT_H

View file

@ -30,6 +30,9 @@
void opcodes_call(void);
void opcodes_ret(void);
void opcodes_rfalse(void);
void opcodes_rtrue(void);
void opcodes_ret_popped(void);
#endif // OC_CALL_H

View file

@ -28,9 +28,15 @@
#include "common.h"
void opcodes_dec_chk(void);
void opcodes_inc_chk(void);
void opcodes_je(void);
void opcodes_jg(void);
void opcodes_jin(void);
void opcodes_jl(void);
void opcodes_jump(void);
void opcodes_jz(void);
void opcodes_test(void);
#endif // OC_COMPARE_H

View file

@ -28,4 +28,7 @@
#include "common.h"
void opcodes_read(void);
#endif // OC_INPUT_H

View file

@ -29,6 +29,13 @@
void opcodes_add(void);
void opcodes_and(void);
void opcodes_dec(void);
void opcodes_div(void);
void opcodes_inc(void);
void opcodes_mod(void);
void opcodes_mul(void);
void opcodes_or(void);
void opcodes_sub(void);

View file

@ -28,8 +28,11 @@
#include "common.h"
void opcodes_load(void);
void opcodes_loadb(void);
void opcodes_loadw(void);
void opcodes_store(void);
void opcodes_storeb(void);
void opcodes_storew(void);

View file

@ -28,4 +28,9 @@
#include "common.h"
void opcodes_nop(void);
void opcodes_quit(void);
void opcodes_random(void);
#endif // OC_MISC_H

View file

@ -28,7 +28,18 @@
#include "common.h"
void opcodes_clear_attr(void);
void opcodes_get_child(void);
void opcodes_get_next_prop(void);
void opcodes_get_parent(void);
void opcodes_get_prop(void);
void opcodes_get_prop_addr(void);
void opcodes_get_prop_len(void);
void opcodes_get_sibling(void);
void opcodes_insert_obj(void);
void opcodes_put_prop(void);
void opcodes_remove_obj(void);
void opcodes_set_attr(void);
void opcodes_test_attr(void);

View file

@ -30,6 +30,12 @@
void opcodes_new_line(void);
void opcodes_print(void);
void opcodes_print_addr(void);
void opcodes_print_char(void);
void opcodes_print_num(void);
void opcodes_print_obj(void);
void opcodes_print_paddr(void);
void opcodes_print_ret(void);
#endif // OC_OUTPUT_H

View file

@ -28,4 +28,9 @@
#include "common.h"
void opcodes_save(void);
void opcodes_restart(void);
void opcodes_restore(void);
#endif // OC_SAVE_H

View file

@ -28,13 +28,19 @@
#include "common.h"
uint8_t portByteGet(uint16_t address);
void portByteSet(uint16_t address, uint8_t value);
void portDie(char *fmt, ...);
void portPrintChars(char *chars, uint16_t len);
void portStoryLoad(void);
uint16_t portWordGet(uint16_t address);
void portWordSet(uint16_t address, uint16_t value);
uint8_t portByteGet(uint16_t address);
void portByteSet(uint16_t address, uint8_t value);
void portCharsPrint(char *chars, uint16_t len);
void portDie(char *fmt, ...);
void portFileClose(uint32_t *handle);
byte portFileByteRead(uint32_t *handle);
bool portFileByteWrite(uint32_t *handle, byte value);
bool portFileReadOpen(uint32_t *handle, char *name);
bool portFileWriteOpen(uint32_t *handle, char *name);
uint16_t portRandomGet(int16_t range);
void portStoryLoad(void);
uint16_t portWordGet(uint16_t address);
void portWordSet(uint16_t address, uint16_t value);
#endif // PORTME_H

View file

@ -42,6 +42,35 @@ uint32_t objectPointerGet(uint16_t objectId) {
}
uint32_t objectPointerParentGet(uint32_t objectPointer) {
uint32_t result = 0;
uint32_t parent;
if (storyVersion() <= 3) {
parent = ZPEEK(objectPointer + 4);
result = parent ? objectPointerGet(parent) : 0;
} else {
portDie(MSG_UNIMPLEMENTED);
}
return result;
}
uint16_t objectPropertyDefaultGet(uint32_t propertyId) {
uint32_t values;
if (((storyVersion() <= 3) && (propertyId > 31)) || ((storyVersion() >= 4) && (propertyId > 63))) {
//***TODO*** Should we die here? This seems to work.
return 0;
}
values = storyObjectTableAddress() + ((propertyId - 1) * 2);
return ZPEEKW(values);
}
uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size) {
uint32_t ptr = objectPointerGet(objectId);
uint16_t addr;
@ -78,3 +107,35 @@ uint8_t objectPropertyGet(uint16_t objectId, uint32_t propertyId, uint8_t *size)
}
uint16_t objectRelationGet(uint16_t objectId, uint8_t relationship) {
uint32_t objPtr = objectPointerGet(objectId);
uint16_t result = 0;
if (storyVersion() <= 3) {
result = ZPEEKW(objPtr + relationship);
} else {
portDie(MSG_UNIMPLEMENTED);
}
return result;
}
void objectUnparent(uint16_t objectId) {
uint32_t objPtr = objectPointerGet(objectId);
uint32_t parentPtr = objectPointerParentGet(objPtr);
uint32_t ptr;
if (parentPtr != 0) {
if (storyVersion() <= 3) {
ptr = parentPtr + 6; // 4 to skip attrs, 2 to skip to child.
while (ZPEEK(ptr) != objectId) { // If not direct child, look through sibling list..
ptr = objectPointerGet(ZPEEK(ptr)) + 5;
}
ZPOKE(ptr, ZPEEK(objPtr + 5)); // obj sibling takes obj's place.
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
}

View file

@ -93,3 +93,18 @@ void opcodes_call(void) {
void opcodes_ret(void) {
interpreterDoReturn(__state.operands[0]);
}
void opcodes_rfalse(void) {
interpreterDoReturn(0);
}
void opcodes_rtrue(void) {
interpreterDoReturn(1);
}
void opcodes_ret_popped(void) {
// Top of stack.
interpreterDoReturn(variableLoad(0));
}

View file

@ -24,6 +24,12 @@
#include "oc_compare.h"
#include "state.h"
#include "interpreter.h"
#include "variable.h"
#include "object.h"
#include "story.h"
#include "portme.h"
#include "messages.h"
#include "memory.h"
void opcodes_je(void) {
@ -41,6 +47,48 @@ void opcodes_je(void) {
}
void opcodes_dec_chk(void) {
int16_t val = variableLoad(__state.operands[0]);
val--;
variableStore(__state.operands[0], val);
interpreterDoBranch(((int16_t)val < (int16_t)__state.operands[1]) ? 1 : 0);
}
void opcodes_inc_chk(void) {
int16_t val = variableLoad(__state.operands[0]);
val++;
variableStore(__state.operands[0], val);
interpreterDoBranch(((int16_t)val > (int16_t)__state.operands[1]) ? 1 : 0);
}
void opcodes_jg(void) {
interpreterDoBranch(((int16_t)__state.operands[0] > (int16_t)__state.operands[1]) ? 1 : 0);
}
void opcodes_jin(void) {
uint16_t objId = __state.operands[0];
uint16_t parentId = __state.operands[1];
uint32_t objPtr = objectPointerGet(objId);
// Zork 1 will trigger this on "go X" where "x" isn't a direction.
if (objPtr == 0) return;
if (storyVersion() <= 3) {
interpreterDoBranch((ZPEEKW(objPtr + 4) == parentId) ? 1 : 0);
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
void opcodes_jl(void) {
interpreterDoBranch(((int16_t)__state.operands[0] < (int16_t)__state.operands[1]) ? 1 : 0);
}
void opcodes_jump(void) {
__state.pc = __state.pc + ((int16_t)__state.operands[0]) - 2;
}
@ -51,3 +99,7 @@ void opcodes_jz(void) {
}
void opcodes_test(void) {
interpreterDoBranch(((__state.operands[0] & __state.operands[1]) == __state.operands[0]) ? 1 : 0);
}

View file

@ -22,3 +22,11 @@
#include "oc_input.h"
#include "portme.h"
#include "messages.h"
void opcodes_read(void) {
//***TODO***
portDie(MSG_UNIMPLEMENTED);
}

View file

@ -28,11 +28,45 @@
void opcodes_add(void) {
variableStore(ZPEEK(__state.pc++), __state.operands[0] + __state.operands[1]);
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] + (int16_t)__state.operands[1]);
}
void opcodes_and(void) {
variableStore(ZPEEK(__state.pc++), __state.operands[0] & __state.operands[1]);
}
void opcodes_dec(void) {
variableStore(__state.operands[0], variableLoad(__state.operands[0]) - 1);
}
void opcodes_div(void) {
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] / (int16_t)__state.operands[1]);
}
void opcodes_inc(void) {
variableStore(__state.operands[0], variableLoad(__state.operands[0]) + 1);
}
void opcodes_mod(void) {
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] % (int16_t)__state.operands[1]);
}
void opcodes_mul(void) {
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] * (int16_t)__state.operands[1]);
}
void opcodes_or(void) {
variableStore(ZPEEK(__state.pc++), __state.operands[0] | __state.operands[1]);
}
void opcodes_sub(void) {
variableStore(ZPEEK(__state.pc++), __state.operands[0] - __state.operands[1]);
variableStore(ZPEEK(__state.pc++), (int16_t)__state.operands[0] - (int16_t)__state.operands[1]);
}

View file

@ -27,6 +27,17 @@
#include "memory.h"
void opcodes_load(void) {
variableStore(ZPEEK(__state.pc++), ZPEEK((__state.operands[0] & 0xFF)));
}
void opcodes_loadb(void) {
uint16_t offset = __state.operands[0] + __state.operands[1];
variableStore(ZPEEK(__state.pc++), ZPEEK(offset));
}
void opcodes_loadw(void) {
uint16_t offset = __state.operands[0] + (__state.operands[1] * 2);
variableStore(ZPEEK(__state.pc++), ZPEEKW(offset));
@ -38,6 +49,11 @@ void opcodes_store(void) {
}
void opcodes_storeb(void) {
ZPOKE(__state.operands[0] + __state.operands[1], __state.operands[2]);
}
void opcodes_storew(void) {
ZPOKEW(__state.operands[0] + (__state.operands[1] * 2), __state.operands[2]);
}

View file

@ -22,3 +22,21 @@
#include "oc_misc.h"
#include "state.h"
#include "variable.h"
#include "portme.h"
void opcodes_nop(void) {
// Well this one is easy.
}
void opcodes_quit(void) {
__state.quit = true;
}
void opcodes_random(void) {
variableStore((__state.pc++), portRandomGet((int16_t)__state.operands[0]));
}

View file

@ -29,13 +29,133 @@
#include "portme.h"
#include "messages.h"
#include "object.h"
#include "variable.h"
void opcodes_clear_attr(void) {
uint32_t ptr = objectPointerGet(__state.operands[0]);
uint16_t attrId = __state.operands[1];
// Zork 1 will trigger this on "go X" where "x" isn't a direction, so ignore it.
if (ptr == 0) return;
if (storyVersion() <= 3) {
ptr += (attrId / 8);
ZPOKE(ptr, ZPEEK(ptr) & ~(0x80 >> (attrId & 7)));
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
void opcodes_get_child(void) {
uint16_t result = objectRelationGet(__state.operands[0], 6);
variableStore(ZPEEK(__state.pc++), result);
interpreterDoBranch(result != 0 ? 1 : 0);
}
void opcodes_get_next_prop(void) {
uint16_t objId = __state.operands[0];
bool firstProp = (__state.operands[1] == 0);
uint16_t result = 0;
uint8_t size = 0;
uint32_t ptr = objectPropertyGet(objId, firstProp ? 0xFFFFFFFF : __state.operands[1], &size);
if (ptr == 0) {
portDie(MSG_OP_OBJ_MISSING_PROPERTY);
}
if (storyVersion() <= 3) {
// 5 bits for the prop id.
result = ZPEEK(ptr + (firstProp ? -1 : (int8_t)size)) & 0x1f;
} else {
portDie(MSG_UNIMPLEMENTED);
}
variableStore(ZPEEK(__state.pc++), result);
}
void opcodes_get_parent(void) {
uint16_t result = objectRelationGet(__state.operands[0], 4);
variableStore(ZPEEK(__state.pc++), result);
interpreterDoBranch(result != 0 ? 1 : 0);
}
void opcodes_get_prop(void) {
uint16_t objId = __state.operands[0];
uint16_t propId = __state.operands[1];
uint16_t result = 0;
uint8_t size = 0;
uint32_t ptr = objectPropertyGet(objId, propId, &size);
if (ptr == 0) {
result = objectPropertyDefaultGet(propId);
} else {
result = ZPEEK(ptr);
}
variableStore(ZPEEK(__state.pc++), result);
}
void opcodes_get_prop_addr(void) {
uint16_t objId = __state.operands[0];
uint16_t propId = __state.operands[1];
variableStore(ZPEEK(__state.pc++), objectPropertyGet(objId, propId, NULL));
}
void opcodes_get_prop_len(void) {
uint16_t result = 0;
uint8_t info;
// This must return 0 if OP0 is zero, to avoid a bug in older Infocom games.
if (__state.operands[0] != 0) {
if (storyVersion() <= 3) {
info = ZPEEK(__state.operands[0] - 1);
result = ((info >> 5) & 0x7) + 1; // 3 bits for property size.
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
variableStore(ZPEEK(__state.pc++), result);
}
void opcodes_get_sibling(void) {
uint16_t result = objectRelationGet(__state.operands[0], 5);
variableStore(ZPEEK(__state.pc++), result);
interpreterDoBranch(result != 0 ? 1 : 0);
}
void opcodes_insert_obj(void) {
uint32_t objPtr = objectPointerGet(__state.operands[0]);
uint32_t dstPtr = objectPointerGet(__state.operands[1]);
if (storyVersion() <= 3) {
// Take object out of tree.
objectUnparent(__state.operands[0]);
// Reinsert in right spot.
ZPOKE(objPtr + 4, __state.operands[1]);
ZPOKE(objPtr + 5, ZPEEK(dstPtr + 6));
ZPOKE(dstPtr + 6, __state.operands[0]);
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
void opcodes_put_prop(void) {
uint8_t size = 0;
uint8_t ptr = objectPropertyGet(__state.operands[0], __state.operands[1], &size);
if (ptr == 0) portDie(MSG_OP_VAR_MISSING_PROPERTY);
if (ptr == 0) portDie(MSG_OP_OBJ_MISSING_PROPERTY);
if (size == 1) {
ZPOKE(ptr, (__state.operands[2] & 0xff));
@ -45,6 +165,35 @@ void opcodes_put_prop(void) {
}
void opcodes_remove_obj(void) {
uint16_t objId = __state.operands[0];
uint32_t objPtr = objectPointerGet(objId);
if (storyVersion() <= 3) {
// Remove object from tree.
objectUnparent(objId);
// Clear out object's relationships.
ZPOKE(objPtr + 4, 0); // Parent.
ZPOKE(objPtr + 5, 0); // Sibling.
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
void opcodes_set_attr(void) {
uint32_t ptr = objectPointerGet(__state.operands[0]);
uint16_t attrId = __state.operands[1];
if (storyVersion() <= 3) {
ptr += (attrId / 8);
ZPOKE(ptr, ZPEEK(ptr) | 0x80 >> (attrId & 7));
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
void opcodes_test_attr(void) {
uint32_t ptr = objectPointerGet(__state.operands[0]);
uint16_t attrId = __state.operands[1];

View file

@ -25,13 +25,81 @@
#include "state.h"
#include "portme.h"
#include "zscii.h"
#include "memory.h"
#include "story.h"
#include "object.h"
#include "messages.h"
#include "interpreter.h"
void opcodes_new_line(void) {
portPrintChars("\n", 1);
portCharsPrint("\n", 1);
}
void opcodes_print(void) {
__state.pc += zsciiPrint(__state.pc, 0);
}
void opcodes_print_addr(void) {
zsciiPrint(__state.operands[0], 0);
}
void opcodes_print_char(void) {
static char c[2] = { 0, 0 };
c[0] = zsciiDecodeChar(__state.operands[0]);
if (c[0]) portCharsPrint(c, 1);
}
static void opcodes_print_num_helper(int16_t val) {
static char c[2] = { 0, 0 };
if (val < 0) {
portCharsPrint("-", 1);
val = -val;
}
if (val > 9) {
opcodes_print_num_helper(val / 10);
}
c[0] = '0' + (val % 10);
portCharsPrint(c, 1);
}
void opcodes_print_num(void) {
opcodes_print_num_helper(__state.operands[0]);
}
void opcodes_print_obj(void) {
uint32_t ptr = objectPointerGet(__state.operands[0]);
uint32_t addr;
if (storyVersion() <= 3) {
// Skip to properties field.
ptr += 7;
// Dereference to get to property table.
addr = ZPEEKW(ptr);
zsciiPrint(addr + 1, 0);
} else {
portDie(MSG_UNIMPLEMENTED);
}
}
void opcodes_print_paddr(void) {
zsciiPrint(memoryUnpackAddress(__state.operands[0], MEMORY_PRINT), 0);
}
void opcodes_print_ret(void) {
__state.pc += zsciiPrint(__state.pc, 0);
portCharsPrint("\n", 1);
interpreterDoReturn(1);
}

View file

@ -22,3 +22,101 @@
#include "oc_save.h"
#include "interpreter.h"
#include "state.h"
#include "portme.h"
#include "story.h"
#include "memory.h"
void opcodes_save(void) {
uint32_t f;
bool ok;
uint16_t i;
uint8_t *b;
ok = portFileWriteOpen(&f, "save.dat");
// Write out PC.
b = (uint8_t *)&__state.pc;
ok &= portFileByteWrite(&f, b[0]);
ok &= portFileByteWrite(&f, b[1]);
ok &= portFileByteWrite(&f, b[2]);
ok &= portFileByteWrite(&f, b[3]);
// Write out SP.
b = (uint8_t *)&__state.sp;
ok &= portFileByteWrite(&f, b[0]);
ok &= portFileByteWrite(&f, b[1]);
// Write out BP.
b = (uint8_t *)&__state.sp;
ok &= portFileByteWrite(&f, b[0]);
ok &= portFileByteWrite(&f, b[1]);
// Write out dynamic memory.
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
ok &= portFileByteWrite(&f, ZPEEK(i));
}
// Write out stack.
for (i=0; i<__state.sp; i++) {
b = (uint8_t *)&__state.stack[i];
ok &= portFileByteWrite(&f, b[0]);
ok &= portFileByteWrite(&f, b[1]);
}
portFileClose(&f);
interpreterDoBranch(ok ? 1 : 0);
}
void opcodes_restart(void) {
stateReset();
portStoryLoad();
storySetup();
}
void opcodes_restore(void) {
uint32_t f;
bool ok;
uint16_t i;
uint8_t *b;
ok = portFileReadOpen(&f, "save.dat");
// Read PC.
b = (uint8_t *)&__state.pc;
b[0] = portFileByteRead(&f);
b[1] = portFileByteRead(&f);
b[2] = portFileByteRead(&f);
b[3] = portFileByteRead(&f);
// Read SP.
b = (uint8_t *)&__state.sp;
b[0] = portFileByteRead(&f);
b[1] = portFileByteRead(&f);
// Read BP.
b = (uint8_t *)&__state.bp;
b[0] = portFileByteRead(&f);
b[1] = portFileByteRead(&f);
// Read dynamic memory.
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
ZPOKE(i, portFileByteRead(&f));
}
// Read stack.
for (i=0; i<__state.sp; i++) {
b = (uint8_t *)&__state.stack[i];
b[0] = portFileByteRead(&f);
b[1] = portFileByteRead(&f);
}
portFileClose(&f);
interpreterDoBranch(ok ? 1 : 0);
}

View file

@ -54,78 +54,78 @@
void opcodesBuiltInitialTable(void) {
// 2-operand instructions...
OP(1, je);
mOP(2, jl);
mOP(3, jg);
mOP(4, dec_chk);
mOP(5, inc_chk);
mOP(6, jin);
mOP(7, test);
mOP(8, or);
mOP(9, and);
OP(2, jl);
OP(3, jg);
OP(4, dec_chk);
OP(5, inc_chk);
OP(6, jin);
OP(7, test);
OP(8, or);
OP(9, and);
OP(10, test_attr);
mOP(11, set_attr);
mOP(12, clear_attr);
OP(11, set_attr);
OP(12, clear_attr);
OP(13, store);
mOP(14, insert_obj);
OP(14, insert_obj);
OP(15, loadw);
mOP(16, loadb);
mOP(17, get_prop);
mOP(18, get_prop_addr);
mOP(19, get_next_prop);
OP(16, loadb);
OP(17, get_prop);
OP(18, get_prop_addr);
OP(19, get_next_prop);
OP(20, add);
OP(21, sub);
mOP(22, mul);
mOP(23, div);
mOP(24, mod);
OP(22, mul);
OP(23, div);
OP(24, mod);
// 1-operand instructions...
OP(128, jz);
mOP(129, get_sibling);
mOP(130, get_child);
mOP(131, get_parent);
mOP(132, get_prop_len);
mOP(133, inc);
mOP(134, dec);
mOP(135, print_addr);
OP(129, get_sibling);
OP(130, get_child);
OP(131, get_parent);
OP(132, get_prop_len);
OP(133, inc);
OP(134, dec);
OP(135, print_addr);
mOP(137, remove_obj);
mOP(138, print_obj);
OP(137, remove_obj);
OP(138, print_obj);
OP(139, ret);
OP(140, jump);
mOP(141, print_paddr);
mOP(142, load);
OP(141, print_paddr);
OP(142, load);
mOP(143, not);
// 0-operand instructions...
mOP(176, rtrue);
mOP(177, rfalse);
OP(176, rtrue);
OP(177, rfalse);
OP(178, print);
mOP(179, print_ret);
mOP(180, nop);
mOP(181, save);
mOP(182, restore);
mOP(183, restart);
mOP(184, ret_popped);
OP(179, print_ret);
OP(180, nop);
OP(181, save);
OP(182, restore);
OP(183, restart);
OP(184, ret_popped);
mOP(185, pop);
mOP(186, quit);
OP(186, quit);
OP(187, new_line);
// variable operand instructions...
OP(224, call);
OP(225, storew);
mOP(226, storeb);
OP(226, storeb);
OP(227, put_prop);
mOP(228, read);
mOP(229, print_char);
mOP(230, print_num);
mOP(231, random);
mOP(232, push);
mOP(233, pull);
OP(228, read);
OP(229, print_char);
OP(230, print_num);
OP(231, random);
OP(232, push);
OP(233, pull);
if (storyVersion() < 3) return;
mOP(188, show_status);
mOP(189, verify);
OP(189, verify);
mOP(234, split_window);
mOP(235, set_window);

View file

@ -46,6 +46,14 @@ void portByteSet(uint16_t address, uint8_t value) {
}
void portCharsPrint(char *chars, uint16_t len) {
uint16_t x;
for (x=0; x<len; x++) {
printf("%c", chars[x]);
}
}
void portDie(char *fmt, ...) {
va_list ap;
@ -59,11 +67,36 @@ void portDie(char *fmt, ...) {
}
void portPrintChars(char *chars, uint16_t len) {
uint16_t x;
for (x=0; x<len; x++) {
printf("%c", chars[x]);
}
void portFileClose(uint32_t *handle) {
}
byte portFileByteRead(uint32_t *handle) {
return 0;
}
bool portFileByteWrite(uint32_t *handle, byte value) {
return false;
}
bool portFileReadOpen(uint32_t *handle, char *name) {
return false;
}
bool portFileWriteOpen(uint32_t *handle, char *name) {
return false;
}
uint16_t portRandomGet(int16_t range) {
// If range is zero, randomize with "best" random seed.
// If range is negative, use the positive value to seed.
return 42;
}

View file

@ -193,7 +193,7 @@ uint32_t zsciiPrint(uint32_t pc, bool abbr) {
ret = zsciiDecode(pc, abbr, __memoryBuffer, &decodedChars);
}
portPrintChars(__memoryBuffer, decodedChars);
portCharsPrint(__memoryBuffer, decodedChars);
return ret;
}