Word wrap fixed.

This commit is contained in:
Scott Duensing 2024-02-04 18:45:34 -06:00
parent f491abb894
commit 1632f50b2f
18 changed files with 196 additions and 80 deletions

View file

@ -26,6 +26,7 @@ set(HEADERS
story.h
text.h
variable.h
window.h
zscii.h
# czech.z3.h
zork1.h
@ -53,6 +54,7 @@ set(SOURCE
story.c
text.c
variable.c
window.c
zscii.c
)
list(TRANSFORM SOURCE PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/src/")
@ -60,11 +62,10 @@ list(TRANSFORM SOURCE PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/src/")
add_executable(${CMAKE_PROJECT_NAME}
${HEADERS}
${SOURCE}
src/text.c
include/text.h
)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
#target_link_libraries(${CMAKE_PROJECT_NAME}
#)
target_link_libraries(${CMAKE_PROJECT_NAME}
-lcurses
)

View file

@ -34,7 +34,6 @@ bool interpreterParseOperand(uint8_t opType, uint8_t operandId);
uint8_t interpreterParseVariableOperands(uint8_t index);
void interpreterRun(void);
void interpreterTokenizeInput(void);
void interpreterUpdateStatusBar(void);
#endif // INTERPRETER_H

View file

@ -46,6 +46,7 @@
#define MSG_OP_CALL_STACK_OVERFLOW "Stack overflow!"
#define MSG_OP_INPUT_BUFFER_TOO_SMALL "Text buffer too small for reading."
#define MSG_OP_OBJ_MISSING_PROPERTY "Missing object property."
#define MSG_OP_WIN_NO_SPLITTING "Window splitting is not supported."
#else // DEBUGGING
#define MSG_UNIMPLEMENTED ""
#define MSG_INT_INVALID_EXT_OPCODE ""
@ -64,6 +65,7 @@
#define MSG_OP_CALL_STACK_OVERFLOW ""
#define MSG_OP_INPUT_BUFFER_TOO_SMALL ""
#define MSG_OP_OBJ_MISSING_PROPERTY ""
#define MSG_OP_WIN_NO_SPLITTING ""
#endif // DEBUGGING

View file

@ -28,4 +28,9 @@
#include "common.h"
void opcodes_set_window(void);
void opcodes_show_status(void);
void opcodes_split_window(void);
#endif // OC_WINDOW_H

View file

@ -30,9 +30,9 @@
uint8_t portByteGet(uint32_t address);
void portByteSet(uint32_t address, uint8_t value);
void portCharPrint(char c);
char portCharGet(void);
void portCharGetPos(byte *x, byte *y);
void portCharPrint(char c);
void portCharSetPos(byte x, byte y);
void portDie(char *fmt, ...);
bool portFileRestore(void);

View file

@ -40,6 +40,9 @@ typedef struct stateS {
uint8_t operandCount;
uint16_t operands[8];
char alphabetTable[78];
uint16_t statusBarLen;
uint16_t currentWindow;
uint16_t upperWindowLineCount; // If 0, there is no window split.
#ifdef DEBUGGING
char *opcodesName[256];
char *extOpcodesName[30];

36
include/window.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WINDOW_H
#define WINDOW_H
#include "common.h"
void windowSet(uint16_t oldWindow, uint16_t newWindow);
void windowSplit(uint16_t oldLines, uint16_t newLines);
void windowUpdateStatusBar(void);
#endif // WINDOW_H

View file

@ -26,6 +26,7 @@ set(HEADERS
story.h
text.h
variable.h
window.h
zscii.h
# czech.z3.h
# zork1.h
@ -52,6 +53,7 @@ set(SOURCE
story.c
text.c
variable.c
window.c
zscii.c
)
list(TRANSFORM SOURCE PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../../src/")

View file

@ -42,6 +42,7 @@
#include "memory.h"
#include "state.h"
#include "interpreter.h"
#include "lib.h"
#define BASE_ADDRESS 0x10000
@ -153,6 +154,13 @@ bool portFileSave(void) {
char portCharGet(void) {
#if 1
static char playback[] = "open mailbox\ntake leaflet\nread leaflet\ndrop leaflet\n";
static uint32_t pointer = 0;
if (pointer < libStrLen(playback)) return playback[pointer++];
#endif
return getchar();
}

View file

@ -41,4 +41,5 @@
#include "../src/story.c"
#include "../src/text.c"
#include "../src/variable.c"
#include "../src/window.c"
#include "../src/zscii.c"

View file

@ -363,8 +363,3 @@ void interpreterTokenizeInput(void) {
ZPOKE(__state.operands[1] + 1, numToks);
}
void interpreterUpdateStatusBar(void) {
//***TODO***
}

View file

@ -28,6 +28,7 @@
#include "messages.h"
#include "interpreter.h"
#include "text.h"
#include "window.h"
void opcodes_read(void) {
@ -43,7 +44,7 @@ void opcodes_read(void) {
if (inputLen == 0) portDie(MSG_OP_INPUT_BUFFER_TOO_SMALL);
interpreterUpdateStatusBar();
windowUpdateStatusBar();
// Read input from user.
textInput(input, inputLen);

View file

@ -28,6 +28,7 @@
#include "story.h"
#include "opcodes.h"
#include "memory.h"
#include "window.h"
void opcodes_save(void) {
@ -47,5 +48,12 @@ void opcodes_restart(void) {
void opcodes_restore(void) {
interpreterDoBranch(portFileRestore() ? 1 : 0);
bool ok = portFileRestore();
uint16_t oldLines = __state.upperWindowLineCount;
// Collapse upper window.
__state.upperWindowLineCount = 0;
windowSplit(oldLines, 0);
interpreterDoBranch(ok ? 1 : 0);
}

View file

@ -22,3 +22,34 @@
#include "oc_window.h"
#include "story.h"
#include "state.h"
#include "messages.h"
#include "window.h"
void opcodes_set_window(void) {
uint16_t oldWindow = __state.upperWindowLineCount;
// If the interpreter has not set the flag for splitting, this is illegal.
if ((storyFlags() & STORY_FLAG_V3_SCREEN_SPLITTING) == 0) portDie(MSG_OP_WIN_NO_SPLITTING);
__state.currentWindow = __state.operands[0];
windowSet(oldWindow, __state.currentWindow);
}
void opcodes_show_status(void) {
windowUpdateStatusBar();
}
void opcodes_split_window(void) {
uint16_t oldSize = __state.upperWindowLineCount;
// If the interpreter has not set the flag for splitting, this is illegal.
if ((storyFlags() & STORY_FLAG_V3_SCREEN_SPLITTING) == 0) portDie(MSG_OP_WIN_NO_SPLITTING);
__state.upperWindowLineCount = __state.operands[0];
windowSplit(oldSize, __state.upperWindowLineCount);
}

View file

@ -122,11 +122,11 @@ void opcodesBuiltInitialTable(void) {
if (storyVersion() < 3) return;
mOP(188, show_status);
OP(188, show_status);
OP(189, verify);
mOP(234, split_window);
mOP(235, set_window);
OP(234, split_window);
OP(235, set_window);
mOP(243, output_stream);
mOP(244, input_stream);

View file

@ -25,15 +25,17 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "portme.h"
#include "story.h"
#include "memory.h"
#include "state.h"
#include "interpreter.h"
#pragma push_macro("bool")
#undef bool
#include <curses.h>
#pragma pop_macro("bool")
#include "zork1.h"
//#include "czech.z3.h"
@ -52,15 +54,47 @@ void portByteSet(uint32_t address, uint8_t value) {
}
char portCharGet(void) {
#if 1
static char playback[] = "open mailbox\ntake leaflet\nread leaflet\n";
static uint32_t pointer = 0;
if (pointer < strlen(playback)) return playback[pointer++];
return getch();
#else
return getch();
#endif
}
void portCharGetPos(byte *x, byte *y) {
byte xt;
byte yt;
getyx(stdscr, yt, xt);
*x = xt + 1;
*y = yt + 1;
}
void portCharPrint(char c) {
printf("%c", c);
fflush(stdout);
addch(c);
refresh();
}
void portCharSetPos(byte x, byte y) {
move(x - 1, y - 1);
}
void portDie(char *fmt, ...) {
va_list ap;
endwin();
printf("\n");
va_start(ap, fmt);
vprintf(fmt, ap);
@ -124,46 +158,6 @@ bool portFileSave(void) {
}
/* reads from keypress, doesn't echo */
int getch(void) {
struct termios oldattr, newattr;
int ch;
tcgetattr( STDIN_FILENO, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
return ch;
}
void portInput(uint32_t ramAddr, uint8_t length) {
uint8_t i;
char c;
for (i=0; i<length; i++) {
c = getch();
// Delete/Backspace.
if ((c == 8) || (c == 127)) {
if (i > 0) {
printf("\b \b");
i -=2;
}
} else {
ZPOKE(ramAddr + i, c);
// Enter/Return.
if ((c == 13) || (c == 10)) {
printf("\n");
break;
}
printf("%c", c);
}
fflush(stdout);
}
}
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.
@ -173,21 +167,9 @@ uint16_t portRandomGet(int16_t range) {
void portStoryLoad(void) {
// For now, we just copy an embedded Zork 1 into RAM.
memcpy(_RAM, zork1, zork1_len);
//memcpy(_RAM, czech_z3, czech_z3_len);
// 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.
// Currently no status bar.
ZPOKE(STORY_FLAG_V3, ZPEEK(STORY_FLAG_V3) | STORY_FLAG_V3_STATUS_LINE_NOT_AVAILABLE);
// Uncomment for status bar and window splitting.
//POKE(STORY_FLAG_V3, PEEK(STORY_FLAG_V3) & ~STORY_FLAG_V3_STATUS_LINE_NOT_AVAILABLE);
//POKE(STORY_FLAG_V3, PEEK(STORY_FLAG_V3) | STORY_FLAG_V3_SCREEN_SPLITTING);
}
@ -204,11 +186,17 @@ void portWordSet(uint32_t address, uint16_t value) {
int main(void) {
initscr();
cbreak();
noecho();
stateReset();
portStoryLoad();
opcodesSetup();
storySetup();
storySetup(COLS - 1, LINES - 1);
interpreterRun();
endwin();
return 0;
}

View file

@ -31,14 +31,13 @@ void textCharPrint(char c) {
static char lineBuffer[256];
static uint16_t lineWidth = 0;
byte width = ZPEEK(STORY_SCREEN_WIDTH_CHARACTERS);
byte height = ZPEEK(STORY_SCREEN_HEIGHT_LINES);
byte space;
byte i;
byte x;
byte y;
// Do we need to word wrap?
if (lineWidth == width - 1) {
if (lineWidth == width - 2) {
// Are we printing a space or CR? If so, just go to next line.
if ((c == ' ') || (c == '\n')) {
c = '\n';
@ -50,8 +49,7 @@ void textCharPrint(char c) {
// Did we find a space?
if (space == 0) {
// No. Just wrap.
portCharPrint('\n');
lineWidth = 0;
c = '\n';
} else {
// Move to after space.
space++;
@ -71,8 +69,7 @@ void textCharPrint(char c) {
lineBuffer[x++] = lineBuffer[i];
portCharPrint(lineBuffer[i]);
}
// Wrap buffer.
lineWidth = 0;
lineWidth = x;
}
}
}

39
src/window.c Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "window.h"
void windowSet(uint16_t oldWindow, uint16_t newWindow) {
}
void windowSplit(uint16_t oldLines, uint16_t newLines) {
}
void windowUpdateStatusBar(void) {
//***TODO***
}