Files
scummvm-cursorfix/engines/glk/scott/seas_of_blood.cpp
2026-02-02 04:50:13 +01:00

860 lines
24 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on ScottFree interpreter version 1.14 developed by Swansea
* University Computer Society without disassembly of any other game
* drivers, only of game databases as permitted by EEC law (for purposes
* of compatibility).
*
* Licensed under GPLv2
*
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
*/
#include "glk/scott/scott.h"
#include "glk/scott/saga_draw.h"
#include "glk/scott/resource.h"
#include "glk/scott/decompress_text.h"
#include "glk/scott/seas_of_blood.h"
namespace Glk {
namespace Scott {
#define VICTORY 0
#define LOSS 1
#define DRAW 2
#define FLEE 3
#define ERROR 99
int getEnemyStats(int *strike, int *stamina, int *boatFlag);
void battleLoop(int enemy, int strike, int stamina, int boatFlag);
void swapStaminaAndCrewStrength(void);
void bloodBattle(void);
void adventureSheet(void) {
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
g_scott->glk_set_style(style_Preformatted);
g_scott->output("\nADVENTURE SHEET\n\n");
g_scott->output("SKILL :");
g_scott->outputNumber(9);
g_scott->output(" STAMINA :");
g_scott->outputNumber(_G(_counters)[3]);
g_scott->output("\nLOG :");
g_scott->outputNumber(_G(_counters)[6]);
if (_G(_counters)[6] < 10)
g_scott->output(" PROVISIONS :");
else
g_scott->output(" PROVISIONS :"); // one less space!
g_scott->outputNumber(_G(_counters)[5]);
g_scott->output("\nCREW STRIKE:");
g_scott->outputNumber(9);
g_scott->output(" CREW STRENGTH:");
g_scott->outputNumber(_G(_counters)[7]);
g_scott->output("\n\n * * * * * * * * * * * * * * * * * * * * *\n\n");
g_scott->listInventory();
g_scott->output("\n");
g_scott->glk_set_style(style_Normal);
}
void bloodAction(int p) {
switch (p) {
case 0:
break;
case 1:
// Update LOG
_G(_counters)[6]++;
break;
case 2:
// Battle
g_scott->look();
g_scott->output("You are attacked \n");
g_scott->output("<HIT ENTER> \n");
g_scott->hitEnter();
bloodBattle();
break;
default:
error("bloodAction: Unhandled special action %d", p);
break;
}
}
void mirrorLeftHalf(void) {
for (int line = 0; line < 12; line++) {
for (int col = 32; col > 16; col--) {
_G(_buffer)[line * 32 + col - 1][8] = _G(_buffer)[line * 32 + (32 - col)][8];
for (int pixrow = 0; pixrow < 8; pixrow++)
_G(_buffer)[line * 32 + col - 1][pixrow] = _G(_buffer)[line * 32 + (32 - col)][pixrow];
flip(_G(_buffer)[line * 32 + col - 1]);
}
}
}
void replaceColour(uint8_t before, uint8_t after) {
// I don't think any of the data has bit 7 set,
// so masking it is probably unnecessary, but this is what
// the original code does.
uint8_t beforeink = before & 7;
uint8_t afterink = after & 7;
uint8_t inkmask = 0x07;
uint8_t beforepaper = beforeink << 3;
uint8_t afterpaper = afterink << 3;
uint8_t papermask = 0x38;
for (int j = 0; j < 384; j++) {
if ((_G(_buffer)[j][8] & inkmask) == beforeink) {
_G(_buffer)[j][8] = (_G(_buffer)[j][8] & ~inkmask) | afterink;
}
if ((_G(_buffer)[j][8] & papermask) == beforepaper) {
_G(_buffer)[j][8] = (_G(_buffer)[j][8] & ~papermask) | afterpaper;
}
}
}
void drawColour(uint8_t x, uint8_t y, uint8_t colour, uint8_t length) {
for (int i = 0; i < length; i++) {
_G(_buffer)[y * 32 + x + i][8] = colour;
}
}
void makeLight(void) {
for (int i = 0; i < 384; i++) {
_G(_buffer)[i][8] = _G(_buffer)[i][8] | 0x40;
}
}
void flipImage(void) {
uint8_t mirror[384][9];
for (int line = 0; line < 12; line++) {
for (int col = 32; col > 0; col--) {
for (int pixrow = 0; pixrow < 9; pixrow++)
mirror[line * 32 + col - 1][pixrow] = _G(_buffer)[line * 32 + (32 - col)][pixrow];
flip(mirror[line * 32 + col - 1]);
}
}
memcpy(_G(_buffer), mirror, 384 * 9);
}
void drawObjectImage(uint8_t x, uint8_t y) {
for (int i = 0; i < _G(_gameHeader)->_numItems; i++) {
if (_G(_items)[i]._flag != MY_LOC)
continue;
if (_G(_items)[i]._location != MY_LOC)
continue;
drawSagaPictureAtPos(_G(_items)[i]._image, x, y);
_G(_shouldDrawObjectImages) = 0;
}
}
void drawBlood(int loc) {
memset(_G(_buffer), 0, 384 * 9);
uint8_t *ptr = _G(_bloodImageData);
for (int i = 0; i < loc; i++) {
while (*(ptr) != 0xff)
ptr++;
ptr++;
}
while (ptr < _G(_bloodImageData) + 2010) {
switch (*ptr) {
case 0xff:
if (loc == 13) {
_G(_buffer)[8 * 32 + 18][8] = _G(_buffer)[8 * 32 + 18][8] & ~0x40;
_G(_buffer)[8 * 32 + 17][8] = _G(_buffer)[8 * 32 + 17][8] & ~0x40;
_G(_buffer)[8 * 32 + 9][8] = _G(_buffer)[8 * 32 + 9][8] & ~0x40;
_G(_buffer)[8 * 32 + 10][8] = _G(_buffer)[8 * 32 + 10][8] & ~0x40;
}
return;
case 0xfe:
mirrorLeftHalf();
break;
case 0xfD:
replaceColour(*(ptr + 1), *(ptr + 2));
ptr += 2;
break;
case 0xfc: // Draw colour: x, y, attribute, length
drawColour(*(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4));
ptr = ptr + 4;
break;
case 0xfb: // Make all screen colours bright
makeLight();
break;
case 0xfa: // Flip entire image horizontally
flipImage();
break;
case 0xf9: // Draw object image (if present) at x, y
drawObjectImage(*(ptr + 1), *(ptr + 2));
ptr = ptr + 2;
break;
default: // else draw image *ptr at x, y
drawSagaPictureAtPos(*ptr, *(ptr + 1), *(ptr + 2));
ptr = ptr + 2;
}
ptr++;
}
}
void seasOfBloodRoomImage(void) {
_G(_shouldDrawObjectImages) = 1;
drawBlood(MY_LOC);
for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++)
if (_G(_items)[ct]._image && _G(_shouldDrawObjectImages)) {
if ((_G(_items)[ct]._flag & 127) == MY_LOC && _G(_items)[ct]._location == MY_LOC) {
g_scott->drawImage(_G(_items)[ct]._image);
}
}
drawSagaPictureFromBuffer();
}
//static void SOBPrint(winid_t w, const char *fmt, ...)
//#ifdef __GNUC__
// __attribute__((__format__(__printf__, 2, 3)))
//#endif
// ;
static void SOBPrint(winid_t w, const char *fmt, ...) {
va_list ap;
char msg[2048];
int size = sizeof msg;
va_start(ap, fmt);
vsnprintf(msg, size, fmt, ap);
va_end(ap);
g_scott->glk_put_string_stream(g_scott->glk_window_get_stream(w), msg);
}
glui32 optimalDicePixelSize(glui32 *width, glui32 *height) {
int idealWidth = 8;
int idealHeight = 8;
*width = idealWidth;
*height = idealHeight;
int multiplier = 1;
uint graphwidth, graphheight;
g_scott->glk_window_get_size(_G(_leftDiceWin), &graphwidth, &graphheight);
multiplier = graphheight / idealHeight;
if ((glui32)(idealWidth * multiplier) > graphwidth)
multiplier = graphwidth / idealWidth;
if (multiplier < 2)
multiplier = 2;
multiplier = multiplier / 2;
*width = idealWidth * multiplier;
*height = idealHeight * multiplier;
return multiplier;
}
static void drawBorder(winid_t win) {
uint width, height;
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_window_get_size(win, &width, &height);
height--;
width -= 2;
g_scott->glk_window_move_cursor(win, 0, 0);
g_scott->glk_put_char_uni(0x250F); // Top left corner
for (glui32 i = 1; i < width; i++)
g_scott->glk_put_char_uni(0x2501); // Top
g_scott->glk_put_char_uni(0x2513); // Top right corner
for (glui32 i = 1; i < height; i++) {
g_scott->glk_window_move_cursor(win, 0, i);
g_scott->glk_put_char_uni(0x2503);
g_scott->glk_window_move_cursor(win, width, i);
g_scott->glk_put_char_uni(0x2503);
}
g_scott->glk_window_move_cursor(win, 0, height);
g_scott->glk_put_char_uni(0x2517);
for (glui32 i = 1; i < width; i++)
g_scott->glk_put_char_uni(0x2501);
g_scott->glk_put_char_uni(0x251B);
}
static void redrawStaticText(winid_t win, int boatFlag) {
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_window_move_cursor(win, 2, 4);
if (boatFlag) {
g_scott->glk_put_string("STRIKE :\n");
g_scott->glk_window_move_cursor(win, 2, 5);
g_scott->glk_put_string("CRW STR :");
} else {
g_scott->glk_put_string("SKILL :\n");
g_scott->glk_window_move_cursor(win, 2, 5);
g_scott->glk_put_string("STAMINA :");
}
if (win == _G(_battleRight)) {
uint width;
g_scott->glk_window_get_size(_G(_battleRight), &width, 0);
g_scott->glk_window_move_cursor(_G(_battleRight), width - 6, 1);
g_scott->glk_put_string("YOU");
}
}
static void redrawBattleScreen(int boatFlag) {
uint graphwidth, graphheight;
glui32 optimal_width, optimal_height;
g_scott->glk_window_get_size(_G(_leftDiceWin), &graphwidth, &graphheight);
_G(_dicePixelSize) = optimalDicePixelSize(&optimal_width, &optimal_height);
_G(_diceXOffset) = (graphwidth - optimal_width) / 2;
_G(_diceYOffset) = (graphheight - optimal_height - _G(_dicePixelSize)) / 2;
drawBorder(_G(_topWindow));
drawBorder(_G(_battleRight));
redrawStaticText(_G(_topWindow), boatFlag);
redrawStaticText(_G(_battleRight), boatFlag);
}
static void setupBattleScreen(int boatFlag) {
winid_t parent = g_scott->glk_window_get_parent(_G(_topWindow));
g_scott->glk_window_set_arrangement(parent, winmethod_Above | winmethod_Fixed, 7, _G(_topWindow));
g_scott->glk_window_clear(_G(_topWindow));
g_scott->glk_window_clear(_G(_bottomWindow));
_G(_battleRight) = g_scott->glk_window_open(_G(_topWindow), winmethod_Right | winmethod_Proportional,
50, wintype_TextGrid, 0);
_G(_leftDiceWin) = g_scott->glk_window_open(_G(_topWindow), winmethod_Right | winmethod_Proportional,
30, wintype_Graphics, 0);
_G(_rightDiceWin) = g_scott->glk_window_open(_G(_battleRight), winmethod_Left | winmethod_Proportional, 30,
wintype_Graphics, 0);
// Set the graphics window background to match the top window background, best as we can, and clear the window.
if (g_scott->glk_style_measure(_G(_topWindow), style_Normal, stylehint_BackColor,
&_G(_backgroundColour))) {
g_scott->glk_window_set_background_color(_G(_leftDiceWin), _G(_backgroundColour));
g_scott->glk_window_set_background_color(_G(_rightDiceWin), _G(_backgroundColour));
g_scott->glk_window_clear(_G(_leftDiceWin));
g_scott->glk_window_clear(_G(_rightDiceWin));
}
if (_G(_palChosen) == C64B)
_G(_diceColour) = 0x5f48e9;
else
_G(_diceColour) = 0xff0000;
redrawBattleScreen(boatFlag);
}
void bloodBattle(void) {
int enemy, strike, stamina, boatFlag;
enemy = getEnemyStats(&strike, &stamina, &boatFlag); // Determine their stats
if (enemy == 0) {
error("Seas of blood battle: No enemy in location?\n");
return;
}
setupBattleScreen(boatFlag);
battleLoop(enemy, strike, stamina, boatFlag); // Into the battle loops
if (boatFlag)
swapStaminaAndCrewStrength(); // Switch back stamina - crew strength
g_scott->glk_window_close(_G(_leftDiceWin), nullptr);
g_scott->glk_window_close(_G(_rightDiceWin), nullptr);
g_scott->glk_window_close(_G(_battleRight), nullptr);
g_scott->closeGraphicsWindow();
g_scott->openGraphicsWindow();
seasOfBloodRoomImage();
}
int getEnemyStats(int *strike, int *stamina, int *boatFlag) {
int enemy, i = 0;
while (i < 124) {
enemy = _G(_enemyTable)[i];
if (_G(_items)[enemy]._location == MY_LOC) {
i++;
*strike = _G(_enemyTable)[i++];
*stamina = _G(_enemyTable)[i++];
*boatFlag = _G(_enemyTable)[i];
if (*boatFlag) {
swapStaminaAndCrewStrength(); // Switch stamina - crew strength
}
return enemy;
}
i = i + 4; // Skip to next entry
}
return 0;
}
void drawRect(winid_t win, int32_t x, int32_t y, int32_t width, int32_t height,
int32_t color) {
g_scott->glk_window_fill_rect(win, color, x * _G(_dicePixelSize) + _G(_diceXOffset),
y * _G(_dicePixelSize) + _G(_diceYOffset),
width * _G(_dicePixelSize), height * _G(_dicePixelSize));
}
void drawGraphicalDice(winid_t win, int number) {
// The eye-less dice backgrounds consist of two rectangles on top of each
// other
drawRect(win, 1, 2, 7, 5, _G(_diceColour));
drawRect(win, 2, 1, 5, 7, _G(_diceColour));
switch (number + 1) {
case 1:
drawRect(win, 4, 4, 1, 1, _G(_backgroundColour));
break;
case 2:
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
break;
case 3:
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
drawRect(win, 4, 4, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
break;
case 4:
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
drawRect(win, 2, 2, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 6, 1, 1, _G(_backgroundColour));
break;
case 5:
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
drawRect(win, 2, 2, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 6, 1, 1, _G(_backgroundColour));
drawRect(win, 4, 4, 1, 1, _G(_backgroundColour));
break;
case 6:
drawRect(win, 2, 6, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 2, 1, 1, _G(_backgroundColour));
drawRect(win, 2, 2, 1, 1, _G(_backgroundColour));
drawRect(win, 2, 4, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 4, 1, 1, _G(_backgroundColour));
drawRect(win, 6, 6, 1, 1, _G(_backgroundColour));
break;
default:
break;
}
}
void updateDice(int ourTurn, int leftDice, int rightDice) {
leftDice--;
rightDice--;
g_scott->glk_window_clear(_G(_leftDiceWin));
g_scott->glk_window_clear(_G(_rightDiceWin));
_G(_diceXOffset) = _G(_diceXOffset) - _G(_dicePixelSize);
drawGraphicalDice(_G(_leftDiceWin), leftDice);
_G(_diceXOffset) = _G(_diceXOffset) + _G(_dicePixelSize);
drawGraphicalDice(_G(_rightDiceWin), rightDice);
winid_t win = ourTurn ? _G(_battleRight) : _G(_topWindow);
g_scott->glk_window_move_cursor(win, 2, 1);
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_put_char_uni(0x2680 + leftDice);
g_scott->glk_put_char('+');
g_scott->glk_put_char_uni(0x2680 + rightDice);
g_scott->glk_window_move_cursor(win, 2, 2);
SOBPrint(win, "%d %d", leftDice + 1, rightDice + 1);
}
void printSum(int ourTurn, int sum, int strike) {
winid_t win = ourTurn ? _G(_battleRight) : _G(_topWindow);
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_window_move_cursor(win, 6, 1);
SOBPrint(win, "+ %d = %d", strike, sum);
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_battleRight)));
g_scott->glk_window_move_cursor(_G(_battleRight), 6, 1);
g_scott->glk_put_string("+ 9 = ");
}
void updateResult(int ourTurn, int strike, int stamina, int boatFlag) {
winid_t win = ourTurn ? _G(_battleRight) : _G(_topWindow);
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_window_move_cursor(win, 2, 4);
if (boatFlag) {
SOBPrint(win, "STRIKE : %d\n", strike);
g_scott->glk_window_move_cursor(win, 2, 5);
SOBPrint(win, "CRW STR : %d", stamina);
} else {
SOBPrint(win, "SKILL : %d\n", strike);
g_scott->glk_window_move_cursor(win, 2, 5);
SOBPrint(win, "STAMINA : %d", stamina);
}
}
void clearResult(void) {
winid_t win = _G(_topWindow);
uint width;
for (int j = 0; j < 2; j++) {
g_scott->glk_window_get_size(win, &width, 0);
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_window_move_cursor(win, 11, 1);
for (int i = 0; i < 10; i++)
g_scott->glk_put_string(" ");
drawBorder(win);
win = _G(_battleRight);
}
}
void clearStamina(void) {
winid_t win = _G(_topWindow);
uint width;
for (int j = 0; j < 2; j++) {
g_scott->glk_window_get_size(win, &width, 0);
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(win));
g_scott->glk_window_move_cursor(win, 11, 5);
for (int i = 0; i < (int)width - 13; i++)
g_scott->glk_put_string(" ");
drawBorder(win);
win = _G(_battleRight);
}
}
static void rearrangeBattleDisplay(int strike, int stamina, int boatFlag) {
g_scott->updateSettings();
g_scott->glk_cancel_char_event(_G(_topWindow));
g_scott->closeGraphicsWindow();
g_scott->glk_window_close(_G(_battleRight), nullptr);
g_scott->glk_window_close(_G(_leftDiceWin), nullptr);
g_scott->glk_window_close(_G(_rightDiceWin), nullptr);
seasOfBloodRoomImage();
setupBattleScreen(boatFlag);
updateResult(0, strike, stamina, boatFlag);
updateResult(1, 9, _G(_counters)[3], boatFlag);
drawBorder(_G(_topWindow));
drawBorder(_G(_battleRight));
redrawStaticText(_G(_topWindow), boatFlag);
redrawStaticText(_G(_battleRight), boatFlag);
g_scott->glk_request_char_event(_G(_topWindow));
}
int rollDice(int strike, int stamina, int boatFlag) {
clearResult();
redrawStaticText(_G(_battleRight), boatFlag);
g_scott->glk_request_timer_events(60);
int rolls = 0;
int ourTurn = 0;
int leftDice = 1 + g_scott->getRandomNumber(100) % 6;
int rightDice = 1 + g_scott->getRandomNumber(100) % 6;
int ourResult;
int theirResult = 0;
int theirDiceStopped = 0;
event_t event;
int enemyRolls = 20 + g_scott->getRandomNumber(100) % 10;
g_scott->glk_cancel_char_event(_G(_topWindow));
g_scott->glk_request_char_event(_G(_topWindow));
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
g_scott->glk_put_string("Their throw");
int delay = 60;
while (!g_vm->shouldQuit()) {
g_scott->glk_select(&event);
if (event.type == evtype_Timer) {
if (theirDiceStopped) {
g_scott->glk_request_timer_events(60);
theirDiceStopped = 0;
printSum(ourTurn, theirResult, strike);
ourTurn = 1;
g_scott->glk_window_clear(_G(_bottomWindow));
g_scott->glk_cancel_char_event(_G(_topWindow));
g_scott->glk_request_char_event(_G(_topWindow));
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
g_scott->glk_put_string("Your throw\n");
g_scott->glk_put_string("<ENTER> to stop dice");
if (!boatFlag)
g_scott->glk_put_string(" <X> to run");
} else if (ourTurn == 0) {
g_scott->glk_request_timer_events(delay);
}
rolls++;
if (rolls % 2)
leftDice = 1 + g_scott->getRandomNumber(100) % 6;
else
rightDice = 1 + g_scott->getRandomNumber(100) % 6;
updateDice(ourTurn, leftDice, rightDice);
if (ourTurn == 0 && rolls == enemyRolls) {
g_scott->glk_window_clear(_G(_bottomWindow));
theirResult = leftDice + rightDice + strike;
SOBPrint(_G(_bottomWindow), "Their result: %d + %d + %d = %d\n", leftDice,
rightDice, strike, theirResult);
g_scott->glk_request_timer_events(1000);
theirDiceStopped = 1;
}
}
if (event.type == evtype_CharInput) {
if (ourTurn && (event.val1 == keycode_Return)) {
updateDice(ourTurn, leftDice, rightDice);
ourResult = leftDice + rightDice + 9;
printSum(ourTurn, ourResult, 9);
if (theirResult > ourResult) {
return LOSS;
} else if (ourResult > theirResult) {
return VICTORY;
} else {
return DRAW;
}
} else if (MY_LOC != 1 && (event.val1 == 'X' || event.val1 == 'x')) {
MY_LOC = _G(_savedRoom);
return FLEE;
} else {
g_scott->glk_request_char_event(_G(_topWindow));
}
}
if (event.type == evtype_Arrange) {
rearrangeBattleDisplay(strike, stamina, boatFlag);
}
}
return ERROR;
}
void battleHitEnter(int strike, int stamina, int boatFlag) {
g_scott->glk_request_char_event(_G(_bottomWindow));
event_t ev;
int result = 0;
do {
g_scott->glk_select(&ev);
if (ev.type == evtype_CharInput) {
if (ev.val1 == keycode_Return) {
result = 1;
} else {
g_scott->glk_request_char_event(_G(_bottomWindow));
}
}
if (ev.type == evtype_Arrange) {
rearrangeBattleDisplay(strike, stamina, boatFlag);
}
} while (result == 0 && !g_vm->shouldQuit());
}
void battleLoop(int enemy, int strike, int stamina, int boatFlag) {
updateResult(0, strike, stamina, boatFlag);
updateResult(1, 9, _G(_counters)[3], boatFlag);
do {
int result = rollDice(strike, stamina, boatFlag);
g_scott->glk_cancel_char_event(_G(_topWindow));
g_scott->glk_window_clear(_G(_bottomWindow));
clearStamina();
g_scott->glk_stream_set_current(g_scott->glk_window_get_stream(_G(_bottomWindow)));
if (result == LOSS) {
_G(_counters)[3] -= 2;
if (_G(_counters)[3] <= 0) {
SOBPrint(_G(_bottomWindow), "%s\n",
boatFlag ? "THE BANSHEE HAS BEEN SUNK!"
: "YOU HAVE BEEN KILLED!");
_G(_counters)[3] = 0;
_G(_bitFlags) |= (1 << 6);
_G(_counters)[7] = 0;
} else {
SOBPrint(_G(_bottomWindow), "%s", _G(_battleMessages)[1 + g_scott->getRandomNumber(100) % 5 + 16 * boatFlag]);
}
} else if (result == VICTORY) {
stamina -= 2;
if (stamina <= 0) {
g_scott->glk_put_string("YOU HAVE WON!\n");
_G(_bitFlags) &= ~(1 << 6);
stamina = 0;
} else {
SOBPrint(_G(_bottomWindow), "%s", _G(_battleMessages)[6 + g_scott->getRandomNumber(100) % 5 + 16 * boatFlag]);
}
} else if (result == FLEE) {
_G(_bitFlags) |= (1 << 6);
MY_LOC = _G(_savedRoom);
return;
} else {
SOBPrint(_G(_bottomWindow), "%s", _G(_battleMessages)[11 + g_scott->getRandomNumber(100) % 5 + 16 * boatFlag]);
}
g_scott->glk_put_string("\n\n");
if (_G(_counters)[3] > 0 && stamina > 0) {
g_scott->glk_put_string("<ENTER> to roll dice");
if (!boatFlag)
g_scott->glk_put_string(" <X> to run");
}
updateResult(0, strike, stamina, boatFlag);
updateResult(1, 9, _G(_counters)[3], boatFlag);
battleHitEnter(strike, stamina, boatFlag);
g_scott->glk_window_clear(_G(_bottomWindow));
} while (stamina > 0 && _G(_counters)[3] > 0 && !g_vm->shouldQuit());
}
void swapStaminaAndCrewStrength(void) {
uint8_t temp = _G(_counters)[7]; // Crew strength
_G(_counters)[7] = _G(_counters)[3]; // Stamina
_G(_counters)[3] = temp;
}
int loadExtraSeasOfBloodData(void) {
_G(_drawToBuffer) = 1;
int offset;
offset = 0x47b7 + _G(_fileBaselineOffset);
uint8_t *ptr = seekToPos(_G(_entireFile), offset);
int ct;
for (ct = 0; ct < 124; ct++) {
_G(_enemyTable)[ct] = *(ptr++);
if (_G(_enemyTable)[ct] == 0xff)
break;
}
ptr = seekToPos(_G(_entireFile), 0x71DA + _G(_fileBaselineOffset));
for (int i = 0; i < 32; i++) {
_G(_battleMessages)[i] = decompressText(ptr, i);
}
offset = 0x7af5 - 16357 + _G(_fileBaselineOffset);
int data_length = 2010;
_G(_bloodImageData) = new uint8_t[data_length];
ptr = seekToPos(_G(_entireFile), offset);
for (int i = 0; i < data_length; i++)
_G(_bloodImageData)[i] = *(ptr++);
for (int i = I_DONT_UNDERSTAND; i <= THATS_BEYOND_MY_POWER; i++)
_G(_sys)[i] = _G(_systemMessages)[4 - I_DONT_UNDERSTAND + i];
for (int i = YOU_ARE; i <= HIT_ENTER; i++)
_G(_sys)[i] = _G(_systemMessages)[13 - YOU_ARE + i];
_G(_sys)[OK] = _G(_systemMessages)[2];
_G(_sys)[PLAY_AGAIN] = _G(_systemMessages)[3];
_G(_sys)[YOURE_CARRYING_TOO_MUCH] = _G(_systemMessages)[27];
_G(_items)[125]._text = "A loose plank";
_G(_items)[125]._autoGet = "PLAN";
return 0;
}
int loadExtraSeasOfBlood64Data(void) {
_G(_drawToBuffer) = 1;
int offset;
offset = 0x3fee + _G(_fileBaselineOffset);
uint8_t *ptr;
ptr = seekToPos(_G(_entireFile), offset);
int ct;
for (ct = 0; ct < 124; ct++) {
_G(_enemyTable)[ct] = *(ptr++);
if (_G(_enemyTable)[ct] == 0xff)
break;
}
offset = 0x82f6 + _G(_fileBaselineOffset);
ptr = seekToPos(_G(_entireFile), offset);
for (int i = 0; i < 32; i++) {
_G(_battleMessages)[i] = decompressText(ptr, i);
}
offset = 0x5299 + _G(_fileBaselineOffset);
int data_length = 2010;
_G(_bloodImageData) = new uint8_t[data_length];
ptr = seekToPos(_G(_entireFile), offset);
for (int i = 0; i < data_length; i++) {
_G(_bloodImageData)[i] = *(ptr++);
}
SysMessageType messagekey[] = {
NORTH,
SOUTH,
EAST,
WEST,
UP,
DOWN,
EXITS,
YOU_SEE,
YOU_ARE,
YOU_CANT_GO_THAT_WAY,
OK,
WHAT_NOW,
HUH,
YOU_HAVE_IT,
YOU_HAVENT_GOT_IT,
DROPPED,
TAKEN,
INVENTORY,
YOU_DONT_SEE_IT,
THATS_BEYOND_MY_POWER,
DIRECTION,
YOURE_CARRYING_TOO_MUCH,
PLAY_AGAIN,
RESUME_A_SAVED_GAME,
YOU_CANT_DO_THAT_YET,
I_DONT_UNDERSTAND,
NOTHING};
for (int i = 0; i < 27; i++) {
_G(_sys)[messagekey[i]] = _G(_systemMessages)[i];
}
return 0;
}
} // End of namespace Scott
} // End of namespace Glk