Initial commit
This commit is contained in:
101
engines/glk/hugo/detection.cpp
Normal file
101
engines/glk/hugo/detection.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/detection.h"
|
||||
#include "glk/hugo/detection_tables.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "common/md5.h"
|
||||
#include "engines/game.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
void HugoMetaEngine::getSupportedGames(PlainGameList &games) {
|
||||
for (const PlainGameDescriptor *pd = HUGO_GAME_LIST; pd->gameId; ++pd) {
|
||||
games.push_back(*pd);
|
||||
}
|
||||
}
|
||||
|
||||
const GlkDetectionEntry* HugoMetaEngine::getDetectionEntries() {
|
||||
return HUGO_GAMES;
|
||||
}
|
||||
|
||||
GameDescriptor HugoMetaEngine::findGame(const char *gameId) {
|
||||
for (const PlainGameDescriptor *pd = HUGO_GAME_LIST; pd->gameId; ++pd) {
|
||||
if (!strcmp(gameId, pd->gameId))
|
||||
return *pd;
|
||||
}
|
||||
|
||||
return PlainGameDescriptor::empty();
|
||||
}
|
||||
|
||||
bool HugoMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
|
||||
const char *const EXTENSIONS[] = { ".hex", nullptr };
|
||||
|
||||
// Loop through the files of the folder
|
||||
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
|
||||
// Check for a recognised filename
|
||||
if (file->isDirectory())
|
||||
continue;
|
||||
Common::String filename = file->getName();
|
||||
bool hasExt = false;
|
||||
for (const char *const *ext = &EXTENSIONS[0]; *ext && !hasExt; ++ext)
|
||||
hasExt = filename.hasSuffixIgnoreCase(*ext);
|
||||
if (!hasExt)
|
||||
continue;
|
||||
|
||||
// Open up the file and calculate the md5
|
||||
Common::File gameFile;
|
||||
if (!gameFile.open(*file))
|
||||
continue;
|
||||
|
||||
Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
|
||||
size_t filesize = gameFile.size();
|
||||
gameFile.close();
|
||||
|
||||
// Check for known games
|
||||
const GlkDetectionEntry *p = HUGO_GAMES;
|
||||
while (p->_gameId && (md5 != p->_md5 || filesize != p->_filesize))
|
||||
++p;
|
||||
|
||||
if (!p->_gameId) {
|
||||
const PlainGameDescriptor &desc = HUGO_GAME_LIST[0];
|
||||
gameList.push_back(GlkDetectedGame(desc.gameId, desc.description, filename, md5, filesize));
|
||||
} else {
|
||||
PlainGameDescriptor gameDesc = findGame(p->_gameId);
|
||||
gameList.push_back(GlkDetectedGame(p->_gameId, gameDesc.description, p->_extra, filename, p->_language));
|
||||
}
|
||||
}
|
||||
|
||||
return !gameList.empty();
|
||||
}
|
||||
|
||||
void HugoMetaEngine::detectClashes(Common::StringMap &map) {
|
||||
for (const PlainGameDescriptor *pd = HUGO_GAME_LIST; pd->gameId; ++pd) {
|
||||
if (map.contains(pd->gameId))
|
||||
error("Duplicate game Id found - %s", pd->gameId);
|
||||
map[pd->gameId] = "";
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
67
engines/glk/hugo/detection.h
Normal file
67
engines/glk/hugo/detection.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_HUGO_DETECTION
|
||||
#define GLK_HUGO_DETECTION
|
||||
|
||||
#include "common/fs.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "engines/game.h"
|
||||
#include "glk/detection.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
/**
|
||||
* Meta engine for Hugo interpreter
|
||||
*/
|
||||
class HugoMetaEngine {
|
||||
public:
|
||||
/**
|
||||
* Get a list of supported games
|
||||
*/
|
||||
static void getSupportedGames(PlainGameList &games);
|
||||
|
||||
/**
|
||||
* Get the detection entries
|
||||
*/
|
||||
static const GlkDetectionEntry* getDetectionEntries();
|
||||
|
||||
/**
|
||||
* Returns a game description for the given game Id, if it's supported
|
||||
*/
|
||||
static GameDescriptor findGame(const char *gameId);
|
||||
|
||||
/**
|
||||
* Detect supported games
|
||||
*/
|
||||
static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList);
|
||||
|
||||
/**
|
||||
* Check for game Id clashes with other sub-engines
|
||||
*/
|
||||
static void detectClashes(Common::StringMap &map);
|
||||
};
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
179
engines/glk/hugo/detection_tables.h
Normal file
179
engines/glk/hugo/detection_tables.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/game.h"
|
||||
#include "common/language.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
const PlainGameDescriptor HUGO_GAME_LIST[] = {
|
||||
{ "hugo", "Hugo IF Game" },
|
||||
|
||||
{ "acs", "A Crimson Spring" },
|
||||
{ "adv350h", "Adventure, 350 point Colossal Cave" },
|
||||
{ "annoyotron2", "Aggravatron: Annoyotron II" },
|
||||
{ "babyuncleny", "Baby Uncle New Year" },
|
||||
{ "captainspeedo14", "Captain Speedo: Victim of the Vacuum" },
|
||||
{ "captainspeedo16", "Captain Speedo: Let Them Heat cake!" },
|
||||
{ "captainspeedo42", "Captain Speedo: So Long, and Thanks for All the Books!" },
|
||||
{ "captainspeedo112", "Captain Speedo: Alert on Aleph V!" },
|
||||
{ "captainspeedotng", "Captain Speedo: The New Generation" },
|
||||
{ "cb2", "The Clockwork Boy 2" },
|
||||
{ "chicken", "The Chicken's Dilemma" },
|
||||
{ "clockworkboy", "Tales of a Clockwork Boy"},
|
||||
{ "cryptozookeeper", "Cryptozookeeper" },
|
||||
{ "dino", "The Loneliness of the Long Distance Runner" },
|
||||
{ "distress", "Distress" },
|
||||
{ "dddhugo", "Doom, Death, Destruction and All That" },
|
||||
{ "down", "Down" },
|
||||
{ "dragonhunt", "Dragon Hunt" },
|
||||
{ "eastofeastwood", "East of Eastwood" },
|
||||
{ "enceladus", "Enceladus" },
|
||||
{ "fallacyofdawn", "Fallacy of Dawn" },
|
||||
{ "futureboy", "Future Boy!" },
|
||||
{ "guiltybastards", "Guilty Bastards" },
|
||||
{ "halloweenhorror1", "The Halloween Horror - part 1" },
|
||||
{ "halloweenhorror2", "The Halloween Horror - part 2" },
|
||||
{ "hammurabi_rme", "Hammurabi (by Rick Merrill)" },
|
||||
{ "htgessay", "Hauning the Ghosts" },
|
||||
{ "hugoclock", "The Hugo Clock" },
|
||||
{ "hugozork", "Hugo Zork 1" },
|
||||
{ "ish", "Escape from Ice Station Hippo" },
|
||||
{ "leather", "Leather" },
|
||||
{ "madrigal", "Madrigals of War and Love" },
|
||||
{ "marjorie", "Will the Real Marjorie Hopkirk Please Stand Up?" },
|
||||
{ "ndrift", "Necrotic Drift" },
|
||||
{ "nextday", "The Next Day" },
|
||||
{ "nmnl", "Nothing More, Nothing Less" },
|
||||
{ "overbrook", "Overbrook, an Interactive House Tour" },
|
||||
{ "pantomime", "Pantomime" },
|
||||
{ "partyarty", "Party Arty, Man of La Munchies" },
|
||||
{ "paxless", "PAXLess, Quest to the IF Suite" },
|
||||
{ "pirateadv", "Pirate Adventure" },
|
||||
{ "pom", "Persistence of Memory" },
|
||||
{ "renga", "Renga in Four Parts" },
|
||||
{ "retronemesis", "Retro-Nemesis" },
|
||||
{ "scavhunt", "Scavenger Hunt" },
|
||||
{ "spinning", "Spinning" },
|
||||
{ "spur", "Spur, A Western Misadventure" },
|
||||
{ "squest", "SceptreQuest" },
|
||||
{ "stormoverlondon", "Storm Over London" },
|
||||
{ "teleporttest", "Teleport Test"},
|
||||
{ "tetrish", "Tetris" },
|
||||
{ "theoniondestiny", "The Onion of Destiny" },
|
||||
{ "theprofile", "The Profile" },
|
||||
{ "tradingpunches", "Trading Punches" },
|
||||
{ "travellingswordsman", "Tales of the Travelling Swordsman" },
|
||||
{ "tripkey", "Tripkey" },
|
||||
{ "trollface", "Trollface" },
|
||||
{ "vaulthugoii", "Vault of Hugo II: Electric Boogaloo" },
|
||||
{ "wfte", "Waiting for The End" },
|
||||
{ "worldbuilder", "Word Builder" },
|
||||
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const GlkDetectionEntry HUGO_GAMES[] = {
|
||||
DT_ENTRY1("acs", "0.09.0 Beta", "8788f1e28a4cd875f220155b2aeae8c8", 356450),
|
||||
DT_ENTRY1("acs", "1.0.04 Text Only", "37682bc8cbcc6706b8bd81d0d0b6745e", 371811),
|
||||
DT_ENTRY1("acs", "1.0.04", "1daad86bee94f4519681c441d4f0f2bc", 371658),
|
||||
DT_ENTRY0("adv350h", "d6735640ca21797f24e3cadb12be4ae2", 124148),
|
||||
DT_ENTRY0("annoyotron2", "944056721054fd1c9af9d1e95e63ce52", 66762),
|
||||
DT_ENTRY0("babyuncleny", "e2bedee095297428c8043c35c4fdca17", 71128),
|
||||
DT_ENTRY0("captainspeedo14", "c4ee09af9c66d9322adeaa599c97a591", 59700),
|
||||
DT_ENTRY0("captainspeedo16", "0d11e711150f08d0c04f9b414ba5c71b", 67984),
|
||||
DT_ENTRY0("captainspeedo42", "5a704cc50805400416f25105162025b6", 65544),
|
||||
DT_ENTRY0("captainspeedo112", "6ccbc38144b5b83627e022ec83f7ced6", 59706),
|
||||
DT_ENTRY0("captainspeedotng", "bc38464151bbba4dd37795ea42f041e8", 63837),
|
||||
DT_ENTRY0("cb2", "232827c10abd45c98d77ceffaf9ac9fa", 155732),
|
||||
DT_ENTRY0("chicken", "eed5770a3f88d95987d018271ffa2342", 48718),
|
||||
DT_ENTRY0("clockworkboy", "c42a897dc519597fb41ed2d310fc67be", 73139),
|
||||
DT_ENTRY1("clockworkboy", "Competition Release", "c3c24c9b98933b0e47b229b50c53d501", 63451),
|
||||
DT_ENTRY0("cryptozookeeper", "1b8301b969882c46ffa9f635e1695c41", 840567),
|
||||
DT_ENTRY1("cryptozookeeper", "1.05", "411494b65bf491ab3dd7237eaa7387a7", 1136856),
|
||||
DT_ENTRY0("dddhugo", "8d15ee9bd41d0cc1ffa97b1d3397a2f7", 50908),
|
||||
DT_ENTRY0("dino", "e465ea9b77192432c6af82715ef59ef7", 59056),
|
||||
DT_ENTRY0("distress", "fe61c8722d8625d3d196b3d390346a55", 188317),
|
||||
DT_ENTRY1("down", "r1", "7daf198e81a92b152bf6a0969210aa77", 94323),
|
||||
DT_ENTRY1("down", "r4", "4bc119c61d3cdf5d796c36b1d9a023c6", 99561),
|
||||
DT_ENTRY0("dragonhunt", "93db9cdf1d2d2800715c93fff0d48a59", 68944),
|
||||
DT_ENTRY0("eastofeastwood", "ebc4e37c66fca8a07b5782b57686ce07", 42445),
|
||||
DT_ENTRY1("enceladus", "1.00", "49b3e2a3087455c31ce929427f9510d8", 233986),
|
||||
DT_ENTRY1("enceladus", "1.01", "092ffa4ca5d35d83013a1094b58ce22c", 234191),
|
||||
DT_ENTRY1("fallacyofdawn", "1.05", "8821566e2d3b301c6dc705f2bea54eb1", 729176),
|
||||
DT_ENTRY1("fallacyofdawn", "1.07", "bebb4427004a6cded72068b0ea04b7b6", 730694),
|
||||
DT_ENTRY1("futureboy", "Demo", "cfce7ee7893bb5adc9ba4ea198f38201", 827396),
|
||||
DT_ENTRY1("guiltybastards", "Text Only", "77efc9a102a406a3b123172bb37e87e7", 246971),
|
||||
DT_ENTRY0("guiltybastards", "77efc9a102a406a3b123172bb37e87e7", 246971),
|
||||
DT_ENTRY0("halloweenhorror1", "db76f8a419767ebe6d1ad304e8001cba", 68923),
|
||||
DT_ENTRY0("halloweenhorror2", "34bb57521acd33f1f985f0898d8104a8", 55574),
|
||||
DT_ENTRY0("hammurabi_rme", "738739f9dc7ffa041a13445b23e77e37", 46905),
|
||||
DT_ENTRY0("htgessay", "c3b5bce395f3f54097077f830dad70ac", 142921),
|
||||
DT_ENTRY1("hugoclock", "v1", "9a1ab9fd3fcb52ed99751e8525020739", 105469),
|
||||
DT_ENTRY1("hugoclock", "v2", "53a0b99011ccb14ddc45cfeb8c23d417", 120887),
|
||||
DT_ENTRY0("hugozork", "b525f8bc83bc735fb5c62edd1b486499", 172150),
|
||||
DT_ENTRY0("ish", "023c9083378fcd1a08d97e60910b54da", 113958),
|
||||
DT_ENTRY0("leather", "4b8dc6050cec83b304f1eed39f4c6c24", 58409),
|
||||
DT_ENTRY0("madrigal", "e63550ddff05b06d8148ec4f05d4eabc", 66902),
|
||||
DT_ENTRY1("marjorie", "Demo", "826ff07155c2334a7d26aa826cae82e2", 55205),
|
||||
DT_ENTRY1("ndrift", "1.03", "fea92564f4ae4c626841aa4c93fcb31e", 556591),
|
||||
DT_ENTRY1("ndrift", "1.04", "8e23d867e3fc13157c1b31195550244d", 556990),
|
||||
DT_ENTRY0("nextday", "2c5a9b95f6fb079986f8a4b178c9fcb4", 136844),
|
||||
DT_ENTRY0("nmnl", "cee4e1ffae1fd562d507d65c143739ef", 171732),
|
||||
DT_ENTRY0("overbrook", "0ed7b671ed9cd3b6362419b5159366e3", 70752),
|
||||
DT_ENTRY1("pantomime", "Release 1", "874d6dab0820fd4b550d5d8c87cb8783", 247545),
|
||||
DT_ENTRY1("pantomime", "Release 2", "1067b09fda08eafb09d53b51ffe73e7d", 248466),
|
||||
DT_ENTRY1("partyarty", "v1", "7047bc315ad1410ef38a771e539c40b3", 84396),
|
||||
DT_ENTRY1("partyarty", "v2", "62dac43addf6ea21e5759e098998773b", 86845),
|
||||
DT_ENTRY1("paxless", "Release 1", "db00b1242a4a0898c2d0d2d1c77103f4", 61973),
|
||||
DT_ENTRY1("paxless", "Release 2", "c4038b711d9f0ecb4ca2586623471a52", 61973),
|
||||
DT_ENTRY0("pirateadv", "81c961f121e4465adb4592eee2bcc2d5", 53915),
|
||||
DT_ENTRY1("pom", "r1", "9a3724529fce408c2f4a2a1bbb635748", 92889),
|
||||
DT_ENTRY1("pom", "r2", "ba86e162ba30e6dbe82abc96648486da", 95577),
|
||||
DT_ENTRY0("renga", "c79032bdc349863f02a4fab30beafd35", 64373),
|
||||
DT_ENTRY0("retronemesis", "517908b4503c653a0d9bb326d00b22ab", 101526),
|
||||
DT_ENTRY0("scavhunt", "665dce1a0f552e95590b983a3f2106da", 129514),
|
||||
DT_ENTRY0("spinning", "487d0a0cdcf55407a09cafdf6ca32237", 99140),
|
||||
DT_ENTRY0("spur", "77968cf043ecc012b4938c690b81227c", 185338),
|
||||
DT_ENTRY0("squest", "3e91849c6e8ea3072aa58e96010b6078", 36322),
|
||||
DT_ENTRY0("stormoverlondon", "13767bc8e9ca0795b6084f13da904d32", 119420),
|
||||
DT_ENTRY0("teleporttest", "4cc54ad4d5b8f3628aa3925272311efb", 100723),
|
||||
DT_ENTRY0("tetrish", "da1299e86f9fcded1f9a41979685ec02", 6464),
|
||||
DT_ENTRY0("theoniondestiny", "29435113419753447900f644e8858ed1", 52942),
|
||||
DT_ENTRY1("theprofile", "v1.00", "2231e5789fc6d1a956a40d630478ef4a", 78569),
|
||||
DT_ENTRY1("theprofile", "v1.02", "618c8c3702f98bc58a0a100b7380d51a", 80015),
|
||||
DT_ENTRY1("tradingpunches", "1.6", "e7ca0323da847c364ad12e160af6c494", 294441),
|
||||
DT_ENTRY1("tradingpunches", "1.9", "b31b2eed49e788429cd9c5c641a3e713", 315934),
|
||||
DT_ENTRY0("travellingswordsman", "37378ff2cfe75d0cfb581b7777036040", 431432),
|
||||
DT_ENTRY0("tripkey", "f76297d8ff7658752aa5a29417bbb274", 188058),
|
||||
DT_ENTRY0("trollface", "ff47b6d8f36cc2a4c2d41fa878631e77", 90620),
|
||||
DT_ENTRY1("trollface", "Strict Mode Release", "acffc9c316749a2d96f452a1feb5c788", 86182),
|
||||
DT_ENTRY0("vaulthugoii", "632054772b73993e5d7672c430d04d36", 61530),
|
||||
DT_ENTRY0("wfte", "695233c271d6e355652bd11d0cc8da5e", 73099),
|
||||
DT_ENTRY1("worldbuilder", "v1", "ca41b45835288f694871769ab22b8a5a", 82732),
|
||||
DT_ENTRY1("worldbuilder", "v2", "031ff1a1364cd0d42600dc1bac967255", 90382),
|
||||
|
||||
DT_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
1243
engines/glk/hugo/heexpr.cpp
Normal file
1243
engines/glk/hugo/heexpr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
625
engines/glk/hugo/heglk.cpp
Normal file
625
engines/glk/hugo/heglk.cpp
Normal file
@@ -0,0 +1,625 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/hugo.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
void Hugo::hugo_init_screen() {
|
||||
// Open the main window...
|
||||
mainwin = currentwin = glk_window_open(nullptr, 0, 0, wintype_TextBuffer, 1);
|
||||
assert(mainwin);
|
||||
|
||||
// ...and set it up for default output
|
||||
glk_set_window(mainwin);
|
||||
|
||||
// By setting the width and height so high, we're basically forcing the Glk library
|
||||
// to deal with text-wrapping and page ends
|
||||
SCREENWIDTH = 0x7fff;
|
||||
SCREENHEIGHT = 0x7fff;
|
||||
FIXEDCHARWIDTH = 1;
|
||||
FIXEDLINEHEIGHT = 1;
|
||||
|
||||
hugo_settextwindow(1, 1,
|
||||
SCREENWIDTH/FIXEDCHARWIDTH, SCREENHEIGHT/FIXEDLINEHEIGHT);
|
||||
}
|
||||
|
||||
void Hugo::hugo_getline(const char *prmpt) {
|
||||
event_t ev;
|
||||
char gotline = 0;
|
||||
|
||||
/* Just in case we try to get line input from a Glk-illegal
|
||||
window that hasn't been created, switch as a failsafe
|
||||
to mainwin
|
||||
*/
|
||||
if (currentwin == nullptr)
|
||||
glk_set_window(currentwin = mainwin);
|
||||
|
||||
/* Print prompt */
|
||||
glk_put_string(prmpt);
|
||||
|
||||
/* Request line input */
|
||||
glk_request_line_event(currentwin, buffer, MAXBUFFER, 0);
|
||||
|
||||
while (!gotline) {
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
/* Grab an event */
|
||||
glk_select(&ev);
|
||||
|
||||
switch (ev.type)
|
||||
{
|
||||
case evtype_LineInput:
|
||||
/* (Will always be currentwin, but anyway) */
|
||||
if (ev.window == currentwin) {
|
||||
gotline = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The line we have received in commandbuf is not null-terminated */
|
||||
buffer[ev.val1] = '\0'; /* i.e., the length */
|
||||
|
||||
/* Copy the input to the script file (if open) */
|
||||
if (script) {
|
||||
Common::String text = Common::String::format("%s%s\n", prmpt, buffer);
|
||||
script->putBuffer(text.c_str(), text.size());
|
||||
}
|
||||
}
|
||||
|
||||
int Hugo::hugo_waitforkey() {
|
||||
event_t ev;
|
||||
char gotchar = 0;
|
||||
|
||||
/* Just in case we try to get key input from a Glk-illegal
|
||||
window that hasn't been created, switch as a failsafe
|
||||
to mainwin
|
||||
*/
|
||||
if (currentwin == nullptr)
|
||||
glk_set_window(currentwin = mainwin);
|
||||
|
||||
#if defined (NO_KEYPRESS_CURSOR)
|
||||
if (currentwin != mainwin)
|
||||
{
|
||||
glk_window_move_cursor(currentwin, currentpos / CHARWIDTH, currentline - 1);
|
||||
hugo_print("*");
|
||||
glk_window_move_cursor(currentwin, currentpos / CHARWIDTH, currentline - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
glk_request_char_event(currentwin);
|
||||
|
||||
while (!gotchar)
|
||||
{
|
||||
/* Grab an event */
|
||||
glk_select(&ev);
|
||||
|
||||
switch (ev.type) {
|
||||
case evtype_CharInput:
|
||||
/* (Will always be mainwin, but anyway) */
|
||||
if (ev.window == currentwin) {
|
||||
gotchar = true;
|
||||
}
|
||||
break;
|
||||
case evtype_Quit:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert Glk special keycodes: */
|
||||
switch (ev.val1)
|
||||
{
|
||||
case keycode_Left: ev.val1 = 8; break;
|
||||
case keycode_Right: ev.val1 = 21; break;
|
||||
case keycode_Up: ev.val1 = 11; break;
|
||||
case keycode_Down: ev.val1 = 10; break;
|
||||
case keycode_Return: ev.val1 = 13; break;
|
||||
case keycode_Escape: ev.val1 = 27; break;
|
||||
}
|
||||
|
||||
#if defined (NO_KEYPRESS_CURSOR)
|
||||
if (currentwin != mainwin)
|
||||
{
|
||||
glk_window_move_cursor(currentwin, currentpos / CHARWIDTH, currentline - 1);
|
||||
hugo_print(" ");
|
||||
glk_window_move_cursor(currentwin, currentpos / CHARWIDTH, currentline - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ev.val1;
|
||||
}
|
||||
|
||||
int Hugo::hugo_iskeywaiting() {
|
||||
var[system_status] = STAT_UNAVAILABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Hugo::hugo_timewait(int n) {
|
||||
uint32 millisecs;
|
||||
event_t ev;
|
||||
|
||||
if (!glk_gestalt(gestalt_Timer, 0))
|
||||
return false;
|
||||
if (n == 0) return true;
|
||||
|
||||
|
||||
millisecs = 1000 / n;
|
||||
if (millisecs == 0)
|
||||
millisecs = 1;
|
||||
|
||||
// For the time being, we're going to disallow
|
||||
// millisecond delays in Glk (1) because there's no
|
||||
// point, and (2) so that we can tell we're running
|
||||
// under Glk.
|
||||
if (millisecs < 1000) return false;
|
||||
|
||||
glk_request_timer_events(millisecs);
|
||||
while (1)
|
||||
{
|
||||
glk_select(&ev);
|
||||
if (ev.type == evtype_Timer)
|
||||
break;
|
||||
}
|
||||
glk_request_timer_events(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Hugo::hugo_clearfullscreen() {
|
||||
glk_window_clear(mainwin);
|
||||
if (secondwin) glk_window_clear(secondwin);
|
||||
if (auxwin) glk_window_clear(auxwin);
|
||||
|
||||
/* See hugo_print() for the need for this */
|
||||
if (currentwin == mainwin) mainwin_bgcolor = glk_bgcolor;
|
||||
|
||||
/* Must be set: */
|
||||
currentpos = 0;
|
||||
currentline = 1;
|
||||
|
||||
if (!inwindow) just_cleared_screen = true;
|
||||
}
|
||||
|
||||
void Hugo::hugo_clearwindow() {
|
||||
/* Clears the currently defined window, moving the cursor to the top-left
|
||||
corner of the window */
|
||||
|
||||
/* If the engine thinks we're in a window, but Glk was
|
||||
unable to comply, don't clear the window, because it's
|
||||
not really a window
|
||||
*/
|
||||
if (inwindow && currentwin == mainwin) return;
|
||||
if (currentwin == nullptr) return;
|
||||
|
||||
glk_window_clear(currentwin);
|
||||
|
||||
/* See hugo_print() for the need for this */
|
||||
if (currentwin == mainwin) mainwin_bgcolor = glk_bgcolor;
|
||||
|
||||
/* If we're in a fixed-font (i.e., textgrid) auxiliary
|
||||
window when we call for a clear, close auxwin and reset
|
||||
the current window to mainwin
|
||||
*/
|
||||
if (auxwin)
|
||||
{
|
||||
stream_result_t sr;
|
||||
|
||||
glk_window_close(auxwin, &sr);
|
||||
auxwin = nullptr;
|
||||
glk_set_window(currentwin = mainwin);
|
||||
}
|
||||
|
||||
/* Must be set: */
|
||||
currentpos = 0;
|
||||
currentline = 1;
|
||||
|
||||
if (!inwindow) just_cleared_screen = true;
|
||||
}
|
||||
|
||||
void Hugo::hugo_settextmode() {
|
||||
charwidth = FIXEDCHARWIDTH;
|
||||
lineheight = FIXEDLINEHEIGHT;
|
||||
}
|
||||
|
||||
void Hugo::hugo_settextwindow(int left, int top, int right, int bottom) {
|
||||
/* Hugo's arbitrarily positioned windows don't currently
|
||||
mesh with what Glk has to offer, so we have to ignore any
|
||||
non-Glk-ish Windows and just maintain the current
|
||||
parameters
|
||||
*/
|
||||
if ((top != 1 || bottom >= physical_windowbottom / FIXEDLINEHEIGHT + 1)
|
||||
/* Pre-v2.4 didn't support proper windowing */
|
||||
&& (game_version >= 24 || !inwindow))
|
||||
{
|
||||
in_valid_window = false;
|
||||
|
||||
/* Glk-illegal floating window; setting currentwin
|
||||
to nullptr will tell hugo_print() not to print in it:
|
||||
*/
|
||||
if (bottom<physical_windowbottom / FIXEDLINEHEIGHT + 1)
|
||||
{
|
||||
currentwin = nullptr;
|
||||
glk_set_window(mainwin);
|
||||
return;
|
||||
}
|
||||
else
|
||||
glk_set_window(currentwin = mainwin);
|
||||
}
|
||||
|
||||
/* Otherwise this is a valid window (positioned along the
|
||||
top of the screen a la a status window), so... */
|
||||
else
|
||||
{
|
||||
/* Arbitrary height of 4 lines for pre-v2.4 windows */
|
||||
if (game_version < 24) bottom = 4;
|
||||
|
||||
/* ...either create a new window if none exists... */
|
||||
if (!secondwin)
|
||||
{
|
||||
glk_stylehint_set(wintype_TextGrid, style_Normal, stylehint_ReverseColor, 1);
|
||||
glk_stylehint_set(wintype_TextGrid, style_Subheader, stylehint_ReverseColor, 1);
|
||||
glk_stylehint_set(wintype_TextGrid, style_Emphasized, stylehint_ReverseColor, 1);
|
||||
|
||||
//winid_t p = glk_window_get_parent(mainwin);
|
||||
secondwin = glk_window_open(mainwin,//p,
|
||||
winmethod_Above | winmethod_Fixed,
|
||||
bottom,
|
||||
wintype_TextGrid,
|
||||
0);
|
||||
}
|
||||
|
||||
/* ...or resize the existing one if necessary */
|
||||
else if (bottom != secondwin_bottom)
|
||||
{
|
||||
winid_t p;
|
||||
|
||||
p = glk_window_get_parent(secondwin);
|
||||
glk_window_set_arrangement(p,
|
||||
winmethod_Above | winmethod_Fixed,
|
||||
bottom,
|
||||
secondwin);
|
||||
}
|
||||
|
||||
if (secondwin)
|
||||
{
|
||||
if (game_version < 24)
|
||||
glk_window_clear(secondwin);
|
||||
|
||||
glk_set_window(currentwin = secondwin);
|
||||
in_valid_window = true;
|
||||
secondwin_bottom = bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentwin = nullptr;
|
||||
glk_set_window(mainwin);
|
||||
secondwin_bottom = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
physical_windowleft = (left - 1)*FIXEDCHARWIDTH;
|
||||
physical_windowtop = (top - 1)*FIXEDLINEHEIGHT;
|
||||
physical_windowright = right*FIXEDCHARWIDTH - 1;
|
||||
physical_windowbottom = bottom*FIXEDLINEHEIGHT - 1;
|
||||
physical_windowwidth = (right - left + 1)*FIXEDCHARWIDTH;
|
||||
physical_windowheight = (bottom - top + 1)*FIXEDLINEHEIGHT;
|
||||
}
|
||||
|
||||
int Hugo::heglk_get_linelength() {
|
||||
static uint width;
|
||||
|
||||
// Try to use whatever fixed-width linelength is available
|
||||
if (secondwin)
|
||||
glk_window_get_size(secondwin, &width, nullptr);
|
||||
else if (auxwin)
|
||||
glk_window_get_size(auxwin, &width, nullptr);
|
||||
|
||||
// Otherwise try to approximate it by the proportionally spaced linelength
|
||||
else
|
||||
glk_window_get_size(mainwin, &width, nullptr);
|
||||
|
||||
// -1 to override automatic line wrapping
|
||||
return width - 1;
|
||||
}
|
||||
|
||||
int Hugo::heglk_get_screenheight() {
|
||||
static uint height = 0, mainheight = 0;
|
||||
|
||||
if (secondwin)
|
||||
glk_window_get_size(secondwin, nullptr, &height);
|
||||
else if (auxwin)
|
||||
glk_window_get_size(auxwin, nullptr, &height);
|
||||
|
||||
glk_window_get_size(mainwin, nullptr, &mainheight);
|
||||
|
||||
return height + mainheight;
|
||||
}
|
||||
|
||||
void Hugo::hugo_settextpos(int x, int y) {
|
||||
if (currentwin == nullptr) return;
|
||||
|
||||
// Try to determine if we're trying to position fixed-width text in the main window,
|
||||
// as in a menu, for example
|
||||
if (!just_cleared_screen && !inwindow &&
|
||||
!(glk_current_font & PROP_FONT)
|
||||
&& y != 1 /* not just cls */
|
||||
&& y < SCREENHEIGHT - 0x0f) /* 0x0f is arbitrary */
|
||||
{
|
||||
/* See if we're already in the auxiliary window */
|
||||
if (currentwin != auxwin)
|
||||
{
|
||||
/* If not, create it, making it 100% of
|
||||
mainwin's height
|
||||
*/
|
||||
if (auxwin == nullptr)
|
||||
{
|
||||
auxwin = glk_window_open(mainwin,
|
||||
winmethod_Below | winmethod_Proportional,
|
||||
100,
|
||||
wintype_TextGrid,
|
||||
0);
|
||||
}
|
||||
else
|
||||
glk_window_clear(auxwin);
|
||||
|
||||
glk_set_window(currentwin = auxwin);
|
||||
}
|
||||
}
|
||||
|
||||
/* On the other hand, if we were in a textgrid window and
|
||||
no longer need to be, get out
|
||||
*/
|
||||
else if (auxwin)
|
||||
{
|
||||
stream_result_t sr;
|
||||
|
||||
/* Close auxwin */
|
||||
glk_window_close(auxwin, &sr);
|
||||
auxwin = nullptr;
|
||||
|
||||
/* Clear the screen (both windows) */
|
||||
glk_window_clear(mainwin);
|
||||
glk_window_clear(secondwin);
|
||||
|
||||
glk_set_window(currentwin = mainwin);
|
||||
}
|
||||
|
||||
just_cleared_screen = false;
|
||||
|
||||
/* Can only move the Glk cursor in a textgrid window */
|
||||
if (currentwin != mainwin)
|
||||
glk_window_move_cursor(currentwin, x - 1, y - 1);
|
||||
|
||||
/* Must be set: */
|
||||
currentline = y;
|
||||
currentpos = (x - 1)*CHARWIDTH; /* Note: zero-based */
|
||||
}
|
||||
|
||||
void Hugo::hugo_print(const char *a) {
|
||||
static char just_printed_linefeed = false;
|
||||
/* static already_modified_style = false; */
|
||||
|
||||
/* Can't print in a Glk-illegal window since it hasn't been
|
||||
created
|
||||
*/
|
||||
if (currentwin == nullptr) return;
|
||||
|
||||
/* In lieu of colors, in case we're highlighting something
|
||||
such as a menu selection:
|
||||
*/
|
||||
/*
|
||||
if (!inwindow and glk_bgcolor!=mainwin_bgcolor)
|
||||
{
|
||||
if (!already_modified_style)
|
||||
{
|
||||
if (glk_current_font & BOLD_FONT)
|
||||
glk_set_style(style_Normal);
|
||||
else
|
||||
glk_set_style(style_Emphasized);
|
||||
}
|
||||
already_modified_style = true;
|
||||
}
|
||||
else
|
||||
already_modified_style = false;
|
||||
*/
|
||||
|
||||
if (a[0] == '\n')
|
||||
{
|
||||
if (!just_printed_linefeed)
|
||||
{
|
||||
glk_put_string("\n");
|
||||
}
|
||||
else
|
||||
just_printed_linefeed = false;
|
||||
}
|
||||
else if (a[0] == '\r')
|
||||
{
|
||||
if (!just_printed_linefeed)
|
||||
{
|
||||
glk_put_string("\n");
|
||||
just_printed_linefeed = true;
|
||||
}
|
||||
else
|
||||
just_printed_linefeed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
glk_put_string(a);
|
||||
just_printed_linefeed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Hugo::hugo_font(int f) {
|
||||
static char using_prop_font = false;
|
||||
|
||||
glk_current_font = f;
|
||||
|
||||
glk_set_style(style_Normal);
|
||||
|
||||
if (f & BOLD_FONT)
|
||||
glk_set_style(style_Subheader);
|
||||
|
||||
if (f & UNDERLINE_FONT)
|
||||
glk_set_style(style_Emphasized);
|
||||
|
||||
if (f & ITALIC_FONT)
|
||||
glk_set_style(style_Emphasized);
|
||||
|
||||
if (f & PROP_FONT)
|
||||
using_prop_font = true;
|
||||
|
||||
/* Have to comment this out, it seems, because it will mess up the
|
||||
alignment of the input in the main window
|
||||
if (!(f & PROP_FONT))
|
||||
glk_set_style(style_Preformatted);
|
||||
*/
|
||||
|
||||
/* Workaround to decide if we have to open auxwin for positioned
|
||||
non-proportional text:
|
||||
*/
|
||||
if (!(f & PROP_FONT))
|
||||
{
|
||||
/* If at top of screen, and changing to a fixed-
|
||||
width font (a situation which wouldn't normally
|
||||
be adjusted for by hugo_settextpos())
|
||||
*/
|
||||
if (!inwindow && currentline == 1 && currentpos == 0 && using_prop_font)
|
||||
{
|
||||
just_cleared_screen = false;
|
||||
hugo_settextpos(1, 2);
|
||||
glk_window_move_cursor(currentwin, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hugo::hugo_settextcolor(int c) {
|
||||
// Set the foreground color to hugo_color(c)
|
||||
glk_fcolor = hugo_color(c);
|
||||
}
|
||||
|
||||
void Hugo::hugo_setbackcolor(int c) {
|
||||
// Set the background color to hugo_color(c)
|
||||
glk_bgcolor = hugo_color(c);
|
||||
}
|
||||
|
||||
int Hugo::hugo_color(int c) {
|
||||
if (c == 16) c = DEF_FCOLOR;
|
||||
else if (c == 17) c = DEF_BGCOLOR;
|
||||
else if (c == 18) c = DEF_SLFCOLOR;
|
||||
else if (c == 19) c = DEF_SLBGCOLOR;
|
||||
else if (c == 20) c = hugo_color(fcolor); /* match foreground */
|
||||
|
||||
/* Uncomment this block of code and change "c = ..." values if the system
|
||||
palette differs from the Hugo palette.
|
||||
|
||||
If colors are unavailable on the system in question, it may suffice
|
||||
to have black, white, and brightwhite (i.e. boldface). It is expected
|
||||
that colored text will be visible on any other-colored background.
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case HUGO_BLACK: c = 0; break;
|
||||
case HUGO_BLUE: c = 1; break;
|
||||
case HUGO_GREEN: c = 2; break;
|
||||
case HUGO_CYAN: c = 3; break;
|
||||
case HUGO_RED: c = 4; break;
|
||||
case HUGO_MAGENTA: c = 5; break;
|
||||
case HUGO_BROWN: c = 6; break;
|
||||
case HUGO_WHITE: c = 7; break;
|
||||
case HUGO_DARK_GRAY: c = 8; break;
|
||||
case HUGO_LIGHT_BLUE: c = 9; break;
|
||||
case HUGO_LIGHT_GREEN: c = 10; break;
|
||||
case HUGO_LIGHT_CYAN: c = 11; break;
|
||||
case HUGO_LIGHT_RED: c = 12; break;
|
||||
case HUGO_LIGHT_MAGENTA: c = 13; break;
|
||||
case HUGO_YELLOW: c = 14; break;
|
||||
case HUGO_BRIGHT_WHITE: c = 15; break;
|
||||
*/
|
||||
return c;
|
||||
}
|
||||
|
||||
int Hugo::hugo_charwidth(char a) const {
|
||||
if (a == FORCED_SPACE)
|
||||
return CHARWIDTH; /* same as ' ' */
|
||||
|
||||
else if ((unsigned char)a >= ' ') /* alphanumeric characters */
|
||||
|
||||
return CHARWIDTH; /* for non-proportional */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Hugo::hugo_textwidth(const char *a) const {
|
||||
int i, slen, len = 0;
|
||||
|
||||
slen = (int)strlen(a);
|
||||
|
||||
for (i = 0; i<slen; i++)
|
||||
{
|
||||
if (a[i] == COLOR_CHANGE) i += 2;
|
||||
else if (a[i] == FONT_CHANGE) i++;
|
||||
else
|
||||
len += hugo_charwidth(a[i]);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int Hugo::hugo_strlen(const char *a) const {
|
||||
int i, slen, len = 0;
|
||||
|
||||
slen = (int)strlen(a);
|
||||
|
||||
for (i = 0; i<slen; i++)
|
||||
{
|
||||
if (a[i] == COLOR_CHANGE) i += 2;
|
||||
else if (a[i] == FONT_CHANGE) i++;
|
||||
else len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replacements for things the Glk port doesn't support:
|
||||
*
|
||||
*/
|
||||
|
||||
void Hugo::hugo_setgametitle(const char *t) {}
|
||||
|
||||
int Hugo::hugo_hasvideo() const { return false; }
|
||||
|
||||
int Hugo::hugo_playvideo(HUGO_FILE infile, long reslength, char loop_flag, char background, int volume) {
|
||||
delete infile;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Hugo::hugo_stopvideo(void) {}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
158
engines/glk/hugo/hemedia.cpp
Normal file
158
engines/glk/hugo/hemedia.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/hugo.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
int Hugo::loadres(HUGO_FILE infile, int reslen, int type) {
|
||||
char buf[4096];
|
||||
frefid_t fileref;
|
||||
strid_t stream;
|
||||
long offset;
|
||||
int idVal;
|
||||
int i, n;
|
||||
|
||||
offset = hugo_ftell(infile);
|
||||
for (i = 0; i < numres[type]; i++)
|
||||
if (resids[type][i] == offset)
|
||||
return i;
|
||||
|
||||
/* Too many resources loaded... */
|
||||
if (numres[type] + 1 == MAXRES)
|
||||
return -1;
|
||||
|
||||
idVal = numres[type]++;
|
||||
Common::sprintf_s(buf, "%s%d", type == PIC ? "PIC" : "SND", idVal);
|
||||
resids[type][idVal] = offset;
|
||||
|
||||
fileref = glk_fileref_create_by_name(fileusage_Data, buf, 0);
|
||||
if (!fileref)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream = glk_stream_open_file(fileref, filemode_Write, 0);
|
||||
if (!stream)
|
||||
{
|
||||
glk_fileref_destroy(fileref);
|
||||
return -1;
|
||||
}
|
||||
|
||||
glk_fileref_destroy(fileref);
|
||||
|
||||
while (reslen > 0)
|
||||
{
|
||||
n = hugo_fread(buf, 1, reslen < (int)sizeof(buf) ? reslen : sizeof(buf), infile);
|
||||
if (n <= 0)
|
||||
break;
|
||||
glk_put_buffer_stream(stream, buf, n);
|
||||
reslen -= n;
|
||||
}
|
||||
|
||||
glk_stream_close(stream, nullptr);
|
||||
|
||||
return idVal;
|
||||
}
|
||||
|
||||
int Hugo::hugo_hasgraphics() {
|
||||
/* Returns true if the current display is capable of graphics display */
|
||||
return glk_gestalt(gestalt_Graphics, 0)
|
||||
&& glk_gestalt(gestalt_DrawImage, glk_window_get_type(mainwin));
|
||||
}
|
||||
|
||||
void Hugo::initsound() {
|
||||
if (!glk_gestalt(gestalt_Sound, 0))
|
||||
return;
|
||||
schannel = glk_schannel_create(0);
|
||||
}
|
||||
|
||||
void Hugo::initmusic() {
|
||||
if (!glk_gestalt(gestalt_Sound, 0) || !glk_gestalt(gestalt_SoundMusic, 0))
|
||||
return;
|
||||
mchannel = glk_schannel_create(0);
|
||||
}
|
||||
|
||||
int Hugo::hugo_playmusic(HUGO_FILE infile, long reslen, char loop_flag) {
|
||||
int idVal;
|
||||
|
||||
if (!mchannel)
|
||||
initmusic();
|
||||
if (mchannel)
|
||||
{
|
||||
idVal = loadres(infile, reslen, SND);
|
||||
if (idVal < 0)
|
||||
{
|
||||
hugo_fclose(infile);
|
||||
return false;
|
||||
}
|
||||
glk_schannel_play_ext(mchannel, idVal, loop_flag ? -1 : 1, 0);
|
||||
}
|
||||
|
||||
hugo_fclose(infile);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Hugo::hugo_musicvolume(int vol) {
|
||||
if (!mchannel) initmusic();
|
||||
if (!mchannel) return;
|
||||
glk_schannel_set_volume(mchannel, (vol * 0x10000) / 100);
|
||||
}
|
||||
|
||||
void Hugo::hugo_stopmusic() {
|
||||
if (!mchannel) initmusic();
|
||||
if (!mchannel) return;
|
||||
glk_schannel_stop(mchannel);
|
||||
}
|
||||
|
||||
int Hugo::hugo_playsample(HUGO_FILE infile, long reslen, char loop_flag) {
|
||||
int idVal;
|
||||
|
||||
if (schannel)
|
||||
{
|
||||
idVal = loadres(infile, reslen, SND);
|
||||
if (idVal < 0)
|
||||
{
|
||||
hugo_fclose(infile);
|
||||
return false;
|
||||
}
|
||||
glk_schannel_play_ext(schannel, idVal, loop_flag ? -1 : 1, 0);
|
||||
}
|
||||
|
||||
hugo_fclose(infile);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Hugo::hugo_samplevolume(int vol) {
|
||||
if (!schannel) initsound();
|
||||
if (!schannel) return;
|
||||
glk_schannel_set_volume(schannel, (vol * 0x10000) / 100);
|
||||
}
|
||||
|
||||
void Hugo::hugo_stopsample() {
|
||||
if (!schannel) initsound();
|
||||
if (!schannel) return;
|
||||
glk_schannel_stop(schannel);
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
2391
engines/glk/hugo/hemisc.cpp
Normal file
2391
engines/glk/hugo/hemisc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
670
engines/glk/hugo/heobject.cpp
Normal file
670
engines/glk/hugo/heobject.cpp
Normal file
@@ -0,0 +1,670 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/hugo.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
|
||||
int Hugo::CheckObjectRange(int obj) {
|
||||
if (runtime_warnings) {
|
||||
return CheckinRange((unsigned)obj, (unsigned)objects, "object");
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int Hugo::Child(int obj) {
|
||||
int c;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return 0;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
defseg = objtable;
|
||||
|
||||
c = PeekWord(2 + obj*object_size + object_size - 4);
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int Hugo::Children(int obj) {
|
||||
int count = 0;
|
||||
int nextobj;
|
||||
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
nextobj = Child(obj);
|
||||
while (nextobj)
|
||||
{count++;
|
||||
nextobj = Sibling(nextobj);}
|
||||
return count;
|
||||
}
|
||||
|
||||
int Hugo::Elder(int obj) {
|
||||
int lastobj;
|
||||
int p, cp;
|
||||
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
p = Parent(obj);
|
||||
cp = Child(p);
|
||||
|
||||
if (p==0 || cp==obj)
|
||||
return 0;
|
||||
|
||||
lastobj = cp;
|
||||
while (Sibling(lastobj) != obj)
|
||||
lastobj = Sibling(lastobj);
|
||||
|
||||
return lastobj;
|
||||
}
|
||||
|
||||
unsigned long Hugo::GetAttributes(int obj, int attribute_set) {
|
||||
unsigned long a;
|
||||
|
||||
defseg = objtable;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return 0;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
a = (unsigned long)PeekWord(2 + obj*object_size + attribute_set*4)
|
||||
+ (unsigned long)PeekWord(2 + obj*object_size + attribute_set*4 + 2)*65536L;
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
int Hugo::GetProp(int obj, int p, int n, char s) {
|
||||
char objonly, /* no verbroutine given in before, etc. */
|
||||
isadditive = 0, /* before, after, etc. */
|
||||
gotone = 0, /* when a match has been made */
|
||||
getpropaddress = 0; /* when getting &object.property */
|
||||
int i;
|
||||
int tempself,
|
||||
objtype, /* i.e., what we're matching to */
|
||||
flag = 0;
|
||||
int g = 0;
|
||||
int templocals[MAXLOCALS];
|
||||
int temp_stack_depth;
|
||||
char tempinexpr = inexpr;
|
||||
unsigned int pa, /* property address */
|
||||
offset = 0;
|
||||
long inprop, /* code position in complex property */
|
||||
returnaddr;
|
||||
#if defined (DEBUGGER)
|
||||
long orig_inprop;
|
||||
int tempdbnest;
|
||||
|
||||
/* Don't check a possible non-existent display object (-1) */
|
||||
if (obj!=-1 || display_object!=-1) CheckObjectRange(obj);
|
||||
#endif
|
||||
/* This way either -1 (the non-existent display object) or a too-high
|
||||
object will fail
|
||||
*/
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
/* The display object, which is automatically created by the compiler,
|
||||
did not exist pre-v2.4
|
||||
*/
|
||||
if ((obj==display_object) && game_version>=24)
|
||||
{
|
||||
/* There are no actual default "properties" per se on the
|
||||
display object--but reading them returns certain data about
|
||||
the current state of display affairs
|
||||
*/
|
||||
|
||||
/* no display.<prop> #2, etc. */
|
||||
if (n==1 && p<=pointer_y)
|
||||
{
|
||||
if (p==screenwidth)
|
||||
#if defined (GLK) && defined (ACTUAL_LINELENGTH)
|
||||
g = ACTUAL_LINELENGTH();
|
||||
#else
|
||||
g = SCREENWIDTH/FIXEDCHARWIDTH;
|
||||
#endif
|
||||
else if (p==screenheight)
|
||||
/* ACTUAL_SCREENHEIGHT can be set to a non-portable function if
|
||||
SCREENHEIGHT and SCREENHEIGHT have been set to large values in
|
||||
order to force the non-portable layer to handle wrapping and
|
||||
scrolling (as in the Glk port).
|
||||
*/
|
||||
#if defined (ACTUAL_SCREENHEIGHT)
|
||||
g = ACTUAL_SCREENHEIGHT();
|
||||
#else
|
||||
g = SCREENHEIGHT/FIXEDLINEHEIGHT;
|
||||
#endif
|
||||
else if (p==linelength)
|
||||
/* ACTUAL_LINELENGTH functions similarly to ACTUAL_SCREENWIDTH,
|
||||
above.
|
||||
*/
|
||||
#if defined (ACTUAL_LINELENGTH)
|
||||
g = ACTUAL_LINELENGTH();
|
||||
#else
|
||||
g = physical_windowwidth/FIXEDCHARWIDTH;
|
||||
#endif
|
||||
else if (p==windowlines)
|
||||
g = physical_windowheight/FIXEDLINEHEIGHT;
|
||||
else if (p==cursor_column)
|
||||
g = (currentpos+1+hugo_textwidth(pbuffer))/FIXEDCHARWIDTH;
|
||||
else if (p==cursor_row)
|
||||
g = currentline;
|
||||
else if (p==hasgraphics)
|
||||
g = hugo_hasgraphics();
|
||||
else if (p==title_caption)
|
||||
g = FindWord(game_title);
|
||||
else if (p==hasvideo)
|
||||
#if !defined (COMPILE_V25)
|
||||
g = hugo_hasvideo();
|
||||
#else
|
||||
g = 0;
|
||||
#endif
|
||||
else if (p==needs_repaint)
|
||||
g = display_needs_repaint;
|
||||
else if (p==pointer_x)
|
||||
g = display_pointer_x;
|
||||
else if (p==pointer_y)
|
||||
g = display_pointer_y;
|
||||
else
|
||||
g = 0;
|
||||
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
||||
/* To avoid prematurely getting an address in &obj.prop.prop */
|
||||
if (getaddress && MEM(codeptr)!=DECIMAL_T)
|
||||
getpropaddress = true;
|
||||
|
||||
tempself = var[self];
|
||||
if (!s) var[self] = obj;
|
||||
|
||||
temp_stack_depth = stack_depth;
|
||||
|
||||
|
||||
GetNextProp:
|
||||
|
||||
pa = PropAddr(obj, p, offset);
|
||||
|
||||
defseg = proptable;
|
||||
|
||||
/* If the object doesn't have property p, see if there's a
|
||||
default value.
|
||||
*/
|
||||
if (!pa)
|
||||
{
|
||||
if (offset) goto NoMorePropMatches;
|
||||
|
||||
if (getpropaddress) /* if an &value */
|
||||
g = 0;
|
||||
else
|
||||
g = PeekWord(p * 2 + 2);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Property is a value... */
|
||||
if (Peek(pa+1) < PROP_ROUTINE)
|
||||
{
|
||||
if (getaddress || (int)Peek(pa+1) < n || n<=0)
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (n!=1)
|
||||
CheckinRange(n, (int)Peek(pa+1), "property element");
|
||||
#endif
|
||||
g = 0;
|
||||
}
|
||||
else
|
||||
g = PeekWord(pa + n * 2);
|
||||
}
|
||||
|
||||
/* ...or a property routine */
|
||||
else
|
||||
{
|
||||
/* Check if this is an additive property */
|
||||
defseg = proptable;
|
||||
if (Peek(2 + Peek(0)*2 + p)&ADDITIVE_FLAG)
|
||||
isadditive = true;
|
||||
|
||||
/* If an &value, return the address of the
|
||||
property routine.
|
||||
*/
|
||||
if (getpropaddress)
|
||||
{
|
||||
g = PeekWord(pa+2);
|
||||
goto NoMorePropMatches;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (debug_eval)
|
||||
{
|
||||
debug_eval_error = true;
|
||||
DebugMessageBox("Expression Error",
|
||||
"Property routine illegal in watch/assignment");
|
||||
defseg = gameseg;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* If not a complex property such as
|
||||
before or after:
|
||||
*/
|
||||
if ((game_version>=22 && (Peek(2 + Peek(0)*2 + p)&COMPLEX_FLAG)==0) || (game_version<22 && p!=before && p!=after))
|
||||
{
|
||||
ret = 1;
|
||||
returnaddr = codeptr;
|
||||
|
||||
/* Check to see if this is a valid tail-recursive return... */
|
||||
if (tail_recursion==TAIL_RECURSION_PROPERTY && MEM(codeptr)==EOL_T)
|
||||
{
|
||||
PassLocals(0);
|
||||
tail_recursion_addr = (long)PeekWord(pa+2)*address_scale;
|
||||
return 0;
|
||||
}
|
||||
/* ...but if we're not immediately followed by and end-of-line marker,
|
||||
or another property value, cancel the pending tail-recursion
|
||||
*/
|
||||
else if (MEM(codeptr)!=DECIMAL_T)
|
||||
{
|
||||
tail_recursion = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<MAXLOCALS; i++)
|
||||
templocals[i] = var[MAXGLOBALS+i];
|
||||
|
||||
PassLocals(0);
|
||||
|
||||
SetStackFrame(stack_depth+1, RUNROUTINE_BLOCK, 0, 0);
|
||||
#if defined (DEBUGGER)
|
||||
tempdbnest = dbnest;
|
||||
DebugRunRoutine((long)PeekWord(pa+2)*address_scale);
|
||||
dbnest = tempdbnest;
|
||||
#else
|
||||
RunRoutine((long)PeekWord(pa+2)*address_scale);
|
||||
#endif
|
||||
|
||||
retflag = 0;
|
||||
codeptr = returnaddr;
|
||||
g = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Complex property: */
|
||||
else
|
||||
{
|
||||
for (i=0; i<MAXLOCALS; i++)
|
||||
templocals[i] = var[MAXGLOBALS+i];
|
||||
|
||||
inprop = (long)PeekWord(pa + 2)*address_scale;
|
||||
#ifdef DEBUGGER
|
||||
orig_inprop = inprop;
|
||||
#endif
|
||||
defseg = gameseg;
|
||||
while (Peek(inprop)!=CLOSE_BRACE_T)
|
||||
{
|
||||
returnaddr = codeptr;
|
||||
|
||||
codeptr = inprop;
|
||||
objonly = false;
|
||||
objtype = GetValue();
|
||||
inprop = codeptr;
|
||||
codeptr = returnaddr;
|
||||
|
||||
flag = 0;
|
||||
|
||||
/* If only an object (or other variable) is
|
||||
given, and no verbroutine
|
||||
*/
|
||||
if (Peek(inprop)==JUMP_T)
|
||||
{
|
||||
objonly = true;
|
||||
if (!gotone && obj==objtype) flag = 1;
|
||||
}
|
||||
|
||||
/* Otherwise, one or more verbroutines are
|
||||
specified
|
||||
*/
|
||||
else
|
||||
{
|
||||
while (Peek(inprop)!=JUMP_T)
|
||||
{
|
||||
if (PeekWord(inprop+1)==(unsigned int)var[verbroutine] ||
|
||||
|
||||
/* This is necessary because of the awkward way the pre-v2.2
|
||||
differentiated non-verbroutine blocks, i.e., with Parse
|
||||
*/
|
||||
((game_version<22) && PeekWord(inprop+1)==(unsigned int)parseaddr && !gotone))
|
||||
{
|
||||
if (obj==objtype) flag = 1;
|
||||
}
|
||||
inprop += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag==1)
|
||||
{
|
||||
gotone = true;
|
||||
ret = 1;
|
||||
returnaddr = codeptr;
|
||||
|
||||
SetStackFrame(stack_depth, RUNROUTINE_BLOCK, 0, 0);
|
||||
|
||||
PassLocals(0);
|
||||
#if defined (DEBUGGER)
|
||||
/* Prevent premature stopping */
|
||||
if (debugger_step_over && !debugger_finish)
|
||||
debugger_run = true;
|
||||
|
||||
if (IsBreakpoint(orig_inprop))
|
||||
complex_prop_breakpoint = true;
|
||||
|
||||
Common::sprintf_s(debug_line, "Calling: %s.%s", objectname[obj], propertyname[p]);
|
||||
trace_complex_prop_routine = true;
|
||||
|
||||
tempdbnest = dbnest;
|
||||
DebugRunRoutine(inprop+3);
|
||||
dbnest = tempdbnest;
|
||||
#else
|
||||
RunRoutine(inprop+3);
|
||||
#endif
|
||||
retflag = 0;
|
||||
codeptr = returnaddr;
|
||||
g = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* The following used to read "if (!flag || objonly..."
|
||||
meaning that any non-verbroutine related routines
|
||||
would fall through regardless of whether they returned
|
||||
true or false. I don't recall the rationale for this,
|
||||
and have therefore removed it.
|
||||
*/
|
||||
if (!flag || (objonly && !g) || ((game_version<22) && PeekWord(inprop-2)==(unsigned int)parseaddr))
|
||||
inprop = (long)PeekWord(inprop+1)*address_scale;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<MAXLOCALS; i++)
|
||||
var[MAXGLOBALS+i] = templocals[i];
|
||||
|
||||
if (isadditive && !g)
|
||||
{
|
||||
offset = pa + 4;
|
||||
gotone = false;
|
||||
goto GetNextProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NoMorePropMatches:
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
var[self] = tempself;
|
||||
inexpr = tempinexpr;
|
||||
stack_depth = temp_stack_depth;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
int Hugo::GrandParent(int obj) {
|
||||
int nextobj;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return 0;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
defseg = objtable;
|
||||
while ((nextobj = PeekWord(2 + obj*object_size + object_size-8)) != 0)
|
||||
obj = nextobj;
|
||||
defseg = gameseg;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Hugo::MoveObj(int obj, int p) {
|
||||
int oldparent, prevobj, s;
|
||||
unsigned int objaddr, parentaddr, lastobjaddr;
|
||||
|
||||
if (obj==p) return;
|
||||
if (obj<0 || obj>=objects) return;
|
||||
|
||||
oldparent = Parent(obj);
|
||||
/* if (oldparent==p) return; */
|
||||
|
||||
objaddr = 2 + obj*object_size;
|
||||
|
||||
/* First, detach the object from its old parent and siblings... */
|
||||
|
||||
prevobj = Elder(obj);
|
||||
s = Sibling(obj);
|
||||
defseg = objtable;
|
||||
if (prevobj) /* sibling */
|
||||
PokeWord(2 + prevobj*object_size + object_size-6, s);
|
||||
else /* child */
|
||||
PokeWord(2 + oldparent*object_size + object_size-4, s);
|
||||
|
||||
|
||||
/* Then move it to the new parent... */
|
||||
|
||||
defseg = objtable;
|
||||
PokeWord(objaddr + object_size-8, p); /* new parent */
|
||||
PokeWord(objaddr + object_size-6, 0); /* erase old sibling */
|
||||
|
||||
/* Only operate on the new parent if it isn't object 0 */
|
||||
if (p!=0)
|
||||
{
|
||||
|
||||
/* Object is sole child, or... */
|
||||
if (Child(p)==0)
|
||||
{
|
||||
parentaddr = 2 + p*object_size;
|
||||
defseg = objtable;
|
||||
PokeWord(parentaddr + object_size-4, obj);
|
||||
}
|
||||
|
||||
/* ...object is next sibling. */
|
||||
else
|
||||
{
|
||||
lastobjaddr = 2 + Youngest(p)*object_size;
|
||||
defseg = objtable;
|
||||
PokeWord(lastobjaddr + object_size-6, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *Hugo::Name(int obj) {
|
||||
int p;
|
||||
|
||||
p = GetProp(obj, 0, 1, 0);
|
||||
|
||||
if (p)
|
||||
return GetWord((unsigned int)p);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Hugo::Parent(int obj) {
|
||||
int p;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return 0;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
defseg = objtable;
|
||||
|
||||
p = PeekWord(2 + obj*object_size + object_size-8);
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
unsigned int Hugo::PropAddr(int obj, int p, unsigned int offset) {
|
||||
unsigned char c;
|
||||
int proplen;
|
||||
unsigned int ptr;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
/* Don't check any non-existent display object (-1) */
|
||||
if (p!=-1) CheckinRange(p, properties, "property");
|
||||
CheckObjectRange(obj);
|
||||
#endif
|
||||
/* This way either -1 (the non-existent display object) or a too-high
|
||||
object will fail
|
||||
*/
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
defseg = objtable;
|
||||
|
||||
/* Position in the property table...
|
||||
|
||||
i.e., ptr = PeekWord(2 + obj*object_size + (object_size-2));
|
||||
*/
|
||||
ptr = PeekWord(object_size*(obj+1));
|
||||
|
||||
/* ...unless a position has already been given */
|
||||
if (offset) ptr = offset;
|
||||
|
||||
defseg = proptable;
|
||||
|
||||
c = Peek(ptr);
|
||||
while (c != PROP_END && c != (unsigned char)p)
|
||||
{
|
||||
proplen = Peek(ptr + 1);
|
||||
|
||||
/* Property routine address is 1 word */
|
||||
if (proplen==PROP_ROUTINE) proplen = 1;
|
||||
|
||||
ptr += proplen * 2 + 2;
|
||||
c = Peek(ptr);
|
||||
}
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
if (c==PROP_END)
|
||||
return 0;
|
||||
else
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Hugo::PutAttributes(int obj, unsigned long a, int attribute_set) {
|
||||
unsigned int lword, hword;
|
||||
|
||||
hword = (unsigned int)(a/65536L);
|
||||
lword = (unsigned int)(a%65536L);
|
||||
|
||||
defseg = objtable;
|
||||
|
||||
PokeWord(2 + obj*object_size + attribute_set*4, lword);
|
||||
PokeWord(2 + obj*object_size + attribute_set*4 + 2, hword);
|
||||
|
||||
defseg = gameseg;
|
||||
}
|
||||
|
||||
void Hugo::SetAttribute(int obj, int attr, int c) {
|
||||
unsigned long a, mask;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return;
|
||||
|
||||
a = GetAttributes(obj, attr/32);
|
||||
|
||||
mask = 1L<<(long)(attr%32);
|
||||
|
||||
if (c==1)
|
||||
a = a | mask;
|
||||
else
|
||||
{
|
||||
if (a & mask)
|
||||
a = a ^ mask;
|
||||
}
|
||||
|
||||
PutAttributes(obj, a, attr/32);
|
||||
}
|
||||
|
||||
int Hugo::Sibling(int obj) {
|
||||
int s;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return 0;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
defseg = objtable;
|
||||
|
||||
s = PeekWord(2+ obj*object_size + object_size-6);
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int Hugo::TestAttribute(int obj, int attr, int nattr) {
|
||||
unsigned long a, mask, ta;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (!CheckObjectRange(obj)) return 0;
|
||||
#endif
|
||||
if (obj<0 || obj>=objects) return 0;
|
||||
|
||||
a = GetAttributes(obj, attr/32);
|
||||
|
||||
mask = 1L<<(attr%32);
|
||||
|
||||
ta = a & mask;
|
||||
if (ta) ta = 1;
|
||||
|
||||
if (nattr) ta = ta ^ 1;
|
||||
|
||||
return (int)ta;
|
||||
}
|
||||
|
||||
int Hugo::Youngest(int obj) {
|
||||
int nextobj;
|
||||
|
||||
if (Child(obj)==0) return 0;
|
||||
|
||||
nextobj = Child(obj);
|
||||
|
||||
while (Sibling(nextobj))
|
||||
nextobj = Sibling(nextobj);
|
||||
|
||||
return nextobj;
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
2583
engines/glk/hugo/heparse.cpp
Normal file
2583
engines/glk/hugo/heparse.cpp
Normal file
File diff suppressed because it is too large
Load Diff
458
engines/glk/hugo/heres.cpp
Normal file
458
engines/glk/hugo/heres.cpp
Normal file
@@ -0,0 +1,458 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/hugo.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
void Hugo::DisplayPicture() {
|
||||
if (!hugo_hasgraphics()) {
|
||||
var[system_status] = STAT_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[MAX_RES_PATH], resname[MAX_RES_PATH];
|
||||
g_vm->GetResourceParameters(filename, resname, PICTURE_T);
|
||||
Common::String picName = Common::String::format("%s,%s",
|
||||
filename, resname);
|
||||
|
||||
// Draw game's picture then move cursor down to the next line
|
||||
if (glk_image_draw(mainwin, picName, imagealign_InlineUp, 0)) {
|
||||
glk_put_char('\n');
|
||||
} else {
|
||||
var[system_status] = STAT_LOADERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void Hugo::PlayMusic() {
|
||||
char filename[MAX_RES_PATH], resname[MAX_RES_PATH];
|
||||
char loop_flag = 0;
|
||||
long resstart, reslength;
|
||||
|
||||
if (MEM(codeptr+1)==REPEAT_T) loop_flag = true, codeptr++;
|
||||
|
||||
hugo_stopmusic();
|
||||
|
||||
/* If a 0 parameter is passed, i.e. "music 0" */
|
||||
if (!GetResourceParameters(filename, resname, MUSIC_T))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (extra_param>=0)
|
||||
{
|
||||
if (extra_param > 100) extra_param = 100;
|
||||
hugo_musicvolume(extra_param);
|
||||
}
|
||||
|
||||
if (!(reslength = FindResource(filename, resname)))
|
||||
return;
|
||||
|
||||
/* Find out what type of music resource this is */
|
||||
resstart = hugo_ftell(resource_file);
|
||||
|
||||
/* Check for MIDI */
|
||||
hugo_fseek(resource_file, resstart, SEEK_SET);
|
||||
hugo_fread(resname, 4, 1, resource_file);
|
||||
if (!memcmp(resname, "MThd", 4))
|
||||
{
|
||||
resource_type = MIDI_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* Check for XM */
|
||||
hugo_fseek(resource_file, resstart, SEEK_SET);
|
||||
hugo_fread(resname, 17, 1, resource_file);
|
||||
if (!memcmp(resname, "Extended Module: ", 17))
|
||||
{
|
||||
resource_type = XM_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* Check for S3M */
|
||||
hugo_fseek(resource_file, resstart+0x2c, SEEK_SET);
|
||||
hugo_fread(resname, 4, 1, resource_file);
|
||||
if (!memcmp(resname, "SCRM", 4))
|
||||
{
|
||||
resource_type = S3M_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* Check for MOD */
|
||||
hugo_fseek(resource_file, resstart+1080, SEEK_SET);
|
||||
hugo_fread(resname, 4, 1, resource_file);
|
||||
resname[4] = '\0';
|
||||
/* There are a whole bunch of different MOD identifiers: */
|
||||
if (!strcmp(resname+1, "CHN") || /* 4CHN, 6CHN, 8CHN */
|
||||
!strcmp(resname+2, "CN") || /* 16CN, 32CN */
|
||||
!strcmp(resname, "M.K.") || !strcmp(resname, "M!K!") ||
|
||||
!strcmp(resname, "FLT4") || !strcmp(resname, "CD81") ||
|
||||
!strcmp(resname, "OKTA") || !strcmp(resname, " "))
|
||||
{
|
||||
resource_type = MOD_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* Check for MP3 */
|
||||
/* Assume for now that otherwise unidentified is MP3 */
|
||||
else
|
||||
{
|
||||
resource_type = MP3_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* No file type identified */
|
||||
resource_type = UNKNOWN_R;
|
||||
|
||||
Identified:
|
||||
hugo_fseek(resource_file, resstart, SEEK_SET);
|
||||
|
||||
if (!hugo_playmusic(resource_file, reslength, loop_flag))
|
||||
var[system_status] = STAT_LOADERROR;
|
||||
}
|
||||
|
||||
void Hugo::PlaySample() {
|
||||
char filename[MAX_RES_PATH], resname[MAX_RES_PATH];
|
||||
char loop_flag = 0;
|
||||
long reslength;
|
||||
|
||||
if (MEM(codeptr+1)==REPEAT_T) loop_flag = true, codeptr++;
|
||||
|
||||
hugo_stopsample();
|
||||
|
||||
/* If a 0 parameter is passed, i.e. "sound 0" */
|
||||
if (!GetResourceParameters(filename, resname, SOUND_T))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (extra_param>=0)
|
||||
{
|
||||
if (extra_param > 100) extra_param = 100;
|
||||
hugo_samplevolume(extra_param);
|
||||
}
|
||||
|
||||
if (!(reslength = FindResource(filename, resname)))
|
||||
return;
|
||||
|
||||
/* Find out what kind of audio sample this is */
|
||||
hugo_fread(resname, 4, 1, resource_file);
|
||||
if (!memcmp(resname, "WAVE", 4))
|
||||
resource_type = WAVE_R;
|
||||
else
|
||||
resource_type = UNKNOWN_R;
|
||||
|
||||
hugo_fseek(resource_file, -4, SEEK_CUR);
|
||||
|
||||
if (!hugo_playsample(resource_file, reslength, loop_flag))
|
||||
var[system_status] = STAT_LOADERROR;
|
||||
}
|
||||
|
||||
void Hugo::PlayVideo() {
|
||||
char filename[MAX_RES_PATH], resname[MAX_RES_PATH];
|
||||
char loop_flag = 0, background = 0;
|
||||
int volume = 100;
|
||||
long resstart, reslength;
|
||||
|
||||
#if defined (COMPILE_V25)
|
||||
var[system_status] = STAT_UNAVAILABLE;
|
||||
#endif
|
||||
if (MEM(codeptr+1)==REPEAT_T) loop_flag = true, codeptr++;
|
||||
|
||||
#if !defined (COMPILE_V25)
|
||||
hugo_stopvideo();
|
||||
#endif
|
||||
|
||||
/* If a 0 parameter is passed, i.e. "video 0" */
|
||||
if (!GetResourceParameters(filename, resname, VIDEO_T))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (MEM(codeptr-1)==COMMA_T)
|
||||
{
|
||||
background = (char)GetValue();
|
||||
codeptr++; /* eol */
|
||||
}
|
||||
|
||||
if (extra_param>=0)
|
||||
{
|
||||
if (extra_param > 100) extra_param = 100;
|
||||
volume = extra_param;
|
||||
}
|
||||
|
||||
if (!(reslength = FindResource(filename, resname)))
|
||||
return;
|
||||
|
||||
/* Find out what type of video resource this is */
|
||||
resstart = hugo_ftell(resource_file);
|
||||
|
||||
/* Check for MPEG */
|
||||
hugo_fseek(resource_file, resstart, SEEK_SET);
|
||||
hugo_fread(resname, 4, 1, resource_file);
|
||||
if (resname[2]==0x01 && (unsigned char)resname[3]==0xba)
|
||||
{
|
||||
resource_type = MPEG_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* Check for AVI */
|
||||
hugo_fseek(resource_file, resstart+8, SEEK_SET);
|
||||
hugo_fread(resname, 4, 1, resource_file);
|
||||
if (!memcmp(resname, "AVI ", 4))
|
||||
{
|
||||
resource_type = AVI_R;
|
||||
goto Identified;
|
||||
}
|
||||
|
||||
/* No file type identified */
|
||||
resource_type = UNKNOWN_R;
|
||||
|
||||
Identified:
|
||||
hugo_fseek(resource_file, resstart, SEEK_SET);
|
||||
|
||||
#if !defined (COMPILE_V25)
|
||||
if (!hugo_playvideo(resource_file, reslength, loop_flag, background, volume))
|
||||
var[system_status] = STAT_LOADERROR;
|
||||
#else
|
||||
fclose(resource_file);
|
||||
resource_file = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
long Hugo::FindResource(const char *filename, const char *resname) {
|
||||
char resource_in_file[MAX_RES_PATH];
|
||||
int i, len;
|
||||
int rescount;
|
||||
unsigned int startofdata;
|
||||
long resposition, reslength;
|
||||
#if defined (GLK)
|
||||
frefid_t fref;
|
||||
#endif
|
||||
/* Previously, resource positions were written as 24 bits, which meant that
|
||||
a given resource couldn't start after 16,777,216 bytes or be more than
|
||||
that length. The new resource file format (designated by 'r') corrects this. */
|
||||
int res_32bits = true;
|
||||
|
||||
resource_file = nullptr;
|
||||
|
||||
Common::strcpy_s(loaded_filename, filename);
|
||||
Common::strcpy_s(loaded_resname, resname);
|
||||
if (!strcmp(filename, "")) Common::strcpy_s(loaded_filename, resname);
|
||||
|
||||
/* See if the file is supposed to be in a resourcefile to
|
||||
begin with
|
||||
*/
|
||||
if (!strcmp(filename, ""))
|
||||
goto NotinResourceFile;
|
||||
|
||||
|
||||
/* Open the resourcefile */
|
||||
//hugo_strupr(filename);
|
||||
|
||||
#if !defined (GLK)
|
||||
/* stdio implementation */
|
||||
if (!(resource_file = TrytoOpen(filename, "rb", "games")))
|
||||
if (!(resource_file = TrytoOpen(filename, "rb", "object")))
|
||||
{
|
||||
var[system_status] = STAT_NOFILE;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* Glk implementation */
|
||||
fref = glk_fileref_create_by_name(fileusage_Data | fileusage_BinaryMode,
|
||||
filename, 0);
|
||||
if (glk_fileref_does_file_exist(fref))
|
||||
resource_file = glk_stream_open_file(fref, filemode_Read, 0);
|
||||
else
|
||||
resource_file = nullptr;
|
||||
glk_fileref_destroy(fref);
|
||||
if (!resource_file)
|
||||
{
|
||||
var[system_status] = STAT_NOFILE;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read the resourcefile header */
|
||||
/* if (fgetc(resource_file)!='R') goto ResfileError; */
|
||||
i = hugo_fgetc(resource_file);
|
||||
if (i=='r')
|
||||
res_32bits = true;
|
||||
else if (i=='R')
|
||||
res_32bits = false;
|
||||
else
|
||||
goto ResfileError;
|
||||
/* Read and ignore the resource file version. */
|
||||
hugo_fgetc(resource_file);
|
||||
rescount = hugo_fgetc(resource_file);
|
||||
rescount += hugo_fgetc(resource_file)*256;
|
||||
startofdata = hugo_fgetc(resource_file);
|
||||
startofdata += (unsigned int)hugo_fgetc(resource_file)*256;
|
||||
if (hugo_ferror(resource_file))
|
||||
goto ResfileError;
|
||||
|
||||
|
||||
/* Now skim through the list of resources in the resourcefile to
|
||||
see if we have a match
|
||||
*/
|
||||
for (i=1; i<=rescount; i++)
|
||||
{
|
||||
len = hugo_fgetc(resource_file);
|
||||
if (hugo_ferror(resource_file))
|
||||
goto ResfileError;
|
||||
|
||||
if (!(hugo_fgets(resource_in_file, len+1, resource_file)))
|
||||
goto ResfileError;
|
||||
|
||||
resposition = (long)hugo_fgetc(resource_file);
|
||||
resposition += (long)hugo_fgetc(resource_file)*256L;
|
||||
resposition += (long)hugo_fgetc(resource_file)*65536L;
|
||||
if (res_32bits)
|
||||
{
|
||||
resposition += (long)hugo_fgetc(resource_file)*16777216L;
|
||||
}
|
||||
|
||||
reslength = (long)hugo_fgetc(resource_file);
|
||||
reslength += (long)hugo_fgetc(resource_file)*256L;
|
||||
reslength += (long)hugo_fgetc(resource_file)*65536L;
|
||||
if (res_32bits)
|
||||
{
|
||||
reslength += (long)hugo_fgetc(resource_file)*16777216L;
|
||||
}
|
||||
if (hugo_ferror(resource_file)) goto ResfileError;
|
||||
|
||||
if (!strcmp(resname, resource_in_file))
|
||||
{
|
||||
if (hugo_fseek(resource_file, (long)startofdata+resposition, SEEK_SET))
|
||||
goto ResfileError;
|
||||
return reslength;
|
||||
}
|
||||
}
|
||||
|
||||
ResfileError:
|
||||
|
||||
var[system_status] = STAT_NORESOURCE;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
SwitchtoDebugger();
|
||||
Common::sprintf_s(debug_line, "Unable to find \"%s\" in \"%s\"", resname, filename);
|
||||
DebugMessageBox("Resource Error", debug_line);
|
||||
SwitchtoGame();
|
||||
#endif
|
||||
hugo_fclose(resource_file);
|
||||
resource_file = nullptr;
|
||||
|
||||
|
||||
/* If we get here, we've either been unable to find the named
|
||||
resource in the given resourcefile, or no resourcefile was
|
||||
given
|
||||
*/
|
||||
NotinResourceFile:
|
||||
|
||||
#if !defined (GLK)
|
||||
/* stdio implementation */
|
||||
if (!(resource_file = TrytoOpen(resname, "rb", "resource")))
|
||||
if (!(resource_file = TrytoOpen(resname, "rb", "source")))
|
||||
{
|
||||
if (!strcmp(filename, ""))
|
||||
var[system_status] = STAT_NOFILE;
|
||||
else
|
||||
var[system_status] = STAT_NORESOURCE;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* Glk implementation */
|
||||
fref = glk_fileref_create_by_name(fileusage_Data | fileusage_BinaryMode,
|
||||
resname, 0);
|
||||
if (glk_fileref_does_file_exist(fref))
|
||||
resource_file = glk_stream_open_file(fref, filemode_Read, 0);
|
||||
else
|
||||
resource_file = nullptr;
|
||||
glk_fileref_destroy(fref);
|
||||
if (!resource_file)
|
||||
{
|
||||
if (!strcmp(filename, ""))
|
||||
var[system_status] = STAT_NOFILE;
|
||||
else
|
||||
var[system_status] = STAT_NORESOURCE;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* resource_file here refers to a resource in an individual
|
||||
on-disk file, not a consolidated resource file
|
||||
*/
|
||||
hugo_fseek(resource_file, 0, SEEK_END);
|
||||
reslength = hugo_ftell(resource_file);
|
||||
hugo_fseek(resource_file, 0, SEEK_SET);
|
||||
if (hugo_ferror(resource_file))
|
||||
{
|
||||
hugo_fclose(resource_file);
|
||||
resource_file = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return reslength;
|
||||
}
|
||||
|
||||
int Hugo::GetResourceParameters(char *filename, char *resname, int restype) {
|
||||
int f;
|
||||
|
||||
var[system_status] = 0;
|
||||
|
||||
extra_param = -1;
|
||||
|
||||
codeptr++; /* token--i.e., 'picture', etc. */
|
||||
|
||||
f = GetValue();
|
||||
|
||||
/* If a 0 parameter is passed for "music 0", etc. */
|
||||
if (!f && MEM(codeptr)!=COMMA_T)
|
||||
{
|
||||
++codeptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::strcpy_s(filename, MAX_RES_PATH, GetWord((unsigned int)f));
|
||||
|
||||
if (MEM(codeptr++)!=EOL_T) /* two or more parameters */
|
||||
{
|
||||
hugo_strupr(filename);
|
||||
Common::strcpy_s(resname, MAX_RES_PATH, GetWord(GetValue()));
|
||||
if (MEM(codeptr++)==COMMA_T)
|
||||
{
|
||||
extra_param = GetValue();
|
||||
codeptr++;
|
||||
}
|
||||
}
|
||||
else /* only one parameter */
|
||||
{
|
||||
Common::strcpy_s(resname, MAX_RES_PATH, filename);
|
||||
filename[0] = '\0';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
2631
engines/glk/hugo/herun.cpp
Normal file
2631
engines/glk/hugo/herun.cpp
Normal file
File diff suppressed because it is too large
Load Diff
582
engines/glk/hugo/heset.cpp
Normal file
582
engines/glk/hugo/heset.cpp
Normal file
@@ -0,0 +1,582 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/hugo.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
void Hugo::RunSet(int gotvalue) {
|
||||
char inc = 0; /* increment/decrement */
|
||||
char temparrexpr, propval = 0;
|
||||
int a = 0, t = 0, obj = 0;
|
||||
int newl = 0; /* new length */
|
||||
int newp = 0; /* new property val */
|
||||
unsigned int element = 0; /* of an array */
|
||||
|
||||
unsigned short n, m, v; /* must be 16 bits */
|
||||
|
||||
inobj = 0;
|
||||
|
||||
if (gotvalue!=-1)
|
||||
{
|
||||
obj = gotvalue;
|
||||
t = SetCompound(t);
|
||||
goto StoreVal;
|
||||
}
|
||||
|
||||
t = MEM(codeptr);
|
||||
|
||||
switch (t)
|
||||
{
|
||||
case OBJECTNUM_T:
|
||||
{
|
||||
codeptr++;
|
||||
obj = PeekWord(codeptr);
|
||||
codeptr += 2;
|
||||
t = SetCompound(t);
|
||||
break;
|
||||
}
|
||||
|
||||
case VAR_T:
|
||||
{
|
||||
a = MEM(codeptr + 1);
|
||||
|
||||
/* Check for ++, --, +=, etc. */
|
||||
inc = IsIncrement(codeptr+2);
|
||||
|
||||
if (MEM(codeptr + 2)==EQUALS_T || inc)
|
||||
{
|
||||
if (a < MAXGLOBALS) SaveUndo(VAR_T, a, var[a], 0, 0);
|
||||
|
||||
/* anonymous function */
|
||||
if (!inc && MEM(codeptr+3)==EOL_T)
|
||||
{
|
||||
var[a] = GetAnonymousFunction(codeptr+4);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inc)
|
||||
{
|
||||
var[a] = (Increment(var[a], inc)) + incdec;
|
||||
|
||||
/* backward-compatibility tweak */
|
||||
if ((game_version<23) && MEM(codeptr)!=CLOSE_BRACE_T) codeptr--;
|
||||
|
||||
codeptr++; /* eol */
|
||||
}
|
||||
else
|
||||
{
|
||||
codeptr += 3;
|
||||
inexpr = 1;
|
||||
SetupExpr();
|
||||
inexpr = 0;
|
||||
v = EvalExpr(0);
|
||||
var[a] = v;
|
||||
}
|
||||
|
||||
/* If a global variable */
|
||||
if (a < MAXGLOBALS)
|
||||
{
|
||||
if (a==wordcount) words = var[wordcount];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
obj = var[a];
|
||||
codeptr += 2;
|
||||
t = SetCompound(t);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WORD_T: /* "word" */
|
||||
{
|
||||
codeptr += 2; /* skip "[" */
|
||||
n = GetValue();
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
codeptr += 2; /* skip "] =" */
|
||||
inexpr = 1;
|
||||
SetupExpr();
|
||||
inexpr = 0;
|
||||
|
||||
GetNextWord:
|
||||
if (n >= MAXWORDS) n = MAXWORDS-1;
|
||||
SaveUndo(WORD_T, n, wd[n], 0, 0);
|
||||
wd[n] = EvalExpr(0);
|
||||
|
||||
if (MEM(codeptr)==COMMA_T)
|
||||
{
|
||||
codeptr++;
|
||||
n++;
|
||||
goto GetNextWord;
|
||||
}
|
||||
|
||||
/* Have to (rather unfortunately) rebuild the entire
|
||||
input buffer and word array here
|
||||
*/
|
||||
buffer[0] = '\0';
|
||||
t = 0;
|
||||
for (a=1; a<=(int)MAXWORDS; a++)
|
||||
{
|
||||
if ((unsigned short)wd[a]!=UNKNOWN_WORD)
|
||||
Common::strcpy_s(buffer+t, sizeof(buffer) - t, GetWord(wd[a]));
|
||||
else
|
||||
hugo_itoa(parsed_number, buffer+t, 10, sizeof(buffer) - t);
|
||||
word[a] = buffer + t;
|
||||
t+=strlen(word[a])+1;
|
||||
}
|
||||
|
||||
if (n>(unsigned)var[wordcount])
|
||||
var[wordcount] = n;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case ARRAYDATA_T:
|
||||
case ARRAY_T:
|
||||
{
|
||||
char af_flag = false;
|
||||
/* array[n]... */
|
||||
if (t==ARRAYDATA_T)
|
||||
{
|
||||
m = PeekWord(codeptr + 1);
|
||||
codeptr += 4; /* "[" */
|
||||
n = GetValue();
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
codeptr++; /* "]" */
|
||||
}
|
||||
|
||||
/* ...or array val[n] */
|
||||
else
|
||||
{
|
||||
codeptr++;
|
||||
m = GetValue();
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
codeptr++; /* "[" */
|
||||
n = GetValue();
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
codeptr++; /* "]" */
|
||||
}
|
||||
|
||||
if (game_version>=22)
|
||||
{
|
||||
/* Convert to word value */
|
||||
m*=2;
|
||||
|
||||
if (game_version>=23)
|
||||
/* Space for array length */
|
||||
a = 2;
|
||||
}
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
CheckinRange(m+a+n*2, debug_workspace, "array data");
|
||||
#endif
|
||||
/* Check for ++, --, +=, etc. */
|
||||
inc = IsIncrement(codeptr);
|
||||
if (inc)
|
||||
{
|
||||
defseg = arraytable;
|
||||
v = PeekWord(m+a+n*2);
|
||||
defseg = gameseg;
|
||||
v = (Increment(v, inc)) + incdec;
|
||||
|
||||
codeptr++; /* eol */
|
||||
|
||||
element = m+a+n*2;
|
||||
|
||||
goto WriteArrayValue;
|
||||
}
|
||||
|
||||
if (MEM(codeptr)==EQUALS_T)
|
||||
{
|
||||
codeptr++;
|
||||
|
||||
do
|
||||
{
|
||||
element = m+a+n*2;
|
||||
|
||||
temparrexpr = arrexpr;
|
||||
arrexpr = true;
|
||||
|
||||
/* anonymous function */
|
||||
if (!inc && MEM(codeptr)==EOL_T)
|
||||
{
|
||||
v = GetAnonymousFunction(codeptr+1);
|
||||
af_flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = GetValue();
|
||||
}
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
if (arrexpr==false && MEM(codeptr-1)==76)
|
||||
codeptr--;
|
||||
arrexpr = temparrexpr;
|
||||
|
||||
if (!af_flag && (MEM(codeptr)==COMMA_T || MEM(codeptr)==CLOSE_BRACKET_T))
|
||||
codeptr++;
|
||||
WriteArrayValue:
|
||||
defseg = arraytable;
|
||||
|
||||
/* Make sure the value to be written is within range */
|
||||
if ((element>0) && (element < (unsigned)(dicttable-arraytable)*16))
|
||||
{
|
||||
SaveUndo(ARRAYDATA_T, m+a, n, PeekWord(element), 0);
|
||||
|
||||
PokeWord(element, (unsigned int)v);
|
||||
}
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
if (inc || af_flag) return;
|
||||
|
||||
n++;
|
||||
}
|
||||
while (MEM(codeptr)!=EOL_T);
|
||||
|
||||
codeptr++;
|
||||
return;
|
||||
}
|
||||
|
||||
defseg = arraytable;
|
||||
obj = PeekWord((unsigned int)(m+a + n*2));
|
||||
defseg = gameseg;
|
||||
t = SetCompound(t);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StoreVal:
|
||||
|
||||
/* Now store the evaluated expression in the appropriate place... */
|
||||
|
||||
/*
|
||||
t = 1: property
|
||||
t = 2: attribute
|
||||
t = 3: not attribute
|
||||
t = 4: property reference
|
||||
*/
|
||||
|
||||
n = 1;
|
||||
|
||||
if (t==4)
|
||||
{
|
||||
inobj = true;
|
||||
n = GetValue();
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
inobj = false;
|
||||
|
||||
LoopBack:
|
||||
if (MEM(codeptr)==IS_T || MEM(codeptr)==DECIMAL_T)
|
||||
{
|
||||
obj = GetProp(obj, set_value, n, 0);
|
||||
t = SetCompound(t);
|
||||
goto LoopBack;
|
||||
}
|
||||
/* Don't set t = 1 if it changed above before going back
|
||||
to LoopBack:
|
||||
*/
|
||||
else if (t==4)
|
||||
t = 1; /* Just a property */
|
||||
}
|
||||
else if (t==1)
|
||||
{
|
||||
while (MEM(codeptr)==IS_T || MEM(codeptr)==DECIMAL_T)
|
||||
{
|
||||
obj = GetProp(obj, set_value, n, 0);
|
||||
t = SetCompound(t);
|
||||
}
|
||||
}
|
||||
|
||||
switch (t)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
incdec = 0;
|
||||
|
||||
if (MEM(codeptr) != EQUALS_T)
|
||||
{
|
||||
/* Check for ++, --, +=, etc. */
|
||||
if (!(inc = IsIncrement(codeptr)))
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (debug_eval)
|
||||
{
|
||||
debug_eval_error = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
FatalError(ILLEGAL_OP_E);
|
||||
}
|
||||
else if (MEM(codeptr)==EOL_T)
|
||||
{
|
||||
goto GetNextPropVal;
|
||||
}
|
||||
}
|
||||
else
|
||||
codeptr++;
|
||||
|
||||
/* Property routine (anonymous function)... */
|
||||
if (MEM(codeptr)==EOL_T)
|
||||
{
|
||||
/* m = skipptr to the end of the property
|
||||
routine block (i.e., the next statement
|
||||
following it)
|
||||
*/
|
||||
m = PeekWord(codeptr + 1);
|
||||
|
||||
newl = PROP_ROUTINE;
|
||||
newp =(unsigned int)(((codeptr + 4)+(codeptr + 4)%address_scale)/address_scale);
|
||||
codeptr = (long)m*address_scale;
|
||||
m = PropAddr(obj, set_value, 0);
|
||||
}
|
||||
|
||||
/* ...or not */
|
||||
else
|
||||
{
|
||||
GetNextPropVal:
|
||||
inexpr = false;
|
||||
temparrexpr = multiprop;
|
||||
multiprop = true;
|
||||
propval = true;
|
||||
if (!inc) newp = GetValue();
|
||||
#if defined (DEBUGGER)
|
||||
if ((debug_eval) && debug_eval_error)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!multiprop)
|
||||
codeptr--;
|
||||
multiprop = temparrexpr;
|
||||
|
||||
m = PropAddr(obj, set_value, 0);
|
||||
if (m)
|
||||
{
|
||||
defseg = proptable;
|
||||
newl = Peek((unsigned int)m + 1);
|
||||
if (newl==PROP_ROUTINE) newl = 1;
|
||||
}
|
||||
|
||||
/* Deal with setting built-in display object
|
||||
properties
|
||||
*/
|
||||
else if ((obj==display_object) && n==1)
|
||||
{
|
||||
if (set_value==title_caption)
|
||||
{
|
||||
Common::strlcpy(game_title, GetWord(newp), MAX_GAME_TITLE);
|
||||
hugo_setgametitle(game_title);
|
||||
}
|
||||
else if (set_value==needs_repaint)
|
||||
{
|
||||
display_needs_repaint = (char)newp;
|
||||
}
|
||||
}
|
||||
#if defined (DEBUGGER)
|
||||
/*
|
||||
else if (runtime_warnings)
|
||||
{
|
||||
RuntimeWarning("Setting non-existent property");
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Write property obj.z = newl words of newp */
|
||||
|
||||
if (m && (int)n <= 0)
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
RuntimeWarning("Property element <= 0");
|
||||
#endif
|
||||
if (inc) codeptr++;
|
||||
}
|
||||
else if (m && (int)n <= newl)
|
||||
{
|
||||
defseg = proptable;
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
CheckinRange((unsigned)n, (unsigned)Peek(m+1), "property element");
|
||||
#endif
|
||||
/* Check to make sure this property value is within range */
|
||||
if ((unsigned)(m+2+(n-1)*2)<(unsigned)(eventtable-proptable)*16)
|
||||
{
|
||||
SaveUndo(PROP_T, obj, (unsigned int)set_value, n, PeekWord((unsigned int)(m+2+(n-1)*2)));
|
||||
|
||||
/* Save the (possibly changed) length) */
|
||||
Poke((unsigned int)m + 1, (unsigned char)newl);
|
||||
|
||||
/* An assignment such as obj.prop++ or
|
||||
obj.prop += ...
|
||||
*/
|
||||
if (inc)
|
||||
{
|
||||
PokeWord((unsigned int)(m+2+(n-1)*2), Increment(PeekWord((unsigned int)(m+2+(n-1)*2)), inc) + incdec);
|
||||
codeptr++; /* eol */
|
||||
}
|
||||
|
||||
/* A regular obj.prop = ... assignment */
|
||||
else
|
||||
PokeWord((unsigned int)(m+2+(n-1)*2), newp);
|
||||
}
|
||||
}
|
||||
else if (inc) codeptr++; /* eol */
|
||||
|
||||
defseg = gameseg;
|
||||
|
||||
if (inc) return;
|
||||
|
||||
if (propval && MEM(codeptr)==COMMA_T)
|
||||
{n++;
|
||||
codeptr++;
|
||||
goto GetNextPropVal;}
|
||||
|
||||
if (propval) codeptr++;
|
||||
if (MEM(codeptr)==EOL_T) codeptr++;
|
||||
return;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
ModifyAttribute:
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
CheckinRange((unsigned int)set_value, (unsigned)attributes, "attribute");
|
||||
#endif
|
||||
SaveUndo(ATTR_T, obj, (unsigned int)set_value, TestAttribute(obj, (unsigned int)set_value, 0), 0);
|
||||
|
||||
SetAttribute(obj, set_value, (t==2));
|
||||
t = 2; /* reset after 'not' */
|
||||
|
||||
if (MEM(codeptr++)==EOL_T) return;
|
||||
|
||||
/* Allow multiple attributes, comma-separated */
|
||||
if (MEM(codeptr)==COMMA_T)
|
||||
codeptr++;
|
||||
|
||||
if (MEM(codeptr)==NOT_T)
|
||||
{
|
||||
t = 3;
|
||||
codeptr++;
|
||||
}
|
||||
|
||||
set_value = GetValue();
|
||||
goto ModifyAttribute;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (debug_eval)
|
||||
{
|
||||
debug_eval_error = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Not any sort of variable data type */
|
||||
FatalError(ILLEGAL_OP_E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Hugo::GetAnonymousFunction(long addr) {
|
||||
long skipaddr;
|
||||
unsigned int af_addr;
|
||||
|
||||
skipaddr = PeekWord(addr);
|
||||
/* The address of the anonymous function is the next address boundary,
|
||||
calculated as:
|
||||
(((addr+2)/address_scale+1)*address_scale)/address_scale */
|
||||
af_addr =(unsigned int)((addr+2)/address_scale+1);
|
||||
codeptr = (long)skipaddr*address_scale;
|
||||
return af_addr;
|
||||
}
|
||||
|
||||
int Hugo::SetCompound(int t) {
|
||||
if (Peek(codeptr)==DECIMAL_T) /* obj.property */
|
||||
{
|
||||
codeptr++;
|
||||
inobj = 1;
|
||||
set_value = GetValue(); /* the prop. # */
|
||||
inobj = 0;
|
||||
|
||||
if (Peek(codeptr)==POUND_T) /* if obj.prop #... */
|
||||
{
|
||||
codeptr++;
|
||||
return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Peek(codeptr)==IS_T) /* obj is ... */
|
||||
{
|
||||
inobj = 1;
|
||||
if (Peek(codeptr+1)==NOT_T)
|
||||
{
|
||||
codeptr += 2;
|
||||
set_value = GetValue(); /* the attr. # */
|
||||
inobj = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
codeptr++;
|
||||
set_value = GetValue(); /* the attr. # */
|
||||
inobj = 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
if (debug_eval)
|
||||
debug_eval_error = true;
|
||||
else
|
||||
#endif
|
||||
|
||||
FatalError(ILLEGAL_OP_E);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
78
engines/glk/hugo/htokens.cpp
Normal file
78
engines/glk/hugo/htokens.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/htokens.h"
|
||||
#include "common/algorithm.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
const char *const HTokens::token[] = {
|
||||
/* 0x00 - 0x0f */
|
||||
"", "(", ")", ".", ":", "=", "-", "+",
|
||||
"*", "/", "|", ";", "{", "}", "[", "]",
|
||||
|
||||
/* 0x10 - 0x1f */
|
||||
"#", "~", ">=", "<=", "~=", "&", ">", "<",
|
||||
"if", ",", "else", "elseif", "while", "do", "select", "case",
|
||||
|
||||
/* 0x20 - 0x2f */
|
||||
"for", "return", "break", "and", "or", "jump", "run", "is",
|
||||
"not", "true", "false", "local", "verb", "xverb", "held", "multi",
|
||||
|
||||
/* 0x30 - 0x3f */
|
||||
"multiheld", "newline", "anything", "print",
|
||||
"number", "capital", "text", "graphics",
|
||||
"color", "remove", "move", "to",
|
||||
"parent", "sibling", "child", "youngest",
|
||||
|
||||
/* 0x40 - 0x4f */
|
||||
"eldest", "younger", "elder", "prop#",
|
||||
"attr#", "var#", "dictentry#", "textdata#",
|
||||
"routine#","debugdata#","objectnum#", "value#",
|
||||
"eol#", "system", "notheld", "multinotheld",
|
||||
|
||||
/* 0x50 - 0x5f */
|
||||
"window", "random", "word", "locate",
|
||||
"parse$", "children", "in", "pause",
|
||||
"runevents", "arraydata#", "call", "stringdata#",
|
||||
"save", "restore", "quit", "input",
|
||||
|
||||
/* 0x60 - 0x6f */
|
||||
"serial$", "cls", "scripton", "scriptoff",
|
||||
"restart", "hex", "object", "xobject",
|
||||
"string", "array", "printchar", "undo",
|
||||
"dict", "recordon", "recordoff", "writefile",
|
||||
|
||||
/* 0x70 - */
|
||||
"readfile", "writeval", "readval", "playback",
|
||||
"colour", "picture", "label#", "sound",
|
||||
"music", "repeat", "addcontext", "video"
|
||||
};
|
||||
|
||||
int HTokens::token_hash[TOKENS + 1];
|
||||
|
||||
HTokens::HTokens() {
|
||||
Common::fill(&token_hash[0], &token_hash[TOKENS + 1], 0);
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
99
engines/glk/hugo/htokens.h
Normal file
99
engines/glk/hugo/htokens.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_HUGO_HTOKENS
|
||||
#define GLK_HUGO_HTOKENS
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
/*
|
||||
* This file contains token definitions for the Hugo Compiler and Engine
|
||||
* The enum constants of type TOKEN_T reflect the token names given in the token array.
|
||||
* Token names followed by a # are for system use.
|
||||
*/
|
||||
|
||||
/* i.e., highest numbered token */
|
||||
#define TOKENS 0x7B
|
||||
|
||||
/* arbitrary */
|
||||
#define HASH_KEY 1023
|
||||
|
||||
enum TOKEN_T {
|
||||
/* 0x00 - 0x0f */
|
||||
NULL_T, OPEN_BRACKET_T, CLOSE_BRACKET_T, DECIMAL_T,
|
||||
COLON_T, EQUALS_T, MINUS_T, PLUS_T,
|
||||
ASTERISK_T, FORWARD_SLASH_T, PIPE_T, SEMICOLON_T,
|
||||
OPEN_BRACE_T, CLOSE_BRACE_T, OPEN_SQUARE_T, CLOSE_SQUARE_T,
|
||||
|
||||
/* 0x10 - 0x1f */
|
||||
POUND_T, TILDE_T, GREATER_EQUAL_T, LESS_EQUAL_T,
|
||||
NOT_EQUAL_T, AMPERSAND_T, GREATER_T, LESS_T,
|
||||
IF_T, COMMA_T, ELSE_T, ELSEIF_T,
|
||||
WHILE_T, DO_T, SELECT_T, CASE_T,
|
||||
|
||||
/* 0x20 - 0x2f */
|
||||
FOR_T, RETURN_T, BREAK_T, AND_T,
|
||||
OR_T, JUMP_T, RUN_T, IS_T,
|
||||
NOT_T, TRUE_T, FALSE_T, LOCAL_T,
|
||||
VERB_T, XVERB_T, HELD_T, MULTI_T,
|
||||
|
||||
/* 0x30 - 0x3f */
|
||||
MULTIHELD_T, NEWLINE_T, ANYTHING_T, PRINT_T,
|
||||
NUMBER_T, CAPITAL_T, TEXT_T, GRAPHICS_T,
|
||||
COLOR_T, REMOVE_T, MOVE_T, TO_T,
|
||||
PARENT_T, SIBLING_T, CHILD_T, YOUNGEST_T,
|
||||
|
||||
/* 0x40 - 0x4f */
|
||||
ELDEST_T, YOUNGER_T, ELDER_T, PROP_T,
|
||||
ATTR_T, VAR_T, DICTENTRY_T, TEXTDATA_T,
|
||||
ROUTINE_T, DEBUGDATA_T, OBJECTNUM_T, VALUE_T,
|
||||
EOL_T, SYSTEM_T, NOTHELD_T, MULTINOTHELD_T,
|
||||
|
||||
/* 0x50 - 0x5f */
|
||||
WINDOW_T, RANDOM_T, WORD_T, LOCATE_T,
|
||||
PARSE_T, CHILDREN_T, IN_T, PAUSE_T,
|
||||
RUNEVENTS_T, ARRAYDATA_T, CALL_T, STRINGDATA_T,
|
||||
SAVE_T, RESTORE_T, QUIT_T, INPUT_T,
|
||||
|
||||
/* 0x60 - 0x6f */
|
||||
SERIAL_T, CLS_T, SCRIPTON_T, SCRIPTOFF_T,
|
||||
RESTART_T, HEX_T, OBJECT_T, XOBJECT_T,
|
||||
STRING_T, ARRAY_T, PRINTCHAR_T, UNDO_T,
|
||||
DICT_T, RECORDON_T, RECORDOFF_T, WRITEFILE_T,
|
||||
|
||||
/* 0x70 - */
|
||||
READFILE_T, WRITEVAL_T, READVAL_T, PLAYBACK_T,
|
||||
COLOUR_T, PICTURE_T, LABEL_T, SOUND_T,
|
||||
MUSIC_T, REPEAT_T, ADDCONTEXT_T, VIDEO_T
|
||||
};
|
||||
|
||||
struct HTokens {
|
||||
static const char *const token[];
|
||||
static int token_hash[];
|
||||
|
||||
HTokens();
|
||||
};
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
331
engines/glk/hugo/hugo.cpp
Normal file
331
engines/glk/hugo/hugo.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/hugo.h"
|
||||
#include "glk/hugo/resource_archive.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
Hugo *g_vm;
|
||||
|
||||
Hugo::Hugo(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
|
||||
mainwin(nullptr), currentwin(nullptr), secondwin(nullptr), auxwin(nullptr),
|
||||
runtime_warnings(false), dbnest(0), address_scale(16),
|
||||
SCREENWIDTH(0), SCREENHEIGHT(0), FIXEDCHARWIDTH(0), FIXEDLINEHEIGHT(0),
|
||||
// heexpr
|
||||
evalcount(0), incdec(0), getaddress(0), inexpr(0), inobj(0), last_precedence(0),
|
||||
// hemedia
|
||||
mchannel(nullptr), schannel(nullptr),
|
||||
// hemisc
|
||||
game_version(0), object_size(24), game(nullptr), script(nullptr),
|
||||
playback(nullptr), record(nullptr), io(nullptr), ioblock('\0'), ioerror('\0'),
|
||||
codestart(0), objtable(0), eventtable(0), proptable(0), arraytable(0), dicttable(0),
|
||||
syntable(0), initaddr(0), mainaddr(0), parseaddr(0), parseerroraddr(0),
|
||||
findobjectaddr(0), endgameaddr(0), speaktoaddr(0), performaddr(0),
|
||||
objects(0), events(0), dictcount(0), syncount(0), mem(nullptr), loaded_in_memory(true),
|
||||
defseg(0), gameseg(0), codeptr(0), codeend(0), currentpos(0), currentline(0), full(0),
|
||||
def_fcolor(0), def_bgcolor(0), def_slfcolor(0), def_slbgcolor(0), fcolor(0), bgcolor(0),
|
||||
icolor(0), default_bgcolor(0), currentfont(0), capital(0), textto(0),
|
||||
physical_windowwidth(0), physical_windowheight(0), physical_windowtop(0),
|
||||
physical_windowleft(0), physical_windowbottom(0), physical_windowright(0),
|
||||
inwindow(0), charwidth(0), lineheight(0), current_text_x(0), current_text_y(0),
|
||||
skipping_more(false), undoptr(0), undoturn(0), undoinvalid(0), undorecord(0),
|
||||
context_commands(0), in_valid_window(false), glk_fcolor(DEF_FCOLOR), glk_bgcolor(DEF_BGCOLOR),
|
||||
mainwin_bgcolor(0), glk_current_font(0), just_cleared_screen(false), secondwin_bottom(0),
|
||||
// heobject
|
||||
display_object(-1), display_needs_repaint(0), display_pointer_x(0), display_pointer_y(0),
|
||||
// heparse
|
||||
words(0), parsed_number(0), remaining(0), xverb(0), starts_with_verb(0),
|
||||
grammaraddr(0), obj_parselist(nullptr), domain(0), odomain(0), objcount(0),
|
||||
parse_allflag(false), pobjcount(0), pobj(0), obj_match_state(0), object_is_number(0),
|
||||
objgrammar(0), objstart(0), objfinish(0), addflag(false), speaking(0), oopscount(0),
|
||||
parse_called_twice(0), reparse_everything(0), full_buffer(0), recursive_call(false),
|
||||
parse_location(0),
|
||||
// heres
|
||||
resource_file(nullptr), extra_param(0), resource_type(0),
|
||||
// herun
|
||||
arguments_passed(0), ret(0), retflag(0), during_player_input(false), override_full(0),
|
||||
game_reset(false), stack_depth(0), tail_recursion(0), tail_recursion_addr(0),
|
||||
last_window_top(0), last_window_bottom(0), last_window_left(0), last_window_right(0),
|
||||
lowest_windowbottom(0), physical_lowest_windowbottom(0), just_left_window(false),
|
||||
// heset
|
||||
arrexpr(0), multiprop(0), set_value(0)
|
||||
#if defined (DEBUGGER)
|
||||
, debug_eval(false), debug_eval_error(false), debugger_step_over(false),
|
||||
debugger_finish(false), debugger_run(false), debugger_interrupt(false),
|
||||
debugger_skip(false), runtime_error(false), currentroutine(false),
|
||||
complex_prop_breakpoint(false), trace_complex_prop_routine(false), routines(0),
|
||||
properties(0), current_locals(0), this_codeptr(0), debug_workspace(0), attributes(0),
|
||||
original_dictcount(0), buffered_code_lines(0), debugger_has_stepped_back(false),
|
||||
debugger_step_back(false), debugger_collapsing(0), runaway_counter(0), history_count(0),
|
||||
active_screen(0), step_nest(0), history_last(0)
|
||||
#endif
|
||||
{
|
||||
g_vm = this;
|
||||
gamefile[0] = '\0';
|
||||
|
||||
// heexpr
|
||||
Common::fill(&eval[0], &eval[MAX_EVAL_ELEMENTS], 0);
|
||||
Common::fill(&var[0], &var[MAXLOCALS + MAXGLOBALS], 0);
|
||||
|
||||
// hemedia
|
||||
Common::fill(&resids[0][0], &resids[1][MAXRES], 0);
|
||||
numres[0] = numres[1] = 0;
|
||||
|
||||
// hemisc
|
||||
Common::fill(&context_command[0][0], &context_command[MAX_CONTEXT_COMMANDS - 1][64], 0);
|
||||
Common::fill(&id[0], &id[3], '\0');
|
||||
Common::fill(&serial[0], &serial[9], '\0');
|
||||
Common::fill(&pbuffer[0], &pbuffer[MAXBUFFER * 2 + 1], 0);
|
||||
Common::fill(&undostack[0][0], &undostack[MAXUNDO - 1][5], 0);
|
||||
|
||||
// heparse
|
||||
Common::fill(&buffer[0], &buffer[MAXBUFFER + MAXWORDS], '\0');
|
||||
Common::fill(&errbuf[0], &errbuf[MAXBUFFER + 1], 0);
|
||||
Common::fill(&line[0], &line[1025], 0);
|
||||
Common::fill(&word[0], &word[MAXWORDS + 1], (char *)nullptr);
|
||||
Common::fill(&wd[0], &wd[MAXWORDS + 1], 0);
|
||||
Common::fill(&parseerr[0], &parseerr[MAXBUFFER + 1], '\0');
|
||||
Common::fill(&parsestr[0], &parsestr[MAXBUFFER + 1], '\0');
|
||||
Common::fill(&objlist[0], &objlist[MAXOBJLIST], 0);
|
||||
Common::fill(&objword_cache[0], &objword_cache[MAXWORDS], 0);
|
||||
Common::fill(&oops[0], &oops[MAXBUFFER + 1], '\0');
|
||||
Common::fill(&punc_string[0], &punc_string[64], '\0');
|
||||
|
||||
// heres
|
||||
Common::fill(&loaded_filename[0], &loaded_filename[MAX_RES_PATH], '\0');
|
||||
Common::fill(&loaded_resname[0], &loaded_resname[MAX_RES_PATH], '\0');
|
||||
|
||||
// herun
|
||||
Common::fill(&passlocal[0], &passlocal[MAXLOCALS], 0);
|
||||
|
||||
// heset
|
||||
game_title[0] = '\0';
|
||||
|
||||
// Miscellaneous
|
||||
_savegameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
|
||||
|
||||
#ifdef DEBUGGER
|
||||
debug_line[0] = '\0';
|
||||
Common::fill(&objectname[0], &objectname[MAX_OBJECT], (char *)nullptr);
|
||||
Common::fill(&propertyname[0], &propertyname[MAX_PROPERTY], (char *)nullptr);
|
||||
Common::fill(&codeline[0][0], &codeline[9][0], 0);
|
||||
Common::fill(&localname[0][0], &localname[9][0], 0);
|
||||
Common::fill(&code_history[0], &code_history[MAX_CODE_HISTORY], 0);
|
||||
Common::fill(&dbnest_history[0], &dbnest_history[MAX_CODE_HISTORY], 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Hugo::~Hugo() {
|
||||
g_vm = nullptr;
|
||||
}
|
||||
|
||||
void Hugo::runGame() {
|
||||
hugo_init_screen();
|
||||
|
||||
SetupDisplay();
|
||||
|
||||
Common::strcpy_s(gamefile, getFilename().c_str());
|
||||
pbuffer[0] = '\0';
|
||||
|
||||
ResourceArchive *res = new ResourceArchive();
|
||||
SearchMan.add("Resources", res);
|
||||
|
||||
gameseg = 0;
|
||||
|
||||
LoadGame();
|
||||
|
||||
playGame();
|
||||
|
||||
hugo_cleanup_screen();
|
||||
|
||||
hugo_blockfree(mem);
|
||||
mem = nullptr;
|
||||
hugo_closefiles();
|
||||
}
|
||||
|
||||
Common::Error Hugo::readSaveData(Common::SeekableReadStream *rs) {
|
||||
char testid[3], testserial[9];
|
||||
int lbyte, hbyte;
|
||||
int j;
|
||||
unsigned int k, undosize;
|
||||
long i;
|
||||
|
||||
/* Check ID */
|
||||
testid[0] = (char)hugo_fgetc(rs);
|
||||
testid[1] = (char)hugo_fgetc(rs);
|
||||
testid[2] = '\0';
|
||||
if (hugo_ferror(rs)) goto RestoreError;
|
||||
|
||||
if (strcmp(testid, id)) {
|
||||
GUIErrorMessage(_("Incorrect rs file."));
|
||||
goto RestoreError;
|
||||
}
|
||||
|
||||
/* Check serial number */
|
||||
if (!hugo_fgets(testserial, 9, rs)) goto RestoreError;
|
||||
if (strcmp(testserial, serial)) {
|
||||
GUIErrorMessage(_("Save file created by different version."));
|
||||
goto RestoreError;
|
||||
}
|
||||
|
||||
/* Restore variables */
|
||||
for (k = 0; k<MAXGLOBALS + MAXLOCALS; k++) {
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF)
|
||||
goto RestoreError;
|
||||
var[k] = lbyte + hbyte * 256;
|
||||
}
|
||||
|
||||
/* Restore objtable and above */
|
||||
|
||||
if (hugo_fseek(game, objtable*16L, SEEK_SET)) goto RestoreError;
|
||||
i = 0;
|
||||
|
||||
while (i<codeend-(long)(objtable*16L)) {
|
||||
if ((hbyte = hugo_fgetc(rs))==EOF && hugo_ferror(rs)) goto RestoreError;
|
||||
|
||||
if (hbyte == 0) {
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF && hugo_ferror(rs)) goto RestoreError;
|
||||
SETMEM(objtable*16L+i, (unsigned char)lbyte);
|
||||
i++;
|
||||
|
||||
/* Skip byte in game file */
|
||||
if (hugo_fgetc(game)==EOF) goto RestoreError;
|
||||
} else {
|
||||
while (hbyte--) {
|
||||
/* Get unchanged game file byte */
|
||||
if ((lbyte = hugo_fgetc(game))==EOF) goto RestoreError;
|
||||
SETMEM(objtable*16L+i, (unsigned char)lbyte);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore undo data */
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF)
|
||||
goto RestoreError;
|
||||
undosize = lbyte + hbyte*256;
|
||||
|
||||
/* We can only restore undo data if it was saved by a port with
|
||||
the same MAXUNDO as us */
|
||||
if (undosize == MAXUNDO) {
|
||||
for (k = 0; k < MAXUNDO; k++) {
|
||||
for (j=0; j<5; j++) {
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF)
|
||||
goto RestoreError;
|
||||
undostack[k][j] = lbyte + hbyte*256;
|
||||
}
|
||||
}
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF) goto RestoreError;
|
||||
undoptr = lbyte + hbyte*256;
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF) goto RestoreError;
|
||||
undoturn = lbyte + hbyte*256;
|
||||
if ((lbyte = hugo_fgetc(rs))==EOF || (hbyte = hugo_fgetc(rs))==EOF) goto RestoreError;
|
||||
undoinvalid = (unsigned char)lbyte, undorecord = (unsigned char)hbyte;
|
||||
}
|
||||
else undoinvalid = true;
|
||||
|
||||
return Common::kNoError;
|
||||
|
||||
RestoreError:
|
||||
return Common::kReadingFailed;
|
||||
}
|
||||
|
||||
Common::Error Hugo::writeGameData(Common::WriteStream *ws) {
|
||||
int c, j;
|
||||
int lbyte, hbyte;
|
||||
long i;
|
||||
int samecount = 0;
|
||||
|
||||
/* Write ID */
|
||||
if (hugo_fputc(id[0], ws) == EOF || hugo_fputc(id[1], ws) == EOF) goto SaveError;
|
||||
|
||||
/* Write serial number */
|
||||
if (hugo_fputs(serial, ws) == EOF) goto SaveError;
|
||||
|
||||
/* Save variables */
|
||||
for (c = 0; c<MAXGLOBALS + MAXLOCALS; c++) {
|
||||
hbyte = (unsigned int)var[c] / 256;
|
||||
lbyte = (unsigned int)var[c] - hbyte * 256;
|
||||
if (hugo_fputc(lbyte, ws) == EOF || hugo_fputc(hbyte, ws) == EOF) goto SaveError;
|
||||
}
|
||||
|
||||
/* Save objtable to end of code space */
|
||||
|
||||
if (hugo_fseek(game, objtable * 16L, SEEK_SET)) goto SaveError;
|
||||
|
||||
for (i = 0; i <= codeend - (long)(objtable * 16L); i++) {
|
||||
if ((lbyte = hugo_fgetc(game)) == EOF) goto SaveError;
|
||||
hbyte = MEM(objtable * 16L + i);
|
||||
|
||||
/* If memory same as original game file */
|
||||
if (lbyte == hbyte && samecount < 255)
|
||||
samecount++;
|
||||
|
||||
/* If memory differs (or samecount exceeds 1 byte) */
|
||||
else {
|
||||
if (samecount)
|
||||
if (hugo_fputc(samecount, ws) == EOF) goto SaveError;
|
||||
|
||||
if (lbyte != hbyte) {
|
||||
if (hugo_fputc(0, ws) == EOF) goto SaveError;
|
||||
if (hugo_fputc(hbyte, ws) == EOF) goto SaveError;
|
||||
samecount = 0;
|
||||
}
|
||||
else samecount = 1;
|
||||
}
|
||||
}
|
||||
if (samecount)
|
||||
if (hugo_fputc(samecount, ws) == EOF) goto SaveError;
|
||||
|
||||
/* Save undo data */
|
||||
|
||||
/* Save the number of turns in this port's undo stack */
|
||||
hbyte = (unsigned int)MAXUNDO / 256;
|
||||
lbyte = (unsigned int)MAXUNDO - hbyte * 256;
|
||||
if (hugo_fputc(lbyte, ws) == EOF || hugo_fputc(hbyte, ws) == EOF)
|
||||
goto SaveError;
|
||||
for (c = 0; c < MAXUNDO; c++) {
|
||||
for (j = 0; j < 5; j++) {
|
||||
hbyte = (unsigned int)undostack[c][j] / 256;
|
||||
lbyte = (unsigned int)undostack[c][j] - hbyte * 256;
|
||||
if (hugo_fputc(lbyte, ws) == EOF || hugo_fputc(hbyte, ws) == EOF)
|
||||
goto SaveError;
|
||||
}
|
||||
}
|
||||
if (hugo_fputc(undoptr - (undoptr / 256) * 256, ws) == EOF || hugo_fputc(undoptr / 256, ws) == EOF)
|
||||
goto SaveError;
|
||||
if (hugo_fputc(undoturn - (undoturn / 256) * 256, ws) == EOF || hugo_fputc(undoturn / 256, ws) == EOF)
|
||||
goto SaveError;
|
||||
if (hugo_fputc(undoinvalid, ws) == EOF || hugo_fputc(undorecord, ws) == EOF)
|
||||
goto SaveError;
|
||||
|
||||
return Common::kNoError;
|
||||
|
||||
SaveError:
|
||||
return Common::kWritingFailed;
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
1217
engines/glk/hugo/hugo.h
Normal file
1217
engines/glk/hugo/hugo.h
Normal file
File diff suppressed because it is too large
Load Diff
194
engines/glk/hugo/hugo_defines.h
Normal file
194
engines/glk/hugo/hugo_defines.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_HUGO_DEFINES
|
||||
#define GLK_HUGO_DEFINES
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
#define HEVERSION 3
|
||||
#define HEREVISION 3
|
||||
#define HEINTERIM ".0"
|
||||
|
||||
#define GLK
|
||||
#define GRAPHICS_SUPPORTED
|
||||
#define SOUND_SUPPORTED
|
||||
#define SETTITLE_SUPPORTED
|
||||
#define SAVEGAMEDATA_REPLACED
|
||||
#define RESTOREGAMEDATA_REPLACED
|
||||
|
||||
// There's a bunch of debugging code in the original Hugo sources behind DEBUGGER defines,
|
||||
// but doesn't actually have any implementation of them. I've put in some stub methods,
|
||||
// with the idea that debugger code could eventually be hooked up to the ScummVM debugger.
|
||||
// So for now the debugger defined is commented out, since with debugger enabled the games
|
||||
// don't work properly
|
||||
//#define DEBUGGER 1
|
||||
|
||||
|
||||
#define MAXOBJLIST 32
|
||||
#define MAX_CONTEXT_COMMANDS 32
|
||||
#define MAX_EVAL_ELEMENTS 256
|
||||
#define MAX_GAME_TITLE 64
|
||||
#define MAX_DEBUG_LINE 256
|
||||
#define MAX_OBJECT 999
|
||||
#define MAX_PROPERTY 999
|
||||
// maximum number of matchable object words
|
||||
#define MAX_MOBJ 16
|
||||
// Larger than normal since Glk doesn't break up paragraphs (1024+256)
|
||||
#define MAXBUFFER 1280
|
||||
#define MAXUNDO 1024
|
||||
#define MAXCALLS 99
|
||||
#define MAXBREAKPOINTS 99
|
||||
#define MAX_CODE_HISTORY 99
|
||||
#define MAX_RES_PATH 255
|
||||
#define MAXRES 1024
|
||||
#define CHARWIDTH 1
|
||||
|
||||
#define HUGO_FILE strid_t
|
||||
#define MAXPATH 256
|
||||
#define MAXFILENAME 256
|
||||
#define MAXDRIVE 256
|
||||
#define MAXDIR 256
|
||||
#define MAXEXT 256
|
||||
|
||||
#define DEF_PRN ""
|
||||
#define DEF_FCOLOR 0
|
||||
#define DEF_BGCOLOR 15
|
||||
#define DEF_SLFCOLOR 15
|
||||
#define DEF_SLBGCOLOR 1
|
||||
|
||||
/* These static values are not changeable--they depend largely on internals of the Engine. */
|
||||
#define MAXATTRIBUTES 128
|
||||
#define MAXGLOBALS 240
|
||||
#define MAXLOCALS 16
|
||||
#define MAXPOBJECTS 256 /* contenders for disambiguation */
|
||||
#define MAXWORDS 32 /* in an input line */
|
||||
#define MAXSTACKDEPTH 256 /* for nesting {...} */
|
||||
|
||||
|
||||
/* The positions of various data in the header: */
|
||||
#define H_GAMEVERSION 0x00
|
||||
#define H_ID 0x01
|
||||
#define H_SERIAL 0x03
|
||||
#define H_CODESTART 0x0B
|
||||
|
||||
#define H_OBJTABLE 0x0D /* data tables */
|
||||
#define H_PROPTABLE 0x0F
|
||||
#define H_EVENTTABLE 0x11
|
||||
#define H_ARRAYTABLE 0x13
|
||||
#define H_DICTTABLE 0x15
|
||||
#define H_SYNTABLE 0x17
|
||||
|
||||
#define H_INIT 0x19 /* junction routines */
|
||||
#define H_MAIN 0x1B
|
||||
#define H_PARSE 0x1D
|
||||
#define H_PARSEERROR 0x1F
|
||||
#define H_FINDOBJECT 0x21
|
||||
#define H_ENDGAME 0x23
|
||||
#define H_SPEAKTO 0x25
|
||||
#define H_PERFORM 0x27
|
||||
|
||||
#define H_TEXTBANK 0x29
|
||||
|
||||
/* additional debugger header information */
|
||||
#define H_DEBUGGABLE 0x3A
|
||||
#define H_DEBUGDATA 0x3B
|
||||
#define H_DEBUGWORKSPACE 0x3E
|
||||
|
||||
/* Printing control codes--embedded in strings printed by AP(). */
|
||||
#define FONT_CHANGE 1
|
||||
#define COLOR_CHANGE 2
|
||||
#define NO_CONTROLCHAR 3
|
||||
#define NO_NEWLINE 30
|
||||
#define FORCED_SPACE 31 /* Can't be <= # colors/font codes + 1
|
||||
(See AP() for the reason) */
|
||||
|
||||
/* Font control codes--these bitmasks follow FONT_CHANGE codes. */
|
||||
#define NORMAL_FONT 0
|
||||
#define BOLD_FONT 1
|
||||
#define ITALIC_FONT 2
|
||||
#define UNDERLINE_FONT 4
|
||||
#define PROP_FONT 8
|
||||
|
||||
/* CHAR_TRANSLATION is simply a value that is added to an ASCII character
|
||||
in order to encode the text, i.e., make it unreadable to casual
|
||||
browsing.
|
||||
*/
|
||||
#define CHAR_TRANSLATION 0x14
|
||||
|
||||
/* Passed to GetWord() */
|
||||
#define PARSE_STRING_VAL 0xFFF0
|
||||
#define SERIAL_STRING_VAL 0xFFF1
|
||||
|
||||
/* Returned by FindWord() */
|
||||
#define UNKNOWN_WORD 0xFFFF
|
||||
|
||||
/* Bitmasks for certain qualities of properties */
|
||||
#define ADDITIVE_FLAG 1
|
||||
#define COMPLEX_FLAG 2
|
||||
|
||||
/* Property-table indicators */
|
||||
#define PROP_END 255
|
||||
#define PROP_ROUTINE 255
|
||||
|
||||
#define MEM(addr) (mem[addr])
|
||||
#define SETMEM(addr, n) (mem[addr] = n)
|
||||
#define GETMEMADDR(addr) (&mem[addr])
|
||||
#define HUGO_PTR
|
||||
|
||||
#define RESET_STACK_DEPTH (-1)
|
||||
|
||||
#define RUNROUTINE_BLOCK 1
|
||||
#define CONDITIONAL_BLOCK 2
|
||||
#define DOWHILE_BLOCK 3
|
||||
|
||||
#define TAIL_RECURSION_ROUTINE (-1)
|
||||
#define TAIL_RECURSION_PROPERTY (-2)
|
||||
|
||||
/* For system_status: */
|
||||
#define STAT_UNAVAILABLE ((short)-1)
|
||||
#define STAT_NOFILE 101
|
||||
#define STAT_NORESOURCE 102
|
||||
#define STAT_LOADERROR 103
|
||||
|
||||
#define PRINTFATALERROR(a) error("%s", a)
|
||||
|
||||
#define PIC 0
|
||||
#define SND 1
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
#define VIEW_CALLS 0
|
||||
#define VIEW_LOCALS 1
|
||||
#define CODE_WINDOW 2
|
||||
#define VIEW_BREAKPOINTS 3
|
||||
#define VIEW_WATCH 4
|
||||
|
||||
#define FORCE_REDRAW 1
|
||||
|
||||
#endif
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
174
engines/glk/hugo/hugo_types.h
Normal file
174
engines/glk/hugo/hugo_types.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_HUGO_TYPES
|
||||
#define GLK_HUGO_TYPES
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
/**
|
||||
* Library/engine globals
|
||||
*/
|
||||
enum EngineGlobals {
|
||||
object = 0,
|
||||
xobject = 1,
|
||||
self = 2,
|
||||
wordcount = 3,
|
||||
player = 4,
|
||||
actor = 5,
|
||||
location = 6,
|
||||
verbroutine = 7,
|
||||
endflag = 8,
|
||||
prompt = 9,
|
||||
objectcount = 10,
|
||||
system_status = 11
|
||||
};
|
||||
|
||||
/**
|
||||
* Library/engine properties
|
||||
*/
|
||||
enum EngineProperties {
|
||||
before = 1,
|
||||
after = 2,
|
||||
noun = 3,
|
||||
adjective = 4,
|
||||
article = 5
|
||||
};
|
||||
|
||||
/**
|
||||
* "display" object properties
|
||||
*/
|
||||
enum ObjectProperties {
|
||||
screenwidth = 1,
|
||||
screenheight = 2,
|
||||
linelength = 3,
|
||||
windowlines = 4,
|
||||
cursor_column = 5,
|
||||
cursor_row = 6,
|
||||
hasgraphics = 7,
|
||||
title_caption = 8,
|
||||
hasvideo = 9,
|
||||
needs_repaint = 10,
|
||||
pointer_x = 11,
|
||||
pointer_y = 12
|
||||
};
|
||||
|
||||
/**
|
||||
* Fatal errors
|
||||
*/
|
||||
enum ERROR_TYPE {
|
||||
MEMORY_E = 1, ///< out of memory
|
||||
OPEN_E, ///< error opening file
|
||||
READ_E, ///< error reading from file
|
||||
WRITE_E, ///< error writing to file
|
||||
EXPECT_VAL_E, ///< expecting value
|
||||
UNKNOWN_OP_E, ///< unknown operation
|
||||
ILLEGAL_OP_E, ///< illegal operation
|
||||
OVERFLOW_E, ///< overflow
|
||||
DIVIDE_E ///< divide by zero
|
||||
};
|
||||
|
||||
enum RESOURCE_TYPE {
|
||||
JPEG_R, ///< JPEG image
|
||||
WAVE_R, ///< RIFF WAVE audio sample
|
||||
MOD_R, ///< MOD music module
|
||||
S3M_R, ///< S3M music module
|
||||
XM_R, ///< XM music module
|
||||
MIDI_R, ///< MIDI music
|
||||
MP3_R, ///< MP3 audio layer
|
||||
AVI_R, ///< Video for Windows
|
||||
MPEG_R, ///< MPEG video
|
||||
UNKNOWN_R
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure used for disambiguation in MatchObject()
|
||||
*/
|
||||
struct pobject_structure {
|
||||
int obj; ///< the actual object number
|
||||
char type; ///< referred to by noun or adjective
|
||||
|
||||
pobject_structure() : obj(0), type(0) {}
|
||||
};
|
||||
|
||||
struct SAVED_WINDOW_DATA {
|
||||
int left, top, right, bottom;
|
||||
int width, height, charwidth, lineheight;
|
||||
int currentpos, currentline;
|
||||
int currentfont;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure used for navigating {...} blocks:
|
||||
*/
|
||||
struct CODE_BLOCK {
|
||||
int type; ///< see #defines, below
|
||||
long brk; ///< break address, or 0 to indicate NOP
|
||||
long returnaddr; ///< used only for do-while loops
|
||||
#if defined (DEBUGGER)
|
||||
int dbnest; ///< for recovering from 'break'
|
||||
#endif
|
||||
|
||||
CODE_BLOCK() : type(0), brk(0), returnaddr(0)
|
||||
#if defined (DEBUGGER)
|
||||
, dbnest(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
enum DEBUGGER_ERROR {
|
||||
D_MEMORY_ERROR
|
||||
};
|
||||
|
||||
struct CALL {
|
||||
long addr;
|
||||
bool param;
|
||||
|
||||
CALL() : addr(0), param(false) {}
|
||||
};
|
||||
|
||||
struct WINDOW {
|
||||
int count;
|
||||
bool changed;
|
||||
|
||||
WINDOW() : count(99), changed(false) {}
|
||||
};
|
||||
|
||||
struct BREAKPOINT {
|
||||
bool isbreak;
|
||||
long addr;
|
||||
const char *in;
|
||||
int count;
|
||||
|
||||
BREAKPOINT() : isbreak(false), addr(0), in(nullptr), count(0) {
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
93
engines/glk/hugo/resource_archive.cpp
Normal file
93
engines/glk/hugo/resource_archive.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/resource_archive.h"
|
||||
#include "glk/hugo/hugo.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
bool ResourceArchive::splitName(const Common::String &name,
|
||||
Common::String &filename, Common::String &resName) {
|
||||
size_t commaIndex = name.findFirstOf(',');
|
||||
if (commaIndex == Common::String::npos)
|
||||
return false;
|
||||
|
||||
filename = Common::String(name.c_str(), commaIndex);
|
||||
resName = Common::String(name.c_str() + commaIndex + 1);
|
||||
|
||||
if (resName.hasSuffixIgnoreCase(".jpg"))
|
||||
resName = Common::String(resName.c_str(), resName.size() - 4);
|
||||
else if (resName.hasSuffixIgnoreCase(".jpeg"))
|
||||
resName = Common::String(resName.c_str(), resName.size() - 5);
|
||||
else if (resName.contains("."))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ResourceArchive::hasFile(const Common::Path &path) const {
|
||||
Common::String filename, resName;
|
||||
|
||||
if (!splitName(path.baseName(), filename, resName))
|
||||
return false;
|
||||
size_t resLength = g_vm->FindResource(filename.c_str(), resName.c_str());
|
||||
g_vm->hugo_fclose(g_vm->resource_file);
|
||||
|
||||
return resLength != 0;
|
||||
}
|
||||
|
||||
const Common::ArchiveMemberPtr ResourceArchive::getMember(const Common::Path &path) const {
|
||||
if (!hasFile(path))
|
||||
return Common::ArchiveMemberPtr();
|
||||
|
||||
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *ResourceArchive::createReadStreamForMember(const Common::Path &path) const {
|
||||
Common::String filename, resName;
|
||||
|
||||
// Split up the file and resource entry; return if it's not one
|
||||
if (!splitName(path.baseName(), filename, resName))
|
||||
return nullptr;
|
||||
|
||||
// Try and get the entry details from the given file
|
||||
size_t resLength = g_vm->FindResource(filename.c_str(), resName.c_str());
|
||||
|
||||
if (!resLength) {
|
||||
g_vm->hugo_fclose(g_vm->resource_file);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Otherwise, load the specified resource
|
||||
byte *buffer = (byte *)malloc(resLength);
|
||||
g_vm->glk_get_buffer_stream(g_vm->resource_file, (char *)buffer, resLength);
|
||||
g_vm->hugo_fclose(g_vm->resource_file);
|
||||
|
||||
// Return a stream to allow access to the data
|
||||
return new Common::MemoryReadStream(buffer, resLength, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
77
engines/glk/hugo/resource_archive.h
Normal file
77
engines/glk/hugo/resource_archive.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_HUGO_RESOURCE_ARCHIVE_H
|
||||
#define GLK_HUGO_RESOURCE_ARCHIVE_H
|
||||
|
||||
#include "common/archive.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
/**
|
||||
* ScummVM archive that provides virtual access to the Hugo
|
||||
* resource files
|
||||
*/
|
||||
class ResourceArchive : public Common::Archive {
|
||||
private:
|
||||
/**
|
||||
* Splits a resource file and entry pair into individual names
|
||||
*/
|
||||
static bool splitName(const Common::String &name,
|
||||
Common::String &filename, Common::String &resName);
|
||||
public:
|
||||
~ResourceArchive() override {}
|
||||
|
||||
/**
|
||||
* Check if a member with the given name is present in the Archive.
|
||||
* Patterns are not allowed, as this is meant to be a quick File::exists()
|
||||
* replacement.
|
||||
*/
|
||||
bool hasFile(const Common::Path &path) const override;
|
||||
|
||||
/**
|
||||
* Add all members of the Archive to list.
|
||||
* Must only append to list, and not remove elements from it.
|
||||
*
|
||||
* @return the number of names added to list
|
||||
*/
|
||||
int listMembers(Common::ArchiveMemberList &list) const override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ArchiveMember representation of the given file.
|
||||
*/
|
||||
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
|
||||
|
||||
/**
|
||||
* Create a stream bound to a member with the specified name in the
|
||||
* archive. If no member with this name exists, 0 is returned.
|
||||
* @return the newly created input stream
|
||||
*/
|
||||
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
|
||||
};
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
119
engines/glk/hugo/stringfn.cpp
Normal file
119
engines/glk/hugo/stringfn.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "glk/hugo/stringfn.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
char *StringFunctions::Left(char a[], int l) {
|
||||
static char *temp;
|
||||
int i;
|
||||
|
||||
temp = GetTempString();
|
||||
|
||||
if (l > (int)strlen(a))
|
||||
l = strlen(a);
|
||||
for (i = 0; i<l; i++)
|
||||
temp[i] = a[i];
|
||||
temp[i] = '\0';
|
||||
return temp;
|
||||
}
|
||||
|
||||
char *StringFunctions::Ltrim(char a[]) {
|
||||
static char *temp;
|
||||
int len = strlen(a);
|
||||
|
||||
temp = GetTempString();
|
||||
Common::strcpy_s(temp, sizeof(_tempString[0]), a);
|
||||
while (temp[0]==' ' || temp[0]=='\t')
|
||||
memmove(temp, temp+1, len + 1);
|
||||
return temp;
|
||||
}
|
||||
|
||||
char *StringFunctions::Mid(char a[], int pos, int n) {
|
||||
static char *temp;
|
||||
int i;
|
||||
|
||||
temp = GetTempString();
|
||||
pos--;
|
||||
if (pos+n > (int)strlen(a))
|
||||
n = strlen(a)-pos;
|
||||
for (i = 0; i<n; i++)
|
||||
temp[i] = a[pos+i];
|
||||
temp[i] = '\0';
|
||||
return temp;
|
||||
}
|
||||
|
||||
char *StringFunctions::Right(char a[], int l) {
|
||||
static char *temp;
|
||||
int i;
|
||||
|
||||
temp = GetTempString();
|
||||
if (l > (int)strlen(a))
|
||||
l = strlen(a);
|
||||
for (i = 0; i<l; i++)
|
||||
temp[i] = a[strlen(a)-l+i];
|
||||
temp[i] = '\0';
|
||||
return temp;
|
||||
}
|
||||
|
||||
char *StringFunctions::Rtrim(char a[]) {
|
||||
static char *temp;
|
||||
int len;
|
||||
|
||||
temp = GetTempString();
|
||||
Common::strcpy_s(temp, sizeof(_tempString[0]), a);
|
||||
while (((len = strlen(temp))) && (temp[len-1]==' ' || temp[len-1]=='\t'))
|
||||
Common::strcpy_s(temp, sizeof(_tempString[0]), Left(temp, len-1));
|
||||
return temp;
|
||||
}
|
||||
|
||||
char *StringFunctions::hugo_strcpy(char *s, const char *t) {
|
||||
char *r = s;
|
||||
while ((*s++ = *t++) != 0) ;
|
||||
return r;
|
||||
}
|
||||
|
||||
char *StringFunctions::GetTempString() {
|
||||
static char *r;
|
||||
|
||||
r = &_tempString[_tempstringCount][0];
|
||||
if (++_tempstringCount >= NUM_TEMPSTRINGS)
|
||||
_tempstringCount = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *StringFunctions::hugo_strlwr(char *s) {
|
||||
for (char *sp = s; *sp; ++sp)
|
||||
*sp = tolower(*sp);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *StringFunctions::hugo_strupr(char *s) {
|
||||
for (char *sp = s; *sp; ++sp)
|
||||
*sp = toupper(*sp);
|
||||
return s;
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
68
engines/glk/hugo/stringfn.h
Normal file
68
engines/glk/hugo/stringfn.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GLK_HUGO_STRINGFN
|
||||
#define GLK_HUGO_STRINGFN
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Glk {
|
||||
namespace Hugo {
|
||||
|
||||
#define NUM_TEMPSTRINGS 2
|
||||
|
||||
/**
|
||||
* The following string-manipulation functions closely mimic BASIC-language string functionality.
|
||||
* They do not alter the provided string; instead, they return a pointer to a static (modified) copy.
|
||||
*/
|
||||
class StringFunctions {
|
||||
private:
|
||||
char _tempString[NUM_TEMPSTRINGS][1025];
|
||||
int _tempstringCount;
|
||||
|
||||
char *GetTempString();
|
||||
public:
|
||||
StringFunctions() : _tempstringCount(0) {
|
||||
Common::fill(&_tempString[0][0], &_tempString[NUM_TEMPSTRINGS - 1][1025], '\0');
|
||||
}
|
||||
|
||||
char *Left(char a[], int l);
|
||||
|
||||
char *Ltrim(char a[]);
|
||||
|
||||
char *Mid(char a[], int pos, int n);
|
||||
|
||||
char *Right(char a[], int l);
|
||||
|
||||
char *Rtrim(char a[]);
|
||||
|
||||
char *hugo_strcpy(char *s, const char *t);
|
||||
|
||||
char *hugo_strlwr(char *s);
|
||||
|
||||
char *hugo_strupr(char *s);
|
||||
};
|
||||
|
||||
} // End of namespace Hugo
|
||||
} // End of namespace Glk
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user