172 lines
3.9 KiB
C
172 lines
3.9 KiB
C
/*
|
|
* 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 "zscii.h"
|
|
#include "portme.h"
|
|
#include "messages.h"
|
|
#include "story.h"
|
|
#include "state.h"
|
|
#include "memory.h"
|
|
#include "text.h"
|
|
|
|
|
|
char zsciiDecodeChar(uint16_t z) {
|
|
char c = 0;
|
|
|
|
//***TODO*** V6+ has more codes.
|
|
|
|
if ((z >= 32) && (z <= 126)) {
|
|
c = z; // ASCII
|
|
} else if (z == 13) {
|
|
c = '\n';
|
|
} else if ((z >= 155) && (z <= 251)) {
|
|
c = '?'; //***TODO*** Extended ZSCII
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
uint32_t zsciiPrint(uint32_t zstr, bool abbr) {
|
|
uint16_t code = 0;
|
|
uint8_t alphabet = 0;
|
|
uint8_t useAbbrTable = 0;
|
|
uint8_t zsciiCollector = 0;
|
|
uint16_t zsciiCode = 0;
|
|
uint32_t decodedChars = 0;
|
|
uint32_t pc = zstr;
|
|
char printVal = 0;
|
|
uint32_t index;
|
|
uint32_t ptr;
|
|
uint16_t abbrAddr;
|
|
uint32_t abbrDecodedChars;
|
|
int8_t i;
|
|
uint8_t ch;
|
|
int16_t newShift;
|
|
|
|
do {
|
|
code = ZPEEKW(pc);
|
|
pc += 2;
|
|
|
|
// Characters are 5 bits each, packed three to a 16-bit word.
|
|
for (i=10; i>=0; i-=5) {
|
|
|
|
newShift = 0;
|
|
printVal = 0;
|
|
ch = ((code >> i) & 0x1f);
|
|
|
|
if (zsciiCollector) {
|
|
if (zsciiCollector == 2) {
|
|
zsciiCode |= ((uint16_t)ch) << 5;
|
|
} else {
|
|
zsciiCode |= ((uint16_t)ch);
|
|
}
|
|
|
|
zsciiCollector--;
|
|
|
|
if (!zsciiCollector) {
|
|
printVal = zsciiDecodeChar(zsciiCode);
|
|
if (printVal) {
|
|
decodedChars++;
|
|
textCharPrint(printVal);
|
|
}
|
|
alphabet = 0;
|
|
useAbbrTable = 0;
|
|
zsciiCode = 0;
|
|
} // !zsciiCollector
|
|
|
|
continue;
|
|
|
|
} else if (useAbbrTable) { // zsciiCollector
|
|
|
|
if (abbr) portDie(MSG_INT_NO_ABBR);
|
|
|
|
index = ((32 * (((uint32_t)useAbbrTable) - 1)) + (uint32_t)ch);
|
|
ptr = storyAbbreviationTableAddress() + (index * 2);
|
|
abbrAddr = ZPEEKW(ptr);
|
|
ptr += 2;
|
|
|
|
decodedChars += zsciiPrint(abbrAddr * 2, true);
|
|
|
|
useAbbrTable = 0;
|
|
alphabet = 0; //***FIXME*** Version 3+ has no shift-lock but V1 needs it.
|
|
|
|
continue;
|
|
|
|
} // useAbbrTable
|
|
|
|
switch (ch) {
|
|
case 0:
|
|
printVal = ' ';
|
|
break;
|
|
|
|
case 1:
|
|
if (storyVersion() == 1) {
|
|
printVal = '\n';
|
|
} else {
|
|
useAbbrTable = 1;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
if (storyVersion() <= 2) {
|
|
portDie(MSG_INT_V12_SHIFT);
|
|
} else {
|
|
useAbbrTable = ch;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
case 5:
|
|
if (storyVersion() <= 2) {
|
|
portDie(MSG_INT_V12_SHIFT_LOCK);
|
|
} else {
|
|
newShift = 1;
|
|
alphabet = ch - 3;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((ch == 6) && (alphabet == 2)) {
|
|
zsciiCollector = 2;
|
|
} else {
|
|
printVal = __state.alphabetTable[(alphabet * 26) + (ch - 6)];
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (printVal) {
|
|
decodedChars++;
|
|
textCharPrint(printVal);
|
|
}
|
|
|
|
if (alphabet && !newShift) alphabet = 0;
|
|
|
|
} // for
|
|
|
|
// There is no NULL terminator, you look for a word with the top bit set.
|
|
} while ((code & (1 << 15)) == 0);
|
|
|
|
return pc - zstr;
|
|
}
|