diff --git a/include/portme.h b/include/portme.h index a1db399..308e7d8 100644 --- a/include/portme.h +++ b/include/portme.h @@ -28,6 +28,7 @@ #include "common.h" +void portAttributeSet(byte attribute); uint8_t portByteGet(uint32_t address); void portByteSet(uint32_t address, uint8_t value); char portCharGet(void); diff --git a/include/state.h b/include/state.h index 168e036..7eda2c0 100644 --- a/include/state.h +++ b/include/state.h @@ -40,6 +40,7 @@ typedef struct stateS { uint8_t operandCount; uint16_t operands[8]; char alphabetTable[78]; + uint16_t checksum; char statusBar[256]; byte statusBarLen; byte currentWindow; @@ -48,6 +49,7 @@ typedef struct stateS { byte savedY; bool outputting; bool redirecting; + byte linesOut; #ifdef DEBUGGING char *opcodesName[256]; char *extOpcodesName[30]; diff --git a/include/story.h b/include/story.h index 8c7a943..70d4606 100644 --- a/include/story.h +++ b/include/story.h @@ -118,6 +118,7 @@ #define storyHXTrueDefaultBackgroundColor() portWordGet(storyHeaderExtensionTableAddress() + 12) +void storyChecksumCalculate(void); uint32_t storyLength(void); void storySetup(byte width, byte height); diff --git a/include/text.h b/include/text.h index 4f98637..9fd27fc 100644 --- a/include/text.h +++ b/include/text.h @@ -21,8 +21,8 @@ */ -#ifndef TEXT_H -#define TEXT_H +#ifndef TEXT_ZIP_H +#define TEXT_ZIP_H #include "common.h" @@ -33,6 +33,12 @@ #define STREAM_OUTPUT_MEMORY 3 #define STREAM_OUTPUT_SCRIPT 4 +#define TEXT_ATTR_NORMAL 0 +#define TEXT_ATTR_REVERSE 1 +#define TEXT_ATTR_BOLD 2 +#define TEXT_ATTR_EMPHASIS 4 +#define TEXT_ATTR_FIXED_FONT 8 + void textCharPrint(char c); void textInput(uint32_t ramAddr, uint8_t length); @@ -43,4 +49,4 @@ void textStringPrint(char *s); void textTimePrint(uint16_t hours, uint16_t minutes); -#endif // TEXT_H +#endif // TEXT_ZIP_H diff --git a/ports/dos-like/CMakeLists.txt b/ports/dos-like/CMakeLists.txt index 50510f9..338610d 100644 --- a/ports/dos-like/CMakeLists.txt +++ b/ports/dos-like/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.12) -project(zip LANGUAGES C) +project(dos-like-zip LANGUAGES C) find_package(SDL2 REQUIRED) @@ -30,8 +30,6 @@ set(HEADERS variable.h window.h zscii.h -# czech.z3.h - zork1.h ) list(TRANSFORM HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../../include/") diff --git a/ports/dos-like/dos-like.c b/ports/dos-like/dos-like.c index 4a344e9..31fb2ce 100644 --- a/ports/dos-like/dos-like.c +++ b/ports/dos-like/dos-like.c @@ -30,9 +30,7 @@ #include "story.h" #include "state.h" #include "interpreter.h" - -#include "zork1.h" -//#include "czech.z3.h" +#include "text.h" #pragma push_macro("bool") #undef bool @@ -41,8 +39,38 @@ #pragma pop_macro("bool") -// The F256 has 512k of RAM. We use everything except the lower 64k. -static uint8_t _RAM[1024 * (512 - 64)]; +static char *_storyFile = NULL; +static uint8_t *_RAM = NULL; +static uint8_t _attr = 7; + + +void portAttributeSet(byte attribute) { + switch (attribute) { + case TEXT_ATTR_NORMAL: + textbackground(1); + textcolor(7); + _attr = (1 << 4) + 7; + break; + + case TEXT_ATTR_REVERSE: + textbackground(7); + textcolor(1); + _attr = (7 << 4) + 1; + break; + + case TEXT_ATTR_BOLD: + textbackground(1); + textcolor(15); + _attr = (1 << 4) + 15; + break; + + case TEXT_ATTR_EMPHASIS: + textbackground(1); + textcolor(14); + _attr = (1 << 4) + 14; + break; + } +} uint8_t portByteGet(uint32_t address) { @@ -85,13 +113,17 @@ void portCharGetPos(byte *x, byte *y) { void portCharPrint(char c) { - char ch[2] = { 0, 0 }; + char ch[2] = { 0, 0 }; + uint16_t *p; + uint16_t v = (_attr << 8) + ' '; + byte x; if ((wherex() >= screenwidth()) || (c == '\n')) { gotoxy(0, wherey() + 1); while (wherey() >= screenheight()) { memmove(((uint16_t*)screenbuffer()), ((uint16_t*)screenbuffer()) + screenwidth(), screenwidth() * (screenheight() - 1) * sizeof(uint16_t)); - memset(((uint16_t*)screenbuffer()) + screenwidth() * (screenheight() - 1), 0, screenwidth() * sizeof(uint16_t)); + p = (uint16_t *)screenbuffer() + (screenwidth() * (screenheight() - 1)); + for (x=0; x ${SETTINGS} -CLANG="mos-f256k-clang -I../../../include -I${F256}/include -I${F256}/f256lib -Os" +CLANG="mos-f256k-clang -I${F256}/include -I../../../include -I${F256}/f256lib -Os" [[ -d .builddir ]] && rm -rf .builddir mkdir -p .builddir diff --git a/ports/f256/f256zip.c b/ports/f256/f256zip.c index 8d5bc6a..c1f76a0 100644 --- a/ports/f256/f256zip.c +++ b/ports/f256/f256zip.c @@ -42,12 +42,36 @@ #include "memory.h" #include "state.h" #include "interpreter.h" -#include "lib.h" +#include "../../include/text.h" #define BASE_ADDRESS 0x10000 +static char *_saveName = 0; + + +void portAttributeSet(byte attribute) { + switch (attribute) { + case TEXT_ATTR_NORMAL: + textSetColor(7, 1); + break; + + case TEXT_ATTR_REVERSE: + textSetColor(1, 7); + break; + + case TEXT_ATTR_BOLD: + textSetColor(15, 1); + break; + + case TEXT_ATTR_EMPHASIS: + textSetColor(14, 1); + break; + } +} + + uint8_t portByteGet(uint32_t address) { return FAR_PEEK(BASE_ADDRESS + address); } @@ -97,7 +121,7 @@ bool portFileRestore(void) { uint32_t i; byte b; - in = fopen("save.dat", "rb"); + in = fopen(_saveName, "rb"); if (in) { ok = true; @@ -128,7 +152,7 @@ bool portFileSave(void) { uint32_t i; byte b; - out = fopen("save.dat", "wb"); + out = fopen(_saveName, "wb"); if (out) { ok = true; @@ -154,7 +178,7 @@ bool portFileSave(void) { char portCharGet(void) { -#if 1 +#if 0 static char playback[] = "open mailbox\ntake leaflet\nread leaflet\ndrop leaflet\n"; static uint32_t pointer = 0; @@ -183,10 +207,13 @@ uint16_t portRandomGet(int16_t range) { void portStoryLoad(void) { // On the F256, the story is loaded into RAM along with the ZIP. + // ***TODO*** This likely breaks the "restart" command. // Later, we probably want to see if the user has a memory expansion // installed. If they do, we can use it and then use the lower memory // for graphics and sound. + + storyChecksumCalculate(); } @@ -201,15 +228,54 @@ void portWordSet(uint32_t address, uint16_t value) { int main(void) { + byte c; + byte colors[16][3] = { + { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0xaa }, + { 0x00, 0xaa, 0x00 }, + { 0x00, 0xaa, 0xaa }, + { 0xaa, 0x00, 0x00 }, + { 0xaa, 0x00, 0xaa }, + { 0xaa, 0x55, 0x00 }, + { 0xaa, 0xaa, 0xaa }, + { 0x55, 0x55, 0x55 }, + { 0x55, 0x55, 0xff }, + { 0x55, 0xff, 0x55 }, + { 0x55, 0xff, 0xff }, + { 0xff, 0x55, 0x55 }, + { 0xff, 0x55, 0xff }, + { 0xff, 0xff, 0x55 }, + { 0xff, 0xff, 0xff } + }; + + _saveName = "zork1.sav"; f256Init(); - textSetCursor(199); + // Load EGA palette into text CLUT. + for (c=0; c<16; c++) { + textDefineForegroundColor(c, colors[c][0], colors[c][1], colors[c][2]); + textDefineBackgroundColor(c, colors[c][0], colors[c][1], colors[c][2]); + } + textEnableBackgroundColors(true); + + textSetColor(15, 0); + textPrint("Welcome to MUDDLE Beta 1, Another Z-Machine!\n\n"); + textSetColor(7, 0); + textPrint("Copyright 2024 Scott Duensing, All Rights Reserved.\n"); + textPrint("Kangaroo Punch Studios https://kangaroopunch.com\n\n\n"); + textSetColor(8, 0); + textPrint("Thinking..."); stateReset(); portStoryLoad(); opcodesSetup(); storySetup(80, 30); + + textSetColor(7, 1); + textClear(); + textSetCursor(199); + interpreterRun(); return 0; diff --git a/src/interpreter.c b/src/interpreter.c index dfaa728..699ff54 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -64,7 +64,7 @@ void interpreterDoReturn(uint16_t r) { if (__state.bp == 0) portDie(MSG_INT_STACK_UNDERFLOW); -#ifdef DEBUGGING +#ifdef DEBUGGINGx printf("Returning: initial pc=%X, bp=%u, sp=%u\n", (unsigned int)__state.pc, __state.bp, __state.sp); #endif @@ -82,7 +82,7 @@ void interpreterDoReturn(uint16_t r) { // Pop the result storage location. storeId = (uint8_t)__state.stack[--__state.sp]; -#ifdef DEBUGGING +#ifdef DEBUGGINGx printf("Returning: new pc=%X, bp=%u, sp=%u\n", (unsigned int)__state.pc, __state.bp, __state.sp); #endif @@ -136,6 +136,10 @@ void interpreterRun(void) { opcodeT op; bool eight; + __state.savedX = 1; + __state.savedY = storyScreenHeightLines(); + portCharSetPos(__state.savedX, __state.savedY); + while (__state.quit == 0) { opcode = ZPEEK(__state.pc++); extended = ((opcode == 190) && (storyVersion() >= 5)) ? true : false; @@ -183,7 +187,7 @@ void interpreterRun(void) { if (op == 0) portDie(MSG_INT_UNIMPLEMENTED_OPCODE, extended ? "ext" : "", opcode); -#ifdef DEBUGGING +#ifdef DEBUGGINGx printf("ins=%u pc=%X sp=%u bp=%u %sopcode=%u ('%s') [", __state.instructionsRun, (unsigned int)__state.pc, @@ -199,6 +203,7 @@ void interpreterRun(void) { printf("%X", (unsigned int)__state.operands[i]); } printf("]\n"); + fflush(stdout); if (__state.instructionsRun == 261) { printf("\n*** BREAKING ***\n"); @@ -247,6 +252,7 @@ void interpreterTokenizeInput(void) { #ifdef DEBUGGING printf("Max parse: %u\n", parseLen); + printf("Parse Input: ["); #endif if (parseLen == 0) portDie(MSG_INT_PARSE_BUFFER_TOO_SMALL); @@ -260,7 +266,9 @@ void interpreterTokenizeInput(void) { while (1) { isSep = false; ch = ZPEEK(ptr); - +#ifdef DEBUGGING + printf("%c", ch); +#endif if ((ch == ' ') || (ch == 0)) { isSep = true; } else { @@ -358,7 +366,9 @@ void interpreterTokenizeInput(void) { } // while #ifdef DEBUGGING + printf("]\n"); printf("Tokenized %u tokens\n", (unsigned int)numToks); + fflush(stdout); #endif ZPOKE(__state.operands[1] + 1, numToks); diff --git a/src/oc_call.c b/src/oc_call.c index a59a8f6..f52d1e5 100644 --- a/src/oc_call.c +++ b/src/oc_call.c @@ -46,7 +46,7 @@ void opcodes_call(void) { } else { routine = memoryUnpackAddress(__state.operands[0], MEMORY_ROUTINE); numLocals = ZPEEK(routine++); -#ifdef DEBUGGING +#ifdef DEBUGGINGx printf("op0=%u routine=%X, numLocals=%d\n", __state.operands[0], (unsigned int)routine, numLocals); #endif if (numLocals > 15) portDie(MSG_OP_CALL_TOO_MANY_LOCALS, numLocals); diff --git a/src/oc_input.c b/src/oc_input.c index 62a2035..3912ab9 100644 --- a/src/oc_input.c +++ b/src/oc_input.c @@ -68,11 +68,15 @@ void opcodes_read(void) { ZPOKE(i, ch); } else if ((ch == '\n') || (ch == '\r') || (ch == 0)) { // End of line, end of input. - ch = 0; - ZPOKE(i, ch); + ZPOKE(i, 0); break; } } + i++; + for (; i= storyScreenHeightLines() - __state.statusWindowLineCount - 1) { + // Display [MORE] prompt. + portCharGetPos(&x, &y); + textStringPrint("[MORE]"); + textStringPrint(" "); + portCharGet(); + portCharSetPos(x, y); + textStringPrint(" "); + portCharSetPos(x, y); + __state.linesOut = 0; + } +} + + static void textNumPrint_r(int32_t val) { if (val > 9) { @@ -212,5 +238,18 @@ void textStringPrint(char *s) { void textTimePrint(uint16_t hours, uint16_t minutes) { + bool PM = (hours < 12) ? false : true; + hours %= 12; + if (hours == 0) hours = 12; + + if (hours < 10) textCharPrint(' '); + textNumPrint(hours); + + textCharPrint(':'); + + if (minutes < 10) textCharPrint('0'); + textNumPrint(minutes); + + textStringPrint((PM ? " pm" : " am")); } diff --git a/src/variable.c b/src/variable.c index ebcddf4..49b03ac 100644 --- a/src/variable.c +++ b/src/variable.c @@ -61,7 +61,7 @@ uint8_t variableAddress(uint8_t var, bool writing) { if (writing) { if (__state.sp >= sizeof(__state.stack)) portDie(MSG_INT_STACK_OVERFLOW); -#ifdef DEBUGGING +#ifdef DEBUGGINGx printf("Push stack\n"); #endif return __state.sp++; @@ -71,7 +71,7 @@ uint8_t variableAddress(uint8_t var, bool writing) { if (__state.sp == 0) portDie(MSG_INT_STACK_UNDERFLOW); numLocals = __state.bp ? __state.stack[__state.bp - 1] : 0; if ((__state.bp + numLocals) >= sizeof(__state.stack)) portDie(MSG_INT_STACK_UNDERFLOW); -#ifdef DEBUGGING +#ifdef DEBUGGINGx printf("Pop stack\n"); #endif return --__state.sp; diff --git a/src/window.c b/src/window.c index 3de22b2..f0a9442 100644 --- a/src/window.c +++ b/src/window.c @@ -130,9 +130,11 @@ void windowSplit(byte newLines) { void windowUpdateStatusBar(void) { + byte width = storyScreenWidthCharacters() - 1; + windowSet(WINDOW_STATUS); portCharSetPos(1, 1); - // Reverse attribute. + portAttributeSet(TEXT_ATTR_REVERSE); textOutputStream(STREAM_OUTPUT_MEMORY, 0); windowPadStatus(1); @@ -142,26 +144,26 @@ void windowUpdateStatusBar(void) { if ((storyFlags() & STORY_STATUS_MASK) == STORY_STATUS_HOURS_MINUTES) { // Timed game. - windowPadStatus(storyScreenWidthCharacters() - 21); + windowPadStatus(width - 21); textStringPrint(" Time: "); textTimePrint(variableLoad(17), variableLoad(18)); } else { // Scored game. - windowPadStatus(storyScreenWidthCharacters() - 31); + windowPadStatus(width - 31); textStringPrint(" Score: "); textNumPrint(variableLoad(17)); - windowPadStatus(storyScreenWidthCharacters() - 15); + windowPadStatus(width - 15); textStringPrint(" Moves: "); textNumPrint(variableLoad(18)); } - windowPadStatus(storyScreenWidthCharacters()); + windowPadStatus(width); __state.statusBar[__state.statusBarLen] = 0; textOutputStream(-STREAM_OUTPUT_MEMORY, 0); textStringPrint(__state.statusBar); - // Normal attribute. + portAttributeSet(TEXT_ATTR_NORMAL); windowSet(WINDOW_TEXT); }