Menuing system almost working.
This commit is contained in:
parent
c03bb427bc
commit
88b4a6850a
19 changed files with 764 additions and 205 deletions
|
@ -25,6 +25,7 @@ set(HEADERS
|
|||
stddclmr.h
|
||||
story.h
|
||||
text.h
|
||||
ui.h
|
||||
variable.h
|
||||
window.h
|
||||
zscii.h
|
||||
|
@ -53,6 +54,7 @@ set(SOURCE
|
|||
state.c
|
||||
story.c
|
||||
text.c
|
||||
ui.c
|
||||
variable.c
|
||||
window.c
|
||||
zscii.c
|
||||
|
|
|
@ -30,7 +30,9 @@
|
|||
|
||||
void libMemSet(byte *start, byte val, uint32_t len);
|
||||
char *libStrChr(char *haystack, char needle);
|
||||
int8_t libStrICmp(char *a, char *b);
|
||||
uint32_t libStrLen(char *str);
|
||||
char libToLower(char c);
|
||||
|
||||
|
||||
#endif // LIB_H
|
||||
|
|
|
@ -42,11 +42,13 @@
|
|||
#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_STA_CANNOT_ALLOCATE_STACK "Cannot allocate stack!"
|
||||
#define MSG_OP_CALL_TOO_MANY_LOCALS "Too many local variables! (%d)"
|
||||
#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."
|
||||
#define MSG_UI_CANNOT_ALLOCATE "Cannot allocate %l bytes!"
|
||||
#else // DEBUGGING
|
||||
#define MSG_UNIMPLEMENTED ""
|
||||
#define MSG_INT_INVALID_EXT_OPCODE ""
|
||||
|
@ -61,11 +63,13 @@
|
|||
#define MSG_INT_V12_SHIFT ""
|
||||
#define MSG_INT_V12_SHIFT_LOCK ""
|
||||
#define MSG_MEM_BUFFER ""
|
||||
#define MSG_STA_CANNOT_ALLOCATE_STACK ""
|
||||
#define MSG_OP_CALL_TOO_MANY_LOCALS ""
|
||||
#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 ""
|
||||
#define MSG_UI_CANNOT_ALLOCATE ""
|
||||
#endif // DEBUGGING
|
||||
|
||||
|
||||
|
|
|
@ -35,11 +35,20 @@ char portCharGet(void);
|
|||
void portCharGetPos(byte *x, byte *y);
|
||||
void portCharPrint(char c);
|
||||
void portCharSetPos(byte x, byte y);
|
||||
void portColorSet(byte f, byte b);
|
||||
void portCursorShow(bool s);
|
||||
void portDie(char *fmt, ...);
|
||||
bool portFileRestore(void);
|
||||
bool portFileSave(void);
|
||||
uint32_t portFClose(void *stream);
|
||||
void *portFOpen(char *pathname, char *mode);
|
||||
uint32_t portFRead(void *ptr, uint32_t size, uint32_t nmemb, void *stream);
|
||||
uint32_t portFWrite(void *ptr, uint32_t size, uint32_t nmemb, void *stream);
|
||||
void portFileLister(void);
|
||||
void portFree(void *ptr);
|
||||
void *portMalloc(uint32_t size);
|
||||
uint16_t portRandomGet(int16_t range);
|
||||
void portStoryLoad(void);
|
||||
void portScreenClear(void);
|
||||
void portStoryLoad(char *story, uint32_t *length);
|
||||
char *portSymbolsGet(void);
|
||||
uint16_t portWordGet(uint32_t address);
|
||||
void portWordSet(uint32_t address, uint16_t value);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
|
||||
typedef struct stateS {
|
||||
uint16_t stack[STACK_SIZE];
|
||||
uint16_t *stack;
|
||||
bool quit;
|
||||
uint32_t pc; // Program Counter
|
||||
uint16_t sp; // Stack Pointer
|
||||
|
|
|
@ -120,7 +120,7 @@
|
|||
|
||||
void storyChecksumCalculate(void);
|
||||
uint32_t storyLength(void);
|
||||
void storySetup(byte width, byte height);
|
||||
void storySetup(void);
|
||||
|
||||
|
||||
#endif // STORY_H
|
||||
|
|
46
include/ui.h
Normal file
46
include/ui.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 UI_H
|
||||
#define UI_H
|
||||
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define UI_KEY_UP 255
|
||||
#define UI_KEY_RIGHT 254
|
||||
#define UI_KEY_DOWN 253
|
||||
#define UI_KEY_LEFT 252
|
||||
|
||||
|
||||
void uiFileAdd(char *filename, uint32_t size);
|
||||
void uiGameSelect(void);
|
||||
char *uiSaveGet(void);
|
||||
void uiSizeGet(byte *w, byte *h);
|
||||
void uiSizeSet(byte w, byte h);
|
||||
char *uiStoryGet(void);
|
||||
uint32_t uiStorySizeGet(void);
|
||||
|
||||
|
||||
#endif // UI_H
|
|
@ -27,6 +27,7 @@ set(HEADERS
|
|||
stddclmr.h
|
||||
story.h
|
||||
text.h
|
||||
ui.h
|
||||
variable.h
|
||||
window.h
|
||||
zscii.h
|
||||
|
@ -52,6 +53,7 @@ set(SOURCE
|
|||
state.c
|
||||
story.c
|
||||
text.c
|
||||
ui.c
|
||||
variable.c
|
||||
window.c
|
||||
zscii.c
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "portme.h"
|
||||
#include "story.h"
|
||||
#include "state.h"
|
||||
#include "interpreter.h"
|
||||
#include "text.h"
|
||||
#include "ui.h"
|
||||
|
||||
#pragma push_macro("bool")
|
||||
#undef bool
|
||||
|
@ -39,35 +39,26 @@
|
|||
#pragma pop_macro("bool")
|
||||
|
||||
|
||||
static char *_storyFile = NULL;
|
||||
static uint8_t *_RAM = NULL;
|
||||
static uint8_t _attr = (1 << 4) + 7;
|
||||
static uint8_t _attr = 0;
|
||||
|
||||
|
||||
void portAttributeSet(byte attribute) {
|
||||
switch (attribute) {
|
||||
case TEXT_ATTR_NORMAL:
|
||||
textbackground(1);
|
||||
textcolor(7);
|
||||
_attr = (1 << 4) + 7;
|
||||
portColorSet(7, 1);
|
||||
break;
|
||||
|
||||
case TEXT_ATTR_REVERSE:
|
||||
textbackground(7);
|
||||
textcolor(1);
|
||||
_attr = (7 << 4) + 1;
|
||||
portColorSet(1, 7);
|
||||
break;
|
||||
|
||||
case TEXT_ATTR_BOLD:
|
||||
textbackground(1);
|
||||
textcolor(15);
|
||||
_attr = (1 << 4) + 15;
|
||||
portColorSet(15, 1);
|
||||
break;
|
||||
|
||||
case TEXT_ATTR_EMPHASIS:
|
||||
textbackground(1);
|
||||
textcolor(14);
|
||||
_attr = (1 << 4) + 14;
|
||||
portColorSet(14, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +91,10 @@ char portCharGet(void) {
|
|||
if (key == KEY_RETURN) c = 13;
|
||||
if (key == KEY_BACK) c = 127;
|
||||
if (key == KEY_DELETE) c = 8;
|
||||
if (key == KEY_UP) c = (char)UI_KEY_UP;
|
||||
if (key == KEY_RIGHT) c = (char)UI_KEY_RIGHT;
|
||||
if (key == KEY_DOWN) c = (char)UI_KEY_DOWN;
|
||||
if (key == KEY_LEFT) c = (char)UI_KEY_LEFT;
|
||||
} while (c == 0);
|
||||
|
||||
return c;
|
||||
|
@ -139,6 +134,22 @@ void portCharSetPos(byte x, byte y) {
|
|||
}
|
||||
|
||||
|
||||
void portColorSet(byte f, byte b) {
|
||||
textcolor(f);
|
||||
textbackground(b);
|
||||
_attr = (f << 4) + b;
|
||||
}
|
||||
|
||||
|
||||
void portCursorShow(bool s) {
|
||||
if (s) {
|
||||
curson();
|
||||
} else {
|
||||
cursoff();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void portDie(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
|
@ -152,56 +163,64 @@ void portDie(char *fmt, ...) {
|
|||
}
|
||||
|
||||
|
||||
bool portFileRestore(void) {
|
||||
|
||||
FILE *in;
|
||||
bool ok = false;
|
||||
|
||||
in = fopen("save.dat", "rb");
|
||||
if (in) {
|
||||
ok = true;
|
||||
|
||||
// Read in PC.
|
||||
ok &= (fread(&__state.pc, sizeof(__state.pc), 1, in) == 1);
|
||||
// Read in SP.
|
||||
ok &= (fread(&__state.sp, sizeof(__state.sp), 1, in) == 1);
|
||||
// Read in BP.
|
||||
ok &= (fread(&__state.bp, sizeof(__state.bp), 1, in) == 1);
|
||||
// Read in dynamic game RAM.
|
||||
ok &= (fread(_RAM, storyStaticMemoryBaseAddress(), 1, in) == 1);
|
||||
// Read in stack.
|
||||
ok &= (fread(__state.stack, sizeof(__state.stack[0]), __state.sp, in) == __state.sp);
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
return ok;
|
||||
uint32_t portFClose(void *stream) {
|
||||
return fclose((FILE *)stream);
|
||||
}
|
||||
|
||||
|
||||
bool portFileSave(void) {
|
||||
FILE *out;
|
||||
bool ok = false;
|
||||
void *portFOpen(char *pathname, char *mode) {
|
||||
return fopen(pathname, mode);
|
||||
}
|
||||
|
||||
out = fopen("save.dat", "wb");
|
||||
if (out) {
|
||||
ok = true;
|
||||
|
||||
// Write out PC.
|
||||
ok &= (fwrite(&__state.pc, sizeof(__state.pc), 1, out) == 1);
|
||||
// Write out SP.
|
||||
ok &= (fwrite(&__state.sp, sizeof(__state.sp), 1, out) == 1);
|
||||
// Write out BP.
|
||||
ok &= (fwrite(&__state.bp, sizeof(__state.bp), 1, out) == 1);
|
||||
// Write out dynamic game RAM.
|
||||
ok &= (fwrite(_RAM, storyStaticMemoryBaseAddress(), 1, out) == 1);
|
||||
// Write out stack.
|
||||
ok &= (fwrite(__state.stack, sizeof(__state.stack[0]), __state.sp, out) == __state.sp);
|
||||
uint32_t portFRead(void *ptr, uint32_t size, uint32_t nmemb, void *stream) {
|
||||
return fread(ptr, size, nmemb, (FILE *)stream);
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
|
||||
uint32_t portFWrite(void *ptr, uint32_t size, uint32_t nmemb, void *stream) {
|
||||
return fwrite(ptr, size, nmemb, (FILE *)stream);
|
||||
}
|
||||
|
||||
|
||||
void portFileLister(void) {
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
uint32_t l;
|
||||
FILE *in;
|
||||
|
||||
if ((dir = opendir("."))) {
|
||||
for (;;) {
|
||||
if ((dirent = readdir(dir))) {
|
||||
// Is this a file or symlink?
|
||||
if ((dirent->d_type == DT_REG) || (dirent->d_type == DT_LNK)) {
|
||||
// Get it's length.
|
||||
in = fopen(dirent->d_name, "rb");
|
||||
if (in) {
|
||||
fseek(in, 0, SEEK_END);
|
||||
l = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
fclose(in);
|
||||
// Add it to the story chooser.
|
||||
uiFileAdd(dirent->d_name, l);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
||||
void portFree(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
void *portMalloc(uint32_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
|
||||
|
@ -218,32 +237,43 @@ uint16_t portRandomGet(int16_t range) {
|
|||
}
|
||||
|
||||
|
||||
void portStoryLoad(void) {
|
||||
void portScreenClear(void) {
|
||||
clrscr();
|
||||
}
|
||||
|
||||
|
||||
void portStoryLoad(char *story, uint32_t *length) {
|
||||
FILE *in;
|
||||
uint32_t length;
|
||||
|
||||
in = fopen(_storyFile, "rb");
|
||||
if (!in) portDie("Unable to open %s!\n", _storyFile);
|
||||
in = fopen(story, "rb");
|
||||
if (!in) portDie("Unable to open %s!\n", story);
|
||||
|
||||
fseek(in, 0, SEEK_END);
|
||||
length = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
|
||||
_RAM = (byte *)malloc(length);
|
||||
_RAM = (byte *)malloc(*length);
|
||||
if (!_RAM) {
|
||||
fclose(in);
|
||||
portDie("Unable to allocate %u bytes!\n", length);
|
||||
portDie("Unable to allocate %u bytes!\n", *length);
|
||||
}
|
||||
|
||||
if (fread(_RAM, length, 1, in) != 1) {
|
||||
if (fread(_RAM, *length, 1, in) != 1) {
|
||||
free(_RAM);
|
||||
fclose(in);
|
||||
portDie("Unable to read %s!\n", _storyFile);
|
||||
portDie("Unable to read %s!\n", story);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
storyChecksumCalculate();
|
||||
|
||||
char *portSymbolsGet(void) {
|
||||
// Box drawing and other symbols needed by the UI.
|
||||
//
|
||||
// 0---1---2
|
||||
// | |
|
||||
// 7 3
|
||||
// | |
|
||||
// 6---5---4
|
||||
|
||||
return "\xda\xc4\xbf\xb3\xd9\xc4\xc0\xb3";
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,24 +288,14 @@ void portWordSet(uint32_t address, uint16_t value) {
|
|||
}
|
||||
|
||||
|
||||
#include "unistd.h"
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc != 2) portDie("Usage: %s [storyfile]\n", argv[0]);
|
||||
|
||||
_storyFile = argv[1];
|
||||
chdir("/home/scott/code/zip/stories");
|
||||
|
||||
setvideomode(videomode_80x25_9x16);
|
||||
curson();
|
||||
textbackground(1);
|
||||
textcolor(7);
|
||||
clrscr();
|
||||
gotoxy(0, screenheight() - 1);
|
||||
|
||||
stateReset();
|
||||
portStoryLoad();
|
||||
opcodesSetup();
|
||||
storySetup(80, 25);
|
||||
interpreterRun();
|
||||
uiSizeSet(80, 25);
|
||||
uiGameSelect();
|
||||
|
||||
free(_RAM);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ set(HEADERS
|
|||
stddclmr.h
|
||||
story.h
|
||||
text.h
|
||||
ui.h
|
||||
variable.h
|
||||
window.h
|
||||
zscii.h
|
||||
|
@ -52,6 +53,7 @@ set(SOURCE
|
|||
state.c
|
||||
story.c
|
||||
text.c
|
||||
ui.c
|
||||
variable.c
|
||||
window.c
|
||||
zscii.c
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
|
||||
PROJECT=f256zip
|
||||
START=0x200
|
||||
START=0x300
|
||||
|
||||
F256=$(pwd)/../../../f256
|
||||
LLVM=${F256}/llvm-mos
|
||||
|
@ -50,8 +50,8 @@ ${F256}/header \
|
|||
pgz 24 \
|
||||
../${PROJECT}.pgz \
|
||||
${START} \
|
||||
${PROJECT}.bin ${START} \
|
||||
../../../stories/zork1-r119-s880429.z3 0x10000
|
||||
${PROJECT}.bin ${START}
|
||||
# ../../../stories/zork1-r119-s880429.z3 0x10000
|
||||
# ../../../tests/testers/czech/czech.z3 0x10000
|
||||
|
||||
#llvm-nm ${PROJECT}.elf > ${PROJECT}.lst
|
||||
|
|
|
@ -38,35 +38,31 @@
|
|||
#include "f256.h"
|
||||
|
||||
#include "portme.h"
|
||||
#include "story.h"
|
||||
#include "memory.h"
|
||||
#include "state.h"
|
||||
#include "interpreter.h"
|
||||
#include "ui.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);
|
||||
portColorSet(7, 1);
|
||||
break;
|
||||
|
||||
case TEXT_ATTR_REVERSE:
|
||||
textSetColor(1, 7);
|
||||
portColorSet(1, 7);
|
||||
break;
|
||||
|
||||
case TEXT_ATTR_BOLD:
|
||||
textSetColor(15, 1);
|
||||
portColorSet(15, 1);
|
||||
break;
|
||||
|
||||
case TEXT_ATTR_EMPHASIS:
|
||||
textSetColor(14, 1);
|
||||
portColorSet(14, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +78,26 @@ void portByteSet(uint32_t address, uint8_t value) {
|
|||
}
|
||||
|
||||
|
||||
char portCharGet(void) {
|
||||
char c;
|
||||
|
||||
#if 0
|
||||
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
|
||||
|
||||
c = getchar();
|
||||
if (c == 16) c = (char)UI_KEY_UP;
|
||||
if (c == 6) c = (char)UI_KEY_RIGHT;
|
||||
if (c == 14) c = (char)UI_KEY_DOWN;
|
||||
if (c == 2) c = (char)UI_KEY_LEFT;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void portCharGetPos(byte *x, byte *y) {
|
||||
byte tx;
|
||||
byte ty;
|
||||
|
@ -106,6 +122,20 @@ void portCharSetPos(byte x, byte y) {
|
|||
}
|
||||
|
||||
|
||||
void portColorSet(byte f, byte b) {
|
||||
textSetColor(f, b);
|
||||
}
|
||||
|
||||
|
||||
void portCursorShow(bool s) {
|
||||
if (s) {
|
||||
textSetCursor(199);
|
||||
} else {
|
||||
textSetCursor(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void portDie(char *fmt, ...) {
|
||||
#ifdef DEBUGGING
|
||||
printf("%s\n", fmt); // Yeah, this isn't right.
|
||||
|
@ -114,78 +144,55 @@ void portDie(char *fmt, ...) {
|
|||
}
|
||||
|
||||
|
||||
bool portFileRestore(void) {
|
||||
|
||||
FILE *in;
|
||||
bool ok = false;
|
||||
uint32_t i;
|
||||
byte b;
|
||||
|
||||
in = fopen(_saveName, "rb");
|
||||
if (in) {
|
||||
ok = true;
|
||||
|
||||
// Read in PC.
|
||||
ok &= (fread(&__state.pc, sizeof(__state.pc), 1, in) == 1);
|
||||
// Read in SP.
|
||||
ok &= (fread(&__state.sp, sizeof(__state.sp), 1, in) == 1);
|
||||
// Read in BP.
|
||||
ok &= (fread(&__state.bp, sizeof(__state.bp), 1, in) == 1);
|
||||
// Read in dynamic game RAM.
|
||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||
ok &= (fread(&b, 1, 1, in) == 1);
|
||||
ZPOKE(i, b);
|
||||
}
|
||||
// Read in stack.
|
||||
ok &= (fread(__state.stack, sizeof(__state.stack[0]), __state.sp, in) == __state.sp);
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
return ok;
|
||||
uint32_t portFClose(void *stream) {
|
||||
return fclose((FILE *)stream);
|
||||
}
|
||||
|
||||
|
||||
bool portFileSave(void) {
|
||||
FILE *out;
|
||||
bool ok = false;
|
||||
uint32_t i;
|
||||
byte b;
|
||||
|
||||
out = fopen(_saveName, "wb");
|
||||
if (out) {
|
||||
ok = true;
|
||||
|
||||
// Write out PC.
|
||||
ok &= (fwrite(&__state.pc, sizeof(__state.pc), 1, out) == 1);
|
||||
// Write out SP.
|
||||
ok &= (fwrite(&__state.sp, sizeof(__state.sp), 1, out) == 1);
|
||||
// Write out BP.
|
||||
ok &= (fwrite(&__state.bp, sizeof(__state.bp), 1, out) == 1);
|
||||
// Write out dynamic game RAM.
|
||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||
b = ZPEEK(i);
|
||||
ok &= (fwrite(&b, 1, 1, out) == 1);
|
||||
}
|
||||
// Write out stack.
|
||||
ok &= (fwrite(__state.stack, sizeof(__state.stack[0]), __state.sp, out) == __state.sp);
|
||||
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
return ok;
|
||||
void *portFOpen(char *pathname, char *mode) {
|
||||
return fopen(pathname, mode);
|
||||
}
|
||||
|
||||
|
||||
char portCharGet(void) {
|
||||
#if 0
|
||||
static char playback[] = "open mailbox\ntake leaflet\nread leaflet\ndrop leaflet\n";
|
||||
static uint32_t pointer = 0;
|
||||
uint32_t portFRead(void *ptr, uint32_t size, uint32_t nmemb, void *stream) {
|
||||
return fread(ptr, size, nmemb, (FILE *)stream);
|
||||
}
|
||||
|
||||
if (pointer < libStrLen(playback)) return playback[pointer++];
|
||||
#endif
|
||||
|
||||
return getchar();
|
||||
uint32_t portFWrite(void *ptr, uint32_t size, uint32_t nmemb, void *stream) {
|
||||
return fwrite(ptr, size, nmemb, (FILE *)stream);
|
||||
}
|
||||
|
||||
|
||||
void portFileLister(void) {
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
uint32_t l;
|
||||
|
||||
if ((dir = opendir("0:"))) {
|
||||
for (;;) {
|
||||
if ((dirent = readdir(dir))) {
|
||||
// Is this a file?
|
||||
if (_DE_ISREG(dirent->d_type)) {
|
||||
// Add it to the story chooser.
|
||||
uiFileAdd(dirent->d_name, dirent->d_blocks * 256);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void portFree(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
void *portMalloc(uint32_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,16 +211,58 @@ uint16_t portRandomGet(int16_t range) {
|
|||
}
|
||||
|
||||
|
||||
void portStoryLoad(void) {
|
||||
void portScreenClear(void) {
|
||||
textClear();
|
||||
}
|
||||
|
||||
// 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.
|
||||
void portStoryLoad(char *story, uint32_t *length) {
|
||||
FILE *in;
|
||||
uint32_t i;
|
||||
byte r;
|
||||
byte b;
|
||||
uint32_t newLength;
|
||||
|
||||
storyChecksumCalculate();
|
||||
in = fopen(story, "rb");
|
||||
if (!in) portDie("Unable to open %s!\n", story);
|
||||
|
||||
// The F256 only returns file sizes in blocks of 256.
|
||||
// We load what we can until we get an error and then
|
||||
// see if we're within 256 to determine success.
|
||||
i = BASE_ADDRESS;
|
||||
do {
|
||||
r = fread(&b, 1, 1, in);
|
||||
if (r == 1) ZPOKE(i++, b);
|
||||
} while (r == 1);
|
||||
|
||||
fclose(in);
|
||||
|
||||
newLength = *length - (i - BASE_ADDRESS);
|
||||
if (newLength > 256) portDie("Unable to read %s!\n", story);
|
||||
|
||||
// Update story length.
|
||||
*length = newLength;
|
||||
}
|
||||
|
||||
|
||||
char *portSymbolsGet(void) {
|
||||
// Box drawing and other symbols needed by the UI.
|
||||
//
|
||||
// 0---1---2
|
||||
// | |
|
||||
// 7 3
|
||||
// | |
|
||||
// 6---5---4
|
||||
|
||||
// 160 a0
|
||||
// 150 96
|
||||
// 161 a1
|
||||
// 130 82
|
||||
// 163 a3
|
||||
// 150 96
|
||||
// 162 a2
|
||||
// 130 82
|
||||
return "\xa0\x96\xa1\x82\xa3\x96\xa2\x82";
|
||||
}
|
||||
|
||||
|
||||
|
@ -248,8 +297,6 @@ int main(void) {
|
|||
{ 0xff, 0xff, 0xff }
|
||||
};
|
||||
|
||||
_saveName = "zork1.sav";
|
||||
|
||||
f256Init();
|
||||
|
||||
// Load EGA palette into text CLUT.
|
||||
|
@ -259,24 +306,30 @@ int main(void) {
|
|||
}
|
||||
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...");
|
||||
/*
|
||||
uint16_t b;
|
||||
c = 0;
|
||||
char ch[2] = {0,0};
|
||||
for (b=1; b<256; b++) {
|
||||
ch[0] = (char)b; // (b == 13 ? ' ' : (char)b);
|
||||
textPrint(ch);
|
||||
textPrint("=");
|
||||
textPrintInt(b);
|
||||
c++;
|
||||
if (c > 11) {
|
||||
c = 0;
|
||||
textPrint("\n");
|
||||
} else {
|
||||
if (b<100) textPrint(" ");
|
||||
if (b<10) textPrint(" ");
|
||||
textPrint(" ");
|
||||
}
|
||||
}
|
||||
portCharGet();
|
||||
*/
|
||||
|
||||
stateReset();
|
||||
portStoryLoad();
|
||||
opcodesSetup();
|
||||
storySetup(80, 30);
|
||||
|
||||
textSetColor(7, 1);
|
||||
textClear();
|
||||
textSetCursor(199);
|
||||
|
||||
interpreterRun();
|
||||
uiSizeSet(80, 30);
|
||||
uiGameSelect();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "../src/state.c"
|
||||
#include "../src/story.c"
|
||||
#include "../src/text.c"
|
||||
#include "../src/ui.c"
|
||||
#include "../src/variable.c"
|
||||
#include "../src/window.c"
|
||||
#include "../src/zscii.c"
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "variable.h"
|
||||
#include "memory.h"
|
||||
#include "lib.h"
|
||||
#include "text.h"
|
||||
|
||||
|
||||
void interpreterDoBranch(int32_t truth) {
|
||||
|
@ -136,10 +137,7 @@ void interpreterRun(void) {
|
|||
opcodeT op;
|
||||
bool eight;
|
||||
|
||||
__state.savedX = 1;
|
||||
__state.savedY = storyScreenHeightLines();
|
||||
portCharSetPos(__state.savedX, __state.savedY);
|
||||
|
||||
// Go!
|
||||
while (__state.quit == 0) {
|
||||
opcode = ZPEEK(__state.pc++);
|
||||
extended = ((opcode == 190) && (storyVersion() >= 5)) ? true : false;
|
||||
|
|
17
src/lib.c
17
src/lib.c
|
@ -43,8 +43,25 @@ char *libStrChr(char *haystack, char needle) {
|
|||
}
|
||||
|
||||
|
||||
int8_t libStrICmp(char *a, char *b) {
|
||||
char d;
|
||||
for (;; a++, b++) {
|
||||
d = libToLower((unsigned char)*a) - libToLower((unsigned char)*b);
|
||||
if (d != 0 || !*a) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t libStrLen(char *str) {
|
||||
uint32_t l = 0;
|
||||
while (str[l] != 0) l++;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
char libToLower(char c) {
|
||||
if ((c >= 'A') && (c <= 'Z')) c = c - ('A' - 'z');
|
||||
return c;
|
||||
}
|
||||
|
|
|
@ -27,30 +27,76 @@
|
|||
#include "portme.h"
|
||||
#include "story.h"
|
||||
#include "opcodes.h"
|
||||
#include "memory.h"
|
||||
#include "window.h"
|
||||
#include "memory.h"
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
void opcodes_save(void) {
|
||||
interpreterDoBranch(portFileSave() ? 1 : 0);
|
||||
void *out;
|
||||
bool ok = false;
|
||||
uint32_t i;
|
||||
byte b;
|
||||
|
||||
out = portFOpen(uiSaveGet(), "wb");
|
||||
if (out) {
|
||||
ok = true;
|
||||
// Write out PC.
|
||||
ok &= (portFWrite(&__state.pc, sizeof(__state.pc), 1, out) == 1);
|
||||
// Write out SP.
|
||||
ok &= (portFWrite(&__state.sp, sizeof(__state.sp), 1, out) == 1);
|
||||
// Write out BP.
|
||||
ok &= (portFWrite(&__state.bp, sizeof(__state.bp), 1, out) == 1);
|
||||
// Write out dynamic game RAM.
|
||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||
b = ZPEEK(i);
|
||||
ok &= (portFWrite(&b, 1, 1, out) == 1);
|
||||
}
|
||||
// Write out stack.
|
||||
ok &= (portFWrite(__state.stack, sizeof(__state.stack[0]), __state.sp, out) == __state.sp);
|
||||
portFClose(out);
|
||||
}
|
||||
|
||||
interpreterDoBranch(ok ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void opcodes_restart(void) {
|
||||
byte width = ZPEEK(STORY_SCREEN_WIDTH_CHARACTERS);
|
||||
byte height = ZPEEK(STORY_SCREEN_HEIGHT_LINES);
|
||||
uint16_t checksum = __state.checksum;
|
||||
uint32_t length = uiStorySizeGet();
|
||||
|
||||
stateReset();
|
||||
portStoryLoad();
|
||||
portStoryLoad(uiStoryGet(), &length); // If they change the file size on the second load, they have more problems than us not updating it.
|
||||
__state.checksum = checksum;
|
||||
opcodesSetup();
|
||||
storySetup(width, height);
|
||||
storySetup();
|
||||
}
|
||||
|
||||
|
||||
void opcodes_restore(void) {
|
||||
bool ok = portFileRestore();
|
||||
void *in = 0;
|
||||
bool ok = false;
|
||||
uint32_t i;
|
||||
byte b;
|
||||
|
||||
in = portFOpen(uiSaveGet(), "rb");
|
||||
if (in) {
|
||||
ok = true;
|
||||
// Read in PC.
|
||||
ok &= (portFRead(&__state.pc, sizeof(__state.pc), 1, in) == 1);
|
||||
// Read in SP.
|
||||
ok &= (portFRead(&__state.sp, sizeof(__state.sp), 1, in) == 1);
|
||||
// Read in BP.
|
||||
ok &= (portFRead(&__state.bp, sizeof(__state.bp), 1, in) == 1);
|
||||
// Read in dynamic game RAM.
|
||||
for (i=0; i<storyStaticMemoryBaseAddress(); i++) {
|
||||
ok &= (portFRead(&b, 1, 1, in) == 1);
|
||||
ZPOKE(i, b);
|
||||
}
|
||||
// Read in stack.
|
||||
ok &= (portFRead(__state.stack, sizeof(__state.stack[0]), __state.sp, in) == __state.sp);
|
||||
portFClose(in);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
// Collapse upper window.
|
||||
|
|
11
src/state.c
11
src/state.c
|
@ -23,12 +23,23 @@
|
|||
|
||||
#include "state.h"
|
||||
#include "lib.h"
|
||||
#include "portme.h"
|
||||
#include "messages.h"
|
||||
|
||||
|
||||
stateT __state;
|
||||
|
||||
static bool _stackAllocated = false;
|
||||
|
||||
|
||||
void stateReset(void) {
|
||||
|
||||
if (!_stackAllocated) {
|
||||
__state.stack = (uint16_t *)portMalloc(sizeof(uint16_t) * STACK_SIZE);
|
||||
if (__state.stack == 0) portDie(MSG_STA_CANNOT_ALLOCATE_STACK);
|
||||
_stackAllocated = true;
|
||||
}
|
||||
|
||||
// Zero out all state data.
|
||||
libMemSet((byte *)&__state, 0, sizeof(stateT));
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "story.h"
|
||||
#include "state.h"
|
||||
#include "memory.h"
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
void storyChecksumCalculate(void) {
|
||||
|
@ -55,11 +56,14 @@ uint32_t storyLength() {
|
|||
}
|
||||
|
||||
|
||||
void storySetup(byte width, byte height) {
|
||||
void storySetup(void) {
|
||||
char *p;
|
||||
uint16_t i;
|
||||
byte width;
|
||||
byte height;
|
||||
|
||||
// Set display size.
|
||||
uiSizeGet(&width, &height);
|
||||
ZPOKE(STORY_SCREEN_WIDTH_CHARACTERS, width);
|
||||
ZPOKE(STORY_SCREEN_HEIGHT_LINES, height);
|
||||
|
||||
|
|
342
src/ui.c
Normal file
342
src/ui.c
Normal file
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* 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 "ui.h"
|
||||
#include "portme.h"
|
||||
#include "lib.h"
|
||||
#include "state.h"
|
||||
#include "opcodes.h"
|
||||
#include "story.h"
|
||||
#include "interpreter.h"
|
||||
#include "messages.h"
|
||||
#include "text.h"
|
||||
|
||||
|
||||
#define uiStringPrintAt(x,y,s) portCharSetPos(x, y); uiStringPrint(s)
|
||||
|
||||
|
||||
typedef struct fileListS {
|
||||
char *filename;
|
||||
byte filenameLen;
|
||||
uint32_t filesize;
|
||||
struct fileListS *next;
|
||||
} fileListT;
|
||||
|
||||
|
||||
static void uiBox(byte x, byte y, byte w, byte h);
|
||||
static void uiCenter(char *m);
|
||||
static void uiDialog(byte fc, byte bc, byte tc, byte y, char *message);
|
||||
static void uiStringPrint(char *s);
|
||||
static void uiTitleDraw(void);
|
||||
|
||||
|
||||
static byte _screenHeight;
|
||||
static byte _screenWidth;
|
||||
static char *_saveName = 0;
|
||||
static fileListT *_games = 0;
|
||||
static byte _longestName = 0;
|
||||
static fileListT *_selected = 0;
|
||||
static uint16_t _gameCount = 0;
|
||||
|
||||
|
||||
static void uiBox(byte x, byte y, byte w, byte h) {
|
||||
byte i;
|
||||
byte j;
|
||||
char *b = portSymbolsGet();
|
||||
|
||||
portCharSetPos(x, y);
|
||||
portCharPrint(b[0]);
|
||||
for (j=0; j<w-2; j++) portCharPrint(b[1]);
|
||||
portCharPrint(b[2]);
|
||||
|
||||
for (i=y+1; i<y+h-1; i++) {
|
||||
portCharSetPos(x, i);
|
||||
portCharPrint(b[7]);
|
||||
for (j=0; j<w-2; j++) portCharPrint(' ');
|
||||
portCharPrint(b[3]);
|
||||
}
|
||||
|
||||
portCharSetPos(x, y+h-1);
|
||||
portCharPrint(b[6]);
|
||||
for (j=0; j<w-2; j++) portCharPrint(b[5]);
|
||||
portCharPrint(b[4]);
|
||||
}
|
||||
|
||||
|
||||
static void uiCenter(char *m) {
|
||||
byte x;
|
||||
byte y;
|
||||
byte w = 80;
|
||||
byte l = libStrLen(m);
|
||||
|
||||
portCharGetPos(&x, &y);
|
||||
portCharSetPos((w - l) * 0.5, y);
|
||||
for (x=0; x<l; x++) portCharPrint(m[x]);
|
||||
portCharSetPos(1, y + 1);
|
||||
}
|
||||
|
||||
|
||||
static void uiDialog(byte fc, byte bc, byte tc, byte y, char *message) {
|
||||
byte l;
|
||||
byte x;
|
||||
|
||||
l = libStrLen(message);
|
||||
x = (_screenWidth - l) * 0.5 - 1;
|
||||
portColorSet(fc, bc);
|
||||
uiBox(x - 1, y, l + 4, 5);
|
||||
portColorSet(tc, bc);
|
||||
uiStringPrintAt(x + 1, y + 2, message);
|
||||
}
|
||||
|
||||
|
||||
void uiFileAdd(char *filename, uint32_t size) {
|
||||
uint32_t l;
|
||||
byte v;
|
||||
fileListT *newGame;
|
||||
fileListT *currentGame;
|
||||
|
||||
l = libStrLen(filename);
|
||||
|
||||
// Right now, we only support V1-V3 games. Filter the rest.
|
||||
if (l > 3) {
|
||||
if ((filename[l - 2] == 'z') || (filename[l - 2] == 'Z')) {
|
||||
if (filename[l - 3] == '.') {
|
||||
v = filename[l - 1] - '0';
|
||||
if (v <= 3) {
|
||||
// Add game to chooser.
|
||||
|
||||
// Create new game entry.
|
||||
newGame = (fileListT *)portMalloc(sizeof(fileListT));
|
||||
if (newGame == 0) portDie(MSG_UI_CANNOT_ALLOCATE, sizeof(fileListT));
|
||||
newGame->filename = (char *)portMalloc(l + 1);
|
||||
if (newGame->filename == 0) portDie(MSG_UI_CANNOT_ALLOCATE, l + 1);
|
||||
for (v=0; v<l+1; v++) newGame->filename[v] = filename[v];
|
||||
newGame->filesize = size;
|
||||
newGame->filenameLen = l;
|
||||
newGame->next = 0;
|
||||
|
||||
// Insert into list, sorted by filename.
|
||||
if ((_games == 0) || (libStrICmp(_games->filename, newGame->filename) >= 0)) {
|
||||
newGame->next = _games;
|
||||
_games = newGame;
|
||||
} else {
|
||||
currentGame = _games;
|
||||
while ((currentGame->next != 0) && (libStrICmp(currentGame->next->filename, newGame->filename) < 0)) {
|
||||
currentGame = currentGame->next;
|
||||
}
|
||||
newGame->next = currentGame->next;
|
||||
currentGame->next = newGame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uiGameSelect(void) {
|
||||
byte x;
|
||||
byte y;
|
||||
byte h;
|
||||
byte w;
|
||||
byte l;
|
||||
uint16_t i;
|
||||
fileListT *g;
|
||||
byte c;
|
||||
uint16_t top;
|
||||
uint16_t selector;
|
||||
|
||||
// ***TODO*** This doesn't check if filenames are too long to fit on the screen.
|
||||
|
||||
portCursorShow(false);
|
||||
uiTitleDraw();
|
||||
portCharGetPos(&x, &y);
|
||||
y += 2;
|
||||
|
||||
portFileLister();
|
||||
|
||||
// No games?
|
||||
if (_games == 0) {
|
||||
uiDialog(15, 4, 14, y, " No story files found! ");
|
||||
portCharGet();
|
||||
return;
|
||||
}
|
||||
|
||||
// Count games and find longest.
|
||||
g = _games;
|
||||
_gameCount = 0;
|
||||
while (g) {
|
||||
_gameCount++;
|
||||
if (g->filenameLen > _longestName) _longestName = g->filenameLen;
|
||||
g = g->next;
|
||||
}
|
||||
|
||||
// Draw chooser window.
|
||||
x = (_screenWidth - _longestName - 4) * 0.5;
|
||||
w = _longestName + 4;
|
||||
h = _screenHeight - y;
|
||||
portColorSet(15, 1);
|
||||
uiBox(x, y, w, h);
|
||||
|
||||
// Adjust for future drawing.
|
||||
x++;
|
||||
y++;
|
||||
h -= 2;
|
||||
w -= 2;
|
||||
|
||||
// Run chooser.
|
||||
top = 0;
|
||||
selector = 0;
|
||||
do {
|
||||
g = _games;
|
||||
// Skip games that have scrolled off the top.
|
||||
for (i=0; i<top; i++) {
|
||||
g = g->next;
|
||||
}
|
||||
// Draw list and selector.
|
||||
for (i=0; i<h; i++) {
|
||||
if (i == selector) {
|
||||
portColorSet(1, 7);
|
||||
_selected = g;
|
||||
} else {
|
||||
portColorSet(7, 1);
|
||||
}
|
||||
portCharSetPos(x, y + i);
|
||||
portCharPrint(' ');
|
||||
uiStringPrint(g->filename);
|
||||
for (c=g->filenameLen+1; c<w; c++) portCharPrint(' ');
|
||||
g = g->next;
|
||||
}
|
||||
// Get input.
|
||||
c = portCharGet();
|
||||
if (c == UI_KEY_DOWN) {
|
||||
if ((selector < h-1) && (selector < _gameCount-1)) {
|
||||
selector++;
|
||||
} else {
|
||||
if (top + h < _gameCount) {
|
||||
top++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == UI_KEY_UP) {
|
||||
if (selector > 0) {
|
||||
selector--;
|
||||
} else {
|
||||
if (top > 0) {
|
||||
top--;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (c != 13);
|
||||
|
||||
// Loading dialog.
|
||||
uiDialog(15, 8, 15, y + 3, " Loading story! ");
|
||||
|
||||
// Generate save game name.
|
||||
_saveName = (char *)portMalloc(_selected->filenameLen + 2);
|
||||
if (_saveName == 0) portDie(MSG_UI_CANNOT_ALLOCATE, _selected->filenameLen + 2);
|
||||
for (i=0; i<_selected->filenameLen; i++) _saveName[i] = _selected->filename[i];
|
||||
_saveName[_selected->filenameLen - 2] = 's';
|
||||
_saveName[_selected->filenameLen - 1] = 'a';
|
||||
_saveName[_selected->filenameLen ] = 'v';
|
||||
_saveName[_selected->filenameLen + 1] = 0;
|
||||
|
||||
// Get ready.
|
||||
stateReset();
|
||||
// uiStringPrint("stateReset()\n");
|
||||
portStoryLoad(_selected->filename, &_selected->filesize);
|
||||
// uiStringPrint("portStoryLoad()\n");
|
||||
storyChecksumCalculate();
|
||||
// uiStringPrint("storyChecksumCalculate()\n");
|
||||
opcodesSetup();
|
||||
storySetup();
|
||||
|
||||
// Set up display.
|
||||
portAttributeSet(TEXT_ATTR_NORMAL);
|
||||
portScreenClear();
|
||||
__state.savedX = 1;
|
||||
__state.savedY = storyScreenHeightLines();
|
||||
portCharSetPos(__state.savedX, __state.savedY);
|
||||
portCursorShow(true);
|
||||
|
||||
// Start the game!
|
||||
interpreterRun();
|
||||
}
|
||||
|
||||
|
||||
char *uiSaveGet(void) {
|
||||
return _saveName;
|
||||
}
|
||||
|
||||
|
||||
void uiSizeGet(byte *w, byte *h) {
|
||||
*w = _screenWidth;
|
||||
*h = _screenHeight;
|
||||
}
|
||||
|
||||
|
||||
void uiSizeSet(byte w, byte h) {
|
||||
_screenWidth = w;
|
||||
_screenHeight = h;
|
||||
}
|
||||
|
||||
|
||||
char *uiStoryGet(void) {
|
||||
return _selected->filename;
|
||||
}
|
||||
|
||||
|
||||
uint32_t uiStorySizeGet(void) {
|
||||
return _selected->filesize;
|
||||
}
|
||||
|
||||
|
||||
static void uiStringPrint(char *s) {
|
||||
byte i = 0;
|
||||
while (s[i] != 0) portCharPrint(s[i++]);
|
||||
}
|
||||
|
||||
|
||||
static void uiTitleDraw(void) {
|
||||
|
||||
portColorSet(9, 0);
|
||||
portScreenClear();
|
||||
portCharSetPos(1, 1);
|
||||
|
||||
uiCenter(" Welcome to... ");
|
||||
portColorSet(11, 0);
|
||||
uiCenter(" __ __ _ _ _ ");
|
||||
uiCenter("| \\/ | | | | | | ");
|
||||
uiCenter("| \\ / |_ _ __| | __| | | ___ ");
|
||||
uiCenter("| |\\/| | | | |/ _` |/ _` | |/ _ \\");
|
||||
uiCenter("| | | | |_| | (_| | (_| | | __/");
|
||||
uiCenter("|_| |_|\\__,_|\\__,_|\\__,_|_|\\___|");
|
||||
uiCenter("");
|
||||
portColorSet(9, 0);
|
||||
uiCenter(" Release 1.0 Beta 2 ");
|
||||
uiCenter("");
|
||||
portColorSet(12, 0);
|
||||
uiCenter("Copyright 2024 Scott Duensing, All Rights Reserved");
|
||||
portColorSet(4, 0);
|
||||
uiCenter("2024 Kangaroo Punch Studios https://kangaroopunch.com");
|
||||
}
|
Loading…
Add table
Reference in a new issue