From 3c2a9b292f5a851529fb0196eab662fd9996a459 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Jun 2011 23:50:01 -0400 Subject: LASTEXPRESS: Move Fight class to its own folder --- engines/lastexpress/debug.cpp | 3 +- engines/lastexpress/entities/anna.cpp | 3 +- engines/lastexpress/entities/ivo.cpp | 3 +- engines/lastexpress/entities/milos.cpp | 3 +- engines/lastexpress/entities/salko.cpp | 3 +- engines/lastexpress/entities/vesna.cpp | 3 +- engines/lastexpress/fight/fight.cpp | 1583 ++++++++++++++++++++++++++++++++ engines/lastexpress/fight/fight.h | 266 ++++++ engines/lastexpress/game/fight.cpp | 1583 -------------------------------- engines/lastexpress/game/fight.h | 266 ------ engines/lastexpress/game/logic.cpp | 4 +- engines/lastexpress/game/menu.cpp | 3 +- engines/lastexpress/module.mk | 2 +- 13 files changed, 1867 insertions(+), 1858 deletions(-) create mode 100644 engines/lastexpress/fight/fight.cpp create mode 100644 engines/lastexpress/fight/fight.h delete mode 100644 engines/lastexpress/game/fight.cpp delete mode 100644 engines/lastexpress/game/fight.h diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index 4b7c5f6a9a..d5c7df0e55 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -31,9 +31,10 @@ #include "lastexpress/data/snd.h" #include "lastexpress/data/subtitle.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/action.h" #include "lastexpress/game/beetle.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp index 0bedda41e8..bce99ad16d 100644 --- a/engines/lastexpress/entities/anna.cpp +++ b/engines/lastexpress/entities/anna.cpp @@ -22,9 +22,10 @@ #include "lastexpress/entities/anna.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp index 35f4ccfb8c..861c3cf9bd 100644 --- a/engines/lastexpress/entities/ivo.cpp +++ b/engines/lastexpress/entities/ivo.cpp @@ -22,9 +22,10 @@ #include "lastexpress/entities/ivo.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savepoint.h" diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp index 587c43cade..45fd6883f0 100644 --- a/engines/lastexpress/entities/milos.cpp +++ b/engines/lastexpress/entities/milos.cpp @@ -24,9 +24,10 @@ #include "lastexpress/entities/vesna.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" diff --git a/engines/lastexpress/entities/salko.cpp b/engines/lastexpress/entities/salko.cpp index 4d510bb9bf..bbaff5f1d9 100644 --- a/engines/lastexpress/entities/salko.cpp +++ b/engines/lastexpress/entities/salko.cpp @@ -22,9 +22,10 @@ #include "lastexpress/entities/salko.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savepoint.h" diff --git a/engines/lastexpress/entities/vesna.cpp b/engines/lastexpress/entities/vesna.cpp index 8e09dbf7b0..79ac934ef9 100644 --- a/engines/lastexpress/entities/vesna.cpp +++ b/engines/lastexpress/entities/vesna.cpp @@ -22,9 +22,10 @@ #include "lastexpress/entities/vesna.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savepoint.h" diff --git a/engines/lastexpress/fight/fight.cpp b/engines/lastexpress/fight/fight.cpp new file mode 100644 index 0000000000..5b3530f488 --- /dev/null +++ b/engines/lastexpress/fight/fight.cpp @@ -0,0 +1,1583 @@ +/* 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/data/cursor.h" +#include "lastexpress/data/scene.h" +#include "lastexpress/data/sequence.h" + +#include "lastexpress/game/entities.h" +#include "lastexpress/game/inventory.h" +#include "lastexpress/game/logic.h" +#include "lastexpress/game/object.h" +#include "lastexpress/game/scenes.h" +#include "lastexpress/game/sound.h" +#include "lastexpress/game/state.h" + +#include "lastexpress/graphics.h" +#include "lastexpress/helpers.h" +#include "lastexpress/lastexpress.h" +#include "lastexpress/resource.h" + +#include "common/func.h" + +namespace LastExpress { + +#define CALL_FUNCTION0(fighter, name) \ + (*fighter->name)(fighter) + +#define CALL_FUNCTION1(fighter, name, a) \ + (*fighter->name)(fighter, a) + +#define REGISTER_PLAYER_FUNCTIONS(name) \ + if (!_data) \ + error("Fight::load##namePlayer - invalid data!"); \ + _data->player->handleAction = new Common::Functor2Mem(this, &Fight::handleAction##name); \ + _data->player->update = new Common::Functor1Mem(this, &Fight::update##name); \ + _data->player->canInteract = new Common::Functor2Mem(this, &Fight::canInteract##name); + +#define REGISTER_OPPONENT_FUNCTIONS(name) \ + if (!_data) \ + error("Fight::load##nameOpponent - invalid data!"); \ + _data->opponent->handleAction = new Common::Functor2Mem(this, &Fight::handleOpponentAction##name); \ + _data->opponent->update = new Common::Functor1Mem(this, &Fight::updateOpponent##name); \ + _data->opponent->canInteract = new Common::Functor2Mem(this, &Fight::canInteract); + +#define CHECK_SEQUENCE2(fighter, value) \ + (fighter->frame->getInfo()->field_33 & value) + +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) { + getSound()->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 (CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) { + if (ev.type == Common::EVENT_LBUTTONUP) + CALL_FUNCTION1(_data->player, handleAction, (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; + getSound()->removeFromQueue(kEntityTables0); + bailout(kFightEndExit); + } + + // Reset timer on right click + if (ev.type == Common::EVENT_RBUTTONUP) { + if (getGlobalTimer()) { + if (getSound()->isBuffered("TIMER")) + getSound()->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::handleMouseMove - egg blinking not implemented!"); + } + + if (!_data || _data->index) + return; + + SceneHotspot *hotspot = NULL; + if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) { + _engine->getCursor()->setStyle(kCursorNormal); + } else { + _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor); + } + + CALL_FUNCTION0(_data->player, update); + CALL_FUNCTION0(_data->opponent, update); + + // Draw sequences + if (!_data->isRunning) + 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->isRunning) { + if (_engine->handleEvents()) + continue; + + getSound()->updateQueue(); + } + + // Cleanup after fight is over + clearData(); + + return _endType; +} + +////////////////////////////////////////////////////////////////////////// +// Status +////////////////////////////////////////////////////////////////////////// + +void Fight::setStopped() { + if (_data) + _data->isRunning = false; +} + +void Fight::bailout(FightEndType type) { + _state = 0; + _endType = type; + setStopped(); +} + +////////////////////////////////////////////////////////////////////////// +// Cleanup +////////////////////////////////////////////////////////////////////////// + +void Fight::clearData() { + if (!_data) + return; + + // Clear data + clearSequences(_data->player); + clearSequences(_data->opponent); + + SAFE_DELETE(_data->player); + SAFE_DELETE(_data->opponent); + + SAFE_DELETE(_data); + + _engine->restoreEventHandlers(); +} + +void Fight::clearSequences(Fighter *combatant) const { + if (!combatant) + return; + + // The original game resets the function pointers to default values, just before deleting the struct + getScenes()->removeAndRedraw(&combatant->frame, false); + + // Free sequences + for (int i = 0; i < (int)combatant->sequences.size(); i++) + SAFE_DELETE(combatant->sequences[i]); +} + +////////////////////////////////////////////////////////////////////////// +// Drawing +////////////////////////////////////////////////////////////////////////// + +void Fight::setSequenceAndDraw(Fighter *combatant, uint32 sequenceIndex, FightSequenceType type) const { + if (combatant->sequences.size() < sequenceIndex) + return; + + switch (type) { + default: + break; + + case kFightSequenceType0: + if (combatant->sequenceIndex) + return; + + combatant->sequence = combatant->sequences[sequenceIndex]; + combatant->sequenceIndex = sequenceIndex; + draw(combatant); + break; + + case kFightSequenceType1: + combatant->sequence = combatant->sequences[sequenceIndex]; + combatant->sequenceIndex = sequenceIndex; + combatant->sequenceIndex2 = 0; + draw(combatant); + break; + + case kFightSequenceType2: + combatant->sequenceIndex2 = sequenceIndex; + break; + } +} + +void Fight::draw(Fighter *combatant) const { + getScenes()->removeAndRedraw(&combatant->frame, false); + + combatant->frameIndex = 0; + combatant->field_24 = 0; +} + +////////////////////////////////////////////////////////////////////////// +// Loading +////////////////////////////////////////////////////////////////////////// + +void Fight::loadData(FightType type) { + if (!_data) + error("Fight::loadData - invalid data!"); + + switch (type) { + default: + break; + + case kFightMilos: + loadMilosPlayer(); + loadMilosOpponent(); + break; + + case kFightAnna: + loadAnnaPlayer(); + loadAnnaOpponent(); + break; + + case kFightIvo: + loadIvoPlayer(); + loadIvoOpponent(); + break; + + case kFightSalko: + loadSalkoPlayer(); + loadSalkoOpponent(); + break; + + case kFightVesna: + loadVesnaPlayer(); + loadVesnaOpponent(); + break; + } + + if (!_data->player || !_data->opponent) + error("Fight::loadData - error loading fight data (type=%d)", type); + + ////////////////////////////////////////////////////////////////////////// + // Start running the fight + _data->isRunning = true; + + if (_state < 5) { + setSequenceAndDraw(_data->player, 0, kFightSequenceType0); + setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0); + goto end_load; + } + + switch(type) { + default: + break; + + case kFightMilos: + _data->opponent->countdown = 1; + setSequenceAndDraw(_data->player, 4, kFightSequenceType0); + setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0); + break; + + case kFightIvo: + _data->opponent->countdown = 1; + setSequenceAndDraw(_data->player, 3, kFightSequenceType0); + setSequenceAndDraw(_data->opponent, 6, kFightSequenceType0); + break; + + case kFightVesna: + _data->opponent->countdown = 1; + setSequenceAndDraw(_data->player, 0, kFightSequenceType0); + setSequenceAndDraw(_data->player, 3, kFightSequenceType2); + setSequenceAndDraw(_data->opponent, 5, kFightSequenceType0); + break; + } + +end_load: + // Setup event handlers + _engine->backupEventHandlers(); + SET_EVENT_HANDLERS(Fight, this); +} + +////////////////////////////////////////////////////////////////////////// +// Shared +////////////////////////////////////////////////////////////////////////// +void Fight::processFighter(Fighter *fighter) { + if (!_data) + error("Fight::processFighter - invalid data!"); + + if (!fighter->sequence) { + if (fighter->frame) { + getScenes()->removeFromQueue(fighter->frame); + getScenes()->setCoordinates(fighter->frame); + } + SAFE_DELETE(fighter->frame); + return; + } + + if (fighter->sequence->count() <= fighter->frameIndex) { + switch(fighter->action) { + default: + break; + + case kFightAction101: + setSequenceAndDraw(fighter, fighter->sequenceIndex2, kFightSequenceType1); + fighter->sequenceIndex2 = 0; + break; + + case kFightActionResetFrame: + fighter->frameIndex = 0; + break; + + case kFightAction103: + setSequenceAndDraw(fighter, 0, kFightSequenceType1); + CALL_FUNCTION1(fighter, handleAction, kFightAction101); + setSequenceAndDraw(fighter->opponent, 0, kFightSequenceType1); + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction101); + CALL_FUNCTION0(fighter->opponent, update); + break; + + case kFightActionWin: + bailout(kFightEndWin); + break; + + case kFightActionLost: + bailout(kFightEndLost); + break; + } + } + + if (_data->isRunning) { + + // Get the current sequence frame + SequenceFrame *frame = new SequenceFrame(fighter->sequence, (uint16)fighter->frameIndex); + frame->getInfo()->location = 1; + + if (fighter->frame == frame) { + delete frame; + return; + } + + getSound()->playFightSound(frame->getInfo()->soundAction, frame->getInfo()->field_31); + + // Add current frame to queue and advance + getScenes()->addToQueue(frame); + fighter->frameIndex++; + + if (fighter->frame) { + getScenes()->removeFromQueue(fighter->frame); + + if (!frame->getInfo()->field_2E) + getScenes()->setCoordinates(fighter->frame); + } + + // Replace by new frame + delete fighter->frame; + fighter->frame = frame; + } +} + +void Fight::handleAction(Fighter *fighter, FightAction action) { + switch (action) { + default: + return; + + case kFightAction101: + break; + + case kFightActionResetFrame: + fighter->countdown--; + break; + + case kFightAction103: + CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); + break; + + case kFightActionWin: + _endType = kFightEndWin; + CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); + break; + + case kFightActionLost: + _endType = kFightEndLost; + CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); + break; + } + + // Update action + fighter->action = action; +} + +bool Fight::canInteract(Fighter const *fighter, FightAction /*= (FightAction)0*/ ) { + return (fighter->action == kFightAction101 && !fighter->sequenceIndex); +} + +void Fight::update(Fighter *fighter) { + + processFighter(fighter); + + if (fighter->frame) + fighter->frame->getInfo()->location = (fighter->action == kFightActionResetFrame ? 2 : 0); +} + +void Fight::updateOpponent(Fighter *fighter) { + + // This is an opponent struct! + Opponent *opponent = (Opponent *)fighter; + + processFighter(opponent); + + if (opponent->field_38 && !opponent->sequenceIndex) + opponent->field_38--; + + if (fighter->frame) + fighter->frame->getInfo()->location = 1; +} + +////////////////////////////////////////////////////////////////////////// +// Milos +////////////////////////////////////////////////////////////////////////// + +void Fight::loadMilosPlayer() { + REGISTER_PLAYER_FUNCTIONS(Milos) + + _data->player->sequences.push_back(loadSequence("2001cr.seq")); + _data->player->sequences.push_back(loadSequence("2001cdl.seq")); + _data->player->sequences.push_back(loadSequence("2001cdr.seq")); + _data->player->sequences.push_back(loadSequence("2001cdm.seq")); + _data->player->sequences.push_back(loadSequence("2001csgr.seq")); + _data->player->sequences.push_back(loadSequence("2001csgl.seq")); + _data->player->sequences.push_back(loadSequence("2001dbk.seq")); +} + +void Fight::loadMilosOpponent() { + REGISTER_OPPONENT_FUNCTIONS(Milos) + + _data->opponent->sequences.push_back(loadSequence("2001or.seq")); + _data->opponent->sequences.push_back(loadSequence("2001oal.seq")); + _data->opponent->sequences.push_back(loadSequence("2001oam.seq")); + _data->opponent->sequences.push_back(loadSequence("2001okl.seq")); + _data->opponent->sequences.push_back(loadSequence("2001okm.seq")); + _data->opponent->sequences.push_back(loadSequence("2001dbk.seq")); + _data->opponent->sequences.push_back(loadSequence("2001wbk.seq")); + + getSound()->playSound(kEntityTables0, "MUS027", SoundManager::kFlagDefault); + + _data->opponent->field_38 = 35; +} + +void Fight::handleActionMilos(Fighter *fighter, FightAction action) { + switch (action) { + default: + handleAction(fighter, action); + return; + + case kFightAction1: + if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 6, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 3, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction2: + if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 6, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction128: + if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4) || fighter->opponent->sequenceIndex != 1) { + switch (fighter->opponent->sequenceIndex) { + default: + setSequenceAndDraw(fighter, rnd(3) + 1, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(fighter, 1, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(fighter, 3, kFightSequenceType0); + break; + } + } else { + setSequenceAndDraw(fighter, 4, kFightSequenceType1); + CALL_FUNCTION0(fighter, update); + } + break; + } +} + +void Fight::updateMilos(Fighter *fighter) { + if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { + + // Draw sequences + if (fighter->opponent->countdown <= 0) { + setSequenceAndDraw(fighter, 5, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1); + + getSound()->removeFromQueue(kEntityTables0); + getSound()->playSound(kEntityTrain, "MUS029", SoundManager::kFlagDefault); + + CALL_FUNCTION1(fighter, handleAction, kFightActionWin); + } + + if (fighter->sequenceIndex == 4) { + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction4); + _endType = kFightEndLost; + } + } + + update(fighter); +} + +bool Fight::canInteractMilos(Fighter const *fighter, FightAction action) { + if (!_data) + error("Fight::canInteractMilos - invalid data!"); + + if (action != kFightAction128 + || _data->player->sequenceIndex != 1 + || !fighter->frame + || CHECK_SEQUENCE2(fighter, 4) + || fighter->opponent->sequenceIndex != 1) { + return canInteract(fighter); + } + + _engine->getCursor()->setStyle(kCursorHand); + + return true; +} + +void Fight::handleOpponentActionMilos(Fighter *fighter, FightAction action) { + if (action == kFightAction4) { + setSequenceAndDraw(fighter, 5, kFightSequenceType1); + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + } else { + if (action != kFightAction131) + handleAction(fighter, action); + } +} + +void Fight::updateOpponentMilos(Fighter *fighter) { + // This is an opponent struct! + Opponent *opponent = (Opponent *)fighter; + + if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { + + if (opponent->opponent->field_34 >= 2) { + switch (rnd(5)) { + default: + break; + + case 0: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType1); + break; + + case 3: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 4: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + } + } else { + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + } + + // Update field_38 + if (opponent->opponent->field_34 < 5) + opponent->field_38 = 6 * (5 - opponent->opponent->field_34); + else + opponent->field_38 = 0; + } + + if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { + if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) + CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); + + if (opponent->opponent->countdown <= 0) { + getSound()->removeFromQueue(kEntityTables0); + CALL_FUNCTION1(opponent, handleAction, kFightActionLost); + } + } + + updateOpponent(opponent); +} + +////////////////////////////////////////////////////////////////////////// +// Anna +////////////////////////////////////////////////////////////////////////// + +void Fight::loadAnnaPlayer() { + if (!_data) + error("Fight::loadAnnaPlayer - invalid data!"); + + // Special case: we are using some shared functions directly + _data->player->handleAction = new Common::Functor2Mem(this, &Fight::handleActionAnna); + _data->player->update = new Common::Functor1Mem(this, &Fight::update); + _data->player->canInteract = new Common::Functor2Mem(this, &Fight::canInteract); + + _data->player->sequences.push_back(loadSequence("2002cr.seq")); + _data->player->sequences.push_back(loadSequence("2002cdl.seq")); + _data->player->sequences.push_back(loadSequence("2002cdr.seq")); + _data->player->sequences.push_back(loadSequence("2002cdm.seq")); + _data->player->sequences.push_back(loadSequence("2002lbk.seq")); +} + +void Fight::loadAnnaOpponent() { + if (!_data) + error("Fight::loadAnnaOpponent - invalid data!"); + + // Special case: we are using some shared functions directly + _data->opponent->handleAction = new Common::Functor2Mem(this, &Fight::handleAction); + _data->opponent->update = new Common::Functor1Mem(this, &Fight::updateOpponentAnna); + _data->opponent->canInteract = new Common::Functor2Mem(this, &Fight::canInteract); + + _data->opponent->sequences.push_back(loadSequence("2002or.seq")); + _data->opponent->sequences.push_back(loadSequence("2002oal.seq")); + _data->opponent->sequences.push_back(loadSequence("2002oam.seq")); + _data->opponent->sequences.push_back(loadSequence("2002oar.seq")); + _data->opponent->sequences.push_back(loadSequence("2002okr.seq")); + _data->opponent->sequences.push_back(loadSequence("2002okml.seq")); + _data->opponent->sequences.push_back(loadSequence("2002okm.seq")); + + getSound()->playSound(kEntityTables0, "MUS030", SoundManager::kFlagDefault); + + _data->opponent->field_38 = 30; +} + +void Fight::handleActionAnna(Fighter *fighter, FightAction action) { + switch (action) { + default: + handleAction(fighter, action); + return; + + case kFightAction1: + if ((fighter->sequenceIndex != 1 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 4, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction2: + if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 4, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction3: + if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 1) || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 4, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction128: + switch (fighter->opponent->sequenceIndex) { + default: + setSequenceAndDraw(fighter, 3, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(fighter, 1, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(fighter, 3, kFightSequenceType0); + break; + + case 3: + setSequenceAndDraw(fighter, 2, kFightSequenceType0); + break; + } + break; + } + + if (fighter->field_34 > 4) { + getSound()->removeFromQueue(kEntityTables0); + bailout(kFightEndWin); + } +} + +void Fight::updateOpponentAnna(Fighter *fighter) { + // This is an opponent struct! + Opponent *opponent = (Opponent *)fighter; + + if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { + + if (opponent->opponent->field_34 >= 2) { + switch (rnd(6)) { + default: + break; + + case 0: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(opponent, 3, kFightSequenceType0); + break; + + case 3: + setSequenceAndDraw(opponent, 3, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 4: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 5: + setSequenceAndDraw(opponent, 3, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + } + } + + // Update field_38 + opponent->field_38 = (int32)rnd(15); + } + + if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { + if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 3) + CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); + + if (opponent->opponent->countdown <= 0) { + getSound()->removeFromQueue(kEntityTables0); + CALL_FUNCTION1(opponent, handleAction, kFightActionLost); + } + } + + updateOpponent(opponent); +} + +////////////////////////////////////////////////////////////////////////// +// Ivo +////////////////////////////////////////////////////////////////////////// + +void Fight::loadIvoPlayer() { + REGISTER_PLAYER_FUNCTIONS(Ivo) + + _data->player->sequences.push_back(loadSequence("2003cr.seq")); + _data->player->sequences.push_back(loadSequence("2003car.seq")); + _data->player->sequences.push_back(loadSequence("2003cal.seq")); + _data->player->sequences.push_back(loadSequence("2003cdr.seq")); + _data->player->sequences.push_back(loadSequence("2003cdm.seq")); + _data->player->sequences.push_back(loadSequence("2003chr.seq")); + _data->player->sequences.push_back(loadSequence("2003chl.seq")); + _data->player->sequences.push_back(loadSequence("2003ckr.seq")); + _data->player->sequences.push_back(loadSequence("2003lbk.seq")); + _data->player->sequences.push_back(loadSequence("2003fbk.seq")); + + _data->player->countdown = 5; +} + +void Fight::loadIvoOpponent() { + REGISTER_OPPONENT_FUNCTIONS(Ivo) + + _data->opponent->sequences.push_back(loadSequence("2003or.seq")); + _data->opponent->sequences.push_back(loadSequence("2003oal.seq")); + _data->opponent->sequences.push_back(loadSequence("2003oar.seq")); + _data->opponent->sequences.push_back(loadSequence("2003odm.seq")); + _data->opponent->sequences.push_back(loadSequence("2003okl.seq")); + _data->opponent->sequences.push_back(loadSequence("2003okj.seq")); + _data->opponent->sequences.push_back(loadSequence("blank.seq")); + _data->opponent->sequences.push_back(loadSequence("csdr.seq")); + _data->opponent->sequences.push_back(loadSequence("2003l.seq")); + + getSound()->playSound(kEntityTables0, "MUS032", SoundManager::kFlagDefault); + + _data->opponent->countdown = 5; + _data->opponent->field_38 = 15; +} + +void Fight::handleActionIvo(Fighter *fighter, FightAction action) { + switch (action) { + default: + handleAction(fighter, action); + return; + + case kFightAction1: + if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 7, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } + break; + + case kFightAction2: + if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 7, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } + break; + + case kFightAction128: + switch (fighter->opponent->sequenceIndex) { + default: + case 1: + setSequenceAndDraw(fighter, 1, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(fighter, 2, kFightSequenceType0); + break; + } + break; + + case kFightAction129: + setSequenceAndDraw(fighter, (fighter->opponent->countdown > 1) ? 4 : 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0); + break; + + case kFightAction130: + setSequenceAndDraw(fighter, 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0); + break; + } +} + +void Fight::updateIvo(Fighter *fighter) { + + if ((fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) && !fighter->frameIndex) + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction131); + + if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { + + // Draw sequences + if (fighter->opponent->countdown <= 0) { + setSequenceAndDraw(fighter, 9, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, 8, kFightSequenceType1); + getSound()->removeFromQueue(kEntityTables0); + + CALL_FUNCTION1(fighter, handleAction, kFightActionWin); + return; + } + + if (fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) + CALL_FUNCTION1(fighter->opponent, handleAction, (FightAction)fighter->sequenceIndex); + } + + update(fighter); +} + +bool Fight::canInteractIvo(Fighter const *fighter, FightAction action) { + if (action == kFightAction129 || action == kFightAction130) + return (fighter->sequenceIndex >= 8); + + return canInteract(fighter); +} + +void Fight::handleOpponentActionIvo(Fighter *fighter, FightAction action) { + // This is an opponent struct! + Opponent *opponent = (Opponent *)fighter; + + switch (action) { + default: + handleAction(fighter, action); + break; + + case kFightAction3: + if ((opponent->sequenceIndex != 1 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) { + setSequenceAndDraw(opponent, 6, kFightSequenceType1); + setSequenceAndDraw(opponent->opponent, 6, kFightSequenceType1); + CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103); + } + break; + + case kFightAction4: + if ((opponent->sequenceIndex != 2 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) { + setSequenceAndDraw(opponent, 6, kFightSequenceType1); + setSequenceAndDraw(opponent->opponent, 5, kFightSequenceType1); + CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103); + } + break; + + case kFightAction131: + if (opponent->sequenceIndex) + break; + + if (rnd(100) <= (unsigned int)(opponent->countdown > 2 ? 60 : 75)) { + setSequenceAndDraw(opponent, 3 , kFightSequenceType1); + if (opponent->opponent->sequenceIndex == 4) + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + } + break; + } +} + +void Fight::updateOpponentIvo(Fighter *fighter) { + // This is an opponent struct! + Opponent *opponent = (Opponent *)fighter; + + if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { + + if (opponent->opponent->field_34 >= 2) { + switch (rnd(5)) { + default: + break; + + case 0: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 3: + setSequenceAndDraw(opponent, 0, kFightSequenceType2); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + + case 4: + setSequenceAndDraw(opponent, 0, kFightSequenceType1); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + } + } + + // Update field_38 + opponent->field_38 = 3 * opponent->countdown + (int32)rnd(10); + } + + if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { + + if (opponent->opponent->countdown <= 0) { + setSequenceAndDraw(opponent, 7, kFightSequenceType1); + setSequenceAndDraw(opponent->opponent, 8, kFightSequenceType1); + getSound()->removeFromQueue(kEntityTables0); + + CALL_FUNCTION1(opponent->opponent, handleAction, kFightActionWin); + + return; + } + + if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) + CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); + } + + updateOpponent(opponent); +} + +////////////////////////////////////////////////////////////////////////// +// Salko +////////////////////////////////////////////////////////////////////////// + +void Fight::loadSalkoPlayer() { + REGISTER_PLAYER_FUNCTIONS(Salko) + + _data->player->sequences.push_back(loadSequence("2004cr.seq")); + _data->player->sequences.push_back(loadSequence("2004cdr.seq")); + _data->player->sequences.push_back(loadSequence("2004chj.seq")); + _data->player->sequences.push_back(loadSequence("2004bk.seq")); + + _data->player->countdown = 2; +} + +void Fight::loadSalkoOpponent() { + REGISTER_OPPONENT_FUNCTIONS(Salko) + + _data->opponent->sequences.push_back(loadSequence("2004or.seq")); + _data->opponent->sequences.push_back(loadSequence("2004oam.seq")); + _data->opponent->sequences.push_back(loadSequence("2004oar.seq")); + _data->opponent->sequences.push_back(loadSequence("2004okr.seq")); + _data->opponent->sequences.push_back(loadSequence("2004ohm.seq")); + _data->opponent->sequences.push_back(loadSequence("blank.seq")); + + getSound()->playSound(kEntityTables0, "MUS035", SoundManager::kFlagDefault); + + _data->opponent->countdown = 3; + _data->opponent->field_38 = 30; +} + +void Fight::handleActionSalko(Fighter *fighter, FightAction action) { + switch (action) { + default: + handleAction(fighter, action); + return; + + case kFightAction1: + case kFightAction2: + if (fighter->sequenceIndex != 1 && CHECK_SEQUENCE2(fighter, 4)) { + fighter->field_34 = 0; + + setSequenceAndDraw(fighter, 3, kFightSequenceType1); + setSequenceAndDraw(fighter->opponent, (action == kFightAction1 ? 3 : 4), kFightSequenceType1); + + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + + if (action == kFightAction2) + fighter->countdown= 0; + + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction5: + if (fighter->sequenceIndex != 3) { + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } + break; + + case kFightAction128: + setSequenceAndDraw(fighter, 1, kFightSequenceType0); + fighter->field_34 = 0; + break; + + case kFightAction131: + setSequenceAndDraw(fighter, 2, (fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0)); + break; + } +} + +void Fight::updateSalko(Fighter *fighter) { + update(fighter); + + // The original doesn't check for currentSequence2 != NULL (might not happen when everything is working properly, but crashes with our current implementation) + if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { + + if (fighter->opponent->countdown <= 0) { + getSound()->removeFromQueue(kEntityTables0); + bailout(kFightEndWin); + + return; + } + + if (fighter->sequenceIndex == 2) + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction2); + } +} + +bool Fight::canInteractSalko(Fighter const *fighter, FightAction action) { + if (action == kFightAction131) { + if (fighter->sequenceIndex == 1) { + if (fighter->opponent->countdown <= 0) + _engine->getCursor()->setStyle(kCursorHand); + + return true; + } + + return false; + } + + return canInteract(fighter); +} + +void Fight::handleOpponentActionSalko(Fighter *fighter, FightAction action) { + if (action == kFightAction2) { + setSequenceAndDraw(fighter, 5, kFightSequenceType1); + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + } else { + handleAction(fighter, action); + } +} + +void Fight::updateOpponentSalko(Fighter *fighter) { + // This is an opponent struct + Opponent *opponent = (Opponent *)fighter; + + if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { + + switch (rnd(5)) { + default: + break; + + case 0: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + break; + + case 2: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 3: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + + case 4: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + } + + // Update field_38 + opponent->field_38 = 4 * opponent->countdown; + } + + if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { + if (opponent->opponent->countdown <= 0) { + getSound()->removeFromQueue(kEntityTables0); + bailout(kFightEndLost); + + // Stop processing + return; + } + + if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) + CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); + } + + updateOpponent(opponent); +} + +////////////////////////////////////////////////////////////////////////// +// Vesna +////////////////////////////////////////////////////////////////////////// + +void Fight::loadVesnaPlayer() { + REGISTER_PLAYER_FUNCTIONS(Vesna) + + _data->player->sequences.push_back(loadSequence("2005cr.seq")); + _data->player->sequences.push_back(loadSequence("2005cdr.seq")); + _data->player->sequences.push_back(loadSequence("2005cbr.seq")); + _data->player->sequences.push_back(loadSequence("2005bk.seq")); + _data->player->sequences.push_back(loadSequence("2005cdm1.seq")); + _data->player->sequences.push_back(loadSequence("2005chl.seq")); +} + +void Fight::loadVesnaOpponent() { + REGISTER_OPPONENT_FUNCTIONS(Vesna) + + _data->opponent->sequences.push_back(loadSequence("2005or.seq")); + _data->opponent->sequences.push_back(loadSequence("2005oam.seq")); + _data->opponent->sequences.push_back(loadSequence("2005oar.seq")); + _data->opponent->sequences.push_back(loadSequence("2005okml.seq")); + _data->opponent->sequences.push_back(loadSequence("2005okr.seq")); + _data->opponent->sequences.push_back(loadSequence("2005odm1.seq")); + _data->opponent->sequences.push_back(loadSequence("2005csbm.seq")); + _data->opponent->sequences.push_back(loadSequence("2005oam4.seq")); + + getSound()->playSound(kEntityTables0, "MUS038", SoundManager::kFlagDefault); + + _data->opponent->countdown = 4; + _data->opponent->field_38 = 30; +} + +void Fight::handleActionVesna(Fighter *fighter, FightAction action) { + switch (action) { + default: + handleAction(fighter, action); + return; + + case kFightAction1: + if (fighter->sequenceIndex != 1) { + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction2: + if (fighter->sequenceIndex != 2) { + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } else { + fighter->field_34++; + } + break; + + case kFightAction5: + if (fighter->sequenceIndex != 3) { + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + CALL_FUNCTION0(fighter, update); + } + break; + + case kFightAction128: + if (fighter->sequenceIndex == 1 && fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) { + setSequenceAndDraw(fighter, 5, kFightSequenceType1); + } else { + setSequenceAndDraw(fighter, (fighter->opponent->sequenceIndex == 5) ? 3 : 1, kFightSequenceType0); + } + break; + + case kFightAction132: + setSequenceAndDraw(fighter, 2, kFightSequenceType0); + break; + } + + if (fighter->field_34 > 10) { + setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType2); + fighter->opponent->countdown = 1; + fighter->field_34 = 0; + } +} + +void Fight::updateVesna(Fighter *fighter) { + if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { + + if (fighter->sequenceIndex == 3) + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction3); + + if (fighter->opponent->countdown <= 0) { + getSound()->removeFromQueue(kEntityTables0); + bailout(kFightEndWin); + return; + } + + if (fighter->sequenceIndex == 5) + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction5); + } + + update(fighter); +} + +bool Fight::canInteractVesna(Fighter const *fighter, FightAction action) { + if (action != kFightAction128) + return canInteract(fighter); + + if (fighter->sequenceIndex != 1) { + + if (fighter->opponent->sequenceIndex == 5) { + _engine->getCursor()->setStyle(kCursorDown); + return true; + } + + return canInteract(fighter); + } + + if (fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) { + _engine->getCursor()->setStyle(kCursorPunchLeft); + return true; + } + + return false; +} + +void Fight::handleOpponentActionVesna(Fighter *fighter, FightAction action) { + switch (action) { + default: + handleAction(fighter, action); + break; + + case kFightAction3: + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + break; + + case kFightAction5: + setSequenceAndDraw(fighter, 7, kFightSequenceType1); + CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); + if (fighter->countdown <= 1) + fighter->countdown = 1; + break; + + case kFightAction131: + break; + } +} + +void Fight::updateOpponentVesna(Fighter *fighter) { + // This is an opponent struct + Opponent *opponent = (Opponent *)fighter; + + if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { + + if (opponent->opponent->field_34 == 1) { + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + } else { + switch (rnd(6)) { + default: + break; + + case 0: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + break; + + case 1: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + + case 2: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + break; + + case 3: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 4: + setSequenceAndDraw(opponent, 1, kFightSequenceType0); + setSequenceAndDraw(opponent, 2, kFightSequenceType2); + break; + + case 5: + setSequenceAndDraw(opponent, 2, kFightSequenceType0); + setSequenceAndDraw(opponent, 1, kFightSequenceType2); + break; + } + } + + // Update field_38 + opponent->field_38 = 4 * opponent->countdown; + } + + if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { + if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 5) + CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); + + if (opponent->opponent->countdown <= 0) { + + switch (opponent->sequenceIndex) { + default: + break; + + case 1: + setSequenceAndDraw(opponent, 3, kFightSequenceType1); + break; + + case 2: + setSequenceAndDraw(opponent, 4, kFightSequenceType1); + break; + + case 5: + setSequenceAndDraw(opponent, 6, kFightSequenceType1); + break; + } + + setSequenceAndDraw(opponent->opponent, 4, kFightSequenceType1); + + CALL_FUNCTION1(opponent, handleAction, kFightActionLost); + CALL_FUNCTION0(opponent->opponent, update); + CALL_FUNCTION0(opponent, update); + + getSound()->removeFromQueue(kEntityTables0); + + // Stop processing + return; + } + } + + updateOpponent(opponent); +} + +} // End of namespace LastExpress diff --git a/engines/lastexpress/fight/fight.h b/engines/lastexpress/fight/fight.h new file mode 100644 index 0000000000..a33cc93a29 --- /dev/null +++ b/engines/lastexpress/fight/fight.h @@ -0,0 +1,266 @@ +/* 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 LASTEXPRESS_FIGHT_H +#define LASTEXPRESS_FIGHT_H + +/* + Fight structure + --------------- + uint32 {4} - player struct + uint32 {4} - opponent struct + uint32 {4} - hasLost flag + + byte {1} - isRunning + + Fight participant structure + --------------------------- + uint32 {4} - function pointer + uint32 {4} - pointer to fight structure + uint32 {4} - pointer to opponent (fight participant structure) + uint32 {4} - array of sequences + uint32 {4} - number of sequences + uint32 {4} - ?? + uint32 {4} - ?? + uint32 {4} - ?? + uint32 {4} - ?? + uint32 {4} - ?? + uint32 {4} - ?? + uint32 {4} - ?? + uint32 {4} - ?? + uint16 {2} - ?? + uint16 {2} - ?? - only for opponent structure + uint32 {4} - ?? - only for opponent structure + +*/ + +#include "lastexpress/shared.h" + +#include "lastexpress/eventhandler.h" + +#include "common/array.h" + +namespace LastExpress { + +class LastExpressEngine; +class Sequence; +class SequenceFrame; + +////////////////////////////////////////////////////////////////////////// +// TODO : objectify! +class Fight : public EventHandler { +public: + enum FightEndType { + kFightEndWin = 0, + kFightEndLost = 1, + kFightEndExit = 2 + }; + + Fight(LastExpressEngine *engine); + ~Fight(); + + FightEndType setup(FightType type); + + void eventMouse(const Common::Event &ev); + void eventTick(const Common::Event &ev); + + void setStopped(); + void resetState() { _state = 0; } + +private: + enum FightSequenceType { + kFightSequenceType0 = 0, + kFightSequenceType1 = 1, + kFightSequenceType2 = 2 + }; + + enum FightAction { + kFightAction1 = 1, + kFightAction2 = 2, + kFightAction3 = 3, + kFightAction4 = 4, + kFightAction5 = 5, + kFightAction101 = 101, + kFightActionResetFrame = 102, + kFightAction103 = 103, + kFightActionWin = 104, + kFightActionLost = 105, + kFightAction128 = 128, + kFightAction129 = 129, + kFightAction130 = 130, + kFightAction131 = 131, + kFightAction132 = 132 + }; + + struct Fighter { + Common::Functor2 *handleAction; + Common::Functor1 *update; + Common::Functor2 *canInteract; + Fighter *opponent; + Common::Array sequences; + uint32 sequenceIndex; + Sequence *sequence; + SequenceFrame *frame; + uint32 frameIndex; + uint32 field_24; + FightAction action; + uint32 sequenceIndex2; + int32 countdown; // countdown before loosing ? + uint32 field_34; + + Fighter() { + handleAction = NULL; + update = NULL; + canInteract = NULL; + + opponent = NULL; + + sequenceIndex = 0; + sequence = NULL; + frame = NULL; + frameIndex = 0; + + field_24 = 0; + + action = kFightAction101; + sequenceIndex2 = 0; + + countdown = 1; + + field_34 = 0; + } + }; + + // Opponent struct + struct Opponent : Fighter { + int32 field_38; + + Opponent() : Fighter() { + field_38 = 0; + } + }; + + struct FightData { + Fighter *player; + Opponent *opponent; + int32 index; + + Sequence *sequences[20]; + Common::String names[20]; + + bool isRunning; + + FightData() { + player = new Fighter(); + opponent = new Opponent(); + + // Set opponents + player->opponent = opponent; + opponent->opponent = player; + + index = 0; + + isRunning = false; + } + }; + + LastExpressEngine *_engine; + FightData *_data; + FightEndType _endType; + int _state; + + bool _handleTimer; + + // Events + void handleTick(const Common::Event &ev, bool unknown); + + // State + void bailout(FightEndType type); + + + // Drawing + void setSequenceAndDraw(Fighter *fighter, uint32 sequenceIndex, FightSequenceType type) const; + void draw(Fighter *fighter) const; + + // Cleanup + void clearData(); + void clearSequences(Fighter *fighter) const; + + ////////////////////////////////////////////////////////////////////////// + // Loading + void loadData(FightType type); + + // Shared + void processFighter(Fighter *fighter); + + // Default functions + void handleAction(Fighter *fighter, FightAction action); + void update(Fighter *fighter); + bool canInteract(Fighter const *fighter, FightAction = (FightAction)0); + void updateOpponent(Fighter *fighter); + + // Milos + void loadMilosPlayer(); + void loadMilosOpponent(); + void handleActionMilos(Fighter *fighter, FightAction action); + void updateMilos(Fighter *fighter); + bool canInteractMilos(Fighter const *fighter, FightAction action); + void handleOpponentActionMilos(Fighter *fighter, FightAction action); + void updateOpponentMilos(Fighter *fighter); + + // Anna + void loadAnnaPlayer(); + void loadAnnaOpponent(); + void handleActionAnna(Fighter *fighter, FightAction action); + void updateOpponentAnna(Fighter *fighter); + + // Ivo + void loadIvoPlayer(); + void loadIvoOpponent(); + void handleActionIvo(Fighter *fighter, FightAction action); + void updateIvo(Fighter *fighter); + bool canInteractIvo(Fighter const *fighter, FightAction action); + void handleOpponentActionIvo(Fighter *fighter, FightAction action); + void updateOpponentIvo(Fighter *fighter); + + // Salko + void loadSalkoPlayer(); + void loadSalkoOpponent(); + void handleActionSalko(Fighter *fighter, FightAction action); + void updateSalko(Fighter *fighter); + bool canInteractSalko(Fighter const *fighter, FightAction action); + void handleOpponentActionSalko(Fighter *fighter, FightAction action); + void updateOpponentSalko(Fighter *fighter); + + // Vesna + void loadVesnaPlayer(); + void loadVesnaOpponent(); + void handleActionVesna(Fighter *fighter, FightAction action); + void updateVesna(Fighter *fighter); + bool canInteractVesna(Fighter const *fighter, FightAction action); + void handleOpponentActionVesna(Fighter *fighter, FightAction action); + void updateOpponentVesna(Fighter *fighter); +}; + +} // End of namespace LastExpress + +#endif // LASTEXPRESS_FIGHT_H diff --git a/engines/lastexpress/game/fight.cpp b/engines/lastexpress/game/fight.cpp deleted file mode 100644 index ecc43bed2b..0000000000 --- a/engines/lastexpress/game/fight.cpp +++ /dev/null @@ -1,1583 +0,0 @@ -/* 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/game/fight.h" - -#include "lastexpress/data/cursor.h" -#include "lastexpress/data/scene.h" -#include "lastexpress/data/sequence.h" - -#include "lastexpress/game/entities.h" -#include "lastexpress/game/inventory.h" -#include "lastexpress/game/logic.h" -#include "lastexpress/game/object.h" -#include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" -#include "lastexpress/game/state.h" - -#include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" -#include "lastexpress/lastexpress.h" -#include "lastexpress/resource.h" - -#include "common/func.h" - -namespace LastExpress { - -#define CALL_FUNCTION0(fighter, name) \ - (*fighter->name)(fighter) - -#define CALL_FUNCTION1(fighter, name, a) \ - (*fighter->name)(fighter, a) - -#define REGISTER_PLAYER_FUNCTIONS(name) \ - if (!_data) \ - error("Fight::load##namePlayer - invalid data!"); \ - _data->player->handleAction = new Common::Functor2Mem(this, &Fight::handleAction##name); \ - _data->player->update = new Common::Functor1Mem(this, &Fight::update##name); \ - _data->player->canInteract = new Common::Functor2Mem(this, &Fight::canInteract##name); - -#define REGISTER_OPPONENT_FUNCTIONS(name) \ - if (!_data) \ - error("Fight::load##nameOpponent - invalid data!"); \ - _data->opponent->handleAction = new Common::Functor2Mem(this, &Fight::handleOpponentAction##name); \ - _data->opponent->update = new Common::Functor1Mem(this, &Fight::updateOpponent##name); \ - _data->opponent->canInteract = new Common::Functor2Mem(this, &Fight::canInteract); - -#define CHECK_SEQUENCE2(fighter, value) \ - (fighter->frame->getInfo()->field_33 & value) - -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) { - getSound()->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 (CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) { - if (ev.type == Common::EVENT_LBUTTONUP) - CALL_FUNCTION1(_data->player, handleAction, (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; - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndExit); - } - - // Reset timer on right click - if (ev.type == Common::EVENT_RBUTTONUP) { - if (getGlobalTimer()) { - if (getSound()->isBuffered("TIMER")) - getSound()->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::handleMouseMove - egg blinking not implemented!"); - } - - if (!_data || _data->index) - return; - - SceneHotspot *hotspot = NULL; - if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) { - _engine->getCursor()->setStyle(kCursorNormal); - } else { - _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor); - } - - CALL_FUNCTION0(_data->player, update); - CALL_FUNCTION0(_data->opponent, update); - - // Draw sequences - if (!_data->isRunning) - 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->isRunning) { - if (_engine->handleEvents()) - continue; - - getSound()->updateQueue(); - } - - // Cleanup after fight is over - clearData(); - - return _endType; -} - -////////////////////////////////////////////////////////////////////////// -// Status -////////////////////////////////////////////////////////////////////////// - -void Fight::setStopped() { - if (_data) - _data->isRunning = false; -} - -void Fight::bailout(FightEndType type) { - _state = 0; - _endType = type; - setStopped(); -} - -////////////////////////////////////////////////////////////////////////// -// Cleanup -////////////////////////////////////////////////////////////////////////// - -void Fight::clearData() { - if (!_data) - return; - - // Clear data - clearSequences(_data->player); - clearSequences(_data->opponent); - - SAFE_DELETE(_data->player); - SAFE_DELETE(_data->opponent); - - SAFE_DELETE(_data); - - _engine->restoreEventHandlers(); -} - -void Fight::clearSequences(Fighter *combatant) const { - if (!combatant) - return; - - // The original game resets the function pointers to default values, just before deleting the struct - getScenes()->removeAndRedraw(&combatant->frame, false); - - // Free sequences - for (int i = 0; i < (int)combatant->sequences.size(); i++) - SAFE_DELETE(combatant->sequences[i]); -} - -////////////////////////////////////////////////////////////////////////// -// Drawing -////////////////////////////////////////////////////////////////////////// - -void Fight::setSequenceAndDraw(Fighter *combatant, uint32 sequenceIndex, FightSequenceType type) const { - if (combatant->sequences.size() < sequenceIndex) - return; - - switch (type) { - default: - break; - - case kFightSequenceType0: - if (combatant->sequenceIndex) - return; - - combatant->sequence = combatant->sequences[sequenceIndex]; - combatant->sequenceIndex = sequenceIndex; - draw(combatant); - break; - - case kFightSequenceType1: - combatant->sequence = combatant->sequences[sequenceIndex]; - combatant->sequenceIndex = sequenceIndex; - combatant->sequenceIndex2 = 0; - draw(combatant); - break; - - case kFightSequenceType2: - combatant->sequenceIndex2 = sequenceIndex; - break; - } -} - -void Fight::draw(Fighter *combatant) const { - getScenes()->removeAndRedraw(&combatant->frame, false); - - combatant->frameIndex = 0; - combatant->field_24 = 0; -} - -////////////////////////////////////////////////////////////////////////// -// Loading -////////////////////////////////////////////////////////////////////////// - -void Fight::loadData(FightType type) { - if (!_data) - error("Fight::loadData - invalid data!"); - - switch (type) { - default: - break; - - case kFightMilos: - loadMilosPlayer(); - loadMilosOpponent(); - break; - - case kFightAnna: - loadAnnaPlayer(); - loadAnnaOpponent(); - break; - - case kFightIvo: - loadIvoPlayer(); - loadIvoOpponent(); - break; - - case kFightSalko: - loadSalkoPlayer(); - loadSalkoOpponent(); - break; - - case kFightVesna: - loadVesnaPlayer(); - loadVesnaOpponent(); - break; - } - - if (!_data->player || !_data->opponent) - error("Fight::loadData - error loading fight data (type=%d)", type); - - ////////////////////////////////////////////////////////////////////////// - // Start running the fight - _data->isRunning = true; - - if (_state < 5) { - setSequenceAndDraw(_data->player, 0, kFightSequenceType0); - setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0); - goto end_load; - } - - switch(type) { - default: - break; - - case kFightMilos: - _data->opponent->countdown = 1; - setSequenceAndDraw(_data->player, 4, kFightSequenceType0); - setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0); - break; - - case kFightIvo: - _data->opponent->countdown = 1; - setSequenceAndDraw(_data->player, 3, kFightSequenceType0); - setSequenceAndDraw(_data->opponent, 6, kFightSequenceType0); - break; - - case kFightVesna: - _data->opponent->countdown = 1; - setSequenceAndDraw(_data->player, 0, kFightSequenceType0); - setSequenceAndDraw(_data->player, 3, kFightSequenceType2); - setSequenceAndDraw(_data->opponent, 5, kFightSequenceType0); - break; - } - -end_load: - // Setup event handlers - _engine->backupEventHandlers(); - SET_EVENT_HANDLERS(Fight, this); -} - -////////////////////////////////////////////////////////////////////////// -// Shared -////////////////////////////////////////////////////////////////////////// -void Fight::processFighter(Fighter *fighter) { - if (!_data) - error("Fight::processFighter - invalid data!"); - - if (!fighter->sequence) { - if (fighter->frame) { - getScenes()->removeFromQueue(fighter->frame); - getScenes()->setCoordinates(fighter->frame); - } - SAFE_DELETE(fighter->frame); - return; - } - - if (fighter->sequence->count() <= fighter->frameIndex) { - switch(fighter->action) { - default: - break; - - case kFightAction101: - setSequenceAndDraw(fighter, fighter->sequenceIndex2, kFightSequenceType1); - fighter->sequenceIndex2 = 0; - break; - - case kFightActionResetFrame: - fighter->frameIndex = 0; - break; - - case kFightAction103: - setSequenceAndDraw(fighter, 0, kFightSequenceType1); - CALL_FUNCTION1(fighter, handleAction, kFightAction101); - setSequenceAndDraw(fighter->opponent, 0, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction101); - CALL_FUNCTION0(fighter->opponent, update); - break; - - case kFightActionWin: - bailout(kFightEndWin); - break; - - case kFightActionLost: - bailout(kFightEndLost); - break; - } - } - - if (_data->isRunning) { - - // Get the current sequence frame - SequenceFrame *frame = new SequenceFrame(fighter->sequence, (uint16)fighter->frameIndex); - frame->getInfo()->location = 1; - - if (fighter->frame == frame) { - delete frame; - return; - } - - getSound()->playFightSound(frame->getInfo()->soundAction, frame->getInfo()->field_31); - - // Add current frame to queue and advance - getScenes()->addToQueue(frame); - fighter->frameIndex++; - - if (fighter->frame) { - getScenes()->removeFromQueue(fighter->frame); - - if (!frame->getInfo()->field_2E) - getScenes()->setCoordinates(fighter->frame); - } - - // Replace by new frame - delete fighter->frame; - fighter->frame = frame; - } -} - -void Fight::handleAction(Fighter *fighter, FightAction action) { - switch (action) { - default: - return; - - case kFightAction101: - break; - - case kFightActionResetFrame: - fighter->countdown--; - break; - - case kFightAction103: - CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); - break; - - case kFightActionWin: - _endType = kFightEndWin; - CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); - break; - - case kFightActionLost: - _endType = kFightEndLost; - CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); - break; - } - - // Update action - fighter->action = action; -} - -bool Fight::canInteract(Fighter const *fighter, FightAction /*= (FightAction)0*/ ) { - return (fighter->action == kFightAction101 && !fighter->sequenceIndex); -} - -void Fight::update(Fighter *fighter) { - - processFighter(fighter); - - if (fighter->frame) - fighter->frame->getInfo()->location = (fighter->action == kFightActionResetFrame ? 2 : 0); -} - -void Fight::updateOpponent(Fighter *fighter) { - - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - processFighter(opponent); - - if (opponent->field_38 && !opponent->sequenceIndex) - opponent->field_38--; - - if (fighter->frame) - fighter->frame->getInfo()->location = 1; -} - -////////////////////////////////////////////////////////////////////////// -// Milos -////////////////////////////////////////////////////////////////////////// - -void Fight::loadMilosPlayer() { - REGISTER_PLAYER_FUNCTIONS(Milos) - - _data->player->sequences.push_back(loadSequence("2001cr.seq")); - _data->player->sequences.push_back(loadSequence("2001cdl.seq")); - _data->player->sequences.push_back(loadSequence("2001cdr.seq")); - _data->player->sequences.push_back(loadSequence("2001cdm.seq")); - _data->player->sequences.push_back(loadSequence("2001csgr.seq")); - _data->player->sequences.push_back(loadSequence("2001csgl.seq")); - _data->player->sequences.push_back(loadSequence("2001dbk.seq")); -} - -void Fight::loadMilosOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Milos) - - _data->opponent->sequences.push_back(loadSequence("2001or.seq")); - _data->opponent->sequences.push_back(loadSequence("2001oal.seq")); - _data->opponent->sequences.push_back(loadSequence("2001oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2001okl.seq")); - _data->opponent->sequences.push_back(loadSequence("2001okm.seq")); - _data->opponent->sequences.push_back(loadSequence("2001dbk.seq")); - _data->opponent->sequences.push_back(loadSequence("2001wbk.seq")); - - getSound()->playSound(kEntityTables0, "MUS027", SoundManager::kFlagDefault); - - _data->opponent->field_38 = 35; -} - -void Fight::handleActionMilos(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 6, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 3, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction2: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 6, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction128: - if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4) || fighter->opponent->sequenceIndex != 1) { - switch (fighter->opponent->sequenceIndex) { - default: - setSequenceAndDraw(fighter, rnd(3) + 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(fighter, 3, kFightSequenceType0); - break; - } - } else { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - CALL_FUNCTION0(fighter, update); - } - break; - } -} - -void Fight::updateMilos(Fighter *fighter) { - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - // Draw sequences - if (fighter->opponent->countdown <= 0) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1); - - getSound()->removeFromQueue(kEntityTables0); - getSound()->playSound(kEntityTrain, "MUS029", SoundManager::kFlagDefault); - - CALL_FUNCTION1(fighter, handleAction, kFightActionWin); - } - - if (fighter->sequenceIndex == 4) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction4); - _endType = kFightEndLost; - } - } - - update(fighter); -} - -bool Fight::canInteractMilos(Fighter const *fighter, FightAction action) { - if (!_data) - error("Fight::canInteractMilos - invalid data!"); - - if (action != kFightAction128 - || _data->player->sequenceIndex != 1 - || !fighter->frame - || CHECK_SEQUENCE2(fighter, 4) - || fighter->opponent->sequenceIndex != 1) { - return canInteract(fighter); - } - - _engine->getCursor()->setStyle(kCursorHand); - - return true; -} - -void Fight::handleOpponentActionMilos(Fighter *fighter, FightAction action) { - if (action == kFightAction4) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - } else { - if (action != kFightAction131) - handleAction(fighter, action); - } -} - -void Fight::updateOpponentMilos(Fighter *fighter) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 >= 2) { - switch (rnd(5)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType1); - break; - - case 3: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - } else { - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - } - - // Update field_38 - if (opponent->opponent->field_34 < 5) - opponent->field_38 = 6 * (5 - opponent->opponent->field_34); - else - opponent->field_38 = 0; - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - - if (opponent->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - CALL_FUNCTION1(opponent, handleAction, kFightActionLost); - } - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Anna -////////////////////////////////////////////////////////////////////////// - -void Fight::loadAnnaPlayer() { - if (!_data) - error("Fight::loadAnnaPlayer - invalid data!"); - - // Special case: we are using some shared functions directly - _data->player->handleAction = new Common::Functor2Mem(this, &Fight::handleActionAnna); - _data->player->update = new Common::Functor1Mem(this, &Fight::update); - _data->player->canInteract = new Common::Functor2Mem(this, &Fight::canInteract); - - _data->player->sequences.push_back(loadSequence("2002cr.seq")); - _data->player->sequences.push_back(loadSequence("2002cdl.seq")); - _data->player->sequences.push_back(loadSequence("2002cdr.seq")); - _data->player->sequences.push_back(loadSequence("2002cdm.seq")); - _data->player->sequences.push_back(loadSequence("2002lbk.seq")); -} - -void Fight::loadAnnaOpponent() { - if (!_data) - error("Fight::loadAnnaOpponent - invalid data!"); - - // Special case: we are using some shared functions directly - _data->opponent->handleAction = new Common::Functor2Mem(this, &Fight::handleAction); - _data->opponent->update = new Common::Functor1Mem(this, &Fight::updateOpponentAnna); - _data->opponent->canInteract = new Common::Functor2Mem(this, &Fight::canInteract); - - _data->opponent->sequences.push_back(loadSequence("2002or.seq")); - _data->opponent->sequences.push_back(loadSequence("2002oal.seq")); - _data->opponent->sequences.push_back(loadSequence("2002oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2002oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2002okr.seq")); - _data->opponent->sequences.push_back(loadSequence("2002okml.seq")); - _data->opponent->sequences.push_back(loadSequence("2002okm.seq")); - - getSound()->playSound(kEntityTables0, "MUS030", SoundManager::kFlagDefault); - - _data->opponent->field_38 = 30; -} - -void Fight::handleActionAnna(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if ((fighter->sequenceIndex != 1 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction2: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction3: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 1) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction128: - switch (fighter->opponent->sequenceIndex) { - default: - setSequenceAndDraw(fighter, 3, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(fighter, 3, kFightSequenceType0); - break; - - case 3: - setSequenceAndDraw(fighter, 2, kFightSequenceType0); - break; - } - break; - } - - if (fighter->field_34 > 4) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndWin); - } -} - -void Fight::updateOpponentAnna(Fighter *fighter) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 >= 2) { - switch (rnd(6)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 3, kFightSequenceType0); - break; - - case 3: - setSequenceAndDraw(opponent, 3, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 5: - setSequenceAndDraw(opponent, 3, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - } - } - - // Update field_38 - opponent->field_38 = (int32)rnd(15); - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 3) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - - if (opponent->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - CALL_FUNCTION1(opponent, handleAction, kFightActionLost); - } - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Ivo -////////////////////////////////////////////////////////////////////////// - -void Fight::loadIvoPlayer() { - REGISTER_PLAYER_FUNCTIONS(Ivo) - - _data->player->sequences.push_back(loadSequence("2003cr.seq")); - _data->player->sequences.push_back(loadSequence("2003car.seq")); - _data->player->sequences.push_back(loadSequence("2003cal.seq")); - _data->player->sequences.push_back(loadSequence("2003cdr.seq")); - _data->player->sequences.push_back(loadSequence("2003cdm.seq")); - _data->player->sequences.push_back(loadSequence("2003chr.seq")); - _data->player->sequences.push_back(loadSequence("2003chl.seq")); - _data->player->sequences.push_back(loadSequence("2003ckr.seq")); - _data->player->sequences.push_back(loadSequence("2003lbk.seq")); - _data->player->sequences.push_back(loadSequence("2003fbk.seq")); - - _data->player->countdown = 5; -} - -void Fight::loadIvoOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Ivo) - - _data->opponent->sequences.push_back(loadSequence("2003or.seq")); - _data->opponent->sequences.push_back(loadSequence("2003oal.seq")); - _data->opponent->sequences.push_back(loadSequence("2003oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2003odm.seq")); - _data->opponent->sequences.push_back(loadSequence("2003okl.seq")); - _data->opponent->sequences.push_back(loadSequence("2003okj.seq")); - _data->opponent->sequences.push_back(loadSequence("blank.seq")); - _data->opponent->sequences.push_back(loadSequence("csdr.seq")); - _data->opponent->sequences.push_back(loadSequence("2003l.seq")); - - getSound()->playSound(kEntityTables0, "MUS032", SoundManager::kFlagDefault); - - _data->opponent->countdown = 5; - _data->opponent->field_38 = 15; -} - -void Fight::handleActionIvo(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 7, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction2: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 7, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction128: - switch (fighter->opponent->sequenceIndex) { - default: - case 1: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(fighter, 2, kFightSequenceType0); - break; - } - break; - - case kFightAction129: - setSequenceAndDraw(fighter, (fighter->opponent->countdown > 1) ? 4 : 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0); - break; - - case kFightAction130: - setSequenceAndDraw(fighter, 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0); - break; - } -} - -void Fight::updateIvo(Fighter *fighter) { - - if ((fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) && !fighter->frameIndex) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction131); - - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - // Draw sequences - if (fighter->opponent->countdown <= 0) { - setSequenceAndDraw(fighter, 9, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 8, kFightSequenceType1); - getSound()->removeFromQueue(kEntityTables0); - - CALL_FUNCTION1(fighter, handleAction, kFightActionWin); - return; - } - - if (fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) - CALL_FUNCTION1(fighter->opponent, handleAction, (FightAction)fighter->sequenceIndex); - } - - update(fighter); -} - -bool Fight::canInteractIvo(Fighter const *fighter, FightAction action) { - if (action == kFightAction129 || action == kFightAction130) - return (fighter->sequenceIndex >= 8); - - return canInteract(fighter); -} - -void Fight::handleOpponentActionIvo(Fighter *fighter, FightAction action) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - switch (action) { - default: - handleAction(fighter, action); - break; - - case kFightAction3: - if ((opponent->sequenceIndex != 1 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) { - setSequenceAndDraw(opponent, 6, kFightSequenceType1); - setSequenceAndDraw(opponent->opponent, 6, kFightSequenceType1); - CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103); - } - break; - - case kFightAction4: - if ((opponent->sequenceIndex != 2 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) { - setSequenceAndDraw(opponent, 6, kFightSequenceType1); - setSequenceAndDraw(opponent->opponent, 5, kFightSequenceType1); - CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103); - } - break; - - case kFightAction131: - if (opponent->sequenceIndex) - break; - - if (rnd(100) <= (unsigned int)(opponent->countdown > 2 ? 60 : 75)) { - setSequenceAndDraw(opponent, 3 , kFightSequenceType1); - if (opponent->opponent->sequenceIndex == 4) - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - } - break; - } -} - -void Fight::updateOpponentIvo(Fighter *fighter) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 >= 2) { - switch (rnd(5)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 3: - setSequenceAndDraw(opponent, 0, kFightSequenceType2); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 0, kFightSequenceType1); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - } - - // Update field_38 - opponent->field_38 = 3 * opponent->countdown + (int32)rnd(10); - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - - if (opponent->opponent->countdown <= 0) { - setSequenceAndDraw(opponent, 7, kFightSequenceType1); - setSequenceAndDraw(opponent->opponent, 8, kFightSequenceType1); - getSound()->removeFromQueue(kEntityTables0); - - CALL_FUNCTION1(opponent->opponent, handleAction, kFightActionWin); - - return; - } - - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Salko -////////////////////////////////////////////////////////////////////////// - -void Fight::loadSalkoPlayer() { - REGISTER_PLAYER_FUNCTIONS(Salko) - - _data->player->sequences.push_back(loadSequence("2004cr.seq")); - _data->player->sequences.push_back(loadSequence("2004cdr.seq")); - _data->player->sequences.push_back(loadSequence("2004chj.seq")); - _data->player->sequences.push_back(loadSequence("2004bk.seq")); - - _data->player->countdown = 2; -} - -void Fight::loadSalkoOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Salko) - - _data->opponent->sequences.push_back(loadSequence("2004or.seq")); - _data->opponent->sequences.push_back(loadSequence("2004oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2004oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2004okr.seq")); - _data->opponent->sequences.push_back(loadSequence("2004ohm.seq")); - _data->opponent->sequences.push_back(loadSequence("blank.seq")); - - getSound()->playSound(kEntityTables0, "MUS035", SoundManager::kFlagDefault); - - _data->opponent->countdown = 3; - _data->opponent->field_38 = 30; -} - -void Fight::handleActionSalko(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - case kFightAction2: - if (fighter->sequenceIndex != 1 && CHECK_SEQUENCE2(fighter, 4)) { - fighter->field_34 = 0; - - setSequenceAndDraw(fighter, 3, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, (action == kFightAction1 ? 3 : 4), kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - - if (action == kFightAction2) - fighter->countdown= 0; - - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction5: - if (fighter->sequenceIndex != 3) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction128: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - fighter->field_34 = 0; - break; - - case kFightAction131: - setSequenceAndDraw(fighter, 2, (fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0)); - break; - } -} - -void Fight::updateSalko(Fighter *fighter) { - update(fighter); - - // The original doesn't check for currentSequence2 != NULL (might not happen when everything is working properly, but crashes with our current implementation) - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - if (fighter->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndWin); - - return; - } - - if (fighter->sequenceIndex == 2) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction2); - } -} - -bool Fight::canInteractSalko(Fighter const *fighter, FightAction action) { - if (action == kFightAction131) { - if (fighter->sequenceIndex == 1) { - if (fighter->opponent->countdown <= 0) - _engine->getCursor()->setStyle(kCursorHand); - - return true; - } - - return false; - } - - return canInteract(fighter); -} - -void Fight::handleOpponentActionSalko(Fighter *fighter, FightAction action) { - if (action == kFightAction2) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - } else { - handleAction(fighter, action); - } -} - -void Fight::updateOpponentSalko(Fighter *fighter) { - // This is an opponent struct - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - switch (rnd(5)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 3: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - - // Update field_38 - opponent->field_38 = 4 * opponent->countdown; - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndLost); - - // Stop processing - return; - } - - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Vesna -////////////////////////////////////////////////////////////////////////// - -void Fight::loadVesnaPlayer() { - REGISTER_PLAYER_FUNCTIONS(Vesna) - - _data->player->sequences.push_back(loadSequence("2005cr.seq")); - _data->player->sequences.push_back(loadSequence("2005cdr.seq")); - _data->player->sequences.push_back(loadSequence("2005cbr.seq")); - _data->player->sequences.push_back(loadSequence("2005bk.seq")); - _data->player->sequences.push_back(loadSequence("2005cdm1.seq")); - _data->player->sequences.push_back(loadSequence("2005chl.seq")); -} - -void Fight::loadVesnaOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Vesna) - - _data->opponent->sequences.push_back(loadSequence("2005or.seq")); - _data->opponent->sequences.push_back(loadSequence("2005oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2005oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2005okml.seq")); - _data->opponent->sequences.push_back(loadSequence("2005okr.seq")); - _data->opponent->sequences.push_back(loadSequence("2005odm1.seq")); - _data->opponent->sequences.push_back(loadSequence("2005csbm.seq")); - _data->opponent->sequences.push_back(loadSequence("2005oam4.seq")); - - getSound()->playSound(kEntityTables0, "MUS038", SoundManager::kFlagDefault); - - _data->opponent->countdown = 4; - _data->opponent->field_38 = 30; -} - -void Fight::handleActionVesna(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if (fighter->sequenceIndex != 1) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction2: - if (fighter->sequenceIndex != 2) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction5: - if (fighter->sequenceIndex != 3) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction128: - if (fighter->sequenceIndex == 1 && fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - } else { - setSequenceAndDraw(fighter, (fighter->opponent->sequenceIndex == 5) ? 3 : 1, kFightSequenceType0); - } - break; - - case kFightAction132: - setSequenceAndDraw(fighter, 2, kFightSequenceType0); - break; - } - - if (fighter->field_34 > 10) { - setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType2); - fighter->opponent->countdown = 1; - fighter->field_34 = 0; - } -} - -void Fight::updateVesna(Fighter *fighter) { - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - if (fighter->sequenceIndex == 3) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction3); - - if (fighter->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndWin); - return; - } - - if (fighter->sequenceIndex == 5) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction5); - } - - update(fighter); -} - -bool Fight::canInteractVesna(Fighter const *fighter, FightAction action) { - if (action != kFightAction128) - return canInteract(fighter); - - if (fighter->sequenceIndex != 1) { - - if (fighter->opponent->sequenceIndex == 5) { - _engine->getCursor()->setStyle(kCursorDown); - return true; - } - - return canInteract(fighter); - } - - if (fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) { - _engine->getCursor()->setStyle(kCursorPunchLeft); - return true; - } - - return false; -} - -void Fight::handleOpponentActionVesna(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - break; - - case kFightAction3: - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - break; - - case kFightAction5: - setSequenceAndDraw(fighter, 7, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - if (fighter->countdown <= 1) - fighter->countdown = 1; - break; - - case kFightAction131: - break; - } -} - -void Fight::updateOpponentVesna(Fighter *fighter) { - // This is an opponent struct - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 == 1) { - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - } else { - switch (rnd(6)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - - case 2: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 3: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 5: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - } - - // Update field_38 - opponent->field_38 = 4 * opponent->countdown; - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 5) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - - if (opponent->opponent->countdown <= 0) { - - switch (opponent->sequenceIndex) { - default: - break; - - case 1: - setSequenceAndDraw(opponent, 3, kFightSequenceType1); - break; - - case 2: - setSequenceAndDraw(opponent, 4, kFightSequenceType1); - break; - - case 5: - setSequenceAndDraw(opponent, 6, kFightSequenceType1); - break; - } - - setSequenceAndDraw(opponent->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(opponent, handleAction, kFightActionLost); - CALL_FUNCTION0(opponent->opponent, update); - CALL_FUNCTION0(opponent, update); - - getSound()->removeFromQueue(kEntityTables0); - - // Stop processing - return; - } - } - - updateOpponent(opponent); -} - -} // End of namespace LastExpress diff --git a/engines/lastexpress/game/fight.h b/engines/lastexpress/game/fight.h deleted file mode 100644 index a33cc93a29..0000000000 --- a/engines/lastexpress/game/fight.h +++ /dev/null @@ -1,266 +0,0 @@ -/* 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 LASTEXPRESS_FIGHT_H -#define LASTEXPRESS_FIGHT_H - -/* - Fight structure - --------------- - uint32 {4} - player struct - uint32 {4} - opponent struct - uint32 {4} - hasLost flag - - byte {1} - isRunning - - Fight participant structure - --------------------------- - uint32 {4} - function pointer - uint32 {4} - pointer to fight structure - uint32 {4} - pointer to opponent (fight participant structure) - uint32 {4} - array of sequences - uint32 {4} - number of sequences - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint16 {2} - ?? - uint16 {2} - ?? - only for opponent structure - uint32 {4} - ?? - only for opponent structure - -*/ - -#include "lastexpress/shared.h" - -#include "lastexpress/eventhandler.h" - -#include "common/array.h" - -namespace LastExpress { - -class LastExpressEngine; -class Sequence; -class SequenceFrame; - -////////////////////////////////////////////////////////////////////////// -// TODO : objectify! -class Fight : public EventHandler { -public: - enum FightEndType { - kFightEndWin = 0, - kFightEndLost = 1, - kFightEndExit = 2 - }; - - Fight(LastExpressEngine *engine); - ~Fight(); - - FightEndType setup(FightType type); - - void eventMouse(const Common::Event &ev); - void eventTick(const Common::Event &ev); - - void setStopped(); - void resetState() { _state = 0; } - -private: - enum FightSequenceType { - kFightSequenceType0 = 0, - kFightSequenceType1 = 1, - kFightSequenceType2 = 2 - }; - - enum FightAction { - kFightAction1 = 1, - kFightAction2 = 2, - kFightAction3 = 3, - kFightAction4 = 4, - kFightAction5 = 5, - kFightAction101 = 101, - kFightActionResetFrame = 102, - kFightAction103 = 103, - kFightActionWin = 104, - kFightActionLost = 105, - kFightAction128 = 128, - kFightAction129 = 129, - kFightAction130 = 130, - kFightAction131 = 131, - kFightAction132 = 132 - }; - - struct Fighter { - Common::Functor2 *handleAction; - Common::Functor1 *update; - Common::Functor2 *canInteract; - Fighter *opponent; - Common::Array sequences; - uint32 sequenceIndex; - Sequence *sequence; - SequenceFrame *frame; - uint32 frameIndex; - uint32 field_24; - FightAction action; - uint32 sequenceIndex2; - int32 countdown; // countdown before loosing ? - uint32 field_34; - - Fighter() { - handleAction = NULL; - update = NULL; - canInteract = NULL; - - opponent = NULL; - - sequenceIndex = 0; - sequence = NULL; - frame = NULL; - frameIndex = 0; - - field_24 = 0; - - action = kFightAction101; - sequenceIndex2 = 0; - - countdown = 1; - - field_34 = 0; - } - }; - - // Opponent struct - struct Opponent : Fighter { - int32 field_38; - - Opponent() : Fighter() { - field_38 = 0; - } - }; - - struct FightData { - Fighter *player; - Opponent *opponent; - int32 index; - - Sequence *sequences[20]; - Common::String names[20]; - - bool isRunning; - - FightData() { - player = new Fighter(); - opponent = new Opponent(); - - // Set opponents - player->opponent = opponent; - opponent->opponent = player; - - index = 0; - - isRunning = false; - } - }; - - LastExpressEngine *_engine; - FightData *_data; - FightEndType _endType; - int _state; - - bool _handleTimer; - - // Events - void handleTick(const Common::Event &ev, bool unknown); - - // State - void bailout(FightEndType type); - - - // Drawing - void setSequenceAndDraw(Fighter *fighter, uint32 sequenceIndex, FightSequenceType type) const; - void draw(Fighter *fighter) const; - - // Cleanup - void clearData(); - void clearSequences(Fighter *fighter) const; - - ////////////////////////////////////////////////////////////////////////// - // Loading - void loadData(FightType type); - - // Shared - void processFighter(Fighter *fighter); - - // Default functions - void handleAction(Fighter *fighter, FightAction action); - void update(Fighter *fighter); - bool canInteract(Fighter const *fighter, FightAction = (FightAction)0); - void updateOpponent(Fighter *fighter); - - // Milos - void loadMilosPlayer(); - void loadMilosOpponent(); - void handleActionMilos(Fighter *fighter, FightAction action); - void updateMilos(Fighter *fighter); - bool canInteractMilos(Fighter const *fighter, FightAction action); - void handleOpponentActionMilos(Fighter *fighter, FightAction action); - void updateOpponentMilos(Fighter *fighter); - - // Anna - void loadAnnaPlayer(); - void loadAnnaOpponent(); - void handleActionAnna(Fighter *fighter, FightAction action); - void updateOpponentAnna(Fighter *fighter); - - // Ivo - void loadIvoPlayer(); - void loadIvoOpponent(); - void handleActionIvo(Fighter *fighter, FightAction action); - void updateIvo(Fighter *fighter); - bool canInteractIvo(Fighter const *fighter, FightAction action); - void handleOpponentActionIvo(Fighter *fighter, FightAction action); - void updateOpponentIvo(Fighter *fighter); - - // Salko - void loadSalkoPlayer(); - void loadSalkoOpponent(); - void handleActionSalko(Fighter *fighter, FightAction action); - void updateSalko(Fighter *fighter); - bool canInteractSalko(Fighter const *fighter, FightAction action); - void handleOpponentActionSalko(Fighter *fighter, FightAction action); - void updateOpponentSalko(Fighter *fighter); - - // Vesna - void loadVesnaPlayer(); - void loadVesnaOpponent(); - void handleActionVesna(Fighter *fighter, FightAction action); - void updateVesna(Fighter *fighter); - bool canInteractVesna(Fighter const *fighter, FightAction action); - void handleOpponentActionVesna(Fighter *fighter, FightAction action); - void updateOpponentVesna(Fighter *fighter); -}; - -} // End of namespace LastExpress - -#endif // LASTEXPRESS_FIGHT_H diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp index 0911c60de0..a8a2ce87b1 100644 --- a/engines/lastexpress/game/logic.cpp +++ b/engines/lastexpress/game/logic.cpp @@ -30,11 +30,13 @@ // Entities #include "lastexpress/entities/chapters.h" +// Fight +#include "lastexpress/fight/fight.h" + // Game #include "lastexpress/game/action.h" #include "lastexpress/game/beetle.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/inventory.h" #include "lastexpress/game/menu.h" #include "lastexpress/game/object.h" diff --git a/engines/lastexpress/game/menu.cpp b/engines/lastexpress/game/menu.cpp index f9eef26326..27a43d8f61 100644 --- a/engines/lastexpress/game/menu.cpp +++ b/engines/lastexpress/game/menu.cpp @@ -28,7 +28,8 @@ #include "lastexpress/data/snd.h" #include "lastexpress/data/scene.h" -#include "lastexpress/game/fight.h" +#include "lastexpress/fight/fight.h" + #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" #include "lastexpress/game/savegame.h" diff --git a/engines/lastexpress/module.mk b/engines/lastexpress/module.mk index 12fbb4f85b..3827c16681 100644 --- a/engines/lastexpress/module.mk +++ b/engines/lastexpress/module.mk @@ -45,10 +45,10 @@ MODULE_OBJS := \ entities/verges.o \ entities/vesna.o \ entities/yasmin.o \ + fight/fight.o \ game/action.o \ game/beetle.o \ game/entities.o \ - game/fight.o \ game/inventory.o \ game/logic.o \ game/menu.o \ -- cgit v1.2.3