/* 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 . * */ /* * 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/types.h" #include "glk/scott/globals.h" #include "glk/scott/resource.h" #include "glk/scott/saga_draw.h" #include "glk/scott/decompress_text.h" #include "glk/scott/robin_of_sherwood.h" namespace Glk { namespace Scott { #define WATERFALL_ANIMATION_RATE 15 void animateLightning(int stage); void sherwoodAction(int p) { event_t ev; switch (p) { case 0: // Flash animation _G(_animationFlag) = 1; g_scott->glk_request_timer_events(15); while (_G(_animationFlag) < 11) { g_scott->glk_select(&ev); if (ev.type == evtype_Timer) { _G(_animationFlag)++; animateLightning(_G(_animationFlag)); } } break; case 1: g_scott->drawImage(0); /* Herne */ g_scott->display(_G(_bottomWindow), "\n%s\n", _G(_sys)[HIT_ENTER].c_str()); g_scott->hitEnter(); _G(_items)[39]._location = 79; g_scott->look(); break; case 2: // Climbing tree in forest _G(_savedRoom) = MY_LOC; MY_LOC = 93; g_scott->look(); break; default: error("sherwoodAction: Unhandled SherwoodAction %d!", p); break; } } int isForestLocation(void) { return (MY_LOC >= 11 && MY_LOC <= 73); } #define TREES 0 #define BUSHES 1 void drawSherwood(int loc) { g_scott->glk_window_clear(_G(_graphics)); int subimage_index = 0; for (int i = 0; i < loc - 11; i++) { // BUSHES type images are made up of 5 smaller images int skip = 5; if (_G(_forestImages)[subimage_index] < 128) // Those with bit 7 unset have 10 (trees only) or 11 (trees with path) skip = 11; subimage_index += skip; } int forest_type = TREES; int subimages; // if bit 7 of the image index is set then this image is BUSHES if (_G(_forestImages)[subimage_index] >= 128) { forest_type = BUSHES; subimages = 5; // if the last subimage value is 255, there is no path } else if (_G(_forestImages)[subimage_index + 10] == 0xff) { // Trees only subimages = 10; } else { // Trees with path subimages = 11; } int xpos = 0, ypos = 0, image_number; for (int i = 0; i < subimages; i++) { if (forest_type == TREES) { if (i >= 8) { if (i == 8) { // Undergrowth ypos = 7; xpos = 0; } else if (i == 9) { // _G(_bottomWindow) path ypos = 10; xpos = 0; } else { // Forward path ypos = 7; xpos = 12; } } else { // Trees (every tree image is 4 characters wide) ypos = 0; xpos = i * 4; } } image_number = _G(_forestImages)[subimage_index++] & 127; drawSagaPictureAtPos(image_number, xpos, ypos); if (forest_type == BUSHES) { xpos += _G(_images)[image_number]._width; } } } void animateWaterfall(int stage) { rectFill(88, 16, 48, 64, _G(_whiteColour)); for (int line = 2; line < 10; line++) { for (int col = 11; col < 17; col++) { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) if ((_G(_screenchars)[col + line * 32][i] & (1 << j)) != 0) { int ypos = line * 8 + i + stage; if (ypos > 79) ypos = ypos - 64; putPixel(col * 8 + j, ypos, _G(_blueColour)); } } } } void animateWaterfallCave(int stage) { rectFill(248, 24, 8, 64, _G(_whiteColour)); for (int line = 3; line < 11; line++) { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) if ((_G(_screenchars)[31 + line * 32][i] & (1 << j)) != 0) { int ypos = line * 8 + i + stage; if (ypos > 87) ypos = ypos - 64; putPixel(248 + j, ypos, _G(_blueColour)); } } } void animateLightning(int stage) { // swich blue and bright yellow if (_G(_palChosen) == C64B) switchPalettes(6, 7); else { switchPalettes(1, 14); switchPalettes(9, 6); } drawSagaPictureNumber(77); if (stage == 11) { g_scott->glk_request_timer_events(0); } else if (stage == 3) { g_scott->glk_request_timer_events(700); } else { g_scott->glk_request_timer_events(40); } } void robinOfSherwoodLook(void) { if (!isForestLocation()) { if (_G(_rooms)[MY_LOC]._image == 255) { g_scott->closeGraphicsWindow(); } else { g_scott->drawImage(_G(_rooms)[MY_LOC]._image); for (int ct = 0; ct <= _G(_gameHeader)->_numItems; ct++) if (_G(_items)[ct]._image) { if ((_G(_items)[ct]._flag & 127) == MY_LOC && _G(_items)[ct]._location == MY_LOC) { g_scott->drawImage(_G(_items)[ct]._image); } } } } if (MY_LOC == 82) // Dummy room where exit from Up a tree goes MY_LOC = _G(_savedRoom); if (MY_LOC == 93) // Up a tree for (int i = 0; i < _G(_gameHeader)->_numItems; i++) if (_G(_items)[i]._location == 93) _G(_items)[i]._location = _G(_savedRoom); if (MY_LOC == 7 && _G(_items)[62]._location == 7) // Left bedroom, open treasure chest g_scott->drawImage(70); if (isForestLocation()) { g_scott->openGraphicsWindow(); drawSherwood(MY_LOC); if (_G(_items)[36]._location == MY_LOC) { //"Gregory the tax collector with his horse and cart" g_scott->drawImage(15); // Horse and cart g_scott->drawImage(3); // Sacks of grain } if (_G(_items)[60]._location == MY_LOC || _G(_items)[77]._location == MY_LOC) { // "A serf driving a horse and cart" g_scott->drawImage(15); // Horse and cart g_scott->drawImage(12); // Hay } if (MY_LOC == 73) { // Outlaws camp g_scott->drawImage(36); // Campfire } } if (MY_LOC == 86 || MY_LOC == 79) { g_scott->glk_request_timer_events(WATERFALL_ANIMATION_RATE); } } void updateRobinOfSherwoodAnimations(void) { _G(_animationFlag)++; if (_G(_animationFlag) > 63) _G(_animationFlag) = 0; if (MY_LOC == 86 || MY_LOC == 79 || MY_LOC == 84) { /* If we're in room 84, the stone circle, we just */ /* want the timer to not switch off */ if (MY_LOC == 86) { animateWaterfall(_G(_animationFlag)); } else if (MY_LOC == 79) { animateWaterfallCave(_G(_animationFlag)); } } else { g_scott->glk_request_timer_events(0); } } GameIDType loadExtraSherwoodData(void) { int offset = 0x3d99 + _G(_fileBaselineOffset); uint8_t *ptr; /* Load the room images */ ptr = seekToPos(_G(_entireFile), offset); if (ptr == 0) return UNKNOWN_GAME; int ct; Room *rp = &_G(_rooms)[0]; for (ct = 0; ct <= _G(_gameHeader)->_numRooms; ct++) { rp->_image = *(ptr++); rp++; if (ct == 10) { for (int i = 0; i < 63; i++) { rp++; ct++; } } } ct = 0; rp = &_G(_rooms)[0]; //int actual_room_number = 0; ptr = seekToPos(_G(_entireFile), 0x5b7e + _G(_fileBaselineOffset)); if (ptr == 0) return UNKNOWN_GAME; do { rp->_text = decompressText(ptr, ct); rp->_text.toLowercase(); ct++; //actual_room_number++; if (ct == 11) { for (int i = 0; i < 61; i++) { rp++; rp->_text = "in Sherwood Forest"; //actual_room_number++; } } rp++; } while (ct < 33); 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_SEE; i <= HIT_ENTER; i++) _G(_sys)[i] = _G(_systemMessages)[15 - YOU_SEE + i]; _G(_sys)[OK] = _G(_systemMessages)[2]; _G(_sys)[TAKEN] = _G(_systemMessages)[2]; _G(_sys)[DROPPED] = _G(_systemMessages)[2]; _G(_sys)[PLAY_AGAIN] = _G(_systemMessages)[3]; _G(_sys)[YOURE_CARRYING_TOO_MUCH] = _G(_systemMessages)[21]; _G(_sys)[YOU_CANT_GO_THAT_WAY] = _G(_systemMessages)[12]; _G(_sys)[YOU_ARE] = _G(_systemMessages)[13]; _G(_sys)[EXITS_DELIMITER] = " "; _G(_sys)[MESSAGE_DELIMITER] = ". "; ptr = seekToPos(_G(_entireFile), 0x3b6e + _G(_fileBaselineOffset)); if (ptr == 0) return UNKNOWN_GAME; int cells = 555; _G(_forestImages) = new uint8_t[cells]; for (int i = 0; i < cells; i++) _G(_forestImages)[i] = *(ptr++); return ROBIN_OF_SHERWOOD; } GameIDType loadExtraSherwoodData64(void) { // white_colour = 1; // blue = 6; int offset = 0x1ffd + _G(_fileBaselineOffset); uint8_t *ptr; /* Load the room images */ ptr = seekToPos(_G(_entireFile), offset); if (ptr == 0) return UNKNOWN_GAME; int ct; Room *rp = &_G(_rooms)[0]; for (ct = 0; ct <= _G(_gameHeader)->_numRooms; ct++) { rp->_image = *(ptr++); rp++; if (ct == 10) { for (int i = 0; i < 63; i++) { rp++; ct++; } } } ct = 0; rp = &_G(_rooms)[0]; //int actual_room_number = 0; offset = 0x402e + _G(_fileBaselineOffset); ptr = seekToPos(_G(_entireFile), offset); if (ptr == 0) return UNKNOWN_GAME; do { rp->_text = decompressText(ptr, ct); rp->_text.toLowercase(); ct++; //actual_room_number++; if (ct == 11) { for (int i = 0; i < 61; i++) { rp++; rp->_text = "in Sherwood Forest"; //actual_room_number++; } } rp++; } while (ct < 33); SysMessageType messagekey[] = {NORTH, SOUTH, EAST, WEST, UP, DOWN, EXITS, YOU_SEE, YOU_ARE, HIT_ENTER, YOU_CANT_GO_THAT_WAY, OK, WHAT_NOW, HUH, YOU_HAVE_IT, TAKEN, DROPPED, YOU_HAVENT_GOT_IT, 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 < 26; i++) { _G(_sys)[messagekey[i]] = _G(_systemMessages)[i]; } _G(_sys)[HIT_ENTER] = _G(_systemMessages)[30]; _G(_sys)[WHAT] = _G(_systemMessages)[13]; _G(_sys)[EXITS_DELIMITER] = " "; _G(_sys)[MESSAGE_DELIMITER] = ". "; offset = 0x2300 + _G(_fileBaselineOffset); ptr = seekToPos(_G(_entireFile), offset); if (ptr == 0) return UNKNOWN_GAME; int cells = 555; _G(_forestImages) = new uint8_t[cells]; for (int i = 0; i < cells; i++) { _G(_forestImages)[i] = *(ptr++); } return ROBIN_OF_SHERWOOD_C64; } } // End of namespace Scott } // End of namespace Glk