mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-02 14:51:40 +00:00
968 lines
26 KiB
C++
968 lines
26 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "ultima/ultima4/core/debugger.h"
|
|
#include "ultima/ultima4/game/context.h"
|
|
#include "ultima/ultima4/game/game.h"
|
|
#include "ultima/ultima4/game/moongate.h"
|
|
#include "ultima/ultima4/game/player.h"
|
|
#include "ultima/ultima4/game/portal.h"
|
|
#include "ultima/ultima4/game/stats.h"
|
|
#include "ultima/ultima4/game/weapon.h"
|
|
#include "ultima/ultima4/gfx/screen.h"
|
|
#include "ultima/ultima4/map/annotation.h"
|
|
#include "ultima/ultima4/map/camp.h"
|
|
#include "ultima/ultima4/map/city.h"
|
|
#include "ultima/ultima4/map/dungeonview.h"
|
|
#include "ultima/ultima4/map/mapmgr.h"
|
|
#include "ultima/ultima4/ultima4.h"
|
|
|
|
namespace Ultima {
|
|
namespace Ultima4 {
|
|
|
|
Debugger *g_debugger;
|
|
|
|
Debugger::Debugger() : Shared::Debugger() {
|
|
g_debugger = this;
|
|
_collisionOverride = false;
|
|
_dontEndTurn = false;
|
|
|
|
registerCmd("move", WRAP_METHOD(Debugger, cmdMove));
|
|
registerCmd("attack", WRAP_METHOD(Debugger, cmdAttack));
|
|
registerCmd("board", WRAP_METHOD(Debugger, cmdBoard));
|
|
registerCmd("cast", WRAP_METHOD(Debugger, cmdCastSpell));
|
|
registerCmd("enter", WRAP_METHOD(Debugger, cmdEnter));
|
|
registerCmd("fire", WRAP_METHOD(Debugger, cmdFire));
|
|
registerCmd("get", WRAP_METHOD(Debugger, cmdGet));
|
|
registerCmd("hole", WRAP_METHOD(Debugger, cmdHoleUp));
|
|
registerCmd("ignite", WRAP_METHOD(Debugger, cmdIgnite));
|
|
registerCmd("jimmy", WRAP_METHOD(Debugger, cmdJimmy));
|
|
|
|
registerCmd("pass", WRAP_METHOD(Debugger, cmdPass));
|
|
|
|
registerCmd("3d", WRAP_METHOD(Debugger, cmd3d));
|
|
registerCmd("collisions", WRAP_METHOD(Debugger, cmdCollisions));
|
|
registerCmd("companions", WRAP_METHOD(Debugger, cmdCompanions));
|
|
registerCmd("destroy", WRAP_METHOD(Debugger, cmdDestroy));
|
|
registerCmd("dungeon", WRAP_METHOD(Debugger, cmdDungeon));
|
|
registerCmd("equipment", WRAP_METHOD(Debugger, cmdEquipment));
|
|
registerCmd("exit", WRAP_METHOD(Debugger, cmdExit));
|
|
registerCmd("gate", WRAP_METHOD(Debugger, cmdGate));
|
|
registerCmd("goto", WRAP_METHOD(Debugger, cmdGoto));
|
|
registerCmd("help", WRAP_METHOD(Debugger, cmdHelp));
|
|
registerCmd("items", WRAP_METHOD(Debugger, cmdItems));
|
|
registerCmd("karma", WRAP_METHOD(Debugger, cmdKarma));
|
|
registerCmd("location", WRAP_METHOD(Debugger, cmdLocation));
|
|
registerCmd("mixtures", WRAP_METHOD(Debugger, cmdMixtures));
|
|
registerCmd("moon", WRAP_METHOD(Debugger, cmdMoon));
|
|
registerCmd("opacity", WRAP_METHOD(Debugger, cmdOpacity));
|
|
registerCmd("peer", WRAP_METHOD(Debugger, cmdPeer));
|
|
registerCmd("reagents", WRAP_METHOD(Debugger, cmdReagents));
|
|
registerCmd("stats", WRAP_METHOD(Debugger, cmdStats));
|
|
registerCmd("summon", WRAP_METHOD(Debugger, cmdSummon));
|
|
registerCmd("torch", WRAP_METHOD(Debugger, cmdTorch));
|
|
registerCmd("transport", WRAP_METHOD(Debugger, cmdTransport));
|
|
registerCmd("up", WRAP_METHOD(Debugger, cmdUp));
|
|
registerCmd("down", WRAP_METHOD(Debugger, cmdDown));
|
|
registerCmd("virtue", WRAP_METHOD(Debugger, cmdVirtue));
|
|
registerCmd("wind", WRAP_METHOD(Debugger, cmdWind));
|
|
}
|
|
|
|
Debugger::~Debugger() {
|
|
g_debugger = nullptr;
|
|
}
|
|
|
|
void Debugger::print(const char *fmt, ...) {
|
|
// Format the string
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
Common::String str = Common::String::vformat(fmt, va);
|
|
va_end(va);
|
|
|
|
printN("%s\n", str.c_str());
|
|
}
|
|
|
|
void Debugger::printN(const char *fmt, ...) {
|
|
// Format the string
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
Common::String str = Common::String::vformat(fmt, va);
|
|
va_end(va);
|
|
|
|
if (isDebuggerActive()) {
|
|
// Strip off any color special characters that aren't
|
|
// relevant for showing the text in the debugger
|
|
Common::String s;
|
|
for (Common::String::iterator it = str.begin(); it != str.end(); ++it) {
|
|
if (*it <= ' ' && *it != '\n')
|
|
s += *it;
|
|
}
|
|
|
|
debugPrintf("%s", s.c_str());
|
|
} else {
|
|
screenMessage("%s", str.c_str());
|
|
}
|
|
}
|
|
|
|
bool Debugger::handleCommand(int argc, const char **argv, bool &keepRunning) {
|
|
bool result = Shared::Debugger::handleCommand(argc, argv, keepRunning);
|
|
|
|
if (result && !isActive()) {
|
|
if (!_dontEndTurn)
|
|
g_game->finishTurn();
|
|
}
|
|
|
|
_dontEndTurn = false;
|
|
return result;
|
|
}
|
|
|
|
void Debugger::getChest(int player) {
|
|
Common::String param = Common::String::format("%d", player);
|
|
const char *argv[2] = { "get", param.c_str() };
|
|
|
|
cmdGet(2, argv);
|
|
}
|
|
|
|
|
|
|
|
bool Debugger::cmdMove(int argc, const char **argv) {
|
|
Direction dir;
|
|
|
|
if (argc == 2) {
|
|
dir = directionFromName(argv[1]);
|
|
} else {
|
|
print("move <direction>");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
Common::String priorMap = g_context->_location->_map->_fname;
|
|
MoveResult retval = g_context->_location->move(dir, true);
|
|
|
|
// horse doubles speed (make sure we're on the same map as the previous move first)
|
|
if (retval & (MOVE_SUCCEEDED | MOVE_SLOWED) &&
|
|
(g_context->_transportContext == TRANSPORT_HORSE) && g_context->_horseSpeed) {
|
|
// to give it a smooth look of movement
|
|
gameUpdateScreen();
|
|
if (priorMap == g_context->_location->_map->_fname)
|
|
g_context->_location->move(dir, false);
|
|
}
|
|
|
|
// Let the movement handler decide to end the turn
|
|
bool endTurn = (retval & MOVE_END_TURN);
|
|
if (!endTurn)
|
|
dontEndTurn();
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Debugger::cmdAttack(int argc, const char **argv) {
|
|
Direction dir;
|
|
|
|
if (argc != 2 && isDebuggerActive()) {
|
|
print("attack <direction>");
|
|
return true;
|
|
}
|
|
|
|
printN("Attack: ");
|
|
if (g_context->_party->isFlying()) {
|
|
screenMessage("\n%cDrift only!%c\n", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
if (argc == 2) {
|
|
dir = directionFromName(argv[1]);
|
|
} else {
|
|
dir = gameGetDirection();
|
|
}
|
|
|
|
if (dir == DIR_NONE) {
|
|
if (isDebuggerActive())
|
|
print("");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
Std::vector<Coords> path = gameGetDirectionalActionPath(
|
|
MASK_DIR(dir), MASK_DIR_ALL, g_context->_location->_coords,
|
|
1, 1, NULL, true);
|
|
for (Std::vector<Coords>::iterator i = path.begin(); i != path.end(); i++) {
|
|
if (attackAt(*i))
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
print("%cNothing to Attack!%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdBoard(int argc, const char **argv) {
|
|
if (g_context->_transportContext != TRANSPORT_FOOT) {
|
|
print("Board: %cCan't!%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
Object *obj = g_context->_location->_map->objectAt(g_context->_location->_coords);
|
|
if (!obj) {
|
|
print("%cBoard What?%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
const Tile *tile = obj->getTile().getTileType();
|
|
if (tile->isShip()) {
|
|
print("Board Frigate!");
|
|
if (g_context->_lastShip != obj)
|
|
g_context->_party->setShipHull(50);
|
|
} else if (tile->isHorse())
|
|
print("Mount Horse!");
|
|
else if (tile->isBalloon())
|
|
print("Board Balloon!");
|
|
else {
|
|
print("%cBoard What?%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
g_context->_party->setTransport(obj->getTile());
|
|
g_context->_location->_map->removeObject(obj);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdCastSpell(int argc, const char **argv) {
|
|
// TODO
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdEnter(int argc, const char **argv) {
|
|
if (!usePortalAt(g_context->_location, g_context->_location->_coords, ACTION_ENTER)) {
|
|
if (!g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_ENTER))
|
|
print("%cEnter what?%c\n", FG_GREY, FG_WHITE);
|
|
} else {
|
|
dontEndTurn();
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdFire(int argc, const char **argv) {
|
|
if (g_context->_transportContext != TRANSPORT_SHIP) {
|
|
print("%cFire What?%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
printN("Fire Cannon!\nDir: ");
|
|
Direction dir = gameGetDirection();
|
|
|
|
if (dir == DIR_NONE)
|
|
return isDebuggerActive();
|
|
|
|
// can only fire broadsides
|
|
int broadsidesDirs = dirGetBroadsidesDirs(g_context->_party->getDirection());
|
|
if (!DIR_IN_MASK(dir, broadsidesDirs)) {
|
|
print("%cBroadsides Only!%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
// nothing (not even mountains!) can block cannonballs
|
|
Std::vector<Coords> path = gameGetDirectionalActionPath(MASK_DIR(dir), broadsidesDirs, g_context->_location->_coords,
|
|
1, 3, NULL, false);
|
|
for (Std::vector<Coords>::iterator i = path.begin(); i != path.end(); i++) {
|
|
if (fireAt(*i, true))
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdGet(int argc, const char **argv) {
|
|
int player = 1;
|
|
if (argc == 2)
|
|
player = strToInt(argv[1]);
|
|
|
|
print("Get Chest!");
|
|
|
|
if (g_context->_party->isFlying()) {
|
|
print("%cDrift only!%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
// first check to see if a chest exists at the current location
|
|
// if one exists, prompt the player for the opener, if necessary
|
|
MapCoords coords;
|
|
g_context->_location->getCurrentPosition(&coords);
|
|
const Tile *tile = g_context->_location->_map->tileTypeAt(coords, WITH_GROUND_OBJECTS);
|
|
|
|
/* get the object for the chest, if it is indeed an object */
|
|
Object *obj = g_context->_location->_map->objectAt(coords);
|
|
if (obj && !obj->getTile().getTileType()->isChest())
|
|
obj = NULL;
|
|
|
|
if (tile->isChest() || obj) {
|
|
// if a spell was cast to open this chest,
|
|
// player will equal -2, otherwise player
|
|
// will default to -1 or the defult character
|
|
// number if one was earlier specified
|
|
if (player == -1) {
|
|
printN("Who opens? ");
|
|
player = gameGetPlayer(false, true);
|
|
}
|
|
if (player == -1)
|
|
return isDebuggerActive();
|
|
|
|
if (obj)
|
|
g_context->_location->_map->removeObject(obj);
|
|
else {
|
|
TileId newTile = g_context->_location->getReplacementTile(coords, tile);
|
|
g_context->_location->_map->_annotations->add(coords, newTile, false, true);
|
|
}
|
|
|
|
// see if the chest is trapped and handle it
|
|
getChestTrapHandler(player);
|
|
|
|
print("The Chest Holds: %d Gold", g_context->_party->getChest());
|
|
|
|
screenPrompt();
|
|
|
|
if (isCity(g_context->_location->_map) && obj == NULL)
|
|
g_context->_party->adjustKarma(KA_STOLE_CHEST);
|
|
} else {
|
|
print("%cNot Here!%c", FG_GREY, FG_WHITE);
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdHoleUp(int argc, const char **argv) {
|
|
print("Hole up & Camp!");
|
|
|
|
if (!(g_context->_location->_context & (CTX_WORLDMAP | CTX_DUNGEON))) {
|
|
print("%cNot here!%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
if (g_context->_transportContext != TRANSPORT_FOOT) {
|
|
print("%cOnly on foot!%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
CombatController *cc = new CampController();
|
|
cc->init(NULL);
|
|
cc->begin();
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdIgnite(int argc, const char **argv) {
|
|
print("Ignite torch!");
|
|
if (g_context->_location->_context == CTX_DUNGEON) {
|
|
if (!g_context->_party->lightTorch())
|
|
print("%cNone left!%c", FG_GREY, FG_WHITE);
|
|
} else {
|
|
print("%cNot here!%c", FG_GREY, FG_WHITE);
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdJimmy(int argc, const char **argv) {
|
|
screenMessage("Jimmy: ");
|
|
Direction dir = gameGetDirection();
|
|
|
|
if (dir == DIR_NONE)
|
|
return isDebuggerActive();
|
|
|
|
Std::vector<Coords> path = gameGetDirectionalActionPath(MASK_DIR(dir), MASK_DIR_ALL, g_context->_location->_coords,
|
|
1, 1, NULL, true);
|
|
for (Std::vector<Coords>::iterator i = path.begin(); i != path.end(); i++) {
|
|
if (jimmyAt(*i))
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
print("%cJimmy what?%c", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdLocate(int argc, const char **argv) {
|
|
// can't use sextant in dungeon or in combat
|
|
if (g_context->_location->_context & ~(CTX_DUNGEON | CTX_COMBAT)) {
|
|
if (g_ultima->_saveGame->_sextants >= 1)
|
|
print("Locate position\nwith sextant\n Latitude: %c'%c\"\nLongitude: %c'%c\"",
|
|
g_context->_location->_coords.y / 16 + 'A', g_context->_location->_coords.y % 16 + 'A',
|
|
g_context->_location->_coords.x / 16 + 'A', g_context->_location->_coords.x % 16 + 'A');
|
|
else
|
|
print("%cLocate position with what?%c", FG_GREY, FG_WHITE);
|
|
} else {
|
|
screenMessage("%cNot here!%c", FG_GREY, FG_WHITE);
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdPass(int argc, const char **argv) {
|
|
print("Pass");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
|
|
bool Debugger::cmd3d(int argc, const char **argv) {
|
|
if (g_context->_location->_context == CTX_DUNGEON) {
|
|
print("3-D view %s\n", DungeonViewer.toggle3DDungeonView() ? "on" : "off");
|
|
} else {
|
|
print("Not here");
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdCollisions(int argc, const char **argv) {
|
|
_collisionOverride = !_collisionOverride;
|
|
print("Collision detection %s",
|
|
_collisionOverride ? "off" : "on");
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdCompanions(int argc, const char **argv) {
|
|
for (int m = g_ultima->_saveGame->_members; m < 8; m++) {
|
|
debug("m = %d\n", m);
|
|
debug("n = %s\n", g_ultima->_saveGame->_players[m].name);
|
|
if (g_context->_party->canPersonJoin(g_ultima->_saveGame->_players[m].name, NULL)) {
|
|
g_context->_party->join(g_ultima->_saveGame->_players[m].name);
|
|
}
|
|
}
|
|
|
|
g_context->_stats->update();
|
|
print("Joined by companions");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdDestroy(int argc, const char **argv) {
|
|
Direction dir;
|
|
|
|
if (argc == 2) {
|
|
dir = directionFromName(argv[1]);
|
|
} else if (isDebuggerActive()) {
|
|
print("destroy <direction>");
|
|
return isDebuggerActive();
|
|
} else {
|
|
screenMessage("Destroy Object\nDir: ");
|
|
dir = gameGetDirection();
|
|
}
|
|
|
|
if (dir == DIR_NONE)
|
|
return isDebuggerActive();
|
|
|
|
Std::vector<Coords> path = gameGetDirectionalActionPath(MASK_DIR(dir),
|
|
MASK_DIR_ALL, g_context->_location->_coords, 1, 1, NULL, true);
|
|
for (Std::vector<Coords>::iterator i = path.begin(); i != path.end(); i++) {
|
|
if (destroyAt(*i)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
print("%cNothing there!%c\n", FG_GREY, FG_WHITE);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdDungeon(int argc, const char **argv) {
|
|
if (g_context->_location->_context & CTX_WORLDMAP) {
|
|
if (argc == 2) {
|
|
int dungNum = strToInt(argv[1]);
|
|
|
|
if (dungNum >= 1 && dungNum <= 8) {
|
|
g_context->_location->_coords = g_context->_location->_map->_portals[dungNum - 1]->_coords;
|
|
return false;
|
|
} else if (dungNum == 9) {
|
|
g_game->setMap(mapMgr->get(MAP_DECEIT), 1, NULL);
|
|
g_context->_location->_coords = MapCoords(1, 0, 7);
|
|
g_ultima->_saveGame->_orientation = DIR_SOUTH;
|
|
} else if (dungNum == 10) {
|
|
g_game->setMap(mapMgr->get(MAP_DESPISE), 1, NULL);
|
|
g_context->_location->_coords = MapCoords(3, 2, 7);
|
|
g_ultima->_saveGame->_orientation = DIR_SOUTH;
|
|
} else if (dungNum == 11) {
|
|
g_game->setMap(mapMgr->get(MAP_DESTARD), 1, NULL);
|
|
g_context->_location->_coords = MapCoords(7, 6, 7);
|
|
g_ultima->_saveGame->_orientation = DIR_SOUTH;
|
|
} else {
|
|
print("Invalid dungeon");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
return false;
|
|
} else {
|
|
print("dungeon <number>");
|
|
}
|
|
} else {
|
|
print("Not here");
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdEquipment(int argc, const char **argv) {
|
|
int i;
|
|
|
|
for (i = ARMR_NONE + 1; i < ARMR_MAX; ++i)
|
|
g_ultima->_saveGame->_armor[i] = 8;
|
|
|
|
for (i = WEAP_HANDS + 1; i < WEAP_MAX; ++i) {
|
|
const Weapon *weapon = Weapon::get(static_cast<WeaponType>(i));
|
|
if (weapon->loseWhenUsed() || weapon->loseWhenRanged())
|
|
g_ultima->_saveGame->_weapons[i] = 99;
|
|
else
|
|
g_ultima->_saveGame->_weapons[i] = 8;
|
|
}
|
|
|
|
print("All equipment given");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdExit(int argc, const char **argv) {
|
|
if (!g_game->exitToParentMap()) {
|
|
print("Not Here");
|
|
} else {
|
|
g_music->play();
|
|
print("Exited");
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdGate(int argc, const char **argv) {
|
|
int gateNum = (argc == 2) ? strToInt(argv[1]) : -1;
|
|
|
|
if (!g_context || !g_game || gateNum < 1 || gateNum > 8) {
|
|
print("Gate <1 to 8>");
|
|
} else {
|
|
if (!isDebuggerActive())
|
|
print("Gate %d!", gateNum);
|
|
|
|
if (g_context->_location->_map->isWorldMap()) {
|
|
const Coords *moongate = moongateGetGateCoordsForPhase(gateNum - 1);
|
|
if (moongate) {
|
|
g_context->_location->_coords = *moongate;
|
|
return false;
|
|
}
|
|
} else {
|
|
print("Not here!");
|
|
}
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdGoto(int argc, const char **argv) {
|
|
Common::String dest;
|
|
|
|
if (argc == 2) {
|
|
dest = argv[1];
|
|
} else if (isDebuggerActive()) {
|
|
print("teleport <destination name>");
|
|
return true;
|
|
} else {
|
|
screenMessage("Goto: ");
|
|
dest = gameGetInput(32);
|
|
screenMessage("\n");
|
|
}
|
|
|
|
dest.toLowercase();
|
|
|
|
bool found = false;
|
|
for (unsigned p = 0; p < g_context->_location->_map->_portals.size(); p++) {
|
|
MapId destid = g_context->_location->_map->_portals[p]->_destid;
|
|
Common::String destNameLower = mapMgr->get(destid)->getName();
|
|
destNameLower.toLowercase();
|
|
|
|
if (destNameLower.find(dest) != Common::String::npos) {
|
|
screenMessage("\n%s\n", mapMgr->get(destid)->getName().c_str());
|
|
g_context->_location->_coords = g_context->_location->_map->_portals[p]->_coords;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
MapCoords coords = g_context->_location->_map->getLabel(dest);
|
|
if (coords != MapCoords::nowhere) {
|
|
print("%s", dest.c_str());
|
|
g_context->_location->_coords = coords;
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
return false;
|
|
} else {
|
|
if (isDebuggerActive())
|
|
print("Can't find %s", dest.c_str());
|
|
else
|
|
print("Can't find\n%s", dest.c_str());
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
}
|
|
|
|
bool Debugger::cmdHelp(int argc, const char **argv) {
|
|
if (!isDebuggerActive()) {
|
|
screenMessage("Help!\n");
|
|
screenPrompt();
|
|
}
|
|
|
|
/* Help! send me to Lord British (who conveniently is right around where you are)! */
|
|
g_game->setMap(mapMgr->get(100), 1, NULL);
|
|
g_context->_location->_coords.x = 19;
|
|
g_context->_location->_coords.y = 8;
|
|
g_context->_location->_coords.z = 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Debugger::cmdItems(int argc, const char **argv) {
|
|
SaveGame &sg = *g_ultima->_saveGame;
|
|
sg._torches = 99;
|
|
sg._gems = 99;
|
|
sg._keys = 99;
|
|
sg._sextants = 1;
|
|
sg._items = ITEM_SKULL | ITEM_CANDLE | ITEM_BOOK | ITEM_BELL | ITEM_KEY_C | ITEM_KEY_L | ITEM_KEY_T | ITEM_HORN | ITEM_WHEEL;
|
|
sg._stones = 0xff;
|
|
sg._runes = 0xff;
|
|
sg._food = 999900;
|
|
sg._gold = 9999;
|
|
|
|
g_context->_stats->update();
|
|
print("All items given");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdKarma(int argc, const char **argv) {
|
|
print("Karma!\n");
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
Common::String line = Common::String::format("%s:",
|
|
getVirtueName(static_cast<Virtue>(i)));
|
|
while (line.size() < 13)
|
|
line += ' ';
|
|
|
|
if (g_ultima->_saveGame->_karma[i] > 0)
|
|
line += Common::String::format("%.2d", g_ultima->_saveGame->_karma[i]);
|
|
else
|
|
line += "--";
|
|
print("%s", line.c_str());
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdLocation(int argc, const char **argv) {
|
|
const MapCoords &pos = g_context->_location->_coords;
|
|
|
|
if (isDebuggerActive()) {
|
|
if (g_context->_location->_map->isWorldMap())
|
|
print("Location: %s x: %d, y: %d",
|
|
"World Map", pos.x, pos.y);
|
|
else
|
|
print("Location: %s x: %d, y: %d, z: %d",
|
|
g_context->_location->_map->getName().c_str(), pos.x, pos.y, pos.z);
|
|
} else {
|
|
if (g_context->_location->_map->isWorldMap())
|
|
print("\nLocation:\n%s\nx: %d\ny: %d\n", "World Map",
|
|
pos.x, pos.y);
|
|
else
|
|
print("\nLocation:\n%s\nx: %d\ny: %d\nz: %d\n",
|
|
g_context->_location->_map->getName().c_str(), pos.x, pos.y, pos.z);
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdMixtures(int argc, const char **argv) {
|
|
for (int i = 0; i < SPELL_MAX; i++)
|
|
g_ultima->_saveGame->_mixtures[i] = 99;
|
|
|
|
screenMessage("All mixtures given");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdMoon(int argc, const char **argv) {
|
|
int moonNum;
|
|
|
|
if (argc == 2) {
|
|
moonNum = strToInt(argv[1]);
|
|
if (moonNum < 0 || moonNum > 7) {
|
|
print("Invalid moon");
|
|
return true;
|
|
}
|
|
} else {
|
|
moonNum = (g_ultima->_saveGame->_trammelPhase + 1) & 7;
|
|
}
|
|
|
|
while (g_ultima->_saveGame->_trammelPhase != moonNum)
|
|
g_game->updateMoons(true);
|
|
|
|
print("Moons advanced");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdOpacity(int argc, const char **argv) {
|
|
g_context->_opacity = !g_context->_opacity;
|
|
screenMessage("Opacity is %s", g_context->_opacity ? "on" : "off");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdPeer(int argc, const char **argv) {
|
|
if ((g_context->_location->_viewMode == VIEW_NORMAL) || (g_context->_location->_viewMode == VIEW_DUNGEON))
|
|
g_context->_location->_viewMode = VIEW_GEM;
|
|
else if (g_context->_location->_context == CTX_DUNGEON)
|
|
g_context->_location->_viewMode = VIEW_DUNGEON;
|
|
else
|
|
g_context->_location->_viewMode = VIEW_NORMAL;
|
|
|
|
print("Toggle view");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdReagents(int argc, const char **argv) {
|
|
for (int i = 0; i < REAG_MAX; i++)
|
|
g_ultima->_saveGame->_reagents[i] = 99;
|
|
|
|
print("Reagents given");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdStats(int argc, const char **argv) {
|
|
for (int i = 0; i < g_ultima->_saveGame->_members; i++) {
|
|
g_ultima->_saveGame->_players[i]._str = 50;
|
|
g_ultima->_saveGame->_players[i]._dex = 50;
|
|
g_ultima->_saveGame->_players[i]._intel = 50;
|
|
|
|
if (g_ultima->_saveGame->_players[i]._hpMax < 800) {
|
|
g_ultima->_saveGame->_players[i]._xp = 9999;
|
|
g_ultima->_saveGame->_players[i]._hpMax = 800;
|
|
g_ultima->_saveGame->_players[i]._hp = 800;
|
|
}
|
|
}
|
|
|
|
print("Full Stats given");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdSummon(int argc, const char **argv) {
|
|
Common::String creature;
|
|
|
|
if (argc == 2) {
|
|
creature = argv[1];
|
|
} else if (isDebuggerActive()) {
|
|
print("summon <creature name>");
|
|
return true;
|
|
} else {
|
|
screenMessage("Summon!\n");
|
|
screenMessage("What?\n");
|
|
creature = gameGetInput();
|
|
}
|
|
|
|
summonCreature(creature);
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdTorch(int argc, const char **argv) {
|
|
print("Torch: %d\n", g_context->_party->getTorchDuration());
|
|
if (!isDebuggerActive())
|
|
screenPrompt();
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdTransport(int argc, const char **argv) {
|
|
if (!g_context->_location->_map->isWorldMap()) {
|
|
print("Not here!");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
_horse = g_context->_location->_map->_tileset->getByName("horse")->getId();
|
|
_ship = g_context->_location->_map->_tileset->getByName("ship")->getId();
|
|
_balloon = g_context->_location->_map->_tileset->getByName("balloon")->getId();
|
|
|
|
MapCoords coords = g_context->_location->_coords;
|
|
MapTile *choice;
|
|
Tile *tile;
|
|
|
|
// Get the transport of choice
|
|
char transport;
|
|
if (argc >= 2) {
|
|
transport = argv[1][0];
|
|
} else if (isDebuggerActive()) {
|
|
print("transport <transport name>");
|
|
return isDebuggerActive();
|
|
} else {
|
|
transport = ReadChoiceController::get("shb \033\015");
|
|
}
|
|
|
|
switch (transport) {
|
|
case 's':
|
|
choice = &_ship;
|
|
break;
|
|
case 'h':
|
|
choice = &_horse;
|
|
break;
|
|
case 'b':
|
|
choice = &_balloon;
|
|
break;
|
|
default:
|
|
print("Unknown transport");
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
tile = g_context->_location->_map->_tileset->get(choice->getId());
|
|
Direction dir;
|
|
|
|
if (argc == 3) {
|
|
dir = directionFromName(argv[2]);
|
|
} else if (isDebuggerActive()) {
|
|
dir = DIR_NONE;
|
|
} else {
|
|
screenMessage("%s\n", tile->getName().c_str());
|
|
|
|
// Get the direction in which to create the transport
|
|
ReadDirController readDir;
|
|
eventHandler->pushController(&readDir);
|
|
|
|
screenMessage("Dir: ");
|
|
dir = readDir.waitFor();
|
|
}
|
|
|
|
coords.move(dir, g_context->_location->_map);
|
|
|
|
if (coords != g_context->_location->_coords) {
|
|
bool ok = false;
|
|
MapTile *ground = g_context->_location->_map->tileAt(coords, WITHOUT_OBJECTS);
|
|
|
|
switch (transport) {
|
|
case 's':
|
|
ok = ground->getTileType()->isSailable();
|
|
break;
|
|
case 'h':
|
|
ok = ground->getTileType()->isWalkable();
|
|
break;
|
|
case 'b':
|
|
ok = ground->getTileType()->isWalkable();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (choice && ok) {
|
|
g_context->_location->_map->addObject(*choice, *choice, coords);
|
|
print("%s created!", tile->getName().c_str());
|
|
} else if (!choice) {
|
|
print("Invalid transport!");
|
|
} else {
|
|
print("Can't place %s there!", tile->getName().c_str());
|
|
}
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdUp(int argc, const char **argv) {
|
|
if ((g_context->_location->_context & CTX_DUNGEON) && (g_context->_location->_coords.z > 0)) {
|
|
g_context->_location->_coords.z--;
|
|
|
|
return false;
|
|
} else {
|
|
print("Leaving...");
|
|
g_game->exitToParentMap();
|
|
g_music->play();
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
}
|
|
|
|
bool Debugger::cmdDown(int argc, const char **argv) {
|
|
if ((g_context->_location->_context & CTX_DUNGEON) && (g_context->_location->_coords.z < 7)) {
|
|
g_context->_location->_coords.z++;
|
|
return false;
|
|
} else {
|
|
print("Not here");
|
|
return isDebuggerActive();
|
|
}
|
|
}
|
|
|
|
bool Debugger::cmdVirtue(int argc, const char **argv) {
|
|
if (argc == 1) {
|
|
for (int i = 0; i < 8; i++)
|
|
g_ultima->_saveGame->_karma[i] = 0;
|
|
|
|
g_context->_stats->update();
|
|
screenMessage("Full virtues");
|
|
} else {
|
|
int virtue = strToInt(argv[1]);
|
|
|
|
if (virtue <= 0 || virtue >= VIRT_MAX) {
|
|
print("Invalid virtue");
|
|
} else {
|
|
print("Improved %s", getVirtueName((Virtue)virtue));
|
|
|
|
if (g_ultima->_saveGame->_karma[virtue] == 99)
|
|
g_ultima->_saveGame->_karma[virtue] = 0;
|
|
else if (g_ultima->_saveGame->_karma[virtue] != 0)
|
|
g_ultima->_saveGame->_karma[virtue] += 10;
|
|
if (g_ultima->_saveGame->_karma[virtue] > 99)
|
|
g_ultima->_saveGame->_karma[virtue] = 99;
|
|
g_context->_stats->update();
|
|
}
|
|
}
|
|
|
|
return isDebuggerActive();
|
|
}
|
|
|
|
bool Debugger::cmdWind(int argc, const char **argv) {
|
|
Common::String windDir;
|
|
|
|
if (argc == 2) {
|
|
windDir = argv[1];
|
|
} else if (isDebuggerActive()) {
|
|
print("wind <direction or 'lock'>");
|
|
return true;
|
|
} else {
|
|
print("Wind Dir ('l' to lock)");
|
|
windDir = gameGetInput();
|
|
}
|
|
|
|
windDir.toLowercase();
|
|
if (windDir == "lock" || windDir == "l") {
|
|
g_context->_windLock = !g_context->_windLock;
|
|
print("Wind direction is %slocked",
|
|
g_context->_windLock ? "" : "un");
|
|
} else {
|
|
Direction dir = directionFromName(windDir);
|
|
|
|
if (dir == DIR_NONE) {
|
|
print("Unknown direction");
|
|
return isDebuggerActive();
|
|
} else {
|
|
g_context->_windDirection = dir;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
} // End of namespace Ultima4
|
|
} // End of namespace Ultima
|