[Scummvm-git-logs] scummvm master -> b8c3775644ce8f21366d2fb284deab3939a2d527
dreammaster
paulfgilbert at gmail.com
Mon Apr 13 01:54:42 UTC 2020
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
6f4f4e828f ULTIMA4: Hooking up movement as keybinding actions
6b637be1bd ULTIMA4: Making attack & board keybinder actions
e5894a132e ULTIMA4: Better handling for keybind actions ending turns
dba370697f ULTIMA4: Changed enter to a keybinder action
b8c3775644 ULTIMA4: Shifting more actions to keybindings
Commit: 6f4f4e828fc5196070e6adb18fe7b21e422d5ce7
https://github.com/scummvm/scummvm/commit/6f4f4e828fc5196070e6adb18fe7b21e422d5ce7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-04-12T18:54:30-07:00
Commit Message:
ULTIMA4: Hooking up movement as keybinding actions
Changed paths:
engines/ultima/shared/engine/debugger.cpp
engines/ultima/shared/engine/debugger.h
engines/ultima/ultima4/core/debugger.cpp
engines/ultima/ultima4/core/debugger.h
engines/ultima/ultima4/events/event_scummvm.cpp
engines/ultima/ultima4/game/game.cpp
engines/ultima/ultima4/meta_engine.cpp
engines/ultima/ultima4/meta_engine.h
diff --git a/engines/ultima/shared/engine/debugger.cpp b/engines/ultima/shared/engine/debugger.cpp
index 1c80fc4b5f..a81ba8d319 100644
--- a/engines/ultima/shared/engine/debugger.cpp
+++ b/engines/ultima/shared/engine/debugger.cpp
@@ -47,8 +47,80 @@ int Debugger::strToInt(const char *s) {
return (int)tmp;
}
+void Debugger::splitString(const Common::String &str,
+ Common::StringArray &argv) {
+ // Clear the vector
+ argv.clear();
+
+ bool quoted = false;
+ Common::String::const_iterator it;
+ int ch;
+ Common::String arg;
+
+ for (it = str.begin(); it != str.end(); ++it) {
+ ch = *it;
+
+ // Toggle quoted string handling
+ if (ch == '\"') {
+ quoted = !quoted;
+ continue;
+ }
+
+ // Handle \\, \", \', \n, \r, \t
+ if (ch == '\\') {
+ Common::String::const_iterator next = it + 1;
+ if (next != str.end()) {
+ if (*next == '\\' || *next == '\"' || *next == '\'') {
+ ch = *next;
+ ++it;
+ } else if (*next == 'n') {
+ ch = '\n';
+ ++it;
+ } else if (*next == 'r') {
+ ch = '\r';
+ ++it;
+ } else if (*next == 't') {
+ ch = '\t';
+ ++it;
+ } else if (*next == ' ') {
+ ch = ' ';
+ ++it;
+ }
+ }
+ }
+
+ // A space, a tab, line feed, carriage return
+ if (!quoted && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
+ // If we are not empty then we are at the end of the arg
+ // otherwise we will ignore the extra chars
+ if (!arg.empty()) {
+ argv.push_back(arg);
+ arg.clear();
+ }
+
+ continue;
+ }
+
+ // Add the charater to the string
+ arg += ch;
+ }
+
+ // Push any arg if it's left
+ if (!arg.empty())
+ argv.push_back(arg);
+}
+
void Debugger::executeCommand(const Common::String &cmd) {
+ // Split up the command, and form a const char * array
+ Common::StringArray args;
+ splitString(cmd, args);
+
+ Common::Array<const char *> argv;
+ for (uint idx = 0; idx < args.size(); ++idx)
+ argv.push_back(args[idx].c_str());
+ // Execute the command
+ executeCommand(argv.size(), &argv[0]);
}
void Debugger::executeCommand(int argc, const char **argv) {
diff --git a/engines/ultima/shared/engine/debugger.h b/engines/ultima/shared/engine/debugger.h
index a93872f29b..12767e387a 100644
--- a/engines/ultima/shared/engine/debugger.h
+++ b/engines/ultima/shared/engine/debugger.h
@@ -40,6 +40,11 @@ protected:
* Converts a string to an integer
*/
int strToInt(const char *s);
+
+ /**
+ * Split up a command string into arg values
+ */
+ void splitString(const Common::String &str, Common::StringArray &argv);
public:
Debugger();
~Debugger() override {}
diff --git a/engines/ultima/ultima4/core/debugger.cpp b/engines/ultima/ultima4/core/debugger.cpp
index 84348a2348..a6dfc30900 100644
--- a/engines/ultima/ultima4/core/debugger.cpp
+++ b/engines/ultima/ultima4/core/debugger.cpp
@@ -42,6 +42,8 @@ Debugger::Debugger() : Shared::Debugger() {
g_debugger = this;
_collisionOverride = false;
+ registerCmd("move", WRAP_METHOD(Debugger, cmdMove));
+
registerCmd("3d", WRAP_METHOD(Debugger, cmd3d));
registerCmd("collisions", WRAP_METHOD(Debugger, cmdCollisions));
registerCmd("companions", WRAP_METHOD(Debugger, cmdCompanions));
@@ -156,6 +158,37 @@ bool Debugger::destroyAt(const Coords &coords) {
}
+bool Debugger::cmdMove(int argc, const char **argv) {
+ Direction dir;
+
+ if (argc == 2) {
+ dir = directionFromName(argv[1]);
+ } else {
+ print("move <direction>");
+ return isActive();
+ }
+
+ 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)
+ g_game->finishTurn();
+
+ return false;
+}
+
+
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");
diff --git a/engines/ultima/ultima4/core/debugger.h b/engines/ultima/ultima4/core/debugger.h
index d46cf010a2..ebf1704dd4 100644
--- a/engines/ultima/ultima4/core/debugger.h
+++ b/engines/ultima/ultima4/core/debugger.h
@@ -59,6 +59,12 @@ private:
* Returns a direction from a given string
*/
Direction directionFromName(const Common::String &dirStr);
+private:
+ /**
+ * Move the avatar in a given direction
+ */
+ bool cmdMove(int argc, const char **argv);
+
private:
/**
* Collision detection on/off
diff --git a/engines/ultima/ultima4/events/event_scummvm.cpp b/engines/ultima/ultima4/events/event_scummvm.cpp
index 26f55e4b45..6ff8260715 100644
--- a/engines/ultima/ultima4/events/event_scummvm.cpp
+++ b/engines/ultima/ultima4/events/event_scummvm.cpp
@@ -27,6 +27,7 @@
#include "ultima/ultima4/core/utils.h"
#include "ultima/ultima4/gfx/screen.h"
#include "ultima/ultima4/core/settings.h"
+#include "ultima/ultima4/meta_engine.h"
#include "common/debug.h"
#include "common/system.h"
@@ -243,6 +244,10 @@ void EventHandler::run() {
handleMouseMotionEvent(event);
continue;
+ case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+ MetaEngine::executeAction((KeybindingAction)event.customType);
+ break;
+
case Common::EVENT_QUIT:
_ended = true;
return;
diff --git a/engines/ultima/ultima4/game/game.cpp b/engines/ultima/ultima4/game/game.cpp
index 405a933bf5..9e7113894a 100644
--- a/engines/ultima/ultima4/game/game.cpp
+++ b/engines/ultima/ultima4/game/game.cpp
@@ -628,27 +628,6 @@ bool GameController::keyPressed(int key) {
screenMessage("%cNot here!%c\n", FG_GREY, FG_WHITE);
else
switch (key) {
-
- case U4_UP:
- case U4_DOWN:
- case U4_LEFT:
- case U4_RIGHT: {
- /* move the avatar */
- Common::String previous_map = g_context->_location->_map->_fname;
- MoveResult retval = g_context->_location->move(keyToDirection(key), 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) {
- gameUpdateScreen(); /* to give it a smooth look of movement */
- if (previous_map == g_context->_location->_map->_fname)
- g_context->_location->move(keyToDirection(key), false);
- }
-
- endTurn = (retval & MOVE_END_TURN); /* let the movement handler decide to end the turn */
- }
- break;
-
case ' ':
screenMessage("Pass\n");
break;
diff --git a/engines/ultima/ultima4/meta_engine.cpp b/engines/ultima/ultima4/meta_engine.cpp
index 0e8168db24..ac25c80069 100644
--- a/engines/ultima/ultima4/meta_engine.cpp
+++ b/engines/ultima/ultima4/meta_engine.cpp
@@ -39,14 +39,18 @@ struct KeybindingRecord {
};
static const KeybindingRecord KEYS[] = {
- { ACTION_NORTH, "NORTH", "North", "walk north", "up", nullptr },
- { ACTION_SOUTH, "SOUTH", "South", "walk south", "down", nullptr },
- { ACTION_EAST, "EAST", "East", "walk east", "right", nullptr },
- { ACTION_WEST, "WEST", "West", "walk west", "left", nullptr },
+ { ACTION_NORTH, "UP", "Up", "move up", "UP", nullptr },
+ { ACTION_SOUTH, "DOWN", "Down", "move down", "DOWN", nullptr },
+ { ACTION_WEST, "LEFT", "Left", "move left", "LEFT", nullptr },
+ { ACTION_EAST, "RIGHT", "Right", "move right", "RIGHT", nullptr },
{ ACTION_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
};
+static const KeybindingRecord CHEAT_KEYS[] = {
+ { ACTION_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
+};
+
Common::KeymapArray MetaEngine::initKeymaps() {
Common::KeymapArray keymapArray;
@@ -86,16 +90,20 @@ void MetaEngine::setKeybindingsActive(bool isActive) {
}
-void MetaEngine::pressAction(KeybindingAction keyAction) {
+void MetaEngine::executeAction(KeybindingAction keyAction) {
Common::String methodName = getMethod(keyAction);
if (!methodName.empty())
g_debugger->executeCommand(methodName);
}
Common::String MetaEngine::getMethod(KeybindingAction keyAction) {
- for (const KeybindingRecord *r = KEYS; r->_id; ++r) {
- if (r->_action == keyAction)
- return r->_method;
+ const KeybindingRecord *KEY_ARRAYS[] = { KEYS, CHEAT_KEYS, nullptr };
+
+ for (const KeybindingRecord **arr = KEY_ARRAYS; *arr; ++arr) {
+ for (const KeybindingRecord *r = *arr; r->_id; ++r) {
+ if (r->_action == keyAction)
+ return r->_method;
+ }
}
return Common::String();
diff --git a/engines/ultima/ultima4/meta_engine.h b/engines/ultima/ultima4/meta_engine.h
index 446f1ca016..659d6fbb8c 100644
--- a/engines/ultima/ultima4/meta_engine.h
+++ b/engines/ultima/ultima4/meta_engine.h
@@ -47,9 +47,9 @@ public:
static Common::KeymapArray initKeymaps();
/**
- * Execute an engine keymap press action
+ * Execute an engine keymap action
*/
- static void pressAction(KeybindingAction keyAction);
+ static void executeAction(KeybindingAction keyAction);
/**
* Enables/disables the keymaps when not waiting for an in-game action
Commit: 6b637be1bd6a62747c9a0d563135284a8ad192e7
https://github.com/scummvm/scummvm/commit/6b637be1bd6a62747c9a0d563135284a8ad192e7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-04-12T18:54:30-07:00
Commit Message:
ULTIMA4: Making attack & board keybinder actions
Changed paths:
A engines/ultima/ultima4/core/debugger_actions.cpp
A engines/ultima/ultima4/core/debugger_actions.h
engines/ultima/module.mk
engines/ultima/ultima4/core/debugger.cpp
engines/ultima/ultima4/core/debugger.h
engines/ultima/ultima4/events/controller.h
engines/ultima/ultima4/events/event.cpp
engines/ultima/ultima4/events/event.h
engines/ultima/ultima4/events/event_scummvm.cpp
engines/ultima/ultima4/game/game.cpp
engines/ultima/ultima4/game/game.h
engines/ultima/ultima4/meta_engine.cpp
engines/ultima/ultima4/meta_engine.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 38f2d8ca4e..a3834e9d8b 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -144,6 +144,7 @@ MODULE_OBJS := \
ultima4/core/lzw/u4decode.o \
ultima4/core/config.o \
ultima4/core/debugger.o \
+ ultima4/core/debugger_actions.o \
ultima4/core/error.o \
ultima4/core/settings.o \
ultima4/core/utils.o \
diff --git a/engines/ultima/ultima4/core/debugger.cpp b/engines/ultima/ultima4/core/debugger.cpp
index a6dfc30900..f38eb896c1 100644
--- a/engines/ultima/ultima4/core/debugger.cpp
+++ b/engines/ultima/ultima4/core/debugger.cpp
@@ -43,6 +43,10 @@ Debugger::Debugger() : Shared::Debugger() {
_collisionOverride = 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("pass", WRAP_METHOD(Debugger, cmdPass));
registerCmd("3d", WRAP_METHOD(Debugger, cmd3d));
registerCmd("collisions", WRAP_METHOD(Debugger, cmdCollisions));
@@ -83,78 +87,29 @@ void Debugger::print(const char *fmt, ...) {
Common::String str = Common::String::vformat(fmt, va);
va_end(va);
- if (isActive()) {
- debugPrintf("%s\n", str.c_str());
- } else {
- screenMessage("%s\n", str.c_str());
- }
-}
-
-void Debugger::summonCreature(const Common::String &name) {
- const Creature *m = NULL;
- Common::String creatureName = name;
-
- creatureName.trim();
- if (creatureName.empty()) {
- print("\n");
- return;
- }
-
- /* find the creature by its id and spawn it */
- unsigned int id = atoi(creatureName.c_str());
- if (id > 0)
- m = creatureMgr->getById(id);
-
- if (!m)
- m = creatureMgr->getByName(creatureName);
-
- if (m) {
- if (gameSpawnCreature(m))
- print("\n%s summoned!\n", m->getName().c_str());
- else
- print("\n\nNo place to put %s!\n\n", m->getName().c_str());
-
- return;
- }
-
- print("\n%s not found\n", creatureName.c_str());
-}
-
-Direction Debugger::directionFromName(const Common::String &dirStr) {
- Common::String dir = dirStr;
- dir.toLowercase();
-
- if (dir == "up" || dir == "north")
- return DIR_NORTH;
- else if (dir == "down" || dir == "south")
- return DIR_SOUTH;
- else if (dir == "right" || dir == "east")
- return DIR_EAST;
- else if (dir == "left" || dir == "west")
- return DIR_WEST;
-
- return DIR_NONE;
+ printN("%s\n", str.c_str());
}
-bool Debugger::destroyAt(const Coords &coords) {
- Object *obj = g_context->_location->_map->objectAt(coords);
+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 (obj) {
- if (isCreature(obj)) {
- Creature *c = dynamic_cast<Creature *>(obj);
- screenMessage("%s Destroyed!\n", c->getName().c_str());
- } else {
- Tile *t = g_context->_location->_map->_tileset->get(obj->getTile()._id);
- screenMessage("%s Destroyed!\n", t->getName().c_str());
+ 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;
}
- g_context->_location->_map->removeObject(obj);
- screenPrompt();
-
- return true;
+ debugPrintf("%s", s.c_str());
+ } else {
+ screenMessage("%s", str.c_str());
}
-
- return false;
}
@@ -165,7 +120,7 @@ bool Debugger::cmdMove(int argc, const char **argv) {
dir = directionFromName(argv[1]);
} else {
print("move <direction>");
- return isActive();
+ return isDebuggerActive();
}
Common::String priorMap = g_context->_location->_map->_fname;
@@ -188,6 +143,87 @@ bool Debugger::cmdMove(int argc, const char **argv) {
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);
+ g_game->finishTurn();
+ 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::cmdPass(int argc, const char **argv) {
+ print("Pass");
+ g_game->finishTurn();
+ return isDebuggerActive();
+}
+
bool Debugger::cmd3d(int argc, const char **argv) {
if (g_context->_location->_context == CTX_DUNGEON) {
@@ -196,7 +232,7 @@ bool Debugger::cmd3d(int argc, const char **argv) {
print("Not here");
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdCollisions(int argc, const char **argv) {
@@ -204,7 +240,7 @@ bool Debugger::cmdCollisions(int argc, const char **argv) {
print("Collision detection %s",
_collisionOverride ? "off" : "on");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdCompanions(int argc, const char **argv) {
@@ -218,7 +254,7 @@ bool Debugger::cmdCompanions(int argc, const char **argv) {
g_context->_stats->update();
print("Joined by companions");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdDestroy(int argc, const char **argv) {
@@ -226,16 +262,16 @@ bool Debugger::cmdDestroy(int argc, const char **argv) {
if (argc == 2) {
dir = directionFromName(argv[1]);
- } else if (isActive()) {
+ } else if (isDebuggerActive()) {
print("destroy <direction>");
- return isActive();
+ return isDebuggerActive();
} else {
screenMessage("Destroy Object\nDir: ");
dir = gameGetDirection();
}
if (dir == DIR_NONE)
- return isActive();
+ return isDebuggerActive();
Std::vector<Coords> path = gameGetDirectionalActionPath(MASK_DIR(dir),
MASK_DIR_ALL, g_context->_location->_coords, 1, 1, NULL, true);
@@ -247,7 +283,7 @@ bool Debugger::cmdDestroy(int argc, const char **argv) {
}
print("%cNothing there!%c\n", FG_GREY, FG_WHITE);
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdDungeon(int argc, const char **argv) {
@@ -272,7 +308,7 @@ bool Debugger::cmdDungeon(int argc, const char **argv) {
g_ultima->_saveGame->_orientation = DIR_SOUTH;
} else {
print("Invalid dungeon");
- return isActive();
+ return isDebuggerActive();
}
g_game->finishTurn();
@@ -284,7 +320,7 @@ bool Debugger::cmdDungeon(int argc, const char **argv) {
print("Not here");
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdEquipment(int argc, const char **argv) {
@@ -302,7 +338,7 @@ bool Debugger::cmdEquipment(int argc, const char **argv) {
}
print("All equipment given");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdExit(int argc, const char **argv) {
@@ -314,7 +350,7 @@ bool Debugger::cmdExit(int argc, const char **argv) {
print("Exited");
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdGate(int argc, const char **argv) {
@@ -323,7 +359,7 @@ bool Debugger::cmdGate(int argc, const char **argv) {
if (!g_context || !g_game || gateNum < 1 || gateNum > 8) {
print("Gate <1 to 8>");
} else {
- if (!isActive())
+ if (!isDebuggerActive())
print("Gate %d!", gateNum);
if (g_context->_location->_map->isWorldMap()) {
@@ -338,7 +374,7 @@ bool Debugger::cmdGate(int argc, const char **argv) {
}
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdGoto(int argc, const char **argv) {
@@ -346,7 +382,7 @@ bool Debugger::cmdGoto(int argc, const char **argv) {
if (argc == 2) {
dest = argv[1];
- } else if (isActive()) {
+ } else if (isDebuggerActive()) {
print("teleport <destination name>");
return true;
} else {
@@ -384,17 +420,17 @@ bool Debugger::cmdGoto(int argc, const char **argv) {
g_game->finishTurn();
return false;
} else {
- if (isActive())
+ if (isDebuggerActive())
print("Can't find %s", dest.c_str());
else
print("Can't find\n%s", dest.c_str());
- return isActive();
+ return isDebuggerActive();
}
}
bool Debugger::cmdHelp(int argc, const char **argv) {
- if (!isActive()) {
+ if (!isDebuggerActive()) {
screenMessage("Help!\n");
screenPrompt();
}
@@ -423,7 +459,7 @@ bool Debugger::cmdItems(int argc, const char **argv) {
g_context->_stats->update();
print("All items given");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdKarma(int argc, const char **argv) {
@@ -442,13 +478,13 @@ bool Debugger::cmdKarma(int argc, const char **argv) {
print("%s", line.c_str());
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdLocation(int argc, const char **argv) {
const MapCoords &pos = g_context->_location->_coords;
- if (isActive()) {
+ if (isDebuggerActive()) {
if (g_context->_location->_map->isWorldMap())
print("Location: %s x: %d, y: %d",
"World Map", pos.x, pos.y);
@@ -464,7 +500,7 @@ bool Debugger::cmdLocation(int argc, const char **argv) {
g_context->_location->_map->getName().c_str(), pos.x, pos.y, pos.z);
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdMixtures(int argc, const char **argv) {
@@ -472,7 +508,7 @@ bool Debugger::cmdMixtures(int argc, const char **argv) {
g_ultima->_saveGame->_mixtures[i] = 99;
screenMessage("All mixtures given");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdMoon(int argc, const char **argv) {
@@ -493,13 +529,13 @@ bool Debugger::cmdMoon(int argc, const char **argv) {
g_game->finishTurn();
print("Moons advanced");
- return isActive();
+ 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 isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdPeer(int argc, const char **argv) {
@@ -511,7 +547,7 @@ bool Debugger::cmdPeer(int argc, const char **argv) {
g_context->_location->_viewMode = VIEW_NORMAL;
print("Toggle view");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdReagents(int argc, const char **argv) {
@@ -519,7 +555,7 @@ bool Debugger::cmdReagents(int argc, const char **argv) {
g_ultima->_saveGame->_reagents[i] = 99;
print("Reagents given");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdStats(int argc, const char **argv) {
@@ -536,7 +572,7 @@ bool Debugger::cmdStats(int argc, const char **argv) {
}
print("Full Stats given");
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdSummon(int argc, const char **argv) {
@@ -544,7 +580,7 @@ bool Debugger::cmdSummon(int argc, const char **argv) {
if (argc == 2) {
creature = argv[1];
- } else if (isActive()) {
+ } else if (isDebuggerActive()) {
print("summon <creature name>");
return true;
} else {
@@ -554,21 +590,21 @@ bool Debugger::cmdSummon(int argc, const char **argv) {
}
summonCreature(creature);
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdTorch(int argc, const char **argv) {
print("Torch: %d\n", g_context->_party->getTorchDuration());
- if (!isActive())
+ if (!isDebuggerActive())
screenPrompt();
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdTransport(int argc, const char **argv) {
if (!g_context->_location->_map->isWorldMap()) {
print("Not here!");
- return isActive();
+ return isDebuggerActive();
}
_horse = g_context->_location->_map->_tileset->getByName("horse")->getId();
@@ -583,9 +619,9 @@ bool Debugger::cmdTransport(int argc, const char **argv) {
char transport;
if (argc >= 2) {
transport = argv[1][0];
- } else if (isActive()) {
+ } else if (isDebuggerActive()) {
print("transport <transport name>");
- return isActive();
+ return isDebuggerActive();
} else {
transport = ReadChoiceController::get("shb \033\015");
}
@@ -602,7 +638,7 @@ bool Debugger::cmdTransport(int argc, const char **argv) {
break;
default:
print("Unknown transport");
- return isActive();
+ return isDebuggerActive();
}
tile = g_context->_location->_map->_tileset->get(choice->getId());
@@ -610,7 +646,7 @@ bool Debugger::cmdTransport(int argc, const char **argv) {
if (argc == 3) {
dir = directionFromName(argv[2]);
- } else if (isActive()) {
+ } else if (isDebuggerActive()) {
dir = DIR_NONE;
} else {
screenMessage("%s\n", tile->getName().c_str());
@@ -653,7 +689,7 @@ bool Debugger::cmdTransport(int argc, const char **argv) {
}
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdUp(int argc, const char **argv) {
@@ -667,7 +703,7 @@ bool Debugger::cmdUp(int argc, const char **argv) {
g_game->exitToParentMap();
g_music->play();
- return isActive();
+ return isDebuggerActive();
}
}
@@ -677,7 +713,7 @@ bool Debugger::cmdDown(int argc, const char **argv) {
return false;
} else {
print("Not here");
- return isActive();
+ return isDebuggerActive();
}
}
@@ -706,7 +742,7 @@ bool Debugger::cmdVirtue(int argc, const char **argv) {
}
}
- return isActive();
+ return isDebuggerActive();
}
bool Debugger::cmdWind(int argc, const char **argv) {
@@ -714,7 +750,7 @@ bool Debugger::cmdWind(int argc, const char **argv) {
if (argc == 2) {
windDir = argv[1];
- } else if (isActive()) {
+ } else if (isDebuggerActive()) {
print("wind <direction or 'lock'>");
return true;
} else {
@@ -732,7 +768,7 @@ bool Debugger::cmdWind(int argc, const char **argv) {
if (dir == DIR_NONE) {
print("Unknown direction");
- return isActive();
+ return isDebuggerActive();
} else {
g_context->_windDirection = dir;
}
diff --git a/engines/ultima/ultima4/core/debugger.h b/engines/ultima/ultima4/core/debugger.h
index ebf1704dd4..b1e4f2641b 100644
--- a/engines/ultima/ultima4/core/debugger.h
+++ b/engines/ultima/ultima4/core/debugger.h
@@ -25,6 +25,7 @@
#include "ultima/ultima4/core/coords.h"
#include "ultima/ultima4/core/types.h"
+#include "ultima/ultima4/core/debugger_actions.h"
#include "ultima/shared/engine/debugger.h"
namespace Ultima {
@@ -33,38 +34,59 @@ namespace Ultima4 {
/**
* Debugger base class
*/
-class Debugger : public Shared::Debugger {
+class Debugger : public Shared::Debugger, public DebuggerActions {
private:
MapTile _horse, _ship, _balloon;
-private:
+protected:
/**
- * Prints a message to the console if it's active, or to the
- * game screen if not
+ * Returns true if the debugger is active
*/
- void print(const char *fmt, ...);
+ bool isDebuggerActive() const override {
+ return isActive();
+ }
/**
- * Summons a creature given by 'creatureName'. This can either be given
- * as the creature's name, or the creature's id. Once it finds the
- * creature to be summoned, it calls gameSpawnCreature() to spawn it.
+ * Prints a message to the console if it's active, or to the
+ * game screen if not
*/
- void summonCreature(const Common::String &name);
+ virtual void print(const char *fmt, ...);
/**
- * Destroy object at a given co-ordinate
+ * Prints a message to the console if it's active, or to the
+ * game screen if not, with no newline
*/
- bool destroyAt(const Coords &coords);
+ virtual void printN(const char *fmt, ...);
/**
- * Returns a direction from a given string
+ * Gets the direction for an action
*/
- Direction directionFromName(const Common::String &dirStr);
+ Direction getDirection(int argc, const char **argv);
private:
/**
* Move the avatar in a given direction
*/
bool cmdMove(int argc, const char **argv);
+ /**
+ * Attack
+ */
+ bool cmdAttack(int argc, const char **argv);
+
+ /**
+ * Board transport
+ */
+ bool cmdBoard(int argc, const char **argv);
+
+ /**
+ * Cast spell
+ */
+ bool cmdCastSpell(int argc, const char **argv);
+
+ /**
+ * Pass turn
+ */
+ bool cmdPass(int argc, const char **argv);
+
private:
/**
* Collision detection on/off
diff --git a/engines/ultima/ultima4/core/debugger_actions.cpp b/engines/ultima/ultima4/core/debugger_actions.cpp
new file mode 100644
index 0000000000..ae000b64d5
--- /dev/null
+++ b/engines/ultima/ultima4/core/debugger_actions.cpp
@@ -0,0 +1,138 @@
+/* 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_actions.h"
+#include "ultima/ultima4/game/context.h"
+#include "ultima/ultima4/game/player.h"
+#include "ultima/ultima4/gfx/screen.h"
+#include "ultima/ultima4/gfx/textcolor.h"
+#include "ultima/ultima4/map/combat.h"
+
+namespace Ultima {
+namespace Ultima4 {
+
+void DebuggerActions::summonCreature(const Common::String &name) {
+ const Creature *m = NULL;
+ Common::String creatureName = name;
+
+ creatureName.trim();
+ if (creatureName.empty()) {
+ print("\n");
+ return;
+ }
+
+ /* find the creature by its id and spawn it */
+ unsigned int id = atoi(creatureName.c_str());
+ if (id > 0)
+ m = creatureMgr->getById(id);
+
+ if (!m)
+ m = creatureMgr->getByName(creatureName);
+
+ if (m) {
+ if (gameSpawnCreature(m))
+ print("\n%s summoned!\n", m->getName().c_str());
+ else
+ print("\n\nNo place to put %s!\n\n", m->getName().c_str());
+
+ return;
+ }
+
+ print("\n%s not found\n", creatureName.c_str());
+}
+
+Direction DebuggerActions::directionFromName(const Common::String &dirStr) {
+ Common::String dir = dirStr;
+ dir.toLowercase();
+
+ if (dir == "up" || dir == "north")
+ return DIR_NORTH;
+ else if (dir == "down" || dir == "south")
+ return DIR_SOUTH;
+ else if (dir == "right" || dir == "east")
+ return DIR_EAST;
+ else if (dir == "left" || dir == "west")
+ return DIR_WEST;
+
+ return DIR_NONE;
+}
+
+bool DebuggerActions::destroyAt(const Coords &coords) {
+ Object *obj = g_context->_location->_map->objectAt(coords);
+
+ if (obj) {
+ if (isCreature(obj)) {
+ Creature *c = dynamic_cast<Creature *>(obj);
+ screenMessage("%s Destroyed!\n", c->getName().c_str());
+ } else {
+ Tile *t = g_context->_location->_map->_tileset->get(obj->getTile()._id);
+ screenMessage("%s Destroyed!\n", t->getName().c_str());
+ }
+
+ g_context->_location->_map->removeObject(obj);
+ screenPrompt();
+
+ return true;
+ }
+
+ return false;
+}
+
+bool DebuggerActions::attackAt(const Coords &coords) {
+ Object *under;
+ const Tile *ground;
+ Creature *m;
+
+ m = dynamic_cast<Creature *>(g_context->_location->_map->objectAt(coords));
+ /* nothing attackable: move on to next tile */
+ if (m == NULL || !m->isAttackable())
+ return false;
+
+ /* attack successful */
+ /// TODO: CHEST: Make a user option to not make chests change battlefield
+ /// map (1 of 2)
+ ground = g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITH_GROUND_OBJECTS);
+ if (!ground->isChest()) {
+ ground = g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITHOUT_OBJECTS);
+ if ((under = g_context->_location->_map->objectAt(g_context->_location->_coords)) &&
+ under->getTile().getTileType()->isShip())
+ ground = under->getTile().getTileType();
+ }
+
+ /* You're attacking a townsperson! Alert the guards! */
+ if ((m->getType() == Object::PERSON) && (m->getMovementBehavior() != MOVEMENT_ATTACK_AVATAR))
+ g_context->_location->_map->alertGuards();
+
+ /* not good karma to be killing the innocent. Bad avatar! */
+ if (m->isGood() || /* attacking a good creature */
+ /* attacking a docile (although possibly evil) person in town */
+ ((m->getType() == Object::PERSON) && (m->getMovementBehavior() != MOVEMENT_ATTACK_AVATAR)))
+ g_context->_party->adjustKarma(KA_ATTACKED_GOOD);
+
+ CombatController *cc = new CombatController(CombatMap::mapForTile(ground, g_context->_party->getTransport().getTileType(), m));
+ cc->init(m);
+ cc->begin();
+ return false;
+}
+
+} // End of namespace Ultima4
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima4/core/debugger_actions.h b/engines/ultima/ultima4/core/debugger_actions.h
new file mode 100644
index 0000000000..c696fdc1e1
--- /dev/null
+++ b/engines/ultima/ultima4/core/debugger_actions.h
@@ -0,0 +1,84 @@
+/* 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.
+ *
+ */
+
+#ifndef ULTIMA4_CORE_DEBUGGER_ACTIONS_H
+#define ULTIMA4_CORE_DEBUGGER_ACTIONS_H
+
+#include "ultima/ultima4/core/coords.h"
+#include "ultima/ultima4/core/types.h"
+#include "ultima/shared/engine/debugger.h"
+
+namespace Ultima {
+namespace Ultima4 {
+
+/**
+ * This is a secondary class inherited by the Debugger class
+ * that contains various support methods for implementing the
+ * different actions players can take in the game
+ */
+class DebuggerActions {
+protected:
+ /**
+ * Returns true if the debugger is active
+ */
+ virtual bool isDebuggerActive() const = 0;
+
+ /**
+ * Prints a message to the console if it's active, or to the
+ * game screen if not
+ */
+ virtual void print(const char *fmt, ...) = 0;
+
+ /**
+ * Prints a message to the console if it's active, or to the
+ * game screen if not
+ */
+ virtual void printN(const char *fmt, ...) = 0;
+public:
+ /**
+ * Summons a creature given by 'creatureName'. This can either be given
+ * as the creature's name, or the creature's id. Once it finds the
+ * creature to be summoned, it calls gameSpawnCreature() to spawn it.
+ */
+ void summonCreature(const Common::String &name);
+
+ /**
+ * Destroy object at a given co-ordinate
+ */
+ bool destroyAt(const Coords &coords);
+
+ /**
+ * Returns a direction from a given string
+ */
+ Direction directionFromName(const Common::String &dirStr);
+
+ /**
+ * Attempts to attack a creature at map coordinates x,y. If no
+ * creature is present at that point, zero is returned.
+ */
+ bool attackAt(const Coords &coords);
+};
+
+} // End of namespace Ultima4
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima4/events/controller.h b/engines/ultima/ultima4/events/controller.h
index 5c4e882202..726cc7d683 100644
--- a/engines/ultima/ultima4/events/controller.h
+++ b/engines/ultima/ultima4/events/controller.h
@@ -23,6 +23,8 @@
#ifndef ULTIMA4_CONTROLLER_H
#define ULTIMA4_CONTROLLER_H
+#include "ultima/ultima4/meta_engine.h"
+
namespace Ultima {
namespace Ultima4 {
@@ -56,9 +58,14 @@ public:
*/
static void timerCallback(void *data);
- /* control methods subclasses may want to override */
+ /** control methods subclasses may want to override */
virtual bool keyPressed(int key) = 0;
+ /**
+ * Handles keybinder actions
+ */
+ virtual void keybinder(KeybindingAction action) {}
+
/**
* The default timerFired handler for a controller. By default,
* timers are ignored, but subclasses can override this method and it
diff --git a/engines/ultima/ultima4/events/event.cpp b/engines/ultima/ultima4/events/event.cpp
index 94cbcee84c..7e365902a7 100644
--- a/engines/ultima/ultima4/events/event.cpp
+++ b/engines/ultima/ultima4/events/event.cpp
@@ -264,10 +264,32 @@ ReadDirController::ReadDirController() {
_value = DIR_NONE;
}
-bool ReadDirController::keyPressed(int key) {
- Direction d = keyToDirection(key);
- bool valid = (d != DIR_NONE);
+void ReadDirController::keybinder(KeybindingAction action) {
+ switch (action) {
+ case KEYBIND_UP:
+ _value = DIR_NORTH;
+ break;
+ case KEYBIND_DOWN:
+ _value = DIR_SOUTH;
+ break;
+ case KEYBIND_LEFT:
+ _value = DIR_WEST;
+ break;
+ case KEYBIND_RIGHT:
+ _value = DIR_EAST;
+ break;
+ case KEYBIND_PASS:
+ _value = DIR_NONE;
+ doneWaiting();
+ break;
+ default:
+ return;
+ }
+
+ doneWaiting();
+}
+bool ReadDirController::keyPressed(int key) {
switch (key) {
case Common::KEYCODE_ESCAPE:
case Common::KEYCODE_SPACE:
@@ -277,11 +299,6 @@ bool ReadDirController::keyPressed(int key) {
return true;
default:
- if (valid) {
- _value = d;
- doneWaiting();
- return true;
- }
break;
}
diff --git a/engines/ultima/ultima4/events/event.h b/engines/ultima/ultima4/events/event.h
index fd44a2aca0..50df579b29 100644
--- a/engines/ultima/ultima4/events/event.h
+++ b/engines/ultima/ultima4/events/event.h
@@ -212,7 +212,16 @@ protected:
class ReadDirController : public WaitableController<Direction> {
public:
ReadDirController();
+
+ /**
+ * Key was pressed
+ */
bool keyPressed(int key) override;
+
+ /**
+ * Handles keybinder actions
+ */
+ void keybinder(KeybindingAction action) override;
};
/**
diff --git a/engines/ultima/ultima4/events/event_scummvm.cpp b/engines/ultima/ultima4/events/event_scummvm.cpp
index 6ff8260715..8f37bfc7cc 100644
--- a/engines/ultima/ultima4/events/event_scummvm.cpp
+++ b/engines/ultima/ultima4/events/event_scummvm.cpp
@@ -245,7 +245,7 @@ void EventHandler::run() {
continue;
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
- MetaEngine::executeAction((KeybindingAction)event.customType);
+ getController()->keybinder((KeybindingAction)event.customType);
break;
case Common::EVENT_QUIT:
diff --git a/engines/ultima/ultima4/game/game.cpp b/engines/ultima/ultima4/game/game.cpp
index 9e7113894a..198fb5d1fb 100644
--- a/engines/ultima/ultima4/game/game.cpp
+++ b/engines/ultima/ultima4/game/game.cpp
@@ -63,6 +63,7 @@
#include "ultima/ultima4/map/dungeonview.h"
#include "ultima/ultima4/sound/music.h"
#include "ultima/ultima4/sound/sound.h"
+#include "ultima/ultima4/meta_engine.h"
#include "common/savefile.h"
#include "common/system.h"
@@ -549,6 +550,10 @@ void gameCastSpell(unsigned int spell, int caster, int param) {
}
}
+void GameController::keybinder(KeybindingAction action) {
+ MetaEngine::executeAction(action);
+}
+
bool GameController::keyPressed(int key) {
bool valid = true;
int endTurn = 1;
@@ -685,14 +690,6 @@ bool GameController::keyPressed(int key) {
endTurn = false;
break;
- case 'a':
- attack();
- break;
-
- case 'b':
- board();
- break;
-
case 'c':
castSpell();
break;
@@ -1211,101 +1208,6 @@ bool ZtatsController::keyPressed(int key) {
}
}
-void attack() {
- screenMessage("Attack: ");
-
- if (g_context->_party->isFlying()) {
- screenMessage("\n%cDrift only!%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- Direction dir = gameGetDirection();
-
- if (dir == DIR_NONE)
- return;
-
- 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;
- }
-
- screenMessage("%cNothing to Attack!%c\n", FG_GREY, FG_WHITE);
-}
-
-/**
- * Attempts to attack a creature at map coordinates x,y. If no
- * creature is present at that point, zero is returned.
- */
-bool attackAt(const Coords &coords) {
- Object *under;
- const Tile *ground;
- Creature *m;
-
- m = dynamic_cast<Creature *>(g_context->_location->_map->objectAt(coords));
- /* nothing attackable: move on to next tile */
- if (m == NULL || !m->isAttackable())
- return false;
-
- /* attack successful */
- /// TODO: CHEST: Make a user option to not make chests change battlefield
- /// map (1 of 2)
- ground = g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITH_GROUND_OBJECTS);
- if (!ground->isChest()) {
- ground = g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITHOUT_OBJECTS);
- if ((under = g_context->_location->_map->objectAt(g_context->_location->_coords)) &&
- under->getTile().getTileType()->isShip())
- ground = under->getTile().getTileType();
- }
-
- /* You're attacking a townsperson! Alert the guards! */
- if ((m->getType() == Object::PERSON) && (m->getMovementBehavior() != MOVEMENT_ATTACK_AVATAR))
- g_context->_location->_map->alertGuards();
-
- /* not good karma to be killing the innocent. Bad avatar! */
- if (m->isGood() || /* attacking a good creature */
- /* attacking a docile (although possibly evil) person in town */
- ((m->getType() == Object::PERSON) && (m->getMovementBehavior() != MOVEMENT_ATTACK_AVATAR)))
- g_context->_party->adjustKarma(KA_ATTACKED_GOOD);
-
- CombatController *cc = new CombatController(CombatMap::mapForTile(ground, g_context->_party->getTransport().getTileType(), m));
- cc->init(m);
- cc->begin();
- return true;
-}
-
-void board() {
- if (g_context->_transportContext != TRANSPORT_FOOT) {
- screenMessage("Board: %cCan't!%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- Object *obj = g_context->_location->_map->objectAt(g_context->_location->_coords);
- if (!obj) {
- screenMessage("%cBoard What?%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- const Tile *tile = obj->getTile().getTileType();
- if (tile->isShip()) {
- screenMessage("Board Frigate!\n");
- if (g_context->_lastShip != obj)
- g_context->_party->setShipHull(50);
- } else if (tile->isHorse())
- screenMessage("Mount Horse!\n");
- else if (tile->isBalloon())
- screenMessage("Board Balloon!\n");
- else {
- screenMessage("%cBoard What?%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- g_context->_party->setTransport(obj->getTile());
- g_context->_location->_map->removeObject(obj);
-}
-
-
void castSpell(int player) {
if (player == -1) {
screenMessage("Cast Spell!\nPlayer: ");
@@ -2545,7 +2447,7 @@ void GameController::timerFired() {
gameTimeSinceLastCommand() > 20) {
/* pass the turn, and redraw the text area so the prompt is shown */
- controller->keyPressed(U4_SPACE);
+ MetaEngine::executeAction(KEYBIND_PASS);
screenRedrawTextArea(TEXT_AREA_X, TEXT_AREA_Y, TEXT_AREA_W, TEXT_AREA_H);
}
}
diff --git a/engines/ultima/ultima4/game/game.h b/engines/ultima/ultima4/game/game.h
index 1842e4cf99..80eb69c131 100644
--- a/engines/ultima/ultima4/game/game.h
+++ b/engines/ultima/ultima4/game/game.h
@@ -110,6 +110,12 @@ public:
GameController();
/* controller functions */
+
+ /**
+ * Keybinder actions
+ */
+ void keybinder(KeybindingAction action) override;
+
/**
* The main key handler for the game. Interpretes each key as a
* command - 'a' for attack, 't' for talk, etc.
@@ -233,9 +239,6 @@ void castSpell(int player = -1);
void gameSpellEffect(int spell, int player, Sound sound);
/* action functions */
-void destroy();
-void attack();
-void board();
void fire();
void getChest(int player = -1);
void holeUp();
diff --git a/engines/ultima/ultima4/meta_engine.cpp b/engines/ultima/ultima4/meta_engine.cpp
index ac25c80069..f06a5fe959 100644
--- a/engines/ultima/ultima4/meta_engine.cpp
+++ b/engines/ultima/ultima4/meta_engine.cpp
@@ -39,16 +39,20 @@ struct KeybindingRecord {
};
static const KeybindingRecord KEYS[] = {
- { ACTION_NORTH, "UP", "Up", "move up", "UP", nullptr },
- { ACTION_SOUTH, "DOWN", "Down", "move down", "DOWN", nullptr },
- { ACTION_WEST, "LEFT", "Left", "move left", "LEFT", nullptr },
- { ACTION_EAST, "RIGHT", "Right", "move right", "RIGHT", nullptr },
-
- { ACTION_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
+ { KEYBIND_UP, "UP", "Up", "move up", "UP", nullptr },
+ { KEYBIND_DOWN, "DOWN", "Down", "move down", "DOWN", nullptr },
+ { KEYBIND_LEFT, "LEFT", "Left", "move left", "LEFT", nullptr },
+ { KEYBIND_RIGHT, "RIGHT", "Right", "move right", "RIGHT", nullptr },
+ { KEYBIND_ATTACK, "ATTACK", "Attack", "attack", "a", nullptr },
+ { KEYBIND_BOARD, "BOARD", "Board", "board", "b", nullptr },
+ { KEYBIND_CAST, "CAST", "Cast", "cast", "c", nullptr },
+ { KEYBIND_PASS, "PASS", "Pass", "pass", "SPACE", nullptr },
+
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
};
static const KeybindingRecord CHEAT_KEYS[] = {
- { ACTION_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
};
diff --git a/engines/ultima/ultima4/meta_engine.h b/engines/ultima/ultima4/meta_engine.h
index 659d6fbb8c..0cdcfbaa83 100644
--- a/engines/ultima/ultima4/meta_engine.h
+++ b/engines/ultima/ultima4/meta_engine.h
@@ -29,9 +29,11 @@ namespace Ultima {
namespace Ultima4 {
enum KeybindingAction {
- ACTION_NORTH, ACTION_SOUTH, ACTION_EAST, ACTION_WEST,
+ KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
+ KEYBIND_ATTACK, KEYBIND_BOARD, KEYBIND_CAST,
+ KEYBIND_PASS,
- ACTION_NONE
+ KEYBIND_NONE
};
class MetaEngine {
Commit: e5894a132e3f2c352ffc78fc199b96c517031943
https://github.com/scummvm/scummvm/commit/e5894a132e3f2c352ffc78fc199b96c517031943
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-04-12T18:54:30-07:00
Commit Message:
ULTIMA4: Better handling for keybind actions ending turns
Changed paths:
engines/ultima/ultima4/core/debugger.cpp
engines/ultima/ultima4/core/debugger.h
diff --git a/engines/ultima/ultima4/core/debugger.cpp b/engines/ultima/ultima4/core/debugger.cpp
index f38eb896c1..e815e16b7b 100644
--- a/engines/ultima/ultima4/core/debugger.cpp
+++ b/engines/ultima/ultima4/core/debugger.cpp
@@ -112,6 +112,15 @@ void Debugger::printN(const char *fmt, ...) {
}
}
+bool Debugger::handleCommand(int argc, const char **argv, bool &keepRunning) {
+ bool result = Shared::Debugger::handleCommand(argc, argv, keepRunning);
+
+ if (result && !isActive() && argv[0] != "move")
+ g_game->finishTurn();
+
+ return result;
+}
+
bool Debugger::cmdMove(int argc, const char **argv) {
Direction dir;
@@ -178,7 +187,6 @@ bool Debugger::cmdAttack(int argc, const char **argv) {
}
print("%cNothing to Attack!%c", FG_GREY, FG_WHITE);
- g_game->finishTurn();
return isDebuggerActive();
}
@@ -220,7 +228,6 @@ bool Debugger::cmdCastSpell(int argc, const char **argv) {
bool Debugger::cmdPass(int argc, const char **argv) {
print("Pass");
- g_game->finishTurn();
return isDebuggerActive();
}
@@ -277,7 +284,6 @@ bool Debugger::cmdDestroy(int argc, const char **argv) {
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)) {
- g_game->finishTurn();
return false;
}
}
@@ -311,7 +317,6 @@ bool Debugger::cmdDungeon(int argc, const char **argv) {
return isDebuggerActive();
}
- g_game->finishTurn();
return false;
} else {
print("dungeon <number>");
@@ -345,7 +350,6 @@ bool Debugger::cmdExit(int argc, const char **argv) {
if (!g_game->exitToParentMap()) {
print("Not Here");
} else {
- g_game->finishTurn();
g_music->play();
print("Exited");
}
@@ -366,7 +370,6 @@ bool Debugger::cmdGate(int argc, const char **argv) {
const Coords *moongate = moongateGetGateCoordsForPhase(gateNum - 1);
if (moongate) {
g_context->_location->_coords = *moongate;
- g_game->finishTurn();
return false;
}
} else {
@@ -417,7 +420,6 @@ bool Debugger::cmdGoto(int argc, const char **argv) {
}
if (found) {
- g_game->finishTurn();
return false;
} else {
if (isDebuggerActive())
@@ -440,7 +442,6 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
g_context->_location->_coords.x = 19;
g_context->_location->_coords.y = 8;
g_context->_location->_coords.z = 0;
- g_game->finishTurn();
return false;
}
@@ -526,7 +527,6 @@ bool Debugger::cmdMoon(int argc, const char **argv) {
while (g_ultima->_saveGame->_trammelPhase != moonNum)
g_game->updateMoons(true);
- g_game->finishTurn();
print("Moons advanced");
return isDebuggerActive();
@@ -695,7 +695,6 @@ bool Debugger::cmdTransport(int argc, const char **argv) {
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--;
- g_game->finishTurn();
return false;
} else {
diff --git a/engines/ultima/ultima4/core/debugger.h b/engines/ultima/ultima4/core/debugger.h
index b1e4f2641b..d2ed92c71b 100644
--- a/engines/ultima/ultima4/core/debugger.h
+++ b/engines/ultima/ultima4/core/debugger.h
@@ -45,17 +45,24 @@ protected:
return isActive();
}
+ /**
+ * Process the given command line.
+ * Returns true if and only if argv[0] is a known command and was
+ * handled, false otherwise.
+ */
+ bool handleCommand(int argc, const char **argv, bool &keepRunning) override;
+
/**
* Prints a message to the console if it's active, or to the
* game screen if not
*/
- virtual void print(const char *fmt, ...);
+ void print(const char *fmt, ...) override;
/**
* Prints a message to the console if it's active, or to the
* game screen if not, with no newline
*/
- virtual void printN(const char *fmt, ...);
+ void printN(const char *fmt, ...) override;
/**
* Gets the direction for an action
Commit: dba370697f1ed153b2b7d018ffd309cbc26994cf
https://github.com/scummvm/scummvm/commit/dba370697f1ed153b2b7d018ffd309cbc26994cf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-04-12T18:54:30-07:00
Commit Message:
ULTIMA4: Changed enter to a keybinder action
Changed paths:
engines/ultima/ultima4/core/debugger.cpp
engines/ultima/ultima4/core/debugger.h
engines/ultima/ultima4/game/game.cpp
engines/ultima/ultima4/meta_engine.cpp
engines/ultima/ultima4/meta_engine.h
diff --git a/engines/ultima/ultima4/core/debugger.cpp b/engines/ultima/ultima4/core/debugger.cpp
index e815e16b7b..fcc5f69484 100644
--- a/engines/ultima/ultima4/core/debugger.cpp
+++ b/engines/ultima/ultima4/core/debugger.cpp
@@ -41,11 +41,13 @@ 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("pass", WRAP_METHOD(Debugger, cmdPass));
registerCmd("3d", WRAP_METHOD(Debugger, cmd3d));
@@ -115,9 +117,12 @@ void Debugger::printN(const char *fmt, ...) {
bool Debugger::handleCommand(int argc, const char **argv, bool &keepRunning) {
bool result = Shared::Debugger::handleCommand(argc, argv, keepRunning);
- if (result && !isActive() && argv[0] != "move")
- g_game->finishTurn();
+ if (result && !isActive()) {
+ if (!_dontEndTurn)
+ g_game->finishTurn();
+ }
+ _dontEndTurn = false;
return result;
}
@@ -146,8 +151,8 @@ bool Debugger::cmdMove(int argc, const char **argv) {
// Let the movement handler decide to end the turn
bool endTurn = (retval & MOVE_END_TURN);
- if (endTurn)
- g_game->finishTurn();
+ if (!endTurn)
+ dontEndTurn();
return false;
}
@@ -226,6 +231,17 @@ bool Debugger::cmdCastSpell(int argc, const char **argv) {
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::cmdPass(int argc, const char **argv) {
print("Pass");
return isDebuggerActive();
diff --git a/engines/ultima/ultima4/core/debugger.h b/engines/ultima/ultima4/core/debugger.h
index d2ed92c71b..042e04ff45 100644
--- a/engines/ultima/ultima4/core/debugger.h
+++ b/engines/ultima/ultima4/core/debugger.h
@@ -37,6 +37,7 @@ namespace Ultima4 {
class Debugger : public Shared::Debugger, public DebuggerActions {
private:
MapTile _horse, _ship, _balloon;
+ bool _dontEndTurn;
protected:
/**
* Returns true if the debugger is active
@@ -68,6 +69,14 @@ protected:
* Gets the direction for an action
*/
Direction getDirection(int argc, const char **argv);
+
+ /**
+ * Used by methods so that when they're triggered by a keybinding
+ * action, stops the turn from being finished when they're done
+ */
+ void dontEndTurn() {
+ _dontEndTurn = true;
+ }
private:
/**
* Move the avatar in a given direction
@@ -89,6 +98,11 @@ private:
*/
bool cmdCastSpell(int argc, const char **argv);
+ /**
+ * Enter location
+ */
+ bool cmdEnter(int argc, const char **argv);
+
/**
* Pass turn
*/
diff --git a/engines/ultima/ultima4/game/game.cpp b/engines/ultima/ultima4/game/game.cpp
index 198fb5d1fb..0fbbcc6bfa 100644
--- a/engines/ultima/ultima4/game/game.cpp
+++ b/engines/ultima/ultima4/game/game.cpp
@@ -717,13 +717,6 @@ bool GameController::keyPressed(int key) {
break;
}
- case 'e':
- if (!usePortalAt(g_context->_location, g_context->_location->_coords, ACTION_ENTER)) {
- if (!g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_ENTER))
- screenMessage("%cEnter what?%c\n", FG_GREY, FG_WHITE);
- } else endTurn = 0; /* entering a portal doesn't end the turn */
- break;
-
case 'f':
fire();
break;
diff --git a/engines/ultima/ultima4/meta_engine.cpp b/engines/ultima/ultima4/meta_engine.cpp
index f06a5fe959..a08ad06a52 100644
--- a/engines/ultima/ultima4/meta_engine.cpp
+++ b/engines/ultima/ultima4/meta_engine.cpp
@@ -46,6 +46,7 @@ static const KeybindingRecord KEYS[] = {
{ KEYBIND_ATTACK, "ATTACK", "Attack", "attack", "a", nullptr },
{ KEYBIND_BOARD, "BOARD", "Board", "board", "b", nullptr },
{ KEYBIND_CAST, "CAST", "Cast", "cast", "c", nullptr },
+ { KEYBIND_ENTER, "ENTER", "Enter", "enter", "e", nullptr },
{ KEYBIND_PASS, "PASS", "Pass", "pass", "SPACE", nullptr },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
diff --git a/engines/ultima/ultima4/meta_engine.h b/engines/ultima/ultima4/meta_engine.h
index 0cdcfbaa83..2875c1b398 100644
--- a/engines/ultima/ultima4/meta_engine.h
+++ b/engines/ultima/ultima4/meta_engine.h
@@ -30,7 +30,7 @@ namespace Ultima4 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
- KEYBIND_ATTACK, KEYBIND_BOARD, KEYBIND_CAST,
+ KEYBIND_ATTACK, KEYBIND_BOARD, KEYBIND_CAST, KEYBIND_ENTER,
KEYBIND_PASS,
KEYBIND_NONE
Commit: b8c3775644ce8f21366d2fb284deab3939a2d527
https://github.com/scummvm/scummvm/commit/b8c3775644ce8f21366d2fb284deab3939a2d527
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-04-12T18:54:30-07:00
Commit Message:
ULTIMA4: Shifting more actions to keybindings
Changed paths:
engines/ultima/ultima4/core/debugger.cpp
engines/ultima/ultima4/core/debugger.h
engines/ultima/ultima4/core/debugger_actions.cpp
engines/ultima/ultima4/core/debugger_actions.h
engines/ultima/ultima4/game/game.cpp
engines/ultima/ultima4/game/game.h
engines/ultima/ultima4/game/spell.cpp
engines/ultima/ultima4/map/combat.cpp
engines/ultima/ultima4/meta_engine.cpp
engines/ultima/ultima4/meta_engine.h
diff --git a/engines/ultima/ultima4/core/debugger.cpp b/engines/ultima/ultima4/core/debugger.cpp
index fcc5f69484..b81bbeaf92 100644
--- a/engines/ultima/ultima4/core/debugger.cpp
+++ b/engines/ultima/ultima4/core/debugger.cpp
@@ -29,6 +29,9 @@
#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"
@@ -48,6 +51,12 @@ Debugger::Debugger() : Shared::Debugger() {
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));
@@ -126,6 +135,14 @@ bool Debugger::handleCommand(int argc, const char **argv, bool &keepRunning) {
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;
@@ -242,6 +259,144 @@ bool Debugger::cmdEnter(int argc, const char **argv) {
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::cmdPass(int argc, const char **argv) {
print("Pass");
return isDebuggerActive();
diff --git a/engines/ultima/ultima4/core/debugger.h b/engines/ultima/ultima4/core/debugger.h
index 042e04ff45..dc75632ac0 100644
--- a/engines/ultima/ultima4/core/debugger.h
+++ b/engines/ultima/ultima4/core/debugger.h
@@ -103,6 +103,31 @@ private:
*/
bool cmdEnter(int argc, const char **argv);
+ /**
+ * Fire
+ */
+ bool cmdFire(int argc, const char **argv);
+
+ /**
+ * Get chest
+ */
+ bool cmdGet(int argc, const char **argv);
+
+ /**
+ * Hole Up
+ */
+ bool cmdHoleUp(int argc, const char **argv);
+
+ /**
+ * Ignite Torch
+ */
+ bool cmdIgnite(int argc, const char **argv);
+
+ /**
+ * Jimmy lock
+ */
+ bool cmdJimmy(int argc, const char **argv);
+
/**
* Pass turn
*/
@@ -244,6 +269,13 @@ public:
public:
Debugger();
~Debugger() override;
+
+ /**
+ * Gets a chest.
+ * If the default -2 is used, it bypasses prompting for a
+ * user. Otherwise, a non-negative player number is expected
+ */
+ void getChest(int player = -2);
};
extern Debugger *g_debugger;
diff --git a/engines/ultima/ultima4/core/debugger_actions.cpp b/engines/ultima/ultima4/core/debugger_actions.cpp
index ae000b64d5..2f6cd284a9 100644
--- a/engines/ultima/ultima4/core/debugger_actions.cpp
+++ b/engines/ultima/ultima4/core/debugger_actions.cpp
@@ -21,10 +21,12 @@
*/
#include "ultima/ultima4/core/debugger_actions.h"
+#include "ultima/ultima4/core/utils.h"
#include "ultima/ultima4/game/context.h"
#include "ultima/ultima4/game/player.h"
#include "ultima/ultima4/gfx/screen.h"
#include "ultima/ultima4/gfx/textcolor.h"
+#include "ultima/ultima4/map/annotation.h"
#include "ultima/ultima4/map/combat.h"
namespace Ultima {
@@ -134,5 +136,81 @@ bool DebuggerActions::attackAt(const Coords &coords) {
return false;
}
+bool DebuggerActions::getChestTrapHandler(int player) {
+ TileEffect trapType;
+ int randNum = xu4_random(4);
+
+ /* Do we use u4dos's way of trap-determination, or the original intended way? */
+ int passTest = (settings._enhancements && settings._enhancementsOptions._c64chestTraps) ?
+ (xu4_random(2) == 0) : /* xu4-enhanced */
+ ((randNum & 1) == 0); /* u4dos original way (only allows even numbers through, so only acid and poison show) */
+
+/* Chest is trapped! 50/50 chance */
+ if (passTest) {
+ /* Figure out which trap the chest has */
+ switch (randNum & xu4_random(4)) {
+ case 0:
+ trapType = EFFECT_FIRE;
+ break; /* acid trap (56% chance - 9/16) */
+ case 1:
+ trapType = EFFECT_SLEEP;
+ break; /* sleep trap (19% chance - 3/16) */
+ case 2:
+ trapType = EFFECT_POISON;
+ break; /* poison trap (19% chance - 3/16) */
+ case 3:
+ trapType = EFFECT_LAVA;
+ break; /* bomb trap (6% chance - 1/16) */
+ default:
+ trapType = EFFECT_FIRE;
+ break;
+ }
+
+ /* apply the effects from the trap */
+ if (trapType == EFFECT_FIRE)
+ screenMessage("%cAcid%c Trap!\n", FG_RED, FG_WHITE);
+ else if (trapType == EFFECT_POISON)
+ screenMessage("%cPoison%c Trap!\n", FG_GREEN, FG_WHITE);
+ else if (trapType == EFFECT_SLEEP)
+ screenMessage("%cSleep%c Trap!\n", FG_PURPLE, FG_WHITE);
+ else if (trapType == EFFECT_LAVA)
+ screenMessage("%cBomb%c Trap!\n", FG_RED, FG_WHITE);
+
+ // player is < 0 during the 'O'pen spell (immune to traps)
+ //
+ // if the chest was opened by a PC, see if the trap was
+ // evaded by testing the PC's dex
+ //
+ if ((player >= 0) &&
+ (g_ultima->_saveGame->_players[player]._dex + 25 < xu4_random(100))) {
+ if (trapType == EFFECT_LAVA) /* bomb trap */
+ g_context->_party->applyEffect(trapType);
+ else g_context->_party->member(player)->applyEffect(trapType);
+ } else screenMessage("Evaded!\n");
+
+ return true;
+ }
+
+ return false;
+}
+
+bool DebuggerActions::jimmyAt(const Coords &coords) {
+ MapTile *tile = g_context->_location->_map->tileAt(coords, WITH_OBJECTS);
+
+ if (!tile->getTileType()->isLockedDoor())
+ return false;
+
+ if (g_ultima->_saveGame->_keys) {
+ Tile *door = g_context->_location->_map->_tileset->getByName("door");
+ ASSERT(door, "no door tile found in tileset");
+ g_ultima->_saveGame->_keys--;
+ g_context->_location->_map->_annotations->add(coords, door->getId());
+ screenMessage("\nUnlocked!\n");
+ } else
+ screenMessage("%cNo keys left!%c\n", FG_GREY, FG_WHITE);
+
+ return true;
+}
+
} // End of namespace Ultima4
} // End of namespace Ultima
diff --git a/engines/ultima/ultima4/core/debugger_actions.h b/engines/ultima/ultima4/core/debugger_actions.h
index c696fdc1e1..7df8ca83da 100644
--- a/engines/ultima/ultima4/core/debugger_actions.h
+++ b/engines/ultima/ultima4/core/debugger_actions.h
@@ -76,6 +76,19 @@ public:
* creature is present at that point, zero is returned.
*/
bool attackAt(const Coords &coords);
+
+ /**
+ * Called by getChest() to handle possible traps on chests
+ **/
+ bool getChestTrapHandler(int player);
+
+ /**
+ * Attempts to jimmy a locked door at map coordinates x,y. The locked
+ * door is replaced by a permanent annotation of an unlocked door
+ * tile.
+ */
+ bool jimmyAt(const Coords &coords);
+
};
} // End of namespace Ultima4
diff --git a/engines/ultima/ultima4/game/game.cpp b/engines/ultima/ultima4/game/game.cpp
index 0fbbcc6bfa..4aebcd0506 100644
--- a/engines/ultima/ultima4/game/game.cpp
+++ b/engines/ultima/ultima4/game/game.cpp
@@ -99,9 +99,6 @@ bool talkAt(const Coords &coords);
void talkRunConversation(Conversation &conv, Person *talker, bool showPrompt);
/* action functions */
-bool attackAt(const Coords &coords);
-bool getChestTrapHandler(int player);
-bool jimmyAt(const Coords &coords);
bool openAt(const Coords &coords);
void wearArmor(int player = -1);
void ztatsFor(int player = -1);
@@ -717,30 +714,6 @@ bool GameController::keyPressed(int key) {
break;
}
- case 'f':
- fire();
- break;
-
- case 'g':
- getChest();
- break;
-
- case 'h':
- holeUp();
- break;
-
- case 'i':
- screenMessage("Ignite torch!\n");
- if (g_context->_location->_context == CTX_DUNGEON) {
- if (!g_context->_party->lightTorch())
- screenMessage("%cNone left!%c\n", FG_GREY, FG_WHITE);
- } else screenMessage("%cNot here!%c\n", FG_GREY, FG_WHITE);
- break;
-
- case 'j':
- jimmy();
- break;
-
case 'k':
if (!usePortalAt(g_context->_location, g_context->_location->_coords, ACTION_KLIMB)) {
if (g_context->_transportContext == TRANSPORT_BALLOON) {
@@ -1336,34 +1309,6 @@ void castSpell(int player) {
}
}
-void fire() {
- if (g_context->_transportContext != TRANSPORT_SHIP) {
- screenMessage("%cFire What?%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- screenMessage("Fire Cannon!\nDir: ");
- Direction dir = gameGetDirection();
-
- if (dir == DIR_NONE)
- return;
-
- // can only fire broadsides
- int broadsidesDirs = dirGetBroadsidesDirs(g_context->_party->getDirection());
- if (!DIR_IN_MASK(dir, broadsidesDirs)) {
- screenMessage("%cBroadsides Only!%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- // 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;
- }
-}
-
bool fireAt(const Coords &coords, bool originAvatar) {
bool validObject = false;
bool hitsAvatar = false;
@@ -1422,140 +1367,6 @@ bool fireAt(const Coords &coords, bool originAvatar) {
return objectHit;
}
-/**
- * Get the chest at the current x,y of the current context for player 'player'
- */
-void getChest(int player) {
- screenMessage("Get Chest!\n");
-
- if (g_context->_party->isFlying()) {
- screenMessage("%cDrift only!%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- // 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) {
- screenMessage("Who opens? ");
- player = gameGetPlayer(false, true);
- }
- if (player == -1)
- return;
-
- 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);
-
- screenMessage("The Chest Holds: %d Gold\n", g_context->_party->getChest());
-
- screenPrompt();
-
- if (isCity(g_context->_location->_map) && obj == NULL)
- g_context->_party->adjustKarma(KA_STOLE_CHEST);
- } else {
- screenMessage("%cNot Here!%c\n", FG_GREY, FG_WHITE);
- }
-}
-
-/**
- * Called by getChest() to handle possible traps on chests
- **/
-bool getChestTrapHandler(int player) {
- TileEffect trapType;
- int randNum = xu4_random(4);
-
- /* Do we use u4dos's way of trap-determination, or the original intended way? */
- int passTest = (settings._enhancements && settings._enhancementsOptions._c64chestTraps) ?
- (xu4_random(2) == 0) : /* xu4-enhanced */
- ((randNum & 1) == 0); /* u4dos original way (only allows even numbers through, so only acid and poison show) */
-
- /* Chest is trapped! 50/50 chance */
- if (passTest) {
- /* Figure out which trap the chest has */
- switch (randNum & xu4_random(4)) {
- case 0:
- trapType = EFFECT_FIRE;
- break; /* acid trap (56% chance - 9/16) */
- case 1:
- trapType = EFFECT_SLEEP;
- break; /* sleep trap (19% chance - 3/16) */
- case 2:
- trapType = EFFECT_POISON;
- break; /* poison trap (19% chance - 3/16) */
- case 3:
- trapType = EFFECT_LAVA;
- break; /* bomb trap (6% chance - 1/16) */
- default:
- trapType = EFFECT_FIRE;
- break;
- }
-
- /* apply the effects from the trap */
- if (trapType == EFFECT_FIRE)
- screenMessage("%cAcid%c Trap!\n", FG_RED, FG_WHITE);
- else if (trapType == EFFECT_POISON)
- screenMessage("%cPoison%c Trap!\n", FG_GREEN, FG_WHITE);
- else if (trapType == EFFECT_SLEEP)
- screenMessage("%cSleep%c Trap!\n", FG_PURPLE, FG_WHITE);
- else if (trapType == EFFECT_LAVA)
- screenMessage("%cBomb%c Trap!\n", FG_RED, FG_WHITE);
-
- // player is < 0 during the 'O'pen spell (immune to traps)
- //
- // if the chest was opened by a PC, see if the trap was
- // evaded by testing the PC's dex
- //
- if ((player >= 0) &&
- (g_ultima->_saveGame->_players[player]._dex + 25 < xu4_random(100))) {
- if (trapType == EFFECT_LAVA) /* bomb trap */
- g_context->_party->applyEffect(trapType);
- else g_context->_party->member(player)->applyEffect(trapType);
- } else screenMessage("Evaded!\n");
-
- return true;
- }
-
- return false;
-}
-
-void holeUp() {
- screenMessage("Hole up & Camp!\n");
-
- if (!(g_context->_location->_context & (CTX_WORLDMAP | CTX_DUNGEON))) {
- screenMessage("%cNot here!%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- if (g_context->_transportContext != TRANSPORT_FOOT) {
- screenMessage("%cOnly on foot!%c\n", FG_GREY, FG_WHITE);
- return;
- }
-
- CombatController *cc = new CampController();
- cc->init(NULL);
- cc->begin();
-}
-
void GameController::initMoons() {
int trammelphase = g_ultima->_saveGame->_trammelPhase,
feluccaphase = g_ultima->_saveGame->_feluccaPhase;
@@ -1690,7 +1501,7 @@ void GameController::avatarMoved(MoveEvent &event) {
openAt(new_coords);
event._result = (MoveResult)(MOVE_SUCCEEDED | MOVE_END_TURN);
} else if (tile->getTileType()->isLockedDoor()) {
- jimmyAt(new_coords);
+ g_debugger->jimmyAt(new_coords);
event._result = (MoveResult)(MOVE_SUCCEEDED | MOVE_END_TURN);
} /*else if (mapPersonAt(c->location->map, new_coords) != NULL) {
talkAtCoord(newx, newy, 1, NULL);
@@ -1782,46 +1593,6 @@ void GameController::avatarMovedInDungeon(MoveEvent &event) {
}
}
-void jimmy() {
- screenMessage("Jimmy: ");
- Direction dir = gameGetDirection();
-
- if (dir == DIR_NONE)
- return;
-
- 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;
- }
-
- screenMessage("%cJimmy what?%c\n", FG_GREY, FG_WHITE);
-}
-
-/**
- * Attempts to jimmy a locked door at map coordinates x,y. The locked
- * door is replaced by a permanent annotation of an unlocked door
- * tile.
- */
-bool jimmyAt(const Coords &coords) {
- MapTile *tile = g_context->_location->_map->tileAt(coords, WITH_OBJECTS);
-
- if (!tile->getTileType()->isLockedDoor())
- return false;
-
- if (g_ultima->_saveGame->_keys) {
- Tile *door = g_context->_location->_map->_tileset->getByName("door");
- ASSERT(door, "no door tile found in tileset");
- g_ultima->_saveGame->_keys--;
- g_context->_location->_map->_annotations->add(coords, door->getId());
- screenMessage("\nUnlocked!\n");
- } else
- screenMessage("%cNo keys left!%c\n", FG_GREY, FG_WHITE);
-
- return true;
-}
-
void opendoor() {
/// XXX: Pressing "o" should close any open door.
diff --git a/engines/ultima/ultima4/game/game.h b/engines/ultima/ultima4/game/game.h
index 80eb69c131..cdb9dcebe6 100644
--- a/engines/ultima/ultima4/game/game.h
+++ b/engines/ultima/ultima4/game/game.h
@@ -239,10 +239,6 @@ void castSpell(int player = -1);
void gameSpellEffect(int spell, int player, Sound sound);
/* action functions */
-void fire();
-void getChest(int player = -1);
-void holeUp();
-void jimmy();
void opendoor();
bool gamePeerCity(int city, void *data);
void peer(bool useGem = true);
diff --git a/engines/ultima/ultima4/game/spell.cpp b/engines/ultima/ultima4/game/spell.cpp
index 381adaebe2..968cd4c10d 100644
--- a/engines/ultima/ultima4/game/spell.cpp
+++ b/engines/ultima/ultima4/game/spell.cpp
@@ -21,25 +21,26 @@
*/
#include "ultima/ultima4/ultima4.h"
+#include "ultima/ultima4/core/settings.h"
+#include "ultima/ultima4/core/debugger.h"
+#include "ultima/ultima4/core/utils.h"
+#include "ultima/ultima4/events/event.h"
+#include "ultima/ultima4/game/game.h"
#include "ultima/ultima4/game/spell.h"
+#include "ultima/ultima4/game/context.h"
+#include "ultima/ultima4/game/creature.h"
+#include "ultima/ultima4/game/moongate.h"
+#include "ultima/ultima4/game/player.h"
+#include "ultima/ultima4/gfx/screen.h"
#include "ultima/ultima4/map/annotation.h"
#include "ultima/ultima4/map/combat.h"
-#include "ultima/ultima4/game/context.h"
#include "ultima/ultima4/map/direction.h"
#include "ultima/ultima4/map/dungeon.h"
-#include "ultima/ultima4/events/event.h"
-#include "ultima/ultima4/game/game.h"
#include "ultima/ultima4/map/location.h"
#include "ultima/ultima4/map/map.h"
#include "ultima/ultima4/map/mapmgr.h"
-#include "ultima/ultima4/game/creature.h"
-#include "ultima/ultima4/game/moongate.h"
-#include "ultima/ultima4/game/player.h"
-#include "ultima/ultima4/gfx/screen.h"
-#include "ultima/ultima4/core/settings.h"
#include "ultima/ultima4/map/tile.h"
#include "ultima/ultima4/map/tileset.h"
-#include "ultima/ultima4/core/utils.h"
namespace Ultima {
namespace Ultima4 {
@@ -658,7 +659,7 @@ static int spellNegate(int unused) {
}
static int spellOpen(int unused) {
- getChest(-2); // HACK: -2 will not prompt for opener
+ g_debugger->getChest();
return 1;
}
diff --git a/engines/ultima/ultima4/map/combat.cpp b/engines/ultima/ultima4/map/combat.cpp
index 49d8f4be34..f51a824f1f 100644
--- a/engines/ultima/ultima4/map/combat.cpp
+++ b/engines/ultima/ultima4/map/combat.cpp
@@ -21,29 +21,30 @@
*/
#include "ultima/ultima4/ultima4.h"
-#include "ultima/ultima4/map/combat.h"
-#include "ultima/ultima4/map/annotation.h"
+#include "ultima/ultima4/core/debugger.h"
+#include "ultima/ultima4/core/settings.h"
+#include "ultima/ultima4/core/utils.h"
+#include "ultima/ultima4/events/event.h"
#include "ultima/ultima4/game/context.h"
#include "ultima/ultima4/game/creature.h"
#include "ultima/ultima4/game/death.h"
-#include "ultima/ultima4/map/dungeon.h"
-#include "ultima/ultima4/events/event.h"
#include "ultima/ultima4/game/game.h"
#include "ultima/ultima4/game/item.h"
-#include "ultima/ultima4/map/location.h"
-#include "ultima/ultima4/map/mapmgr.h"
-#include "ultima/ultima4/map/movement.h"
#include "ultima/ultima4/game/names.h"
#include "ultima/ultima4/game/object.h"
#include "ultima/ultima4/game/player.h"
#include "ultima/ultima4/game/portal.h"
-#include "ultima/ultima4/gfx/screen.h"
-#include "ultima/ultima4/core/settings.h"
#include "ultima/ultima4/game/spell.h"
#include "ultima/ultima4/game/stats.h"
-#include "ultima/ultima4/map/tileset.h"
-#include "ultima/ultima4/core/utils.h"
#include "ultima/ultima4/game/weapon.h"
+#include "ultima/ultima4/gfx/screen.h"
+#include "ultima/ultima4/map/combat.h"
+#include "ultima/ultima4/map/annotation.h"
+#include "ultima/ultima4/map/dungeon.h"
+#include "ultima/ultima4/map/location.h"
+#include "ultima/ultima4/map/mapmgr.h"
+#include "ultima/ultima4/map/movement.h"
+#include "ultima/ultima4/map/tileset.h"
#include "ultima/shared/std/containers.h"
#include "common/system.h"
@@ -923,7 +924,7 @@ bool CombatController::keyPressed(int key) {
#endif
case 'g':
screenMessage("Get Chest!\n");
- getChest(_focus);
+ g_debugger->getChest(_focus);
break;
case 'l':
diff --git a/engines/ultima/ultima4/meta_engine.cpp b/engines/ultima/ultima4/meta_engine.cpp
index a08ad06a52..24cf884e9c 100644
--- a/engines/ultima/ultima4/meta_engine.cpp
+++ b/engines/ultima/ultima4/meta_engine.cpp
@@ -47,6 +47,12 @@ static const KeybindingRecord KEYS[] = {
{ KEYBIND_BOARD, "BOARD", "Board", "board", "b", nullptr },
{ KEYBIND_CAST, "CAST", "Cast", "cast", "c", nullptr },
{ KEYBIND_ENTER, "ENTER", "Enter", "enter", "e", nullptr },
+ { KEYBIND_FIRE, "FIRE", "Fire", "fire", "f", nullptr },
+ { KEYBIND_GET, "GET", "Get Chest", "get", "g", nullptr },
+ { KEYBIND_HOLE_UP, "HOLE-UP", "Hole Up", "hole", "h", nullptr },
+ { KEYBIND_JIMMY, "JIMMY", "Jimmy", "jimmy", "j", nullptr },
+ { KEYBIND_IGNITE, "IGNITE", "Ignite", "ignite", "i", nullptr },
+
{ KEYBIND_PASS, "PASS", "Pass", "pass", "SPACE", nullptr },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
diff --git a/engines/ultima/ultima4/meta_engine.h b/engines/ultima/ultima4/meta_engine.h
index 2875c1b398..65a015d418 100644
--- a/engines/ultima/ultima4/meta_engine.h
+++ b/engines/ultima/ultima4/meta_engine.h
@@ -31,6 +31,8 @@ namespace Ultima4 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
KEYBIND_ATTACK, KEYBIND_BOARD, KEYBIND_CAST, KEYBIND_ENTER,
+ KEYBIND_FIRE, KEYBIND_GET, KEYBIND_HOLE_UP, KEYBIND_IGNITE,
+ KEYBIND_JIMMY,
KEYBIND_PASS,
KEYBIND_NONE
More information about the Scummvm-git-logs
mailing list