Word wrap fixed.
This commit is contained in:
parent
f491abb894
commit
1632f50b2f
18 changed files with 196 additions and 80 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
36
include/window.h
Normal 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
|
|
@ -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/")
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -41,4 +41,5 @@
|
|||
#include "../src/story.c"
|
||||
#include "../src/text.c"
|
||||
#include "../src/variable.c"
|
||||
#include "../src/window.c"
|
||||
#include "../src/zscii.c"
|
||||
|
|
|
@ -363,8 +363,3 @@ void interpreterTokenizeInput(void) {
|
|||
|
||||
ZPOKE(__state.operands[1] + 1, numToks);
|
||||
}
|
||||
|
||||
|
||||
void interpreterUpdateStatusBar(void) {
|
||||
//***TODO***
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
104
src/portme.c
104
src/portme.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
39
src/window.c
Normal 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***
|
||||
}
|
Loading…
Add table
Reference in a new issue