mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-13 07:14:59 +00:00
ULTIMA4: Split up controllers into their own files
This commit is contained in:
parent
4e1a461b53
commit
e0607343af
@ -134,6 +134,17 @@ MODULE_OBJS := \
|
||||
ultima1/widgets/urban_widget.o \
|
||||
ultima1/widgets/wench.o \
|
||||
ultima1/game.o \
|
||||
ultima4/controllers/alpha_action_controller.o \
|
||||
ultima4/controllers/controller.o \
|
||||
ultima4/controllers/game_controller.o \
|
||||
ultima4/controllers/key_handler_controller.o \
|
||||
ultima4/controllers/read_choice_controller.o \
|
||||
ultima4/controllers/read_dir_controller.o \
|
||||
ultima4/controllers/read_int_controller.o \
|
||||
ultima4/controllers/read_player_controller.o \
|
||||
ultima4/controllers/read_string_controller.o \
|
||||
ultima4/controllers/wait_controller.o \
|
||||
ultima4/controllers/ztats_controller.o \
|
||||
ultima4/conversation/conversation.o \
|
||||
ultima4/conversation/dialogueloader.o \
|
||||
ultima4/conversation/dialogueloader_hw.o \
|
||||
@ -148,7 +159,6 @@ MODULE_OBJS := \
|
||||
ultima4/core/error.o \
|
||||
ultima4/core/settings.o \
|
||||
ultima4/core/utils.o \
|
||||
ultima4/events/controller.o \
|
||||
ultima4/events/event.o \
|
||||
ultima4/events/event_scummvm.o \
|
||||
ultima4/events/timed_event_mgr.o \
|
||||
|
@ -0,0 +1,59 @@
|
||||
/* 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/controllers/alpha_action_controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
bool AlphaActionController::keyPressed(int key) {
|
||||
if (Common::isLower(key))
|
||||
key = toupper(key);
|
||||
|
||||
if (key >= 'A' && key <= toupper(_lastValidLetter)) {
|
||||
_value = key - 'A';
|
||||
doneWaiting();
|
||||
} else if (key == U4_SPACE || key == U4_ESC || key == U4_ENTER) {
|
||||
screenMessage("\n");
|
||||
_value = -1;
|
||||
doneWaiting();
|
||||
} else {
|
||||
screenMessage("\n%s", _prompt.c_str());
|
||||
g_screen->update();
|
||||
return KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int AlphaActionController::get(char lastValidLetter, const Common::String &prompt, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
AlphaActionController ctrl(lastValidLetter, prompt);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
52
engines/ultima/ultima4/controllers/alpha_action_controller.h
Normal file
52
engines/ultima/ultima4/controllers/alpha_action_controller.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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_CONTROLLERS_ALPHA_ACTION_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_ALPHA_ACTION_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to handle input for commands requiring a letter
|
||||
* argument in the range 'a' - lastValidLetter.
|
||||
*/
|
||||
class AlphaActionController : public WaitableController<int> {
|
||||
public:
|
||||
AlphaActionController(char letter, const Common::String &p) : _lastValidLetter(letter), _prompt(p) {
|
||||
}
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
static int get(char lastValidLetter, const Common::String &prompt, EventHandler *eh = NULL);
|
||||
|
||||
private:
|
||||
char _lastValidLetter;
|
||||
Common::String _prompt;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
@ -20,7 +20,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/events/controller.h"
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
|
||||
namespace Ultima {
|
@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ULTIMA4_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLER_H
|
||||
#ifndef ULTIMA4_CONTROLLERS_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/meta_engine.h"
|
||||
|
||||
@ -113,6 +113,13 @@ private:
|
||||
bool _exitWhenDone;
|
||||
};
|
||||
|
||||
class TurnCompleter {
|
||||
public:
|
||||
virtual ~TurnCompleter() {
|
||||
}
|
||||
virtual void finishTurn() = 0;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
842
engines/ultima/ultima4/controllers/game_controller.cpp
Normal file
842
engines/ultima/ultima4/controllers/game_controller.cpp
Normal file
@ -0,0 +1,842 @@
|
||||
/* 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/controllers/game_controller.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/debugger.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/death.h"
|
||||
#include "ultima/ultima4/game/moongate.h"
|
||||
#include "ultima/ultima4/game/stats.h"
|
||||
#include "ultima/ultima4/gfx/imagemgr.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/map/annotation.h"
|
||||
#include "ultima/ultima4/map/city.h"
|
||||
#include "ultima/ultima4/map/dungeon.h"
|
||||
#include "ultima/ultima4/map/mapmgr.h"
|
||||
#include "ultima/ultima4/map/shrine.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
using namespace std;
|
||||
|
||||
GameController *g_game = NULL;
|
||||
|
||||
static const MouseArea MOUSE_AREAS[] = {
|
||||
{ 3, { { 8, 8 }, { 8, 184 }, { 96, 96 } }, MC_WEST, { U4_ENTER, 0, U4_LEFT } },
|
||||
{ 3, { { 8, 8 }, { 184, 8 }, { 96, 96 } }, MC_NORTH, { U4_ENTER, 0, U4_UP } },
|
||||
{ 3, { { 184, 8 }, { 184, 184 }, { 96, 96 } }, MC_EAST, { U4_ENTER, 0, U4_RIGHT } },
|
||||
{ 3, { { 8, 184 }, { 184, 184 }, { 96, 96 } }, MC_SOUTH, { U4_ENTER, 0, U4_DOWN } },
|
||||
{ 0, { { 0, 0 }, { 0, 0 }, { 0, 0 } }, MC_NORTH, { 0, 0, 0 } }
|
||||
};
|
||||
|
||||
GameController::GameController() : _mapArea(BORDER_WIDTH, BORDER_HEIGHT, VIEWPORT_W, VIEWPORT_H), _paused(false), _pausedTimer(0) {
|
||||
g_game = this;
|
||||
}
|
||||
|
||||
void GameController::initScreen() {
|
||||
Image *screen = imageMgr->get("screen")->_image;
|
||||
|
||||
screen->fillRect(0, 0, screen->width(), screen->height(), 0, 0, 0);
|
||||
g_screen->update();
|
||||
}
|
||||
|
||||
void GameController::initScreenWithoutReloadingState() {
|
||||
g_music->play();
|
||||
imageMgr->get(BKGD_BORDERS)->_image->draw(0, 0);
|
||||
g_context->_stats->update(); /* draw the party stats */
|
||||
|
||||
screenMessage("Press Alt-h for help\n");
|
||||
screenPrompt();
|
||||
|
||||
eventHandler->pushMouseAreaSet(MOUSE_AREAS);
|
||||
|
||||
eventHandler->setScreenUpdate(&gameUpdateScreen);
|
||||
}
|
||||
|
||||
void GameController::init() {
|
||||
initScreen();
|
||||
|
||||
// initialize the global game context, conversation and game state variables
|
||||
g_context = new Context();
|
||||
g_context->_line = TEXT_AREA_H - 1;
|
||||
g_context->col = 0;
|
||||
g_context->_stats = new StatsArea();
|
||||
g_context->_moonPhase = 0;
|
||||
g_context->_windDirection = DIR_NORTH;
|
||||
g_context->_windCounter = 0;
|
||||
g_context->_windLock = false;
|
||||
g_context->_aura = new Aura();
|
||||
g_context->_horseSpeed = 0;
|
||||
g_context->_opacity = 1;
|
||||
g_context->_lastCommandTime = g_system->getMillis();
|
||||
g_context->_lastShip = NULL;
|
||||
}
|
||||
|
||||
void GameController::setMap(Map *map, bool saveLocation, const Portal *portal, TurnCompleter *turnCompleter) {
|
||||
int viewMode;
|
||||
LocationContext context;
|
||||
int activePlayer = g_context->_party->getActivePlayer();
|
||||
MapCoords coords;
|
||||
|
||||
if (!turnCompleter)
|
||||
turnCompleter = this;
|
||||
|
||||
if (portal)
|
||||
coords = portal->_start;
|
||||
else
|
||||
coords = MapCoords(map->_width / 2, map->_height / 2);
|
||||
|
||||
/* If we don't want to save the location, then just return to the previous location,
|
||||
as there may still be ones in the stack we want to keep */
|
||||
if (!saveLocation)
|
||||
exitToParentMap();
|
||||
|
||||
switch (map->_type) {
|
||||
case Map::WORLD:
|
||||
context = CTX_WORLDMAP;
|
||||
viewMode = VIEW_NORMAL;
|
||||
break;
|
||||
case Map::DUNGEON:
|
||||
context = CTX_DUNGEON;
|
||||
viewMode = VIEW_DUNGEON;
|
||||
if (portal)
|
||||
g_ultima->_saveGame->_orientation = DIR_EAST;
|
||||
break;
|
||||
case Map::COMBAT:
|
||||
coords = MapCoords(-1, -1); /* set these to -1 just to be safe; we don't need them */
|
||||
context = CTX_COMBAT;
|
||||
viewMode = VIEW_NORMAL;
|
||||
activePlayer = -1; /* different active player for combat, defaults to 'None' */
|
||||
break;
|
||||
case Map::SHRINE:
|
||||
context = CTX_SHRINE;
|
||||
viewMode = VIEW_NORMAL;
|
||||
break;
|
||||
case Map::CITY:
|
||||
default:
|
||||
context = CTX_CITY;
|
||||
viewMode = VIEW_NORMAL;
|
||||
break;
|
||||
}
|
||||
g_context->_location = new Location(coords, map, viewMode, context, turnCompleter, g_context->_location);
|
||||
g_context->_location->addObserver(this);
|
||||
g_context->_party->setActivePlayer(activePlayer);
|
||||
#ifdef IOS
|
||||
U4IOS::updateGameControllerContext(c->location->context);
|
||||
#endif
|
||||
|
||||
/* now, actually set our new tileset */
|
||||
_mapArea.setTileset(map->_tileset);
|
||||
|
||||
if (isCity(map)) {
|
||||
City *city = dynamic_cast<City *>(map);
|
||||
city->addPeople();
|
||||
}
|
||||
}
|
||||
|
||||
int GameController::exitToParentMap() {
|
||||
if (!g_context->_location)
|
||||
return 0;
|
||||
|
||||
if (g_context->_location->_prev != NULL) {
|
||||
// Create the balloon for Hythloth
|
||||
if (g_context->_location->_map->_id == MAP_HYTHLOTH)
|
||||
createBalloon(g_context->_location->_prev->_map);
|
||||
|
||||
// free map info only if previous location was on a different map
|
||||
if (g_context->_location->_prev->_map != g_context->_location->_map) {
|
||||
g_context->_location->_map->_annotations->clear();
|
||||
g_context->_location->_map->clearObjects();
|
||||
|
||||
/* quench the torch of we're on the world map */
|
||||
if (g_context->_location->_prev->_map->isWorldMap())
|
||||
g_context->_party->quenchTorch();
|
||||
}
|
||||
locationFree(&g_context->_location);
|
||||
|
||||
// restore the tileset to the one the current map uses
|
||||
_mapArea.setTileset(g_context->_location->_map->_tileset);
|
||||
#ifdef IOS
|
||||
U4IOS::updateGameControllerContext(c->location->context);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GameController::finishTurn() {
|
||||
g_context->_lastCommandTime = g_system->getMillis();
|
||||
Creature *attacker = NULL;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* adjust food and moves */
|
||||
g_context->_party->endTurn();
|
||||
|
||||
/* count down the aura, if there is one */
|
||||
g_context->_aura->passTurn();
|
||||
|
||||
gameCheckHullIntegrity();
|
||||
|
||||
/* update party stats */
|
||||
//c->stats->setView(STATS_PARTY_OVERVIEW);
|
||||
|
||||
screenUpdate(&this->_mapArea, true, false);
|
||||
screenWait(1);
|
||||
|
||||
/* Creatures cannot spawn, move or attack while the avatar is on the balloon */
|
||||
if (!g_context->_party->isFlying()) {
|
||||
|
||||
// apply effects from tile avatar is standing on
|
||||
g_context->_party->applyEffect(g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITH_GROUND_OBJECTS)->getEffect());
|
||||
|
||||
// Move creatures and see if something is attacking the avatar
|
||||
attacker = g_context->_location->_map->moveObjects(g_context->_location->_coords);
|
||||
|
||||
// Something's attacking! Start combat!
|
||||
if (attacker) {
|
||||
gameCreatureAttack(attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
// cleanup old creatures and spawn new ones
|
||||
creatureCleanup();
|
||||
checkRandomCreatures();
|
||||
checkBridgeTrolls();
|
||||
}
|
||||
|
||||
/* update map annotations */
|
||||
g_context->_location->_map->_annotations->passTurn();
|
||||
|
||||
if (!g_context->_party->isImmobilized())
|
||||
break;
|
||||
|
||||
if (g_context->_party->isDead()) {
|
||||
deathStart(0);
|
||||
return;
|
||||
} else {
|
||||
screenMessage("Zzzzzz\n");
|
||||
screenWait(4);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_context->_location->_context == CTX_DUNGEON) {
|
||||
Dungeon *dungeon = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
if (g_context->_party->getTorchDuration() <= 0)
|
||||
screenMessage("It's Dark!\n");
|
||||
else g_context->_party->burnTorch();
|
||||
|
||||
/* handle dungeon traps */
|
||||
if (dungeon->currentToken() == DUNGEON_TRAP) {
|
||||
dungeonHandleTrap((TrapType)dungeon->currentSubToken());
|
||||
// a little kludgey to have a second test for this
|
||||
// right here. But without it you can survive an
|
||||
// extra turn after party death and do some things
|
||||
// that could cause a crash, like Hole up and Camp.
|
||||
if (g_context->_party->isDead()) {
|
||||
deathStart(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* draw a prompt */
|
||||
screenPrompt();
|
||||
//screenRedrawTextArea(TEXT_AREA_X, TEXT_AREA_Y, TEXT_AREA_W, TEXT_AREA_H);
|
||||
}
|
||||
|
||||
void GameController::flashTile(const Coords &coords, MapTile tile, int frames) {
|
||||
g_context->_location->_map->_annotations->add(coords, tile, true);
|
||||
|
||||
screenTileUpdate(&g_game->_mapArea, coords);
|
||||
|
||||
screenWait(frames);
|
||||
g_context->_location->_map->_annotations->remove(coords, tile);
|
||||
|
||||
screenTileUpdate(&g_game->_mapArea, coords, false);
|
||||
}
|
||||
|
||||
void GameController::flashTile(const Coords &coords, const Common::String &tilename, int timeFactor) {
|
||||
Tile *tile = g_context->_location->_map->_tileset->getByName(tilename);
|
||||
ASSERT(tile, "no tile named '%s' found in tileset", tilename.c_str());
|
||||
flashTile(coords, tile->getId(), timeFactor);
|
||||
}
|
||||
|
||||
void GameController::update(Party *party, PartyEvent &event) {
|
||||
int i;
|
||||
|
||||
switch (event._type) {
|
||||
case PartyEvent::LOST_EIGHTH:
|
||||
// inform a player he has lost zero or more eighths of avatarhood.
|
||||
screenMessage("\n %cThou hast lost\n an eighth!%c\n", FG_YELLOW, FG_WHITE);
|
||||
break;
|
||||
case PartyEvent::ADVANCED_LEVEL:
|
||||
screenMessage("\n%c%s\nThou art now Level %d%c\n", FG_YELLOW, event._player->getName().c_str(), event._player->getRealLevel(), FG_WHITE);
|
||||
gameSpellEffect('r', -1, SOUND_MAGIC); // Same as resurrect spell
|
||||
break;
|
||||
case PartyEvent::STARVING:
|
||||
screenMessage("\n%cStarving!!!%c\n", FG_YELLOW, FG_WHITE);
|
||||
/* FIXME: add sound effect here */
|
||||
|
||||
// 2 damage to each party member for starving!
|
||||
for (i = 0; i < g_ultima->_saveGame->_members; i++)
|
||||
g_context->_party->member(i)->applyDamage(2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::update(Location *location, MoveEvent &event) {
|
||||
switch (location->_map->_type) {
|
||||
case Map::DUNGEON:
|
||||
avatarMovedInDungeon(event);
|
||||
break;
|
||||
case Map::COMBAT:
|
||||
// FIXME: let the combat controller handle it
|
||||
dynamic_cast<CombatController *>(eventHandler->getController())->movePartyMember(event);
|
||||
break;
|
||||
default:
|
||||
avatarMoved(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::keybinder(KeybindingAction action) {
|
||||
MetaEngine::executeAction(action);
|
||||
}
|
||||
|
||||
bool GameController::keyPressed(int key) {
|
||||
bool valid = true;
|
||||
int endTurn = 1;
|
||||
Object *obj;
|
||||
MapTile *tile;
|
||||
|
||||
/* Translate context-sensitive action key into a useful command */
|
||||
if (key == U4_ENTER && settings._enhancements && settings._enhancementsOptions._smartEnterKey) {
|
||||
/* Attempt to guess based on the character's surroundings etc, what
|
||||
action they want */
|
||||
|
||||
/* Do they want to board something? */
|
||||
if (g_context->_transportContext == TRANSPORT_FOOT) {
|
||||
obj = g_context->_location->_map->objectAt(g_context->_location->_coords);
|
||||
if (obj && (obj->getTile().getTileType()->isShip() ||
|
||||
obj->getTile().getTileType()->isHorse() ||
|
||||
obj->getTile().getTileType()->isBalloon()))
|
||||
key = 'b';
|
||||
}
|
||||
/* Klimb/Descend Balloon */
|
||||
else if (g_context->_transportContext == TRANSPORT_BALLOON) {
|
||||
if (g_context->_party->isFlying())
|
||||
key = 'd';
|
||||
else {
|
||||
#ifdef IOS
|
||||
U4IOS::IOSSuperButtonHelper superHelper;
|
||||
key = ReadChoiceController::get("xk \033\n");
|
||||
#else
|
||||
key = 'k';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* X-it transport */
|
||||
else key = 'x';
|
||||
|
||||
/* Klimb? */
|
||||
if ((g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_KLIMB) != NULL))
|
||||
key = 'k';
|
||||
/* Descend? */
|
||||
else if ((g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_DESCEND) != NULL))
|
||||
key = 'd';
|
||||
|
||||
if (g_context->_location->_context == CTX_DUNGEON) {
|
||||
Dungeon *dungeon = static_cast<Dungeon *>(g_context->_location->_map);
|
||||
bool up = dungeon->ladderUpAt(g_context->_location->_coords);
|
||||
bool down = dungeon->ladderDownAt(g_context->_location->_coords);
|
||||
if (up && down) {
|
||||
#ifdef IOS
|
||||
U4IOS::IOSClimbHelper climbHelper;
|
||||
key = ReadChoiceController::get("kd \033\n");
|
||||
#else
|
||||
key = 'k'; // This is consistent with the previous code. Ideally, I would have a UI here as well.
|
||||
#endif
|
||||
} else if (up) {
|
||||
key = 'k';
|
||||
} else {
|
||||
key = 'd';
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter? */
|
||||
if (g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_ENTER) != NULL)
|
||||
key = 'e';
|
||||
|
||||
/* Get Chest? */
|
||||
if (!g_context->_party->isFlying()) {
|
||||
tile = g_context->_location->_map->tileAt(g_context->_location->_coords, WITH_GROUND_OBJECTS);
|
||||
|
||||
if (tile->getTileType()->isChest()) key = 'g';
|
||||
}
|
||||
|
||||
/* None of these? Default to search */
|
||||
if (key == U4_ENTER) key = 's';
|
||||
}
|
||||
|
||||
if ((g_context->_location->_context & CTX_DUNGEON) && strchr("abefjlotxy", key))
|
||||
screenMessage("%cNot here!%c\n", FG_GREY, FG_WHITE);
|
||||
|
||||
if (valid && endTurn) {
|
||||
if (eventHandler->getController() == g_game)
|
||||
g_context->_location->_turnCompleter->finishTurn();
|
||||
} else if (!endTurn) {
|
||||
/* if our turn did not end, then manually redraw the text prompt */
|
||||
screenPrompt();
|
||||
}
|
||||
|
||||
return valid || KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
|
||||
void GameController::initMoons() {
|
||||
int trammelphase = g_ultima->_saveGame->_trammelPhase,
|
||||
feluccaphase = g_ultima->_saveGame->_feluccaPhase;
|
||||
|
||||
ASSERT(g_context != NULL, "Game context doesn't exist!");
|
||||
ASSERT(g_ultima->_saveGame != NULL, "Savegame doesn't exist!");
|
||||
//ASSERT(mapIsWorldMap(c->location->map) && c->location->viewMode == VIEW_NORMAL, "Can only call gameInitMoons() from the world map!");
|
||||
|
||||
g_ultima->_saveGame->_trammelPhase = g_ultima->_saveGame->_feluccaPhase = 0;
|
||||
g_context->_moonPhase = 0;
|
||||
|
||||
while ((g_ultima->_saveGame->_trammelPhase != trammelphase) ||
|
||||
(g_ultima->_saveGame->_feluccaPhase != feluccaphase))
|
||||
updateMoons(false);
|
||||
}
|
||||
|
||||
void GameController::updateMoons(bool showmoongates) {
|
||||
int realMoonPhase,
|
||||
oldTrammel,
|
||||
trammelSubphase;
|
||||
const Coords *gate;
|
||||
|
||||
if (g_context->_location->_map->isWorldMap()) {
|
||||
oldTrammel = g_ultima->_saveGame->_trammelPhase;
|
||||
|
||||
if (++g_context->_moonPhase >= MOON_PHASES * MOON_SECONDS_PER_PHASE * 4)
|
||||
g_context->_moonPhase = 0;
|
||||
|
||||
trammelSubphase = g_context->_moonPhase % (MOON_SECONDS_PER_PHASE * 4 * 3);
|
||||
realMoonPhase = (g_context->_moonPhase / (4 * MOON_SECONDS_PER_PHASE));
|
||||
|
||||
g_ultima->_saveGame->_trammelPhase = realMoonPhase / 3;
|
||||
g_ultima->_saveGame->_feluccaPhase = realMoonPhase % 8;
|
||||
|
||||
if (g_ultima->_saveGame->_trammelPhase > 7)
|
||||
g_ultima->_saveGame->_trammelPhase = 7;
|
||||
|
||||
if (showmoongates) {
|
||||
/* update the moongates if trammel changed */
|
||||
if (trammelSubphase == 0) {
|
||||
gate = moongateGetGateCoordsForPhase(oldTrammel);
|
||||
if (gate)
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate)
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
} else if (trammelSubphase == 1) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
}
|
||||
} else if (trammelSubphase == 2) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
}
|
||||
} else if (trammelSubphase == 3) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
}
|
||||
} else if ((trammelSubphase > 3) && (trammelSubphase < (MOON_SECONDS_PER_PHASE * 4 * 3) - 3)) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
}
|
||||
} else if (trammelSubphase == (MOON_SECONDS_PER_PHASE * 4 * 3) - 3) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
}
|
||||
} else if (trammelSubphase == (MOON_SECONDS_PER_PHASE * 4 * 3) - 2) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
}
|
||||
} else if (trammelSubphase == (MOON_SECONDS_PER_PHASE * 4 * 3) - 1) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::avatarMoved(MoveEvent &event) {
|
||||
if (event._userEvent) {
|
||||
|
||||
// is filterMoveMessages even used? it doesn't look like the option is hooked up in the configuration menu
|
||||
if (!settings._filterMoveMessages) {
|
||||
switch (g_context->_transportContext) {
|
||||
case TRANSPORT_FOOT:
|
||||
case TRANSPORT_HORSE:
|
||||
screenMessage("%s\n", getDirectionName(event._dir));
|
||||
break;
|
||||
case TRANSPORT_SHIP:
|
||||
if (event._result & MOVE_TURNED)
|
||||
screenMessage("Turn %s!\n", getDirectionName(event._dir));
|
||||
else if (event._result & MOVE_SLOWED)
|
||||
screenMessage("%cSlow progress!%c\n", FG_GREY, FG_WHITE);
|
||||
else
|
||||
screenMessage("Sail %s!\n", getDirectionName(event._dir));
|
||||
break;
|
||||
case TRANSPORT_BALLOON:
|
||||
screenMessage("%cDrift Only!%c\n", FG_GREY, FG_WHITE);
|
||||
break;
|
||||
default:
|
||||
error("bad transportContext %d in avatarMoved()", g_context->_transportContext);
|
||||
}
|
||||
}
|
||||
|
||||
/* movement was blocked */
|
||||
if (event._result & MOVE_BLOCKED) {
|
||||
|
||||
/* if shortcuts are enabled, try them! */
|
||||
if (settings._shortcutCommands) {
|
||||
MapCoords new_coords = g_context->_location->_coords;
|
||||
MapTile *tile;
|
||||
|
||||
new_coords.move(event._dir, g_context->_location->_map);
|
||||
tile = g_context->_location->_map->tileAt(new_coords, WITH_OBJECTS);
|
||||
|
||||
if (tile->getTileType()->isDoor()) {
|
||||
g_debugger->openAt(new_coords);
|
||||
event._result = (MoveResult)(MOVE_SUCCEEDED | MOVE_END_TURN);
|
||||
} else if (tile->getTileType()->isLockedDoor()) {
|
||||
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);
|
||||
event.result = MOVE_SUCCEEDED | MOVE_END_TURN;
|
||||
}*/
|
||||
}
|
||||
|
||||
/* if we're still blocked */
|
||||
if ((event._result & MOVE_BLOCKED) && !settings._filterMoveMessages) {
|
||||
soundPlay(SOUND_BLOCKED, false);
|
||||
screenMessage("%cBlocked!%c\n", FG_GREY, FG_WHITE);
|
||||
}
|
||||
} else if (g_context->_transportContext == TRANSPORT_FOOT || g_context->_transportContext == TRANSPORT_HORSE) {
|
||||
/* movement was slowed */
|
||||
if (event._result & MOVE_SLOWED) {
|
||||
soundPlay(SOUND_WALK_SLOWED);
|
||||
screenMessage("%cSlow progress!%c\n", FG_GREY, FG_WHITE);
|
||||
} else {
|
||||
soundPlay(SOUND_WALK_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* exited map */
|
||||
if (event._result & MOVE_EXIT_TO_PARENT) {
|
||||
screenMessage("%cLeaving...%c\n", FG_GREY, FG_WHITE);
|
||||
exitToParentMap();
|
||||
g_music->play();
|
||||
}
|
||||
|
||||
/* things that happen while not on board the balloon */
|
||||
if (g_context->_transportContext & ~TRANSPORT_BALLOON)
|
||||
checkSpecialCreatures(event._dir);
|
||||
/* things that happen while on foot or horseback */
|
||||
if ((g_context->_transportContext & TRANSPORT_FOOT_OR_HORSE) &&
|
||||
!(event._result & (MOVE_SLOWED | MOVE_BLOCKED))) {
|
||||
if (checkMoongates())
|
||||
event._result = (MoveResult)(MOVE_MAP_CHANGE | MOVE_END_TURN);
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::avatarMovedInDungeon(MoveEvent &event) {
|
||||
Dungeon *dungeon = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
Direction realDir = dirNormalize((Direction)g_ultima->_saveGame->_orientation, event._dir);
|
||||
|
||||
if (!settings._filterMoveMessages) {
|
||||
if (event._userEvent) {
|
||||
if (event._result & MOVE_TURNED) {
|
||||
if (dirRotateCCW((Direction)g_ultima->_saveGame->_orientation) == realDir)
|
||||
screenMessage("Turn Left\n");
|
||||
else screenMessage("Turn Right\n");
|
||||
}
|
||||
/* show 'Advance' or 'Retreat' in dungeons */
|
||||
else screenMessage("%s\n", realDir == g_ultima->_saveGame->_orientation ? "Advance" : "Retreat");
|
||||
}
|
||||
|
||||
if (event._result & MOVE_BLOCKED)
|
||||
screenMessage("%cBlocked!%c\n", FG_GREY, FG_WHITE);
|
||||
}
|
||||
|
||||
/* if we're exiting the map, do this */
|
||||
if (event._result & MOVE_EXIT_TO_PARENT) {
|
||||
screenMessage("%cLeaving...%c\n", FG_GREY, FG_WHITE);
|
||||
exitToParentMap();
|
||||
g_music->play();
|
||||
}
|
||||
|
||||
/* check to see if we're entering a dungeon room */
|
||||
if (event._result & MOVE_SUCCEEDED) {
|
||||
if (dungeon->currentToken() == DUNGEON_ROOM) {
|
||||
int room = (int)dungeon->currentSubToken(); /* get room number */
|
||||
|
||||
/**
|
||||
* recalculate room for the abyss -- there are 16 rooms for every 2 levels,
|
||||
* each room marked with 0xD* where (* == room number 0-15).
|
||||
* for levels 1 and 2, there are 16 rooms, levels 3 and 4 there are 16 rooms, etc.
|
||||
*/
|
||||
if (g_context->_location->_map->_id == MAP_ABYSS)
|
||||
room = (0x10 * (g_context->_location->_coords.z / 2)) + room;
|
||||
|
||||
Dungeon *dng = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
dng->_currentRoom = room;
|
||||
|
||||
/* set the map and start combat! */
|
||||
CombatController *cc = new CombatController(dng->_roomMaps[room]);
|
||||
cc->initDungeonRoom(room, dirReverse(realDir));
|
||||
cc->begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::timerFired() {
|
||||
if (_pausedTimer > 0) {
|
||||
_pausedTimer--;
|
||||
if (_pausedTimer <= 0) {
|
||||
_pausedTimer = 0;
|
||||
_paused = false; /* unpause the game */
|
||||
}
|
||||
}
|
||||
|
||||
if (!_paused && !_pausedTimer) {
|
||||
if (++g_context->_windCounter >= MOON_SECONDS_PER_PHASE * 4) {
|
||||
if (xu4_random(4) == 1 && !g_context->_windLock)
|
||||
g_context->_windDirection = dirRandomDir(MASK_DIR_ALL);
|
||||
g_context->_windCounter = 0;
|
||||
}
|
||||
|
||||
/* balloon moves about 4 times per second */
|
||||
if ((g_context->_transportContext == TRANSPORT_BALLOON) &&
|
||||
g_context->_party->isFlying()) {
|
||||
g_context->_location->move(dirReverse((Direction) g_context->_windDirection), false);
|
||||
}
|
||||
|
||||
updateMoons(true);
|
||||
|
||||
screenCycle();
|
||||
|
||||
/*
|
||||
* force pass if no commands within last 20 seconds
|
||||
*/
|
||||
Controller *controller = eventHandler->getController();
|
||||
if (controller != NULL && (eventHandler->getController() == g_game ||
|
||||
dynamic_cast<CombatController *>(eventHandler->getController()) != NULL) &&
|
||||
gameTimeSinceLastCommand() > 20) {
|
||||
|
||||
/* pass the turn, and redraw the text area so the prompt is shown */
|
||||
MetaEngine::executeAction(KEYBIND_PASS);
|
||||
screenRedrawTextArea(TEXT_AREA_X, TEXT_AREA_Y, TEXT_AREA_W, TEXT_AREA_H);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GameController::checkSpecialCreatures(Direction dir) {
|
||||
int i;
|
||||
Object *obj;
|
||||
static const struct {
|
||||
int x, y;
|
||||
Direction dir;
|
||||
} pirateInfo[] = {
|
||||
{ 224, 220, DIR_EAST }, /* N'M" O'A" */
|
||||
{ 224, 228, DIR_EAST }, /* O'E" O'A" */
|
||||
{ 226, 220, DIR_EAST }, /* O'E" O'C" */
|
||||
{ 227, 228, DIR_EAST }, /* O'E" O'D" */
|
||||
{ 228, 227, DIR_SOUTH }, /* O'D" O'E" */
|
||||
{ 229, 225, DIR_SOUTH }, /* O'B" O'F" */
|
||||
{ 229, 223, DIR_NORTH }, /* N'P" O'F" */
|
||||
{ 228, 222, DIR_NORTH } /* N'O" O'E" */
|
||||
};
|
||||
|
||||
/*
|
||||
* if heading east into pirates cove (O'A" N'N"), generate pirate
|
||||
* ships
|
||||
*/
|
||||
if (dir == DIR_EAST &&
|
||||
g_context->_location->_coords.x == 0xdd &&
|
||||
g_context->_location->_coords.y == 0xe0) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
obj = g_context->_location->_map->addCreature(creatureMgr->getById(PIRATE_ID), MapCoords(pirateInfo[i].x, pirateInfo[i].y));
|
||||
obj->setDirection(pirateInfo[i].dir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if heading south towards the shrine of humility, generate
|
||||
* daemons unless horn has been blown
|
||||
*/
|
||||
if (dir == DIR_SOUTH &&
|
||||
g_context->_location->_coords.x >= 229 &&
|
||||
g_context->_location->_coords.x < 234 &&
|
||||
g_context->_location->_coords.y >= 212 &&
|
||||
g_context->_location->_coords.y < 217 &&
|
||||
*g_context->_aura != Aura::HORN) {
|
||||
for (i = 0; i < 8; i++)
|
||||
g_context->_location->_map->addCreature(creatureMgr->getById(DAEMON_ID), MapCoords(231, g_context->_location->_coords.y + 1, g_context->_location->_coords.z));
|
||||
}
|
||||
}
|
||||
|
||||
bool GameController::checkMoongates() {
|
||||
Coords dest;
|
||||
|
||||
if (moongateFindActiveGateAt(g_ultima->_saveGame->_trammelPhase, g_ultima->_saveGame->_feluccaPhase, g_context->_location->_coords, dest)) {
|
||||
|
||||
gameSpellEffect(-1, -1, SOUND_MOONGATE); // Default spell effect (screen inversion without 'spell' sound effects)
|
||||
|
||||
if (g_context->_location->_coords != dest) {
|
||||
g_context->_location->_coords = dest;
|
||||
gameSpellEffect(-1, -1, SOUND_MOONGATE); // Again, after arriving
|
||||
}
|
||||
|
||||
if (moongateIsEntryToShrineOfSpirituality(g_ultima->_saveGame->_trammelPhase, g_ultima->_saveGame->_feluccaPhase)) {
|
||||
Shrine *shrine_spirituality;
|
||||
|
||||
shrine_spirituality = dynamic_cast<Shrine *>(mapMgr->get(MAP_SHRINE_SPIRITUALITY));
|
||||
|
||||
if (!g_context->_party->canEnterShrine(VIRT_SPIRITUALITY))
|
||||
return true;
|
||||
|
||||
setMap(shrine_spirituality, 1, NULL);
|
||||
g_music->play();
|
||||
|
||||
shrine_spirituality->enter();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameController::creatureCleanup() {
|
||||
ObjectDeque::iterator i;
|
||||
Map *map = g_context->_location->_map;
|
||||
|
||||
for (i = map->_objects.begin(); i != map->_objects.end();) {
|
||||
Object *obj = *i;
|
||||
MapCoords o_coords = obj->getCoords();
|
||||
|
||||
if ((obj->getType() == Object::CREATURE) && (o_coords.z == g_context->_location->_coords.z) &&
|
||||
o_coords.distance(g_context->_location->_coords, g_context->_location->_map) > MAX_CREATURE_DISTANCE) {
|
||||
|
||||
/* delete the object and remove it from the map */
|
||||
i = map->removeObject(i);
|
||||
} else i++;
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::checkRandomCreatures() {
|
||||
int canSpawnHere = g_context->_location->_map->isWorldMap() || g_context->_location->_context & CTX_DUNGEON;
|
||||
#ifdef IOS
|
||||
int spawnDivisor = c->location->context & CTX_DUNGEON ? (53 - (c->location->coords.z << 2)) : 53;
|
||||
#else
|
||||
int spawnDivisor = g_context->_location->_context & CTX_DUNGEON ? (32 - (g_context->_location->_coords.z << 2)) : 32;
|
||||
#endif
|
||||
|
||||
/* If there are too many creatures already,
|
||||
or we're not on the world map, don't worry about it! */
|
||||
if (!canSpawnHere ||
|
||||
g_context->_location->_map->getNumberOfCreatures() >= MAX_CREATURES_ON_MAP ||
|
||||
xu4_random(spawnDivisor) != 0)
|
||||
return;
|
||||
|
||||
gameSpawnCreature(NULL);
|
||||
}
|
||||
|
||||
void GameController::checkBridgeTrolls() {
|
||||
const Tile *bridge = g_context->_location->_map->_tileset->getByName("bridge");
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
// TODO: CHEST: Make a user option to not make chests block bridge trolls
|
||||
if (!g_context->_location->_map->isWorldMap() ||
|
||||
g_context->_location->_map->tileAt(g_context->_location->_coords, WITH_OBJECTS)->_id != bridge->getId() ||
|
||||
xu4_random(8) != 0)
|
||||
return;
|
||||
|
||||
screenMessage("\nBridge Trolls!\n");
|
||||
|
||||
Creature *m = g_context->_location->_map->addCreature(creatureMgr->getById(TROLL_ID), g_context->_location->_coords);
|
||||
CombatController *cc = new CombatController(MAP_BRIDGE_CON);
|
||||
cc->init(m);
|
||||
cc->begin();
|
||||
}
|
||||
|
||||
bool GameController::createBalloon(Map *map) {
|
||||
ObjectDeque::iterator i;
|
||||
|
||||
/* see if the balloon has already been created (and not destroyed) */
|
||||
for (i = map->_objects.begin(); i != map->_objects.end(); i++) {
|
||||
Object *obj = *i;
|
||||
if (obj->getTile().getTileType()->isBalloon())
|
||||
return false;
|
||||
}
|
||||
|
||||
const Tile *balloon = map->_tileset->getByName("balloon");
|
||||
ASSERT(balloon, "no balloon tile found in tileset");
|
||||
map->addObject(balloon->getId(), balloon->getId(), map->getLabel("balloon"));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
174
engines/ultima/ultima4/controllers/game_controller.h
Normal file
174
engines/ultima/ultima4/controllers/game_controller.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 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_CONTROLLERS_GAME_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_GAME_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/core/coords.h"
|
||||
#include "ultima/ultima4/core/observer.h"
|
||||
#include "ultima/ultima4/game/portal.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/map/tileview.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* The main game controller that handles basic game flow and keypresses.
|
||||
*
|
||||
* @todo
|
||||
* <ul>
|
||||
* <li>separate the dungeon specific stuff into another class (subclass?)</li>
|
||||
* </ul>
|
||||
*/
|
||||
class GameController : public Controller, public Observer<Party *, PartyEvent &>, public Observer<Location *, MoveEvent &>,
|
||||
public TurnCompleter {
|
||||
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.
|
||||
*/
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
/**
|
||||
* This function is called every quarter second.
|
||||
*/
|
||||
void timerFired() override;
|
||||
|
||||
/* main game functions */
|
||||
void init();
|
||||
void initScreen();
|
||||
void initScreenWithoutReloadingState();
|
||||
void setMap(Map *map, bool saveLocation, const Portal *portal, TurnCompleter *turnCompleter = NULL);
|
||||
|
||||
/**
|
||||
* Exits the current map and location and returns to its parent location
|
||||
* This restores all relevant information from the previous location,
|
||||
* such as the map, map position, etc. (such as exiting a city)
|
||||
**/
|
||||
int exitToParentMap();
|
||||
|
||||
/**
|
||||
* Terminates a game turn. This performs the post-turn housekeeping
|
||||
* tasks like adjusting the party's food, incrementing the number of
|
||||
* moves, etc.
|
||||
*/
|
||||
void finishTurn() override;
|
||||
|
||||
/**
|
||||
* Provide feedback to user after a party event happens.
|
||||
*/
|
||||
void update(Party *party, PartyEvent &event) override;
|
||||
|
||||
/**
|
||||
* Provide feedback to user after a movement event happens.
|
||||
*/
|
||||
void update(Location *location, MoveEvent &event) override;
|
||||
|
||||
/**
|
||||
* Initializes the moon state according to the savegame file. This method of
|
||||
* initializing the moons (rather than just setting them directly) is necessary
|
||||
* to make sure trammel and felucca stay in sync
|
||||
*/
|
||||
void initMoons();
|
||||
|
||||
/**
|
||||
* Updates the phases of the moons and shows
|
||||
* the visual moongates on the map, if desired
|
||||
*/
|
||||
void updateMoons(bool showmoongates);
|
||||
|
||||
/**
|
||||
* Show an attack flash at x, y on the current map.
|
||||
* This is used for 'being hit' or 'being missed'
|
||||
* by weapons, cannon fire, spells, etc.
|
||||
*/
|
||||
static void flashTile(const Coords &coords, MapTile tile, int timeFactor);
|
||||
|
||||
static void flashTile(const Coords &coords, const Common::String &tilename, int timeFactor);
|
||||
static void doScreenAnimationsWhilePausing(int timeFactor);
|
||||
|
||||
TileView _mapArea;
|
||||
bool _paused;
|
||||
int _pausedTimer;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handles feedback after avatar moved during normal 3rd-person view.
|
||||
*/
|
||||
void avatarMoved(MoveEvent &event);
|
||||
|
||||
/**
|
||||
* Handles feedback after moving the avatar in the 3-d dungeon view.
|
||||
*/
|
||||
void avatarMovedInDungeon(MoveEvent &event);
|
||||
|
||||
/**
|
||||
* Removes creatures from the current map if they are too far away from the avatar
|
||||
*/
|
||||
void creatureCleanup();
|
||||
|
||||
/**
|
||||
* Handles trolls under bridges
|
||||
*/
|
||||
void checkBridgeTrolls();
|
||||
|
||||
/**
|
||||
* Checks creature conditions and spawns new creatures if necessary
|
||||
*/
|
||||
void checkRandomCreatures();
|
||||
|
||||
/**
|
||||
* Checks for valid conditions and handles
|
||||
* special creatures guarding the entrance to the
|
||||
* abyss and to the shrine of spirituality
|
||||
*/
|
||||
void checkSpecialCreatures(Direction dir);
|
||||
|
||||
/**
|
||||
* Checks for and handles when the avatar steps on a moongate
|
||||
*/
|
||||
bool checkMoongates();
|
||||
|
||||
/**
|
||||
* Creates the balloon near Hythloth, but only if the balloon doesn't already exists somewhere
|
||||
*/
|
||||
bool createBalloon(Map *map);
|
||||
};
|
||||
|
||||
extern GameController *g_game;
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
140
engines/ultima/ultima4/controllers/key_handler_controller.cpp
Normal file
140
engines/ultima/ultima4/controllers/key_handler_controller.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/* 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/controllers/key_handler_controller.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
|
||||
KeyHandler::KeyHandler(Callback func, void *d, bool asyncronous) :
|
||||
_handler(func),
|
||||
_async(asyncronous),
|
||||
_data(d) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key-repeat characteristics of the keyboard.
|
||||
*/
|
||||
int KeyHandler::setKeyRepeat(int delay, int interval) {
|
||||
#ifdef TODO
|
||||
return SDL_EnableKeyRepeat(delay, interval);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool KeyHandler::globalHandler(int key) {
|
||||
switch (key) {
|
||||
#if defined(MACOSX)
|
||||
case U4_META + 'q': /* Cmd+q */
|
||||
case U4_META + 'x': /* Cmd+x */
|
||||
#endif
|
||||
case U4_ALT + 'x': /* Alt+x */
|
||||
#if defined(WIN32)
|
||||
case U4_ALT + U4_FKEY + 3:
|
||||
#endif
|
||||
g_ultima->quitGame();
|
||||
EventHandler::end();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyHandler::defaultHandler(int key, void *data) {
|
||||
bool valid = true;
|
||||
|
||||
switch (key) {
|
||||
case '`':
|
||||
if (g_context && g_context->_location)
|
||||
debug(1, "x = %d, y = %d, level = %d, tile = %d (%s)\n", g_context->_location->_coords.x, g_context->_location->_coords.y, g_context->_location->_coords.z, g_context->_location->_map->translateToRawTileIndex(*g_context->_location->_map->tileAt(g_context->_location->_coords, WITH_OBJECTS)), g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITH_OBJECTS)->getName().c_str());
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool KeyHandler::ignoreKeys(int key, void *data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyHandler::handle(int key) {
|
||||
bool processed = false;
|
||||
if (!isKeyIgnored(key)) {
|
||||
processed = globalHandler(key);
|
||||
if (!processed)
|
||||
processed = _handler(key, _data);
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
bool KeyHandler::isKeyIgnored(int key) {
|
||||
switch (key) {
|
||||
case U4_RIGHT_SHIFT:
|
||||
case U4_LEFT_SHIFT:
|
||||
case U4_RIGHT_CTRL:
|
||||
case U4_LEFT_CTRL:
|
||||
case U4_RIGHT_ALT:
|
||||
case U4_LEFT_ALT:
|
||||
case U4_RIGHT_META:
|
||||
case U4_LEFT_META:
|
||||
case U4_TAB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyHandler::operator==(Callback cb) const {
|
||||
return (_handler == cb) ? true : false;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
KeyHandlerController::KeyHandlerController(KeyHandler *handler) {
|
||||
this->_handler = handler;
|
||||
}
|
||||
|
||||
KeyHandlerController::~KeyHandlerController() {
|
||||
delete _handler;
|
||||
}
|
||||
|
||||
bool KeyHandlerController::keyPressed(int key) {
|
||||
ASSERT(_handler != NULL, "key handler must be initialized");
|
||||
return _handler->handle(key);
|
||||
}
|
||||
|
||||
KeyHandler *KeyHandlerController::getKeyHandler() {
|
||||
return _handler;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
123
engines/ultima/ultima4/controllers/key_handler_controller.h
Normal file
123
engines/ultima/ultima4/controllers/key_handler_controller.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* 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_CONTROLLERS_KEY_HANDLER_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_KEY_HANDLER_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A class for handling keystrokes.
|
||||
*/
|
||||
class KeyHandler {
|
||||
public:
|
||||
virtual ~KeyHandler() {}
|
||||
|
||||
/* Typedefs */
|
||||
typedef bool (*Callback)(int, void *);
|
||||
|
||||
/** Additional information to be passed as data param for read buffer key handler */
|
||||
typedef struct ReadBuffer {
|
||||
int (*_handleBuffer)(Common::String *);
|
||||
Common::String *_buffer;
|
||||
int _bufferLen;
|
||||
int _screenX, _screenY;
|
||||
} ReadBuffer;
|
||||
|
||||
/** Additional information to be passed as data param for get choice key handler */
|
||||
typedef struct GetChoice {
|
||||
Common::String _choices;
|
||||
int (*_handleChoice)(int);
|
||||
} GetChoice;
|
||||
|
||||
/* Constructors */
|
||||
KeyHandler(Callback func, void *data = NULL, bool asyncronous = true);
|
||||
|
||||
/* Static functions */
|
||||
static int setKeyRepeat(int delay, int interval);
|
||||
|
||||
/**
|
||||
* Handles any and all keystrokes.
|
||||
* Generally used to exit the application, switch applications,
|
||||
* minimize, maximize, etc.
|
||||
*/
|
||||
static bool globalHandler(int key);
|
||||
|
||||
/* Static default key handler functions */
|
||||
/**
|
||||
* A default key handler that should be valid everywhere
|
||||
*/
|
||||
static bool defaultHandler(int key, void *data);
|
||||
|
||||
/**
|
||||
* A key handler that ignores keypresses
|
||||
*/
|
||||
static bool ignoreKeys(int key, void *data);
|
||||
|
||||
/* Operators */
|
||||
bool operator==(Callback cb) const;
|
||||
|
||||
/* Member functions */
|
||||
/**
|
||||
* Handles a keypress.
|
||||
* First it makes sure the key combination is not ignored
|
||||
* by the current key handler. Then, it passes the keypress
|
||||
* through the global key handler. If the global handler
|
||||
* does not process the keystroke, then the key handler
|
||||
* handles it itself by calling its handler callback function.
|
||||
*/
|
||||
bool handle(int key);
|
||||
|
||||
/**
|
||||
* Returns true if the key or key combination is always ignored by xu4
|
||||
*/
|
||||
virtual bool isKeyIgnored(int key);
|
||||
|
||||
protected:
|
||||
Callback _handler;
|
||||
bool _async;
|
||||
void *_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller that wraps a keyhander function. Keyhandlers are
|
||||
* deprecated -- please use a controller instead.
|
||||
*/
|
||||
class KeyHandlerController : public Controller {
|
||||
public:
|
||||
KeyHandlerController(KeyHandler *handler);
|
||||
~KeyHandlerController();
|
||||
|
||||
bool keyPressed(int key) override;
|
||||
KeyHandler *getKeyHandler();
|
||||
|
||||
private:
|
||||
KeyHandler *_handler;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
@ -0,0 +1,62 @@
|
||||
/* 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/controllers/read_choice_controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
|
||||
ReadChoiceController::ReadChoiceController(const Common::String &choices) {
|
||||
_choices = choices;
|
||||
}
|
||||
|
||||
bool ReadChoiceController::keyPressed(int key) {
|
||||
// Common::isUpper() accepts 1-byte characters, yet the modifier keys
|
||||
// (ALT, SHIFT, ETC) produce values beyond 255
|
||||
if ((key <= 0x7F) && (Common::isUpper(key)))
|
||||
key = tolower(key);
|
||||
|
||||
_value = key;
|
||||
|
||||
if (_choices.empty() || _choices.findFirstOf(_value) < _choices.size()) {
|
||||
// If the value is printable, display it
|
||||
if (!Common::isSpace(key))
|
||||
screenMessage("%c", toupper(key));
|
||||
doneWaiting();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char ReadChoiceController::get(const Common::String &choices, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadChoiceController ctrl(choices);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
49
engines/ultima/ultima4/controllers/read_choice_controller.h
Normal file
49
engines/ultima/ultima4/controllers/read_choice_controller.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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_CONTROLLERS_READ_CHOICE_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_READ_CHOICE_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to read a single key from a provided list.
|
||||
*/
|
||||
class ReadChoiceController : public WaitableController<int> {
|
||||
public:
|
||||
ReadChoiceController(const Common::String &choices);
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
static char get(const Common::String &choices, EventHandler *eh = NULL);
|
||||
|
||||
protected:
|
||||
Common::String _choices;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
76
engines/ultima/ultima4/controllers/read_dir_controller.cpp
Normal file
76
engines/ultima/ultima4/controllers/read_dir_controller.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/* 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/controllers/read_dir_controller.h"
|
||||
#include "ultima/ultima4/map/direction.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
|
||||
ReadDirController::ReadDirController() {
|
||||
_value = 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:
|
||||
case Common::KEYCODE_RETURN:
|
||||
_value = DIR_NONE;
|
||||
doneWaiting();
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
53
engines/ultima/ultima4/controllers/read_dir_controller.h
Normal file
53
engines/ultima/ultima4/controllers/read_dir_controller.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* 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_CONTROLLERS_READ_DIR_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_READ_DIR_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/map/direction.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to read a direction enter with the arrow keys.
|
||||
*/
|
||||
class ReadDirController : public WaitableController<Direction> {
|
||||
public:
|
||||
ReadDirController();
|
||||
|
||||
/**
|
||||
* Key was pressed
|
||||
*/
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
/**
|
||||
* Handles keybinder actions
|
||||
*/
|
||||
void keybinder(KeybindingAction action) override;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
46
engines/ultima/ultima4/controllers/read_int_controller.cpp
Normal file
46
engines/ultima/ultima4/controllers/read_int_controller.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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/controllers/read_int_controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
ReadIntController::ReadIntController(int maxlen, int screenX, int screenY) :
|
||||
ReadStringController(maxlen, screenX, screenY, "0123456789 \n\r\010") {}
|
||||
|
||||
int ReadIntController::get(int maxlen, int screenX, int screenY, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadIntController ctrl(maxlen, screenX, screenY);
|
||||
eh->pushController(&ctrl);
|
||||
ctrl.waitFor();
|
||||
return ctrl.getInt();
|
||||
}
|
||||
|
||||
int ReadIntController::getInt() const {
|
||||
return static_cast<int>(strtol(_value.c_str(), NULL, 10));
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
46
engines/ultima/ultima4/controllers/read_int_controller.h
Normal file
46
engines/ultima/ultima4/controllers/read_int_controller.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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_CONTROLLERS_READ_INT_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_READ_INT_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/read_string_controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to read a integer, terminated by the enter key.
|
||||
* Non-numeric keys are ignored.
|
||||
*/
|
||||
class ReadIntController : public ReadStringController {
|
||||
public:
|
||||
ReadIntController(int maxlen, int screenX, int screenY);
|
||||
|
||||
static int get(int maxlen, int screenX, int screenY, EventHandler *eh = NULL);
|
||||
int getInt() const;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
@ -0,0 +1,64 @@
|
||||
/* 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/controllers/read_player_controller.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
ReadPlayerController::ReadPlayerController() : ReadChoiceController("12345678 \033\n") {
|
||||
#ifdef IOS
|
||||
U4IOS::beginCharacterChoiceDialog();
|
||||
#endif
|
||||
}
|
||||
|
||||
ReadPlayerController::~ReadPlayerController() {
|
||||
#ifdef IOS
|
||||
U4IOS::endCharacterChoiceDialog();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ReadPlayerController::keyPressed(int key) {
|
||||
bool valid = ReadChoiceController::keyPressed(key);
|
||||
if (valid) {
|
||||
if (_value < '1' ||
|
||||
_value > ('0' + g_ultima->_saveGame->_members))
|
||||
_value = '0';
|
||||
} else {
|
||||
_value = '0';
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
int ReadPlayerController::getPlayer() {
|
||||
return _value - '1';
|
||||
}
|
||||
|
||||
int ReadPlayerController::waitFor() {
|
||||
ReadChoiceController::waitFor();
|
||||
return getPlayer();
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
47
engines/ultima/ultima4/controllers/read_player_controller.h
Normal file
47
engines/ultima/ultima4/controllers/read_player_controller.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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_CONTROLLERS_READ_PLAYER_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_READ_PLAYER_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to read a player number.
|
||||
*/
|
||||
class ReadPlayerController : public ReadChoiceController {
|
||||
public:
|
||||
ReadPlayerController();
|
||||
~ReadPlayerController();
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
int getPlayer();
|
||||
int waitFor() override;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
109
engines/ultima/ultima4/controllers/read_string_controller.cpp
Normal file
109
engines/ultima/ultima4/controllers/read_string_controller.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/* 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/controllers/read_string_controller.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
ReadStringController::ReadStringController(int maxlen, int screenX, int screenY, const Common::String &accepted_chars) {
|
||||
_maxLen = maxlen;
|
||||
_screenX = screenX;
|
||||
_screenY = screenY;
|
||||
_view = NULL;
|
||||
_accepted = accepted_chars;
|
||||
}
|
||||
|
||||
ReadStringController::ReadStringController(int maxlen, TextView *view, const Common::String &accepted_chars) {
|
||||
_maxLen = maxlen;
|
||||
_screenX = view->getCursorX();
|
||||
_screenY = view->getCursorY();
|
||||
_view = view;
|
||||
_accepted = accepted_chars;
|
||||
}
|
||||
|
||||
bool ReadStringController::keyPressed(int key) {
|
||||
int valid = true, len = _value.size();
|
||||
size_t pos = Common::String::npos;
|
||||
|
||||
if (key < U4_ALT)
|
||||
pos = _accepted.findFirstOf(key);
|
||||
|
||||
if (pos != Common::String::npos) {
|
||||
if (key == Common::KEYCODE_BACKSPACE) {
|
||||
if (len > 0) {
|
||||
/* remove the last character */
|
||||
_value.erase(len - 1, 1);
|
||||
|
||||
if (_view) {
|
||||
_view->textAt(_screenX + len - 1, _screenY, " ");
|
||||
_view->setCursorPos(_screenX + len - 1, _screenY, true);
|
||||
} else {
|
||||
screenHideCursor();
|
||||
screenTextAt(_screenX + len - 1, _screenY, " ");
|
||||
screenSetCursorPos(_screenX + len - 1, _screenY);
|
||||
screenShowCursor();
|
||||
}
|
||||
}
|
||||
} else if (key == '\n' || key == '\r') {
|
||||
doneWaiting();
|
||||
} else if (len < _maxLen) {
|
||||
/* add a character to the end */
|
||||
_value += key;
|
||||
|
||||
if (_view) {
|
||||
_view->textAt(_screenX + len, _screenY, "%c", key);
|
||||
} else {
|
||||
screenHideCursor();
|
||||
screenTextAt(_screenX + len, _screenY, "%c", key);
|
||||
screenSetCursorPos(_screenX + len + 1, _screenY);
|
||||
g_context->col = len + 1;
|
||||
screenShowCursor();
|
||||
}
|
||||
}
|
||||
} else valid = false;
|
||||
|
||||
return valid || KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
|
||||
Common::String ReadStringController::get(int maxlen, int screenX, int screenY, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadStringController ctrl(maxlen, screenX, screenY);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
Common::String ReadStringController::get(int maxlen, TextView *view, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadStringController ctrl(maxlen, view);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
65
engines/ultima/ultima4/controllers/read_string_controller.h
Normal file
65
engines/ultima/ultima4/controllers/read_string_controller.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* 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_CONTROLLERS_READ_STRING_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_READ_STRING_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/textview.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to read a Common::String, terminated by the enter key.
|
||||
*/
|
||||
class ReadStringController : public WaitableController<Common::String> {
|
||||
public:
|
||||
/**
|
||||
* @param maxlen the maximum length of the Common::String
|
||||
* @param screenX the screen column where to begin input
|
||||
* @param screenY the screen row where to begin input
|
||||
* @param accepted_chars a Common::String characters to be accepted for input
|
||||
*/
|
||||
ReadStringController(int maxlen, int screenX, int screenY, const Common::String &accepted_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 \n\r\010");
|
||||
ReadStringController(int maxlen, TextView *view, const Common::String &accepted_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 \n\r\010");
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
static Common::String get(int maxlen, int screenX, int screenY, EventHandler *eh = NULL);
|
||||
static Common::String get(int maxlen, TextView *view, EventHandler *eh = NULL);
|
||||
#ifdef IOS
|
||||
void setValue(const Common::String &utf8StringValue) {
|
||||
value = utf8StringValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
int _maxLen, _screenX, _screenY;
|
||||
TextView *_view;
|
||||
Common::String _accepted;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
52
engines/ultima/ultima4/controllers/wait_controller.cpp
Normal file
52
engines/ultima/ultima4/controllers/wait_controller.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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/controllers/wait_controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
WaitController::WaitController(unsigned int c) : Controller(), _cycles(c), _current(0) {
|
||||
}
|
||||
|
||||
void WaitController::timerFired() {
|
||||
if (++_current >= _cycles) {
|
||||
_current = 0;
|
||||
eventHandler->setControllerDone(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool WaitController::keyPressed(int key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitController::wait() {
|
||||
Controller_startWait();
|
||||
}
|
||||
|
||||
void WaitController::setCycles(int c) {
|
||||
_cycles = c;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
52
engines/ultima/ultima4/controllers/wait_controller.h
Normal file
52
engines/ultima/ultima4/controllers/wait_controller.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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_CONTROLLERS_WAIT_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_WAIT_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* A controller to pause for a given length of time, ignoring all
|
||||
* keyboard input.
|
||||
*/
|
||||
class WaitController : public Controller {
|
||||
public:
|
||||
WaitController(unsigned int cycles);
|
||||
bool keyPressed(int key) override;
|
||||
void timerFired() override;
|
||||
|
||||
void wait();
|
||||
void setCycles(int c);
|
||||
|
||||
private:
|
||||
unsigned int _cycles;
|
||||
unsigned int _current;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
68
engines/ultima/ultima4/controllers/ztats_controller.cpp
Normal file
68
engines/ultima/ultima4/controllers/ztats_controller.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 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/controllers/ztats_controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/stats.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
bool ZtatsController::keyPressed(int key) {
|
||||
switch (key) {
|
||||
case U4_UP:
|
||||
case U4_LEFT:
|
||||
g_context->_stats->prevItem();
|
||||
return true;
|
||||
case U4_DOWN:
|
||||
case U4_RIGHT:
|
||||
g_context->_stats->nextItem();
|
||||
return true;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
if (g_ultima->_saveGame->_members >= key - '0')
|
||||
g_context->_stats->setView(StatsView(STATS_CHAR1 + key - '1'));
|
||||
return true;
|
||||
case '0':
|
||||
g_context->_stats->setView(StatsView(STATS_WEAPONS));
|
||||
return true;
|
||||
case U4_ESC:
|
||||
case U4_SPACE:
|
||||
case U4_ENTER:
|
||||
g_context->_stats->setView(StatsView(STATS_PARTY_OVERVIEW));
|
||||
doneWaiting();
|
||||
return true;
|
||||
default:
|
||||
return KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
42
engines/ultima/ultima4/controllers/ztats_controller.h
Normal file
42
engines/ultima/ultima4/controllers/ztats_controller.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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_CONTROLLERS_ZTATS_CONTROLLER_H
|
||||
#define ULTIMA4_CONTROLLERS_ZTATS_CONTROLLER_H
|
||||
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
/**
|
||||
* Controls interaction while Ztats are being displayed.
|
||||
*/
|
||||
class ZtatsController : public WaitableController<void *> {
|
||||
public:
|
||||
bool keyPressed(int key) override;
|
||||
};
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
@ -22,6 +22,10 @@
|
||||
|
||||
#include "ultima/ultima4/core/debugger.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/controllers/alpha_action_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_dir_controller.h"
|
||||
#include "ultima/ultima4/controllers/ztats_controller.h"
|
||||
#include "ultima/ultima4/game/armor.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "ultima/ultima4/core/debugger_actions.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_int_controller.h"
|
||||
#include "ultima/ultima4/conversation/conversation.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
|
@ -21,12 +21,13 @@
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/controllers/wait_controller.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/textview.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "common/events.h"
|
||||
|
||||
namespace Ultima {
|
||||
@ -128,205 +129,5 @@ const MouseArea *EventHandler::getMouseAreaSet() const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
ReadStringController::ReadStringController(int maxlen, int screenX, int screenY, const Common::String &accepted_chars) {
|
||||
_maxLen = maxlen;
|
||||
_screenX = screenX;
|
||||
_screenY = screenY;
|
||||
_view = NULL;
|
||||
_accepted = accepted_chars;
|
||||
}
|
||||
|
||||
ReadStringController::ReadStringController(int maxlen, TextView *view, const Common::String &accepted_chars) {
|
||||
_maxLen = maxlen;
|
||||
_screenX = view->getCursorX();
|
||||
_screenY = view->getCursorY();
|
||||
_view = view;
|
||||
_accepted = accepted_chars;
|
||||
}
|
||||
|
||||
bool ReadStringController::keyPressed(int key) {
|
||||
int valid = true, len = _value.size();
|
||||
size_t pos = Common::String::npos;
|
||||
|
||||
if (key < U4_ALT)
|
||||
pos = _accepted.findFirstOf(key);
|
||||
|
||||
if (pos != Common::String::npos) {
|
||||
if (key == Common::KEYCODE_BACKSPACE) {
|
||||
if (len > 0) {
|
||||
/* remove the last character */
|
||||
_value.erase(len - 1, 1);
|
||||
|
||||
if (_view) {
|
||||
_view->textAt(_screenX + len - 1, _screenY, " ");
|
||||
_view->setCursorPos(_screenX + len - 1, _screenY, true);
|
||||
} else {
|
||||
screenHideCursor();
|
||||
screenTextAt(_screenX + len - 1, _screenY, " ");
|
||||
screenSetCursorPos(_screenX + len - 1, _screenY);
|
||||
screenShowCursor();
|
||||
}
|
||||
}
|
||||
} else if (key == '\n' || key == '\r') {
|
||||
doneWaiting();
|
||||
} else if (len < _maxLen) {
|
||||
/* add a character to the end */
|
||||
_value += key;
|
||||
|
||||
if (_view) {
|
||||
_view->textAt(_screenX + len, _screenY, "%c", key);
|
||||
} else {
|
||||
screenHideCursor();
|
||||
screenTextAt(_screenX + len, _screenY, "%c", key);
|
||||
screenSetCursorPos(_screenX + len + 1, _screenY);
|
||||
g_context->col = len + 1;
|
||||
screenShowCursor();
|
||||
}
|
||||
}
|
||||
} else valid = false;
|
||||
|
||||
return valid || KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
|
||||
Common::String ReadStringController::get(int maxlen, int screenX, int screenY, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadStringController ctrl(maxlen, screenX, screenY);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
Common::String ReadStringController::get(int maxlen, TextView *view, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadStringController ctrl(maxlen, view);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
ReadIntController::ReadIntController(int maxlen, int screenX, int screenY) : ReadStringController(maxlen, screenX, screenY, "0123456789 \n\r\010") {}
|
||||
|
||||
int ReadIntController::get(int maxlen, int screenX, int screenY, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadIntController ctrl(maxlen, screenX, screenY);
|
||||
eh->pushController(&ctrl);
|
||||
ctrl.waitFor();
|
||||
return ctrl.getInt();
|
||||
}
|
||||
|
||||
int ReadIntController::getInt() const {
|
||||
return static_cast<int>(strtol(_value.c_str(), NULL, 10));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
ReadChoiceController::ReadChoiceController(const Common::String &choices) {
|
||||
_choices = choices;
|
||||
}
|
||||
|
||||
bool ReadChoiceController::keyPressed(int key) {
|
||||
// Common::isUpper() accepts 1-byte characters, yet the modifier keys
|
||||
// (ALT, SHIFT, ETC) produce values beyond 255
|
||||
if ((key <= 0x7F) && (Common::isUpper(key)))
|
||||
key = tolower(key);
|
||||
|
||||
_value = key;
|
||||
|
||||
if (_choices.empty() || _choices.findFirstOf(_value) < _choices.size()) {
|
||||
// If the value is printable, display it
|
||||
if (!Common::isSpace(key))
|
||||
screenMessage("%c", toupper(key));
|
||||
doneWaiting();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char ReadChoiceController::get(const Common::String &choices, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
ReadChoiceController ctrl(choices);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
ReadDirController::ReadDirController() {
|
||||
_value = 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:
|
||||
case Common::KEYCODE_RETURN:
|
||||
_value = DIR_NONE;
|
||||
doneWaiting();
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
WaitController::WaitController(unsigned int c) : Controller(), _cycles(c), _current(0) {}
|
||||
|
||||
void WaitController::timerFired() {
|
||||
if (++_current >= _cycles) {
|
||||
_current = 0;
|
||||
eventHandler->setControllerDone(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool WaitController::keyPressed(int key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitController::wait() {
|
||||
Controller_startWait();
|
||||
}
|
||||
|
||||
void WaitController::setCycles(int c) {
|
||||
_cycles = c;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima4
|
||||
} // End of namespace Ultima
|
||||
|
@ -23,13 +23,15 @@
|
||||
#ifndef ULTIMA4_EVENT_H
|
||||
#define ULTIMA4_EVENT_H
|
||||
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/events/timed_event_mgr.h"
|
||||
#include "ultima/ultima4/controllers/key_handler_controller.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/shared/std/containers.h"
|
||||
#include "common/events.h"
|
||||
#include "common/list.h"
|
||||
#include "common/str.h"
|
||||
#include "ultima/ultima4/events/controller.h"
|
||||
#include "ultima/ultima4/events/timed_event_mgr.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/shared/std/containers.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
@ -58,190 +60,6 @@ namespace Ultima4 {
|
||||
#define U4_RIGHT_META Common::KEYCODE_RMETA
|
||||
#define U4_LEFT_META Common::KEYCODE_LMETA
|
||||
|
||||
struct MouseArea;
|
||||
class EventHandler;
|
||||
class TextView;
|
||||
|
||||
/**
|
||||
* A class for handling keystrokes.
|
||||
*/
|
||||
class KeyHandler {
|
||||
public:
|
||||
virtual ~KeyHandler() {}
|
||||
|
||||
/* Typedefs */
|
||||
typedef bool (*Callback)(int, void *);
|
||||
|
||||
/** Additional information to be passed as data param for read buffer key handler */
|
||||
typedef struct ReadBuffer {
|
||||
int (*_handleBuffer)(Common::String *);
|
||||
Common::String *_buffer;
|
||||
int _bufferLen;
|
||||
int _screenX, _screenY;
|
||||
} ReadBuffer;
|
||||
|
||||
/** Additional information to be passed as data param for get choice key handler */
|
||||
typedef struct GetChoice {
|
||||
Common::String _choices;
|
||||
int (*_handleChoice)(int);
|
||||
} GetChoice;
|
||||
|
||||
/* Constructors */
|
||||
KeyHandler(Callback func, void *data = NULL, bool asyncronous = true);
|
||||
|
||||
/* Static functions */
|
||||
static int setKeyRepeat(int delay, int interval);
|
||||
|
||||
/**
|
||||
* Handles any and all keystrokes.
|
||||
* Generally used to exit the application, switch applications,
|
||||
* minimize, maximize, etc.
|
||||
*/
|
||||
static bool globalHandler(int key);
|
||||
|
||||
/* Static default key handler functions */
|
||||
/**
|
||||
* A default key handler that should be valid everywhere
|
||||
*/
|
||||
static bool defaultHandler(int key, void *data);
|
||||
|
||||
/**
|
||||
* A key handler that ignores keypresses
|
||||
*/
|
||||
static bool ignoreKeys(int key, void *data);
|
||||
|
||||
/* Operators */
|
||||
bool operator==(Callback cb) const;
|
||||
|
||||
/* Member functions */
|
||||
/**
|
||||
* Handles a keypress.
|
||||
* First it makes sure the key combination is not ignored
|
||||
* by the current key handler. Then, it passes the keypress
|
||||
* through the global key handler. If the global handler
|
||||
* does not process the keystroke, then the key handler
|
||||
* handles it itself by calling its handler callback function.
|
||||
*/
|
||||
bool handle(int key);
|
||||
|
||||
/**
|
||||
* Returns true if the key or key combination is always ignored by xu4
|
||||
*/
|
||||
virtual bool isKeyIgnored(int key);
|
||||
|
||||
protected:
|
||||
Callback _handler;
|
||||
bool _async;
|
||||
void *_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller that wraps a keyhander function. Keyhandlers are
|
||||
* deprecated -- please use a controller instead.
|
||||
*/
|
||||
class KeyHandlerController : public Controller {
|
||||
public:
|
||||
KeyHandlerController(KeyHandler *handler);
|
||||
~KeyHandlerController();
|
||||
|
||||
bool keyPressed(int key) override;
|
||||
KeyHandler *getKeyHandler();
|
||||
|
||||
private:
|
||||
KeyHandler *_handler;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller to read a Common::String, terminated by the enter key.
|
||||
*/
|
||||
class ReadStringController : public WaitableController<Common::String> {
|
||||
public:
|
||||
/**
|
||||
* @param maxlen the maximum length of the Common::String
|
||||
* @param screenX the screen column where to begin input
|
||||
* @param screenY the screen row where to begin input
|
||||
* @param accepted_chars a Common::String characters to be accepted for input
|
||||
*/
|
||||
ReadStringController(int maxlen, int screenX, int screenY, const Common::String &accepted_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 \n\r\010");
|
||||
ReadStringController(int maxlen, TextView *view, const Common::String &accepted_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 \n\r\010");
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
static Common::String get(int maxlen, int screenX, int screenY, EventHandler *eh = NULL);
|
||||
static Common::String get(int maxlen, TextView *view, EventHandler *eh = NULL);
|
||||
#ifdef IOS
|
||||
void setValue(const Common::String &utf8StringValue) {
|
||||
value = utf8StringValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
int _maxLen, _screenX, _screenY;
|
||||
TextView *_view;
|
||||
Common::String _accepted;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller to read a integer, terminated by the enter key.
|
||||
* Non-numeric keys are ignored.
|
||||
*/
|
||||
class ReadIntController : public ReadStringController {
|
||||
public:
|
||||
ReadIntController(int maxlen, int screenX, int screenY);
|
||||
|
||||
static int get(int maxlen, int screenX, int screenY, EventHandler *eh = NULL);
|
||||
int getInt() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller to read a single key from a provided list.
|
||||
*/
|
||||
class ReadChoiceController : public WaitableController<int> {
|
||||
public:
|
||||
ReadChoiceController(const Common::String &choices);
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
static char get(const Common::String &choices, EventHandler *eh = NULL);
|
||||
|
||||
protected:
|
||||
Common::String _choices;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller to read a direction enter with the arrow keys.
|
||||
*/
|
||||
class ReadDirController : public WaitableController<Direction> {
|
||||
public:
|
||||
ReadDirController();
|
||||
|
||||
/**
|
||||
* Key was pressed
|
||||
*/
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
/**
|
||||
* Handles keybinder actions
|
||||
*/
|
||||
void keybinder(KeybindingAction action) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller to pause for a given length of time, ignoring all
|
||||
* keyboard input.
|
||||
*/
|
||||
class WaitController : public Controller {
|
||||
public:
|
||||
WaitController(unsigned int cycles);
|
||||
bool keyPressed(int key) override;
|
||||
void timerFired() override;
|
||||
|
||||
void wait();
|
||||
void setCycles(int c);
|
||||
|
||||
private:
|
||||
unsigned int _cycles;
|
||||
unsigned int _current;
|
||||
};
|
||||
|
||||
#if defined(IOS)
|
||||
#ifndef __OBJC__
|
||||
typedef void *TimedManagerHelper;
|
||||
|
@ -34,112 +34,6 @@
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
||||
KeyHandler::KeyHandler(Callback func, void *d, bool asyncronous) :
|
||||
_handler(func),
|
||||
_async(asyncronous),
|
||||
_data(d) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key-repeat characteristics of the keyboard.
|
||||
*/
|
||||
int KeyHandler::setKeyRepeat(int delay, int interval) {
|
||||
#ifdef TODO
|
||||
return SDL_EnableKeyRepeat(delay, interval);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool KeyHandler::globalHandler(int key) {
|
||||
switch (key) {
|
||||
#if defined(MACOSX)
|
||||
case U4_META + 'q': /* Cmd+q */
|
||||
case U4_META + 'x': /* Cmd+x */
|
||||
#endif
|
||||
case U4_ALT + 'x': /* Alt+x */
|
||||
#if defined(WIN32)
|
||||
case U4_ALT + U4_FKEY + 3:
|
||||
#endif
|
||||
g_ultima->quitGame();
|
||||
EventHandler::end();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyHandler::defaultHandler(int key, void *data) {
|
||||
bool valid = true;
|
||||
|
||||
switch (key) {
|
||||
case '`':
|
||||
if (g_context && g_context->_location)
|
||||
debug(1, "x = %d, y = %d, level = %d, tile = %d (%s)\n", g_context->_location->_coords.x, g_context->_location->_coords.y, g_context->_location->_coords.z, g_context->_location->_map->translateToRawTileIndex(*g_context->_location->_map->tileAt(g_context->_location->_coords, WITH_OBJECTS)), g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITH_OBJECTS)->getName().c_str());
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool KeyHandler::ignoreKeys(int key, void *data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyHandler::handle(int key) {
|
||||
bool processed = false;
|
||||
if (!isKeyIgnored(key)) {
|
||||
processed = globalHandler(key);
|
||||
if (!processed)
|
||||
processed = _handler(key, _data);
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
bool KeyHandler::isKeyIgnored(int key) {
|
||||
switch (key) {
|
||||
case U4_RIGHT_SHIFT:
|
||||
case U4_LEFT_SHIFT:
|
||||
case U4_RIGHT_CTRL:
|
||||
case U4_LEFT_CTRL:
|
||||
case U4_RIGHT_ALT:
|
||||
case U4_LEFT_ALT:
|
||||
case U4_RIGHT_META:
|
||||
case U4_LEFT_META:
|
||||
case U4_TAB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyHandler::operator==(Callback cb) const {
|
||||
return (_handler == cb) ? true : false;
|
||||
}
|
||||
|
||||
KeyHandlerController::KeyHandlerController(KeyHandler *handler) {
|
||||
this->_handler = handler;
|
||||
}
|
||||
|
||||
KeyHandlerController::~KeyHandlerController() {
|
||||
delete _handler;
|
||||
}
|
||||
|
||||
bool KeyHandlerController::keyPressed(int key) {
|
||||
ASSERT(_handler != NULL, "key handler must be initialized");
|
||||
return _handler->handle(key);
|
||||
}
|
||||
|
||||
KeyHandler *KeyHandlerController::getKeyHandler() {
|
||||
return _handler;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
||||
EventHandler::EventHandler() : _timer(settings._eventTimerGranularity), _updateScreen(NULL) {
|
||||
}
|
||||
|
||||
|
@ -20,22 +20,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/ultima4/game/death.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/game/portal.h"
|
||||
#include "ultima/ultima4/game/stats.h"
|
||||
#include "ultima/ultima4/controllers/wait_controller.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/map/map.h"
|
||||
#include "ultima/ultima4/map/annotation.h"
|
||||
#include "ultima/ultima4/map/city.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/map/mapmgr.h"
|
||||
#include "ultima/ultima4/sound/music.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/stats.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Ultima {
|
||||
|
@ -21,6 +21,11 @@
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_dir_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_int_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_player_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_string_controller.h"
|
||||
#include "ultima/ultima4/conversation/conversation.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/debugger.h"
|
||||
@ -72,8 +77,6 @@ namespace Ultima4 {
|
||||
|
||||
using namespace std;
|
||||
|
||||
GameController *g_game = NULL;
|
||||
|
||||
/*-----------------*/
|
||||
/* Functions BEGIN */
|
||||
|
||||
@ -82,132 +85,15 @@ void gameAdvanceLevel(PartyMember *player);
|
||||
void gameInnHandler(void);
|
||||
void gameLostEighth(Virtue virtue);
|
||||
void gamePartyStarving(void);
|
||||
uint32 gameTimeSinceLastCommand(void);
|
||||
|
||||
void mixReagentsSuper();
|
||||
|
||||
/* action functions */
|
||||
void wearArmor(int player = -1);
|
||||
|
||||
/* creature functions */
|
||||
void gameCreatureAttack(Creature *obj);
|
||||
|
||||
/* Functions END */
|
||||
/*---------------*/
|
||||
|
||||
static const MouseArea MOUSE_AREAS[] = {
|
||||
{ 3, { { 8, 8 }, { 8, 184 }, { 96, 96 } }, MC_WEST, { U4_ENTER, 0, U4_LEFT } },
|
||||
{ 3, { { 8, 8 }, { 184, 8 }, { 96, 96 } }, MC_NORTH, { U4_ENTER, 0, U4_UP } },
|
||||
{ 3, { { 184, 8 }, { 184, 184 }, { 96, 96 } }, MC_EAST, { U4_ENTER, 0, U4_RIGHT } },
|
||||
{ 3, { { 8, 184 }, { 184, 184 }, { 96, 96 } }, MC_SOUTH, { U4_ENTER, 0, U4_DOWN } },
|
||||
{ 0, { { 0, 0 }, { 0, 0 }, { 0, 0 } }, MC_NORTH, { 0, 0, 0 } }
|
||||
};
|
||||
|
||||
ReadPlayerController::ReadPlayerController() : ReadChoiceController("12345678 \033\n") {
|
||||
#ifdef IOS
|
||||
U4IOS::beginCharacterChoiceDialog();
|
||||
#endif
|
||||
}
|
||||
|
||||
ReadPlayerController::~ReadPlayerController() {
|
||||
#ifdef IOS
|
||||
U4IOS::endCharacterChoiceDialog();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ReadPlayerController::keyPressed(int key) {
|
||||
bool valid = ReadChoiceController::keyPressed(key);
|
||||
if (valid) {
|
||||
if (_value < '1' ||
|
||||
_value > ('0' + g_ultima->_saveGame->_members))
|
||||
_value = '0';
|
||||
} else {
|
||||
_value = '0';
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
int ReadPlayerController::getPlayer() {
|
||||
return _value - '1';
|
||||
}
|
||||
|
||||
int ReadPlayerController::waitFor() {
|
||||
ReadChoiceController::waitFor();
|
||||
return getPlayer();
|
||||
}
|
||||
|
||||
bool AlphaActionController::keyPressed(int key) {
|
||||
if (Common::isLower(key))
|
||||
key = toupper(key);
|
||||
|
||||
if (key >= 'A' && key <= toupper(_lastValidLetter)) {
|
||||
_value = key - 'A';
|
||||
doneWaiting();
|
||||
} else if (key == U4_SPACE || key == U4_ESC || key == U4_ENTER) {
|
||||
screenMessage("\n");
|
||||
_value = -1;
|
||||
doneWaiting();
|
||||
} else {
|
||||
screenMessage("\n%s", _prompt.c_str());
|
||||
g_screen->update();
|
||||
return KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int AlphaActionController::get(char lastValidLetter, const Common::String &prompt, EventHandler *eh) {
|
||||
if (!eh)
|
||||
eh = eventHandler;
|
||||
|
||||
AlphaActionController ctrl(lastValidLetter, prompt);
|
||||
eh->pushController(&ctrl);
|
||||
return ctrl.waitFor();
|
||||
}
|
||||
|
||||
GameController::GameController() : _mapArea(BORDER_WIDTH, BORDER_HEIGHT, VIEWPORT_W, VIEWPORT_H), _paused(false), _pausedTimer(0) {
|
||||
g_game = this;
|
||||
}
|
||||
|
||||
void GameController::initScreen() {
|
||||
Image *screen = imageMgr->get("screen")->_image;
|
||||
|
||||
screen->fillRect(0, 0, screen->width(), screen->height(), 0, 0, 0);
|
||||
g_screen->update();
|
||||
}
|
||||
|
||||
void GameController::initScreenWithoutReloadingState() {
|
||||
g_music->play();
|
||||
imageMgr->get(BKGD_BORDERS)->_image->draw(0, 0);
|
||||
g_context->_stats->update(); /* draw the party stats */
|
||||
|
||||
screenMessage("Press Alt-h for help\n");
|
||||
screenPrompt();
|
||||
|
||||
eventHandler->pushMouseAreaSet(MOUSE_AREAS);
|
||||
|
||||
eventHandler->setScreenUpdate(&gameUpdateScreen);
|
||||
}
|
||||
|
||||
|
||||
void GameController::init() {
|
||||
initScreen();
|
||||
|
||||
// initialize the global game context, conversation and game state variables
|
||||
g_context = new Context();
|
||||
g_context->_line = TEXT_AREA_H - 1;
|
||||
g_context->col = 0;
|
||||
g_context->_stats = new StatsArea();
|
||||
g_context->_moonPhase = 0;
|
||||
g_context->_windDirection = DIR_NORTH;
|
||||
g_context->_windCounter = 0;
|
||||
g_context->_windLock = false;
|
||||
g_context->_aura = new Aura();
|
||||
g_context->_horseSpeed = 0;
|
||||
g_context->_opacity = 1;
|
||||
g_context->_lastCommandTime = g_system->getMillis();
|
||||
g_context->_lastShip = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the view mode.
|
||||
*/
|
||||
@ -241,238 +127,6 @@ void gameUpdateScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setMap(Map *map, bool saveLocation, const Portal *portal, TurnCompleter *turnCompleter) {
|
||||
int viewMode;
|
||||
LocationContext context;
|
||||
int activePlayer = g_context->_party->getActivePlayer();
|
||||
MapCoords coords;
|
||||
|
||||
if (!turnCompleter)
|
||||
turnCompleter = this;
|
||||
|
||||
if (portal)
|
||||
coords = portal->_start;
|
||||
else
|
||||
coords = MapCoords(map->_width / 2, map->_height / 2);
|
||||
|
||||
/* If we don't want to save the location, then just return to the previous location,
|
||||
as there may still be ones in the stack we want to keep */
|
||||
if (!saveLocation)
|
||||
exitToParentMap();
|
||||
|
||||
switch (map->_type) {
|
||||
case Map::WORLD:
|
||||
context = CTX_WORLDMAP;
|
||||
viewMode = VIEW_NORMAL;
|
||||
break;
|
||||
case Map::DUNGEON:
|
||||
context = CTX_DUNGEON;
|
||||
viewMode = VIEW_DUNGEON;
|
||||
if (portal)
|
||||
g_ultima->_saveGame->_orientation = DIR_EAST;
|
||||
break;
|
||||
case Map::COMBAT:
|
||||
coords = MapCoords(-1, -1); /* set these to -1 just to be safe; we don't need them */
|
||||
context = CTX_COMBAT;
|
||||
viewMode = VIEW_NORMAL;
|
||||
activePlayer = -1; /* different active player for combat, defaults to 'None' */
|
||||
break;
|
||||
case Map::SHRINE:
|
||||
context = CTX_SHRINE;
|
||||
viewMode = VIEW_NORMAL;
|
||||
break;
|
||||
case Map::CITY:
|
||||
default:
|
||||
context = CTX_CITY;
|
||||
viewMode = VIEW_NORMAL;
|
||||
break;
|
||||
}
|
||||
g_context->_location = new Location(coords, map, viewMode, context, turnCompleter, g_context->_location);
|
||||
g_context->_location->addObserver(this);
|
||||
g_context->_party->setActivePlayer(activePlayer);
|
||||
#ifdef IOS
|
||||
U4IOS::updateGameControllerContext(c->location->context);
|
||||
#endif
|
||||
|
||||
/* now, actually set our new tileset */
|
||||
_mapArea.setTileset(map->_tileset);
|
||||
|
||||
if (isCity(map)) {
|
||||
City *city = dynamic_cast<City *>(map);
|
||||
city->addPeople();
|
||||
}
|
||||
}
|
||||
|
||||
int GameController::exitToParentMap() {
|
||||
if (!g_context->_location)
|
||||
return 0;
|
||||
|
||||
if (g_context->_location->_prev != NULL) {
|
||||
// Create the balloon for Hythloth
|
||||
if (g_context->_location->_map->_id == MAP_HYTHLOTH)
|
||||
createBalloon(g_context->_location->_prev->_map);
|
||||
|
||||
// free map info only if previous location was on a different map
|
||||
if (g_context->_location->_prev->_map != g_context->_location->_map) {
|
||||
g_context->_location->_map->_annotations->clear();
|
||||
g_context->_location->_map->clearObjects();
|
||||
|
||||
/* quench the torch of we're on the world map */
|
||||
if (g_context->_location->_prev->_map->isWorldMap())
|
||||
g_context->_party->quenchTorch();
|
||||
}
|
||||
locationFree(&g_context->_location);
|
||||
|
||||
// restore the tileset to the one the current map uses
|
||||
_mapArea.setTileset(g_context->_location->_map->_tileset);
|
||||
#ifdef IOS
|
||||
U4IOS::updateGameControllerContext(c->location->context);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GameController::finishTurn() {
|
||||
g_context->_lastCommandTime = g_system->getMillis();
|
||||
Creature *attacker = NULL;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* adjust food and moves */
|
||||
g_context->_party->endTurn();
|
||||
|
||||
/* count down the aura, if there is one */
|
||||
g_context->_aura->passTurn();
|
||||
|
||||
gameCheckHullIntegrity();
|
||||
|
||||
/* update party stats */
|
||||
//c->stats->setView(STATS_PARTY_OVERVIEW);
|
||||
|
||||
screenUpdate(&this->_mapArea, true, false);
|
||||
screenWait(1);
|
||||
|
||||
/* Creatures cannot spawn, move or attack while the avatar is on the balloon */
|
||||
if (!g_context->_party->isFlying()) {
|
||||
|
||||
// apply effects from tile avatar is standing on
|
||||
g_context->_party->applyEffect(g_context->_location->_map->tileTypeAt(g_context->_location->_coords, WITH_GROUND_OBJECTS)->getEffect());
|
||||
|
||||
// Move creatures and see if something is attacking the avatar
|
||||
attacker = g_context->_location->_map->moveObjects(g_context->_location->_coords);
|
||||
|
||||
// Something's attacking! Start combat!
|
||||
if (attacker) {
|
||||
gameCreatureAttack(attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
// cleanup old creatures and spawn new ones
|
||||
creatureCleanup();
|
||||
checkRandomCreatures();
|
||||
checkBridgeTrolls();
|
||||
}
|
||||
|
||||
/* update map annotations */
|
||||
g_context->_location->_map->_annotations->passTurn();
|
||||
|
||||
if (!g_context->_party->isImmobilized())
|
||||
break;
|
||||
|
||||
if (g_context->_party->isDead()) {
|
||||
deathStart(0);
|
||||
return;
|
||||
} else {
|
||||
screenMessage("Zzzzzz\n");
|
||||
screenWait(4);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_context->_location->_context == CTX_DUNGEON) {
|
||||
Dungeon *dungeon = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
if (g_context->_party->getTorchDuration() <= 0)
|
||||
screenMessage("It's Dark!\n");
|
||||
else g_context->_party->burnTorch();
|
||||
|
||||
/* handle dungeon traps */
|
||||
if (dungeon->currentToken() == DUNGEON_TRAP) {
|
||||
dungeonHandleTrap((TrapType)dungeon->currentSubToken());
|
||||
// a little kludgey to have a second test for this
|
||||
// right here. But without it you can survive an
|
||||
// extra turn after party death and do some things
|
||||
// that could cause a crash, like Hole up and Camp.
|
||||
if (g_context->_party->isDead()) {
|
||||
deathStart(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* draw a prompt */
|
||||
screenPrompt();
|
||||
//screenRedrawTextArea(TEXT_AREA_X, TEXT_AREA_Y, TEXT_AREA_W, TEXT_AREA_H);
|
||||
}
|
||||
|
||||
void GameController::flashTile(const Coords &coords, MapTile tile, int frames) {
|
||||
g_context->_location->_map->_annotations->add(coords, tile, true);
|
||||
|
||||
screenTileUpdate(&g_game->_mapArea, coords);
|
||||
|
||||
screenWait(frames);
|
||||
g_context->_location->_map->_annotations->remove(coords, tile);
|
||||
|
||||
screenTileUpdate(&g_game->_mapArea, coords, false);
|
||||
}
|
||||
|
||||
void GameController::flashTile(const Coords &coords, const Common::String &tilename, int timeFactor) {
|
||||
Tile *tile = g_context->_location->_map->_tileset->getByName(tilename);
|
||||
ASSERT(tile, "no tile named '%s' found in tileset", tilename.c_str());
|
||||
flashTile(coords, tile->getId(), timeFactor);
|
||||
}
|
||||
|
||||
void GameController::update(Party *party, PartyEvent &event) {
|
||||
int i;
|
||||
|
||||
switch (event._type) {
|
||||
case PartyEvent::LOST_EIGHTH:
|
||||
// inform a player he has lost zero or more eighths of avatarhood.
|
||||
screenMessage("\n %cThou hast lost\n an eighth!%c\n", FG_YELLOW, FG_WHITE);
|
||||
break;
|
||||
case PartyEvent::ADVANCED_LEVEL:
|
||||
screenMessage("\n%c%s\nThou art now Level %d%c\n", FG_YELLOW, event._player->getName().c_str(), event._player->getRealLevel(), FG_WHITE);
|
||||
gameSpellEffect('r', -1, SOUND_MAGIC); // Same as resurrect spell
|
||||
break;
|
||||
case PartyEvent::STARVING:
|
||||
screenMessage("\n%cStarving!!!%c\n", FG_YELLOW, FG_WHITE);
|
||||
/* FIXME: add sound effect here */
|
||||
|
||||
// 2 damage to each party member for starving!
|
||||
for (i = 0; i < g_ultima->_saveGame->_members; i++)
|
||||
g_context->_party->member(i)->applyDamage(2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::update(Location *location, MoveEvent &event) {
|
||||
switch (location->_map->_type) {
|
||||
case Map::DUNGEON:
|
||||
avatarMovedInDungeon(event);
|
||||
break;
|
||||
case Map::COMBAT:
|
||||
// FIXME: let the combat controller handle it
|
||||
dynamic_cast<CombatController *>(eventHandler->getController())->movePartyMember(event);
|
||||
break;
|
||||
default:
|
||||
avatarMoved(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gameSpellEffect(int spell, int player, Sound sound) {
|
||||
|
||||
int time;
|
||||
@ -519,99 +173,6 @@ void gameSpellEffect(int spell, int player, Sound sound) {
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::keybinder(KeybindingAction action) {
|
||||
MetaEngine::executeAction(action);
|
||||
}
|
||||
|
||||
bool GameController::keyPressed(int key) {
|
||||
bool valid = true;
|
||||
int endTurn = 1;
|
||||
Object *obj;
|
||||
MapTile *tile;
|
||||
|
||||
/* Translate context-sensitive action key into a useful command */
|
||||
if (key == U4_ENTER && settings._enhancements && settings._enhancementsOptions._smartEnterKey) {
|
||||
/* Attempt to guess based on the character's surroundings etc, what
|
||||
action they want */
|
||||
|
||||
/* Do they want to board something? */
|
||||
if (g_context->_transportContext == TRANSPORT_FOOT) {
|
||||
obj = g_context->_location->_map->objectAt(g_context->_location->_coords);
|
||||
if (obj && (obj->getTile().getTileType()->isShip() ||
|
||||
obj->getTile().getTileType()->isHorse() ||
|
||||
obj->getTile().getTileType()->isBalloon()))
|
||||
key = 'b';
|
||||
}
|
||||
/* Klimb/Descend Balloon */
|
||||
else if (g_context->_transportContext == TRANSPORT_BALLOON) {
|
||||
if (g_context->_party->isFlying())
|
||||
key = 'd';
|
||||
else {
|
||||
#ifdef IOS
|
||||
U4IOS::IOSSuperButtonHelper superHelper;
|
||||
key = ReadChoiceController::get("xk \033\n");
|
||||
#else
|
||||
key = 'k';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* X-it transport */
|
||||
else key = 'x';
|
||||
|
||||
/* Klimb? */
|
||||
if ((g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_KLIMB) != NULL))
|
||||
key = 'k';
|
||||
/* Descend? */
|
||||
else if ((g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_DESCEND) != NULL))
|
||||
key = 'd';
|
||||
|
||||
if (g_context->_location->_context == CTX_DUNGEON) {
|
||||
Dungeon *dungeon = static_cast<Dungeon *>(g_context->_location->_map);
|
||||
bool up = dungeon->ladderUpAt(g_context->_location->_coords);
|
||||
bool down = dungeon->ladderDownAt(g_context->_location->_coords);
|
||||
if (up && down) {
|
||||
#ifdef IOS
|
||||
U4IOS::IOSClimbHelper climbHelper;
|
||||
key = ReadChoiceController::get("kd \033\n");
|
||||
#else
|
||||
key = 'k'; // This is consistent with the previous code. Ideally, I would have a UI here as well.
|
||||
#endif
|
||||
} else if (up) {
|
||||
key = 'k';
|
||||
} else {
|
||||
key = 'd';
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter? */
|
||||
if (g_context->_location->_map->portalAt(g_context->_location->_coords, ACTION_ENTER) != NULL)
|
||||
key = 'e';
|
||||
|
||||
/* Get Chest? */
|
||||
if (!g_context->_party->isFlying()) {
|
||||
tile = g_context->_location->_map->tileAt(g_context->_location->_coords, WITH_GROUND_OBJECTS);
|
||||
|
||||
if (tile->getTileType()->isChest()) key = 'g';
|
||||
}
|
||||
|
||||
/* None of these? Default to search */
|
||||
if (key == U4_ENTER) key = 's';
|
||||
}
|
||||
|
||||
if ((g_context->_location->_context & CTX_DUNGEON) && strchr("abefjlotxy", key))
|
||||
screenMessage("%cNot here!%c\n", FG_GREY, FG_WHITE);
|
||||
|
||||
if (valid && endTurn) {
|
||||
if (eventHandler->getController() == g_game)
|
||||
g_context->_location->_turnCompleter->finishTurn();
|
||||
} else if (!endTurn) {
|
||||
/* if our turn did not end, then manually redraw the text prompt */
|
||||
screenPrompt();
|
||||
}
|
||||
|
||||
return valid || KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
|
||||
Common::String gameGetInput(int maxlen) {
|
||||
screenEnableCursor();
|
||||
screenShowCursor();
|
||||
@ -678,42 +239,6 @@ Direction gameGetDirection() {
|
||||
}
|
||||
}
|
||||
|
||||
bool ZtatsController::keyPressed(int key) {
|
||||
switch (key) {
|
||||
case U4_UP:
|
||||
case U4_LEFT:
|
||||
g_context->_stats->prevItem();
|
||||
return true;
|
||||
case U4_DOWN:
|
||||
case U4_RIGHT:
|
||||
g_context->_stats->nextItem();
|
||||
return true;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
if (g_ultima->_saveGame->_members >= key - '0')
|
||||
g_context->_stats->setView(StatsView(STATS_CHAR1 + key - '1'));
|
||||
return true;
|
||||
case '0':
|
||||
g_context->_stats->setView(StatsView(STATS_WEAPONS));
|
||||
return true;
|
||||
case U4_ESC:
|
||||
case U4_SPACE:
|
||||
case U4_ENTER:
|
||||
g_context->_stats->setView(StatsView(STATS_PARTY_OVERVIEW));
|
||||
doneWaiting();
|
||||
return true;
|
||||
default:
|
||||
return KeyHandler::defaultHandler(key, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool fireAt(const Coords &coords, bool originAvatar) {
|
||||
bool validObject = false;
|
||||
bool hitsAvatar = false;
|
||||
@ -772,233 +297,6 @@ bool fireAt(const Coords &coords, bool originAvatar) {
|
||||
return objectHit;
|
||||
}
|
||||
|
||||
void GameController::initMoons() {
|
||||
int trammelphase = g_ultima->_saveGame->_trammelPhase,
|
||||
feluccaphase = g_ultima->_saveGame->_feluccaPhase;
|
||||
|
||||
ASSERT(g_context != NULL, "Game context doesn't exist!");
|
||||
ASSERT(g_ultima->_saveGame != NULL, "Savegame doesn't exist!");
|
||||
//ASSERT(mapIsWorldMap(c->location->map) && c->location->viewMode == VIEW_NORMAL, "Can only call gameInitMoons() from the world map!");
|
||||
|
||||
g_ultima->_saveGame->_trammelPhase = g_ultima->_saveGame->_feluccaPhase = 0;
|
||||
g_context->_moonPhase = 0;
|
||||
|
||||
while ((g_ultima->_saveGame->_trammelPhase != trammelphase) ||
|
||||
(g_ultima->_saveGame->_feluccaPhase != feluccaphase))
|
||||
updateMoons(false);
|
||||
}
|
||||
|
||||
void GameController::updateMoons(bool showmoongates) {
|
||||
int realMoonPhase,
|
||||
oldTrammel,
|
||||
trammelSubphase;
|
||||
const Coords *gate;
|
||||
|
||||
if (g_context->_location->_map->isWorldMap()) {
|
||||
oldTrammel = g_ultima->_saveGame->_trammelPhase;
|
||||
|
||||
if (++g_context->_moonPhase >= MOON_PHASES * MOON_SECONDS_PER_PHASE * 4)
|
||||
g_context->_moonPhase = 0;
|
||||
|
||||
trammelSubphase = g_context->_moonPhase % (MOON_SECONDS_PER_PHASE * 4 * 3);
|
||||
realMoonPhase = (g_context->_moonPhase / (4 * MOON_SECONDS_PER_PHASE));
|
||||
|
||||
g_ultima->_saveGame->_trammelPhase = realMoonPhase / 3;
|
||||
g_ultima->_saveGame->_feluccaPhase = realMoonPhase % 8;
|
||||
|
||||
if (g_ultima->_saveGame->_trammelPhase > 7)
|
||||
g_ultima->_saveGame->_trammelPhase = 7;
|
||||
|
||||
if (showmoongates) {
|
||||
/* update the moongates if trammel changed */
|
||||
if (trammelSubphase == 0) {
|
||||
gate = moongateGetGateCoordsForPhase(oldTrammel);
|
||||
if (gate)
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate)
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
} else if (trammelSubphase == 1) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
}
|
||||
} else if (trammelSubphase == 2) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
}
|
||||
} else if (trammelSubphase == 3) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
}
|
||||
} else if ((trammelSubphase > 3) && (trammelSubphase < (MOON_SECONDS_PER_PHASE * 4 * 3) - 3)) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
}
|
||||
} else if (trammelSubphase == (MOON_SECONDS_PER_PHASE * 4 * 3) - 3) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x43));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
}
|
||||
} else if (trammelSubphase == (MOON_SECONDS_PER_PHASE * 4 * 3) - 2) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x42));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
}
|
||||
} else if (trammelSubphase == (MOON_SECONDS_PER_PHASE * 4 * 3) - 1) {
|
||||
gate = moongateGetGateCoordsForPhase(g_ultima->_saveGame->_trammelPhase);
|
||||
if (gate) {
|
||||
g_context->_location->_map->_annotations->remove(*gate, g_context->_location->_map->translateFromRawTileIndex(0x41));
|
||||
g_context->_location->_map->_annotations->add(*gate, g_context->_location->_map->translateFromRawTileIndex(0x40));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::avatarMoved(MoveEvent &event) {
|
||||
if (event._userEvent) {
|
||||
|
||||
// is filterMoveMessages even used? it doesn't look like the option is hooked up in the configuration menu
|
||||
if (!settings._filterMoveMessages) {
|
||||
switch (g_context->_transportContext) {
|
||||
case TRANSPORT_FOOT:
|
||||
case TRANSPORT_HORSE:
|
||||
screenMessage("%s\n", getDirectionName(event._dir));
|
||||
break;
|
||||
case TRANSPORT_SHIP:
|
||||
if (event._result & MOVE_TURNED)
|
||||
screenMessage("Turn %s!\n", getDirectionName(event._dir));
|
||||
else if (event._result & MOVE_SLOWED)
|
||||
screenMessage("%cSlow progress!%c\n", FG_GREY, FG_WHITE);
|
||||
else
|
||||
screenMessage("Sail %s!\n", getDirectionName(event._dir));
|
||||
break;
|
||||
case TRANSPORT_BALLOON:
|
||||
screenMessage("%cDrift Only!%c\n", FG_GREY, FG_WHITE);
|
||||
break;
|
||||
default:
|
||||
error("bad transportContext %d in avatarMoved()", g_context->_transportContext);
|
||||
}
|
||||
}
|
||||
|
||||
/* movement was blocked */
|
||||
if (event._result & MOVE_BLOCKED) {
|
||||
|
||||
/* if shortcuts are enabled, try them! */
|
||||
if (settings._shortcutCommands) {
|
||||
MapCoords new_coords = g_context->_location->_coords;
|
||||
MapTile *tile;
|
||||
|
||||
new_coords.move(event._dir, g_context->_location->_map);
|
||||
tile = g_context->_location->_map->tileAt(new_coords, WITH_OBJECTS);
|
||||
|
||||
if (tile->getTileType()->isDoor()) {
|
||||
g_debugger->openAt(new_coords);
|
||||
event._result = (MoveResult)(MOVE_SUCCEEDED | MOVE_END_TURN);
|
||||
} else if (tile->getTileType()->isLockedDoor()) {
|
||||
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);
|
||||
event.result = MOVE_SUCCEEDED | MOVE_END_TURN;
|
||||
}*/
|
||||
}
|
||||
|
||||
/* if we're still blocked */
|
||||
if ((event._result & MOVE_BLOCKED) && !settings._filterMoveMessages) {
|
||||
soundPlay(SOUND_BLOCKED, false);
|
||||
screenMessage("%cBlocked!%c\n", FG_GREY, FG_WHITE);
|
||||
}
|
||||
} else if (g_context->_transportContext == TRANSPORT_FOOT || g_context->_transportContext == TRANSPORT_HORSE) {
|
||||
/* movement was slowed */
|
||||
if (event._result & MOVE_SLOWED) {
|
||||
soundPlay(SOUND_WALK_SLOWED);
|
||||
screenMessage("%cSlow progress!%c\n", FG_GREY, FG_WHITE);
|
||||
} else {
|
||||
soundPlay(SOUND_WALK_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* exited map */
|
||||
if (event._result & MOVE_EXIT_TO_PARENT) {
|
||||
screenMessage("%cLeaving...%c\n", FG_GREY, FG_WHITE);
|
||||
exitToParentMap();
|
||||
g_music->play();
|
||||
}
|
||||
|
||||
/* things that happen while not on board the balloon */
|
||||
if (g_context->_transportContext & ~TRANSPORT_BALLOON)
|
||||
checkSpecialCreatures(event._dir);
|
||||
/* things that happen while on foot or horseback */
|
||||
if ((g_context->_transportContext & TRANSPORT_FOOT_OR_HORSE) &&
|
||||
!(event._result & (MOVE_SLOWED | MOVE_BLOCKED))) {
|
||||
if (checkMoongates())
|
||||
event._result = (MoveResult)(MOVE_MAP_CHANGE | MOVE_END_TURN);
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::avatarMovedInDungeon(MoveEvent &event) {
|
||||
Dungeon *dungeon = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
Direction realDir = dirNormalize((Direction)g_ultima->_saveGame->_orientation, event._dir);
|
||||
|
||||
if (!settings._filterMoveMessages) {
|
||||
if (event._userEvent) {
|
||||
if (event._result & MOVE_TURNED) {
|
||||
if (dirRotateCCW((Direction)g_ultima->_saveGame->_orientation) == realDir)
|
||||
screenMessage("Turn Left\n");
|
||||
else screenMessage("Turn Right\n");
|
||||
}
|
||||
/* show 'Advance' or 'Retreat' in dungeons */
|
||||
else screenMessage("%s\n", realDir == g_ultima->_saveGame->_orientation ? "Advance" : "Retreat");
|
||||
}
|
||||
|
||||
if (event._result & MOVE_BLOCKED)
|
||||
screenMessage("%cBlocked!%c\n", FG_GREY, FG_WHITE);
|
||||
}
|
||||
|
||||
/* if we're exiting the map, do this */
|
||||
if (event._result & MOVE_EXIT_TO_PARENT) {
|
||||
screenMessage("%cLeaving...%c\n", FG_GREY, FG_WHITE);
|
||||
exitToParentMap();
|
||||
g_music->play();
|
||||
}
|
||||
|
||||
/* check to see if we're entering a dungeon room */
|
||||
if (event._result & MOVE_SUCCEEDED) {
|
||||
if (dungeon->currentToken() == DUNGEON_ROOM) {
|
||||
int room = (int)dungeon->currentSubToken(); /* get room number */
|
||||
|
||||
/**
|
||||
* recalculate room for the abyss -- there are 16 rooms for every 2 levels,
|
||||
* each room marked with 0xD* where (* == room number 0-15).
|
||||
* for levels 1 and 2, there are 16 rooms, levels 3 and 4 there are 16 rooms, etc.
|
||||
*/
|
||||
if (g_context->_location->_map->_id == MAP_ABYSS)
|
||||
room = (0x10 * (g_context->_location->_coords.z / 2)) + room;
|
||||
|
||||
Dungeon *dng = dynamic_cast<Dungeon *>(g_context->_location->_map);
|
||||
dng->_currentRoom = room;
|
||||
|
||||
/* set the map and start combat! */
|
||||
CombatController *cc = new CombatController(dng->_roomMaps[room]);
|
||||
cc->initDungeonRoom(room, dirReverse(realDir));
|
||||
cc->begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Peers at a city from A-P (Lycaeum telescope) and functions like a gem
|
||||
*/
|
||||
@ -1062,48 +360,6 @@ void peer(bool useGem) {
|
||||
g_game->_paused = false;
|
||||
}
|
||||
|
||||
void GameController::timerFired() {
|
||||
if (_pausedTimer > 0) {
|
||||
_pausedTimer--;
|
||||
if (_pausedTimer <= 0) {
|
||||
_pausedTimer = 0;
|
||||
_paused = false; /* unpause the game */
|
||||
}
|
||||
}
|
||||
|
||||
if (!_paused && !_pausedTimer) {
|
||||
if (++g_context->_windCounter >= MOON_SECONDS_PER_PHASE * 4) {
|
||||
if (xu4_random(4) == 1 && !g_context->_windLock)
|
||||
g_context->_windDirection = dirRandomDir(MASK_DIR_ALL);
|
||||
g_context->_windCounter = 0;
|
||||
}
|
||||
|
||||
/* balloon moves about 4 times per second */
|
||||
if ((g_context->_transportContext == TRANSPORT_BALLOON) &&
|
||||
g_context->_party->isFlying()) {
|
||||
g_context->_location->move(dirReverse((Direction) g_context->_windDirection), false);
|
||||
}
|
||||
|
||||
updateMoons(true);
|
||||
|
||||
screenCycle();
|
||||
|
||||
/*
|
||||
* force pass if no commands within last 20 seconds
|
||||
*/
|
||||
Controller *controller = eventHandler->getController();
|
||||
if (controller != NULL && (eventHandler->getController() == g_game ||
|
||||
dynamic_cast<CombatController *>(eventHandler->getController()) != NULL) &&
|
||||
gameTimeSinceLastCommand() > 20) {
|
||||
|
||||
/* pass the turn, and redraw the text area so the prompt is shown */
|
||||
MetaEngine::executeAction(KEYBIND_PASS);
|
||||
screenRedrawTextArea(TEXT_AREA_X, TEXT_AREA_Y, TEXT_AREA_W, TEXT_AREA_H);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the hull integrity of the ship and handles
|
||||
* the ship sinking, if necessary
|
||||
@ -1138,83 +394,6 @@ void gameCheckHullIntegrity() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::checkSpecialCreatures(Direction dir) {
|
||||
int i;
|
||||
Object *obj;
|
||||
static const struct {
|
||||
int x, y;
|
||||
Direction dir;
|
||||
} pirateInfo[] = {
|
||||
{ 224, 220, DIR_EAST }, /* N'M" O'A" */
|
||||
{ 224, 228, DIR_EAST }, /* O'E" O'A" */
|
||||
{ 226, 220, DIR_EAST }, /* O'E" O'C" */
|
||||
{ 227, 228, DIR_EAST }, /* O'E" O'D" */
|
||||
{ 228, 227, DIR_SOUTH }, /* O'D" O'E" */
|
||||
{ 229, 225, DIR_SOUTH }, /* O'B" O'F" */
|
||||
{ 229, 223, DIR_NORTH }, /* N'P" O'F" */
|
||||
{ 228, 222, DIR_NORTH } /* N'O" O'E" */
|
||||
};
|
||||
|
||||
/*
|
||||
* if heading east into pirates cove (O'A" N'N"), generate pirate
|
||||
* ships
|
||||
*/
|
||||
if (dir == DIR_EAST &&
|
||||
g_context->_location->_coords.x == 0xdd &&
|
||||
g_context->_location->_coords.y == 0xe0) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
obj = g_context->_location->_map->addCreature(creatureMgr->getById(PIRATE_ID), MapCoords(pirateInfo[i].x, pirateInfo[i].y));
|
||||
obj->setDirection(pirateInfo[i].dir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if heading south towards the shrine of humility, generate
|
||||
* daemons unless horn has been blown
|
||||
*/
|
||||
if (dir == DIR_SOUTH &&
|
||||
g_context->_location->_coords.x >= 229 &&
|
||||
g_context->_location->_coords.x < 234 &&
|
||||
g_context->_location->_coords.y >= 212 &&
|
||||
g_context->_location->_coords.y < 217 &&
|
||||
*g_context->_aura != Aura::HORN) {
|
||||
for (i = 0; i < 8; i++)
|
||||
g_context->_location->_map->addCreature(creatureMgr->getById(DAEMON_ID), MapCoords(231, g_context->_location->_coords.y + 1, g_context->_location->_coords.z));
|
||||
}
|
||||
}
|
||||
|
||||
bool GameController::checkMoongates() {
|
||||
Coords dest;
|
||||
|
||||
if (moongateFindActiveGateAt(g_ultima->_saveGame->_trammelPhase, g_ultima->_saveGame->_feluccaPhase, g_context->_location->_coords, dest)) {
|
||||
|
||||
gameSpellEffect(-1, -1, SOUND_MOONGATE); // Default spell effect (screen inversion without 'spell' sound effects)
|
||||
|
||||
if (g_context->_location->_coords != dest) {
|
||||
g_context->_location->_coords = dest;
|
||||
gameSpellEffect(-1, -1, SOUND_MOONGATE); // Again, after arriving
|
||||
}
|
||||
|
||||
if (moongateIsEntryToShrineOfSpirituality(g_ultima->_saveGame->_trammelPhase, g_ultima->_saveGame->_feluccaPhase)) {
|
||||
Shrine *shrine_spirituality;
|
||||
|
||||
shrine_spirituality = dynamic_cast<Shrine *>(mapMgr->get(MAP_SHRINE_SPIRITUALITY));
|
||||
|
||||
if (!g_context->_party->canEnterShrine(VIRT_SPIRITUALITY))
|
||||
return true;
|
||||
|
||||
setMap(shrine_spirituality, 1, NULL);
|
||||
g_music->play();
|
||||
|
||||
shrine_spirituality->enter();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes objects initially loaded by saveGameMonstersRead,
|
||||
* and alters movement behavior accordingly to match the creature
|
||||
@ -1446,60 +625,6 @@ void gameSetActivePlayer(int player) {
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::creatureCleanup() {
|
||||
ObjectDeque::iterator i;
|
||||
Map *map = g_context->_location->_map;
|
||||
|
||||
for (i = map->_objects.begin(); i != map->_objects.end();) {
|
||||
Object *obj = *i;
|
||||
MapCoords o_coords = obj->getCoords();
|
||||
|
||||
if ((obj->getType() == Object::CREATURE) && (o_coords.z == g_context->_location->_coords.z) &&
|
||||
o_coords.distance(g_context->_location->_coords, g_context->_location->_map) > MAX_CREATURE_DISTANCE) {
|
||||
|
||||
/* delete the object and remove it from the map */
|
||||
i = map->removeObject(i);
|
||||
} else i++;
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::checkRandomCreatures() {
|
||||
int canSpawnHere = g_context->_location->_map->isWorldMap() || g_context->_location->_context & CTX_DUNGEON;
|
||||
#ifdef IOS
|
||||
int spawnDivisor = c->location->context & CTX_DUNGEON ? (53 - (c->location->coords.z << 2)) : 53;
|
||||
#else
|
||||
int spawnDivisor = g_context->_location->_context & CTX_DUNGEON ? (32 - (g_context->_location->_coords.z << 2)) : 32;
|
||||
#endif
|
||||
|
||||
/* If there are too many creatures already,
|
||||
or we're not on the world map, don't worry about it! */
|
||||
if (!canSpawnHere ||
|
||||
g_context->_location->_map->getNumberOfCreatures() >= MAX_CREATURES_ON_MAP ||
|
||||
xu4_random(spawnDivisor) != 0)
|
||||
return;
|
||||
|
||||
gameSpawnCreature(NULL);
|
||||
}
|
||||
|
||||
void GameController::checkBridgeTrolls() {
|
||||
const Tile *bridge = g_context->_location->_map->_tileset->getByName("bridge");
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
// TODO: CHEST: Make a user option to not make chests block bridge trolls
|
||||
if (!g_context->_location->_map->isWorldMap() ||
|
||||
g_context->_location->_map->tileAt(g_context->_location->_coords, WITH_OBJECTS)->_id != bridge->getId() ||
|
||||
xu4_random(8) != 0)
|
||||
return;
|
||||
|
||||
screenMessage("\nBridge Trolls!\n");
|
||||
|
||||
Creature *m = g_context->_location->_map->addCreature(creatureMgr->getById(TROLL_ID), g_context->_location->_coords);
|
||||
CombatController *cc = new CombatController(MAP_BRIDGE_CON);
|
||||
cc->init(m);
|
||||
cc->begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a creature (m) just offscreen of the avatar.
|
||||
* If (m==NULL) then it finds its own creature to spawn and spawns it.
|
||||
@ -1626,22 +751,6 @@ void gameDestroyAllCreatures(void) {
|
||||
g_context->_location->_map->alertGuards();
|
||||
}
|
||||
|
||||
bool GameController::createBalloon(Map *map) {
|
||||
ObjectDeque::iterator i;
|
||||
|
||||
/* see if the balloon has already been created (and not destroyed) */
|
||||
for (i = map->_objects.begin(); i != map->_objects.end(); i++) {
|
||||
Object *obj = *i;
|
||||
if (obj->getTile().getTileType()->isBalloon())
|
||||
return false;
|
||||
}
|
||||
|
||||
const Tile *balloon = map->_tileset->getByName("balloon");
|
||||
ASSERT(balloon, "no balloon tile found in tileset");
|
||||
map->addObject(balloon->getId(), balloon->getId(), map->getLabel("balloon"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Colors assigned to reagents based on my best reading of them
|
||||
// from the book of wisdom. Maybe we could use BOLD to distinguish
|
||||
// the two grey and the two red reagents.
|
||||
|
@ -23,13 +23,13 @@
|
||||
#ifndef ULTIMA4_GAME_H
|
||||
#define ULTIMA4_GAME_H
|
||||
|
||||
#include "ultima/ultima4/events/controller.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/map/map.h"
|
||||
#include "ultima/ultima4/controllers/game_controller.h"
|
||||
#include "ultima/ultima4/core/observer.h"
|
||||
#include "ultima/ultima4/sound/sound.h"
|
||||
#include "ultima/ultima4/map/tileview.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/map/map.h"
|
||||
#include "ultima/ultima4/map/tileview.h"
|
||||
#include "ultima/ultima4/sound/sound.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
@ -53,186 +53,9 @@ typedef enum {
|
||||
VIEW_MIXTURES
|
||||
} ViewMode;
|
||||
|
||||
/**
|
||||
* A controller to read a player number.
|
||||
*/
|
||||
class ReadPlayerController : public ReadChoiceController {
|
||||
public:
|
||||
ReadPlayerController();
|
||||
~ReadPlayerController();
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
int getPlayer();
|
||||
int waitFor() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller to handle input for commands requiring a letter
|
||||
* argument in the range 'a' - lastValidLetter.
|
||||
*/
|
||||
class AlphaActionController : public WaitableController<int> {
|
||||
public:
|
||||
AlphaActionController(char letter, const Common::String &p) : _lastValidLetter(letter), _prompt(p) {}
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
static int get(char lastValidLetter, const Common::String &prompt, EventHandler *eh = NULL);
|
||||
|
||||
private:
|
||||
char _lastValidLetter;
|
||||
Common::String _prompt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Controls interaction while Ztats are being displayed.
|
||||
*/
|
||||
class ZtatsController : public WaitableController<void *> {
|
||||
public:
|
||||
bool keyPressed(int key) override;
|
||||
};
|
||||
|
||||
class TurnCompleter {
|
||||
public:
|
||||
virtual ~TurnCompleter() {}
|
||||
virtual void finishTurn() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The main game controller that handles basic game flow and keypresses.
|
||||
*
|
||||
* @todo
|
||||
* <ul>
|
||||
* <li>separate the dungeon specific stuff into another class (subclass?)</li>
|
||||
* </ul>
|
||||
*/
|
||||
class GameController : public Controller, public Observer<Party *, PartyEvent &>, public Observer<Location *, MoveEvent &>,
|
||||
public TurnCompleter {
|
||||
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.
|
||||
*/
|
||||
bool keyPressed(int key) override;
|
||||
|
||||
/**
|
||||
* This function is called every quarter second.
|
||||
*/
|
||||
void timerFired() override;
|
||||
|
||||
/* main game functions */
|
||||
void init();
|
||||
void initScreen();
|
||||
void initScreenWithoutReloadingState();
|
||||
void setMap(Map *map, bool saveLocation, const Portal *portal, TurnCompleter *turnCompleter = NULL);
|
||||
|
||||
/**
|
||||
* Exits the current map and location and returns to its parent location
|
||||
* This restores all relevant information from the previous location,
|
||||
* such as the map, map position, etc. (such as exiting a city)
|
||||
**/
|
||||
int exitToParentMap();
|
||||
|
||||
/**
|
||||
* Terminates a game turn. This performs the post-turn housekeeping
|
||||
* tasks like adjusting the party's food, incrementing the number of
|
||||
* moves, etc.
|
||||
*/
|
||||
void finishTurn() override;
|
||||
|
||||
/**
|
||||
* Provide feedback to user after a party event happens.
|
||||
*/
|
||||
void update(Party *party, PartyEvent &event) override;
|
||||
|
||||
/**
|
||||
* Provide feedback to user after a movement event happens.
|
||||
*/
|
||||
void update(Location *location, MoveEvent &event) override;
|
||||
|
||||
/**
|
||||
* Initializes the moon state according to the savegame file. This method of
|
||||
* initializing the moons (rather than just setting them directly) is necessary
|
||||
* to make sure trammel and felucca stay in sync
|
||||
*/
|
||||
void initMoons();
|
||||
|
||||
/**
|
||||
* Updates the phases of the moons and shows
|
||||
* the visual moongates on the map, if desired
|
||||
*/
|
||||
void updateMoons(bool showmoongates);
|
||||
|
||||
/**
|
||||
* Show an attack flash at x, y on the current map.
|
||||
* This is used for 'being hit' or 'being missed'
|
||||
* by weapons, cannon fire, spells, etc.
|
||||
*/
|
||||
static void flashTile(const Coords &coords, MapTile tile, int timeFactor);
|
||||
|
||||
static void flashTile(const Coords &coords, const Common::String &tilename, int timeFactor);
|
||||
static void doScreenAnimationsWhilePausing(int timeFactor);
|
||||
|
||||
TileView _mapArea;
|
||||
bool _paused;
|
||||
int _pausedTimer;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handles feedback after avatar moved during normal 3rd-person view.
|
||||
*/
|
||||
void avatarMoved(MoveEvent &event);
|
||||
|
||||
/**
|
||||
* Handles feedback after moving the avatar in the 3-d dungeon view.
|
||||
*/
|
||||
void avatarMovedInDungeon(MoveEvent &event);
|
||||
|
||||
/**
|
||||
* Removes creatures from the current map if they are too far away from the avatar
|
||||
*/
|
||||
void creatureCleanup();
|
||||
|
||||
/**
|
||||
* Handles trolls under bridges
|
||||
*/
|
||||
void checkBridgeTrolls();
|
||||
|
||||
/**
|
||||
* Checks creature conditions and spawns new creatures if necessary
|
||||
*/
|
||||
void checkRandomCreatures();
|
||||
|
||||
/**
|
||||
* Checks for valid conditions and handles
|
||||
* special creatures guarding the entrance to the
|
||||
* abyss and to the shrine of spirituality
|
||||
*/
|
||||
void checkSpecialCreatures(Direction dir);
|
||||
|
||||
/**
|
||||
* Checks for and handles when the avatar steps on a moongate
|
||||
*/
|
||||
bool checkMoongates();
|
||||
|
||||
/**
|
||||
* Creates the balloon near Hythloth, but only if the balloon doesn't already exists somewhere
|
||||
*/
|
||||
bool createBalloon(Map *map);
|
||||
};
|
||||
|
||||
extern GameController *g_game;
|
||||
|
||||
/* map and screen functions */
|
||||
void gameSetViewMode(ViewMode newMode);
|
||||
void gameUpdateScreen(void);
|
||||
void gameUpdateScreen();
|
||||
|
||||
/* spell functions */
|
||||
void gameSpellEffect(int spell, int player, Sound sound);
|
||||
@ -242,16 +65,18 @@ bool gamePeerCity(int city, void *data);
|
||||
void peer(bool useGem = true);
|
||||
bool fireAt(const Coords &coords, bool originAvatar);
|
||||
Direction gameGetDirection();
|
||||
uint32 gameTimeSinceLastCommand();
|
||||
|
||||
/* checking functions */
|
||||
void gameCheckHullIntegrity(void);
|
||||
void gameCheckHullIntegrity();
|
||||
|
||||
/* creature functions */
|
||||
bool creatureRangeAttack(const Coords &coords, Creature *m);
|
||||
void gameCreatureCleanup(void);
|
||||
void gameCreatureCleanup();
|
||||
bool gameSpawnCreature(const class Creature *m);
|
||||
void gameFixupObjects(Map *map);
|
||||
void gameDestroyAllCreatures(void);
|
||||
void gameDestroyAllCreatures();
|
||||
void gameCreatureAttack(Creature *obj);
|
||||
|
||||
/* etc */
|
||||
Common::String gameGetInput(int maxlen = 32);
|
||||
|
@ -20,24 +20,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/game/intro.h"
|
||||
#include "ultima/ultima4/core/error.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/gfx/imagemgr.h"
|
||||
#include "ultima/ultima4/game/menu.h"
|
||||
#include "ultima/ultima4/sound/music.h"
|
||||
#include "ultima/ultima4/sound/sound.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/game/menu.h"
|
||||
#include "ultima/ultima4/controllers/read_string_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/core/error.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/filesys/u4file.h"
|
||||
#include "ultima/ultima4/gfx/imagemgr.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/map/shrine.h"
|
||||
#include "ultima/ultima4/map/tileset.h"
|
||||
#include "ultima/ultima4/map/tilemap.h"
|
||||
#include "ultima/ultima4/filesys/u4file.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/sound/music.h"
|
||||
#include "ultima/ultima4/sound/sound.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
|
||||
|
@ -23,12 +23,12 @@
|
||||
#ifndef ULTIMA4_INTRO_H
|
||||
#define ULTIMA4_INTRO_H
|
||||
|
||||
#include "ultima/ultima4/events/controller.h"
|
||||
#include "ultima/ultima4/game/menu.h"
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/core/observer.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/gfx/imageview.h"
|
||||
#include "ultima/ultima4/game/menu.h"
|
||||
#include "ultima/ultima4/game/textview.h"
|
||||
#include "ultima/ultima4/gfx/imageview.h"
|
||||
#include "ultima/ultima4/map/tileview.h"
|
||||
|
||||
namespace Ultima {
|
||||
|
@ -21,24 +21,25 @@
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/game/item.h"
|
||||
#include "ultima/ultima4/map/annotation.h"
|
||||
#include "ultima/ultima4/game/codex.h"
|
||||
#include "ultima/ultima4/map/combat.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/map/dungeon.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/names.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/game/portal.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/weapon.h"
|
||||
#include "ultima/ultima4/controllers/alpha_action_controller.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/map/annotation.h"
|
||||
#include "ultima/ultima4/map/combat.h"
|
||||
#include "ultima/ultima4/map/dungeon.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/map/map.h"
|
||||
#include "ultima/ultima4/map/mapmgr.h"
|
||||
#include "ultima/ultima4/map/tileset.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/game/weapon.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
@ -20,25 +20,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/game/person.h"
|
||||
#include "ultima/ultima4/map/city.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/conversation/conversation.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/game.h" // Included for ReadPlayerController
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/sound/music.h"
|
||||
#include "ultima/ultima4/game/names.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/game/stats.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/filesys/u4file.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/script.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_int_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_player_controller.h"
|
||||
#include "ultima/ultima4/conversation/conversation.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/filesys/u4file.h"
|
||||
#include "ultima/ultima4/map/city.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/sound/music.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
@ -20,7 +20,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/ultima4.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/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_dir_controller.h"
|
||||
#include "ultima/ultima4/controllers/ztats_controller.h"
|
||||
#include "ultima/ultima4/core/debugger.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/core/utils.h"
|
||||
@ -38,14 +47,8 @@
|
||||
#include "ultima/ultima4/game/stats.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 "ultima/ultima4/ultima4.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Ultima {
|
||||
|
@ -25,14 +25,14 @@
|
||||
|
||||
#include "ultima/ultima4/map/direction.h"
|
||||
#include "ultima/ultima4/map/map.h"
|
||||
#include "ultima/ultima4/events/controller.h"
|
||||
#include "ultima/ultima4/controllers/controller.h"
|
||||
#include "ultima/ultima4/core/observer.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/game/creature.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
#include "ultima/ultima4/game/object.h"
|
||||
#include "ultima/ultima4/core/observer.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/filesys/savegame.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
@ -20,25 +20,28 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/map/shrine.h"
|
||||
#include "ultima/ultima4/map/annotation.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
#include "ultima/ultima4/gfx/imagemgr.h"
|
||||
#include "ultima/ultima4/map/location.h"
|
||||
#include "ultima/ultima4/map/mapmgr.h"
|
||||
#include "ultima/ultima4/map/shrine.h"
|
||||
#include "ultima/ultima4/controllers/read_choice_controller.h"
|
||||
#include "ultima/ultima4/controllers/read_string_controller.h"
|
||||
#include "ultima/ultima4/controllers/wait_controller.h"
|
||||
#include "ultima/ultima4/core/config.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/events/event.h"
|
||||
#include "ultima/ultima4/game/context.h"
|
||||
#include "ultima/ultima4/game/game.h"
|
||||
#include "ultima/ultima4/game/creature.h"
|
||||
#include "ultima/ultima4/sound/music.h"
|
||||
#include "ultima/ultima4/game/names.h"
|
||||
#include "ultima/ultima4/game/player.h"
|
||||
#include "ultima/ultima4/game/portal.h"
|
||||
#include "ultima/ultima4/gfx/imagemgr.h"
|
||||
#include "ultima/ultima4/gfx/screen.h"
|
||||
#include "ultima/ultima4/core/settings.h"
|
||||
#include "ultima/ultima4/map/tileset.h"
|
||||
#include "ultima/ultima4/core/types.h"
|
||||
#include "ultima/ultima4/sound/music.h"
|
||||
#include "ultima/ultima4/ultima4.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima4 {
|
||||
|
@ -108,7 +108,7 @@ static const KeybindingRecord CHEAT_KEYS[] = {
|
||||
{ KEYBIND_CHEAT_UP, "CHEAT-UP", "Up Level", "up", "A+UP", nullptr },
|
||||
{ KEYBIND_CHEAT_DOWN, "CHEAT-DOWN", "Down Level", "down", "A+DOWN", nullptr },
|
||||
{ KEYBIND_CHEAT_VIRTUE, "CHEAT-VIRTUE", "Grant Virtue", "virtue", "A+v", nullptr },
|
||||
{ KEYBIND_CHEAT_WIND, "CHEAT-WIND", "Change Wind", "wind", "A+w", nullptr },
|
||||
{ KEYBIND_CHEAT_WIND, "CHEAT-WIND", "Change Wind", "wind", "A+w", nullptr },
|
||||
|
||||
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user