mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 09:49:11 +00:00
410 lines
10 KiB
C++
410 lines
10 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "lastexpress/fight/fight.h"
|
|
|
|
#include "lastexpress/fight/fighter_anna.h"
|
|
#include "lastexpress/fight/fighter_ivo.h"
|
|
#include "lastexpress/fight/fighter_milos.h"
|
|
#include "lastexpress/fight/fighter_salko.h"
|
|
#include "lastexpress/fight/fighter_vesna.h"
|
|
|
|
#include "lastexpress/data/cursor.h"
|
|
#include "lastexpress/data/sequence.h"
|
|
|
|
#include "lastexpress/game/inventory.h"
|
|
#include "lastexpress/game/logic.h"
|
|
#include "lastexpress/game/object.h"
|
|
#include "lastexpress/game/scenes.h"
|
|
#include "lastexpress/game/state.h"
|
|
|
|
#include "lastexpress/sound/queue.h"
|
|
|
|
#include "lastexpress/graphics.h"
|
|
#include "lastexpress/helpers.h"
|
|
#include "lastexpress/lastexpress.h"
|
|
#include "lastexpress/resource.h"
|
|
|
|
namespace LastExpress {
|
|
|
|
Fight::FightData::FightData() {
|
|
player = NULL;
|
|
opponent = NULL;
|
|
|
|
index = 0;
|
|
|
|
isFightRunning = false;
|
|
}
|
|
|
|
Fight::FightData::~FightData() {
|
|
SAFE_DELETE(player);
|
|
SAFE_DELETE(opponent);
|
|
}
|
|
|
|
Fight::Fight(LastExpressEngine *engine) : _engine(engine), _data(NULL), _endType(kFightEndLost), _state(0), _handleTimer(false) {
|
|
}
|
|
|
|
Fight::~Fight() {
|
|
clearData();
|
|
_data = NULL;
|
|
|
|
// Zero passed pointers
|
|
_engine = NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Events
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Fight::eventMouse(const Common::Event &ev) {
|
|
if (!_data || _data->index)
|
|
return;
|
|
|
|
// TODO move all the egg handling to inventory functions
|
|
|
|
getFlags()->mouseLeftClick = false;
|
|
getFlags()->shouldRedraw = false;
|
|
getFlags()->mouseRightClick = false;
|
|
|
|
if (ev.mouse.x < 608 || ev.mouse.y < 448 || ev.mouse.x >= 640 || ev.mouse.x >= 480) {
|
|
|
|
// Handle right button click
|
|
if (ev.type == Common::EVENT_RBUTTONUP) {
|
|
getSoundQueue()->removeFromQueue(kEntityTables0);
|
|
setStopped();
|
|
|
|
getGlobalTimer() ? _state = 0 : ++_state;
|
|
|
|
getFlags()->mouseRightClick = true;
|
|
}
|
|
|
|
if (_handleTimer) {
|
|
// Timer expired => show with full brightness
|
|
if (!getGlobalTimer())
|
|
getInventory()->drawBlinkingEgg();
|
|
|
|
_handleTimer = false;
|
|
}
|
|
|
|
// Check hotspots
|
|
Scene *scene = getScenes()->get(getState()->scene);
|
|
SceneHotspot *hotspot = NULL;
|
|
|
|
if (!scene->checkHotSpot(ev.mouse, &hotspot)) {
|
|
_engine->getCursor()->setStyle(kCursorNormal);
|
|
} else {
|
|
_engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
|
|
|
|
// Call player function
|
|
if (_data->player->canInteract((Fighter::FightAction)hotspot->action)) {
|
|
if (ev.type == Common::EVENT_LBUTTONUP)
|
|
_data->player->handleAction((Fighter::FightAction)hotspot->action);
|
|
} else {
|
|
_engine->getCursor()->setStyle(kCursorNormal);
|
|
}
|
|
}
|
|
} else {
|
|
// Handle clicks on menu icon
|
|
|
|
if (!_handleTimer) {
|
|
// Timer expired => show with full brightness
|
|
if (!getGlobalTimer())
|
|
getInventory()->drawBlinkingEgg();
|
|
|
|
_handleTimer = true;
|
|
}
|
|
|
|
// Stop fight if clicked
|
|
if (ev.type == Common::EVENT_LBUTTONUP) {
|
|
_handleTimer = false;
|
|
getSoundQueue()->removeFromQueue(kEntityTables0);
|
|
bailout(kFightEndExit);
|
|
}
|
|
|
|
// Reset timer on right click
|
|
if (ev.type == Common::EVENT_RBUTTONUP) {
|
|
if (getGlobalTimer()) {
|
|
if (getSoundQueue()->isBuffered("TIMER"))
|
|
getSoundQueue()->removeFromQueue("TIMER");
|
|
|
|
setGlobalTimer(900);
|
|
}
|
|
}
|
|
}
|
|
|
|
getFlags()->shouldRedraw = true;
|
|
}
|
|
|
|
void Fight::eventTick(const Common::Event &ev) {
|
|
handleTick(ev, true);
|
|
}
|
|
|
|
void Fight::handleTick(const Common::Event &ev, bool isProcessing) {
|
|
// TODO move all the egg handling to inventory functions
|
|
|
|
// Blink egg
|
|
if (getGlobalTimer()) {
|
|
warning("[Fight::handleTick] Egg blinking not implemented");
|
|
}
|
|
|
|
if (!_data || _data->index)
|
|
return;
|
|
|
|
SceneHotspot *hotspot = NULL;
|
|
if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !_data->player->canInteract((Fighter::FightAction)hotspot->action)) {
|
|
_engine->getCursor()->setStyle(kCursorNormal);
|
|
} else {
|
|
_engine->getCursor()->setStyle((CursorStyle)hotspot->cursor);
|
|
}
|
|
|
|
_data->player->update();
|
|
_data->opponent->update();
|
|
|
|
// Draw sequences
|
|
if (!_data->isFightRunning)
|
|
return;
|
|
|
|
if (isProcessing)
|
|
getScenes()->drawFrames(true);
|
|
|
|
if (_data->index) {
|
|
// Set next sequence name index
|
|
_data->index--;
|
|
_data->sequences[_data->index] = loadSequence(_data->names[_data->index]);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Setup
|
|
//////////////////////////////////////////////////////////////////////////
|
|
Fight::FightEndType Fight::setup(FightType type) {
|
|
if (_data)
|
|
error("[Fight::setup] Calling fight setup again while a fight is already in progress");
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Prepare UI & state
|
|
if (_state >= 5 && (type == kFightSalko || type == kFightVesna)) {
|
|
_state = 0;
|
|
return kFightEndWin;
|
|
}
|
|
|
|
getInventory()->showHourGlass();
|
|
// TODO events function
|
|
getFlags()->flag_0 = false;
|
|
getFlags()->mouseRightClick = false;
|
|
getEntities()->reset();
|
|
|
|
// Compute scene to use
|
|
SceneIndex sceneIndex;
|
|
switch(type) {
|
|
default:
|
|
sceneIndex = kSceneFightDefault;
|
|
break;
|
|
|
|
case kFightMilos:
|
|
sceneIndex = (getObjects()->get(kObjectCompartment1).location2 < kObjectLocation3) ? kSceneFightMilos : kSceneFightMilosBedOpened;
|
|
break;
|
|
|
|
case kFightAnna:
|
|
sceneIndex = kSceneFightAnna;
|
|
break;
|
|
|
|
case kFightIvo:
|
|
sceneIndex = kSceneFightIvo;
|
|
break;
|
|
|
|
case kFightSalko:
|
|
sceneIndex = kSceneFightSalko;
|
|
break;
|
|
|
|
case kFightVesna:
|
|
sceneIndex = kSceneFightVesna;
|
|
break;
|
|
}
|
|
|
|
if (getFlags()->shouldRedraw) {
|
|
getFlags()->shouldRedraw = false;
|
|
askForRedraw();
|
|
//redrawScreen();
|
|
}
|
|
|
|
// Load the scene object
|
|
Scene *scene = getScenes()->get(sceneIndex);
|
|
|
|
// Update game entities and state
|
|
getEntityData(kEntityPlayer)->entityPosition = scene->entityPosition;
|
|
getEntityData(kEntityPlayer)->location = scene->location;
|
|
|
|
getState()->scene = sceneIndex;
|
|
|
|
getFlags()->flag_3 = true;
|
|
|
|
// Draw the scene
|
|
_engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC);
|
|
// FIXME move to start of fight?
|
|
askForRedraw();
|
|
redrawScreen();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Setup the fight
|
|
_data = new FightData;
|
|
loadData(type);
|
|
|
|
// Show opponents & egg button
|
|
Common::Event emptyEvent;
|
|
handleTick(emptyEvent, false);
|
|
getInventory()->drawEgg();
|
|
|
|
// Start fight
|
|
_endType = kFightEndLost;
|
|
while (_data->isFightRunning) {
|
|
if (_engine->handleEvents())
|
|
continue;
|
|
|
|
getSoundQueue()->updateQueue();
|
|
}
|
|
|
|
// Cleanup after fight is over
|
|
clearData();
|
|
|
|
return _endType;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Status
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Fight::setStopped() {
|
|
if (_data)
|
|
_data->isFightRunning = false;
|
|
}
|
|
|
|
void Fight::bailout(FightEndType type) {
|
|
_state = 0;
|
|
_endType = type;
|
|
setStopped();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Cleanup
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Fight::clearData() {
|
|
if (!_data)
|
|
return;
|
|
|
|
// Clear data
|
|
SAFE_DELETE(_data);
|
|
|
|
_engine->restoreEventHandlers();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Loading
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Fight::loadData(FightType type) {
|
|
if (!_data)
|
|
error("[Fight::loadData] Data not initialized");
|
|
|
|
switch (type) {
|
|
default:
|
|
break;
|
|
|
|
case kFightMilos:
|
|
_data->player = new FighterPlayerMilos(_engine);
|
|
_data->opponent = new FighterOpponentMilos(_engine);
|
|
break;
|
|
|
|
case kFightAnna:
|
|
_data->player = new FighterPlayerAnna(_engine);
|
|
_data->opponent = new FighterOpponentAnna(_engine);
|
|
break;
|
|
|
|
case kFightIvo:
|
|
_data->player = new FighterPlayerIvo(_engine);
|
|
_data->opponent = new FighterOpponentIvo(_engine);
|
|
break;
|
|
|
|
case kFightSalko:
|
|
_data->player = new FighterPlayerSalko(_engine);
|
|
_data->opponent = new FighterOpponentSalko(_engine);
|
|
break;
|
|
|
|
case kFightVesna:
|
|
_data->player = new FighterPlayerVesna(_engine);
|
|
_data->opponent = new FighterOpponentVesna(_engine);
|
|
break;
|
|
}
|
|
|
|
if (!_data->player || !_data->opponent)
|
|
error("[Fight::loadData] Error loading fight data (type=%d)", type);
|
|
|
|
// Setup opponent pointers
|
|
setOpponents();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Start running the fight
|
|
_data->isFightRunning = true;
|
|
|
|
if (_state < 5) {
|
|
_data->player->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
|
|
_data->opponent->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
|
|
goto end_load;
|
|
}
|
|
|
|
switch(type) {
|
|
default:
|
|
break;
|
|
|
|
case kFightMilos:
|
|
_data->opponent->setCountdown(1);
|
|
_data->player->setSequenceAndDraw(4, Fighter::kFightSequenceType0);
|
|
_data->opponent->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
|
|
break;
|
|
|
|
case kFightIvo:
|
|
_data->opponent->setCountdown(1);
|
|
_data->player->setSequenceAndDraw(3, Fighter::kFightSequenceType0);
|
|
_data->opponent->setSequenceAndDraw(6, Fighter::kFightSequenceType0);
|
|
break;
|
|
|
|
case kFightVesna:
|
|
_data->opponent->setCountdown(1);
|
|
_data->player->setSequenceAndDraw(0, Fighter::kFightSequenceType0);
|
|
_data->player->setSequenceAndDraw(3, Fighter::kFightSequenceType2);
|
|
_data->opponent->setSequenceAndDraw(5, Fighter::kFightSequenceType0);
|
|
break;
|
|
}
|
|
|
|
end_load:
|
|
// Setup event handlers
|
|
_engine->backupEventHandlers();
|
|
SET_EVENT_HANDLERS(Fight, this);
|
|
}
|
|
|
|
void Fight::setOpponents() {
|
|
_data->player->setOpponent(_data->opponent);
|
|
_data->opponent->setOpponent(_data->player);
|
|
|
|
_data->player->setFight(this);
|
|
_data->opponent->setFight(this);
|
|
}
|
|
|
|
} // End of namespace LastExpress
|