Initial commit
This commit is contained in:
386
engines/hadesch/rooms/monster/cyclops.cpp
Normal file
386
engines/hadesch/rooms/monster/cyclops.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2020 Google
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hadesch/hadesch.h"
|
||||
#include "hadesch/video.h"
|
||||
#include "hadesch/rooms/monster.h"
|
||||
|
||||
namespace Hadesch {
|
||||
static const char *kCyclopsShootingEyeOpen = "v7180bh0";
|
||||
static const char *kCyclopsShootingEyeClosed = "v7180bh1";
|
||||
|
||||
enum {
|
||||
kCyclopsZ = 500
|
||||
};
|
||||
|
||||
static const PrePoint cyclopsEyePositions[21] = {
|
||||
{247, 175},
|
||||
{235, 187},
|
||||
{227, 183},
|
||||
{221, 178},
|
||||
{220, 170},
|
||||
{230, 168},
|
||||
{230, 168},
|
||||
{224, 170},
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
{281, 175},
|
||||
{282, 170},
|
||||
{282, 170},
|
||||
{284, 175},
|
||||
{270, 178},
|
||||
{257, 179},
|
||||
{250, 176},
|
||||
{249, 176},
|
||||
{248, 176},
|
||||
{246, 176}
|
||||
};
|
||||
|
||||
static const PrePoint cyclopsEyePositionsBA0[8] = {
|
||||
{246, 176},
|
||||
{248, 174},
|
||||
{249, 166},
|
||||
{248, 171},
|
||||
{0, 0},
|
||||
{241, 183},
|
||||
{244, 181},
|
||||
{246, 176}
|
||||
};
|
||||
|
||||
void Cyclops::handleClick(Common::Point p) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
int frame;
|
||||
if (g_vm->getHeroBelt()->getSelectedStrength() != kPowerStealth || (_currentCyclopsState != 0 && _currentCyclopsState != 1))
|
||||
return;
|
||||
switch (_currentCyclopsState) {
|
||||
case 0:
|
||||
if (!_cyclopsIsHiding)
|
||||
return;
|
||||
frame = room->getAnimFrameNum("v7180bh0");
|
||||
break;
|
||||
case 1:
|
||||
frame = room->getAnimFrameNum("v7040ba0");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cyclopsIsHit(p, frame))
|
||||
return;
|
||||
room->disableMouse();
|
||||
_battleground->stopFight();
|
||||
room->playAnimWithSFX("v7180bj0", "v7180xc0", 500, PlayAnimParams::disappear(), 15352);
|
||||
}
|
||||
|
||||
bool Cyclops::cyclopsIsHit(Common::Point p, int frame) {
|
||||
if (frame < 0 || frame >= ARRAYSIZE(cyclopsEyePositions) || cyclopsEyePositions[frame].get() == Common::Point(0, 0))
|
||||
return false;
|
||||
return cyclopsEyePositions[frame].get().sqrDist(p) <= getSquareOfPrecision();
|
||||
}
|
||||
|
||||
bool Cyclops::cyclopsIsHitBA0(Common::Point p, int frame) {
|
||||
if (frame < 0 || frame >= ARRAYSIZE(cyclopsEyePositionsBA0) || cyclopsEyePositionsBA0[frame].get() == Common::Point(0, 0))
|
||||
return false;
|
||||
return cyclopsEyePositionsBA0[frame].get().sqrDist(p) <= getSquareOfPrecision();
|
||||
}
|
||||
|
||||
unsigned Cyclops::getSquareOfPrecision() {
|
||||
return 2050 - 50 * _battleground->_level;
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState0() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_currentCyclopsState = 0;
|
||||
Common::Point mousePos = g_vm->getMousePos();
|
||||
_cyclopsIsHiding = (g_vm->getHeroBelt()->getSelectedStrength() == kPowerStealth || !cyclopsIsHit(mousePos, 0));
|
||||
room->playAnim(kCyclopsShootingEyeClosed, kCyclopsZ, PlayAnimParams::disappear().partial(0, 11), kCyclopsShootingEyeClosedMidAnim);
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState1() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_currentCyclopsState = 1;
|
||||
|
||||
room->playAnimWithSFX("v7040ba0", "v7040ea0",
|
||||
kCyclopsZ,
|
||||
PlayAnimParams::disappear(),
|
||||
15257);
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState2() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
|
||||
room->playAnimWithSFX(
|
||||
"v7180be0", "v7180ee0", kCyclopsZ,
|
||||
PlayAnimParams::disappear()
|
||||
.partial(0, 4), 15258);
|
||||
_currentCyclopsState = 2;
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState3() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_currentCyclopsState = 3;
|
||||
room->playAnim("v7180be0", kCyclopsZ, PlayAnimParams::disappear().partial(5, 11), 15259);
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState4() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_currentCyclopsState = 4;
|
||||
room->playAnimWithSFX("v7180bk0", "v7180sc0", kCyclopsZ, PlayAnimParams::disappear(), 15260);
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState5() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_currentCyclopsState = 5;
|
||||
room->playAnimWithSFX("v7180bi0", "v7180sa0", kCyclopsZ, PlayAnimParams::disappear().partial(0, 4), 15262);
|
||||
}
|
||||
|
||||
void Cyclops::cyclopsState6() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_currentCyclopsState = 6;
|
||||
|
||||
room->playAnimWithSFX("v7180bi0", "v7180ee0", kCyclopsZ, PlayAnimParams::disappear().partial(5, 11), 15264);
|
||||
}
|
||||
|
||||
Cyclops::Cyclops(Common::SharedPtr<Battleground> battleground) {
|
||||
_battleground = battleground;
|
||||
}
|
||||
|
||||
void Cyclops::enterCyclops(int level) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->playAnimKeepLastFrame("v7180oa0", 600);
|
||||
room->playAnimWithSFX("v7180ba0", "v7180ea0", kCyclopsZ,
|
||||
PlayAnimParams::disappear(),
|
||||
15252);
|
||||
Typhoon::disableHotzones();
|
||||
_cyclopsProximityCheckCountdown = 0;
|
||||
_currentCyclopsState = 0;
|
||||
_cyclopsIsHiding = true;
|
||||
_battleground->_level = level;
|
||||
_battleground->_leavesRemaining = 9;
|
||||
_battleground->_monsterNum = kCyclops;
|
||||
g_vm->getHeroBelt()->setBranchOfLifeFrame(0);
|
||||
}
|
||||
|
||||
void Cyclops::handleEvent(int eventId) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
|
||||
switch (eventId) {
|
||||
case 15252:
|
||||
room->enableMouse();
|
||||
room->playAnimLoop("v7180bl0", 550);
|
||||
_battleground->_isInFight = true;
|
||||
g_vm->addTimer(15266, 100, -1);
|
||||
switch (g_vm->getRnd().getRandomNumberRng(0, 2)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState1();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState2();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15255: {
|
||||
if (_cyclopsIsHiding) {
|
||||
switch (g_vm->getRnd().getRandomNumberRng(0, 4)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState1();
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
cyclopsState2();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (g_vm->getRnd().getRandomNumberRng(0, 4)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState1();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState3();
|
||||
break;
|
||||
case 3:
|
||||
cyclopsState4();
|
||||
break;
|
||||
case 4:
|
||||
cyclopsState5();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 15257:
|
||||
switch (g_vm->getRnd().getRandomNumberRng(0, 2)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState1();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState2();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15258:
|
||||
switch (g_vm->getRnd().getRandomNumberRng(0, 3)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState3();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState4();
|
||||
break;
|
||||
case 3:
|
||||
cyclopsState5();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15259:
|
||||
switch(g_vm->getRnd().getRandomNumberRng(0, 2)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState1();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState2();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15260:
|
||||
switch (g_vm->getRnd().getRandomNumberRng(0, 3)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState3();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState4();
|
||||
break;
|
||||
case 3:
|
||||
cyclopsState5();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15262:
|
||||
switch(g_vm->getRnd().getRandomNumberRng(0, 2)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState3();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState6();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15264:
|
||||
switch(g_vm->getRnd().getRandomNumberRng(0, 3)) {
|
||||
case 0:
|
||||
cyclopsState0();
|
||||
break;
|
||||
case 1:
|
||||
cyclopsState3();
|
||||
break;
|
||||
case 2:
|
||||
cyclopsState4();
|
||||
break;
|
||||
case 3:
|
||||
cyclopsState5();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15266:
|
||||
if (!_battleground->_isInFight || _battleground->_monsterNum != kCyclops)
|
||||
break;
|
||||
if (_currentCyclopsState == 0) {
|
||||
Common::Point mousePos = g_vm->getMousePos();
|
||||
if (_cyclopsProximityCheckCountdown)
|
||||
_cyclopsProximityCheckCountdown--;
|
||||
if (_cyclopsProximityCheckCountdown == 0) {
|
||||
if (_cyclopsIsHiding) {
|
||||
int frame = room->getAnimFrameNum("v7180bh0");
|
||||
if (g_vm->getHeroBelt()->getSelectedStrength() != kPowerStealth
|
||||
&& cyclopsIsHit(mousePos, frame)) {
|
||||
room->stopAnim("v7180bh0");
|
||||
room->playAnim("v7180bh1", kCyclopsZ, PlayAnimParams::disappear().partial(frame, -1), 15255);
|
||||
_cyclopsProximityCheckCountdown = 5;
|
||||
_cyclopsIsHiding = false;
|
||||
}
|
||||
} else {
|
||||
int frame = room->getAnimFrameNum("v7180bh1");
|
||||
if (frame <= 20 && frame >= 0 && !cyclopsIsHit(mousePos, frame) ) {
|
||||
room->stopAnim("v7180bh1");
|
||||
room->playAnim("v7180bh0", kCyclopsZ, PlayAnimParams::disappear().partial(frame, -1), 15255);
|
||||
_cyclopsIsHiding = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_currentCyclopsState == 1) {
|
||||
Common::Point mousePos = g_vm->getMousePos();
|
||||
if (g_vm->getHeroBelt()->getSelectedStrength() != kPowerStealth
|
||||
&& cyclopsIsHitBA0(mousePos, room->getAnimFrameNum("v7040ba0"))) {
|
||||
room->stopAnim("v7040ba0");
|
||||
_currentCyclopsState = 2;
|
||||
room->playAnim(
|
||||
"v7180be0", kCyclopsZ,
|
||||
PlayAnimParams::disappear()
|
||||
.partial(0, 4), 15258);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 15269:
|
||||
for (int i = 0; i < _battleground->getNumOfProjectiles(); i++) {
|
||||
_battleground->launchProjectile(50, Common::Point(60, 203), 0);
|
||||
}
|
||||
room->playSFX("v7140eb0");
|
||||
break;
|
||||
case kCyclopsShootingEyeClosedMidAnim:
|
||||
room->playAnim(kCyclopsShootingEyeClosed, kCyclopsZ, PlayAnimParams::disappear().partial(12, -1), 15255);
|
||||
handleEvent(15269);
|
||||
break;
|
||||
case kCyclopsShootingEyeOpenMidAnim:
|
||||
room->playAnim(kCyclopsShootingEyeOpen, kCyclopsZ, PlayAnimParams::disappear().partial(12, -1), 15255);
|
||||
handleEvent(15269);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
395
engines/hadesch/rooms/monster/illusion.cpp
Normal file
395
engines/hadesch/rooms/monster/illusion.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2020 Google
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hadesch/hadesch.h"
|
||||
#include "hadesch/video.h"
|
||||
#include "hadesch/rooms/monster.h"
|
||||
|
||||
namespace Hadesch {
|
||||
|
||||
struct BirdInfo {
|
||||
int _projectileFrame;
|
||||
const char *_flyAnim;
|
||||
int _birdWidth;
|
||||
int _birdHeight;
|
||||
const char *_interceptAnim;
|
||||
const char *_shootAnim;
|
||||
int _birdShootWidth;
|
||||
int _birdShootHeight;
|
||||
|
||||
Common::Point getBirdSize() const {
|
||||
return Common::Point(_birdWidth, _birdHeight);
|
||||
}
|
||||
|
||||
Common::Point getBirdShootSize() const {
|
||||
return Common::Point(_birdShootWidth, _birdShootHeight);
|
||||
}
|
||||
};
|
||||
|
||||
static const TranscribedSound fakePhilReplics[] = {
|
||||
{"v7220xb0", _hs("unclear utterance")}, // unclear
|
||||
{"v7220xc0", _hs("Hey, this was close, buddy")},
|
||||
{"v7220xd0", _hs("Get hold of thunderbolts")}, // unclear
|
||||
{"v7220xe0", _hs("Keep going, kid. You're doing great job")},
|
||||
{"v7220xf0", _hs("unclear utterance")} // unclear
|
||||
};
|
||||
|
||||
static const BirdInfo birdInfo[] = {
|
||||
{
|
||||
10,
|
||||
"v7220bh2",
|
||||
151, 111,
|
||||
"v7220bp2",
|
||||
"v7220bl2",
|
||||
154, 192,
|
||||
},
|
||||
{
|
||||
6,
|
||||
"v7220bi2",
|
||||
167, 175,
|
||||
"v7220bq2",
|
||||
"v7220bm2",
|
||||
190, 233,
|
||||
},
|
||||
{
|
||||
10,
|
||||
"v7220bh3",
|
||||
151, 111,
|
||||
"v7220bp3",
|
||||
"v7220bl3",
|
||||
154, 192,
|
||||
},
|
||||
{
|
||||
6,
|
||||
"v7220bi3",
|
||||
167, 175,
|
||||
"v7220bq3",
|
||||
"v7220bm3",
|
||||
190, 233,
|
||||
},
|
||||
{
|
||||
10,
|
||||
"v7220bh0",
|
||||
141, 109,
|
||||
"v7220bp0",
|
||||
"v7220bl0",
|
||||
141, 192,
|
||||
},
|
||||
{
|
||||
6,
|
||||
"v7220bi0",
|
||||
110, 172,
|
||||
"v7220bq0",
|
||||
"v7220bm0",
|
||||
94, 233,
|
||||
},
|
||||
{
|
||||
10,
|
||||
"v7220bh1",
|
||||
141, 109,
|
||||
"v7220bp1",
|
||||
"v7220bl1",
|
||||
141, 192,
|
||||
},
|
||||
{
|
||||
6,
|
||||
"v7220bi1",
|
||||
110, 172,
|
||||
"v7220bq1",
|
||||
"v7220bm1",
|
||||
94, 233,
|
||||
}
|
||||
};
|
||||
|
||||
void Illusion::stopAnims() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
|
||||
for (unsigned i = 0; i < ARRAYSIZE(birdInfo); i++)
|
||||
for (unsigned j = 0; j < 3; j++) {
|
||||
room->stopAnim(LayerId(birdInfo[i]._flyAnim, j, "bird"));
|
||||
room->stopAnim(LayerId(birdInfo[i]._interceptAnim, j, "bird"));
|
||||
room->stopAnim(LayerId(birdInfo[i]._shootAnim, j, "bird"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bird::Bird(int id) {
|
||||
_id = id;
|
||||
_isActive = false;
|
||||
}
|
||||
|
||||
void Bird::launch(int level) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_isActive = true;
|
||||
_level = level;
|
||||
makeFlightParams();
|
||||
room->playSFX("v7220eb0");
|
||||
_flightStart = g_vm->getCurrentTime();
|
||||
}
|
||||
|
||||
void Bird::stop() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->stopAnim(LayerId(birdInfo[_birdType]._flyAnim, _id, "bird"));
|
||||
}
|
||||
|
||||
FlightPosition Bird::getFlightPosition(double t) {
|
||||
double t2 = t * t;
|
||||
double t3 = t2 * t;
|
||||
struct FlightPosition fp;
|
||||
|
||||
// Pseudo-Bezier
|
||||
fp.centerPos = ((2 * t3 - 3 * t2 + 1.0) * _startPos
|
||||
+ (t3 - 2 * t2 + t) * _attractor1
|
||||
+ (t3 - t2) * _attractor2
|
||||
+ (-2 * t3 + 3 * t2) * _targetPos);
|
||||
fp.scale = 100 * t;
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
void Bird::makeFlightParams() {
|
||||
Common::RandomSource &rnd = g_vm->getRnd();
|
||||
_startPos = Common::Point(
|
||||
rnd.getRandomNumberRng(250, 350),
|
||||
rnd.getRandomNumberRng(160, 310));
|
||||
|
||||
if (rnd.getRandomBit()) {
|
||||
_targetPos = Common::Point(
|
||||
650, rnd.getRandomNumberRng(100, 300));
|
||||
_field84 = 1;
|
||||
_birdType = rnd.getRandomNumberRng(0, 3);
|
||||
} else {
|
||||
_targetPos = Common::Point(-50, rnd.getRandomNumberRng(100, 300));
|
||||
_field84 = -1;
|
||||
_birdType = 4 + rnd.getRandomNumberRng(0, 3);
|
||||
}
|
||||
|
||||
int _flightLengthFrames;
|
||||
if (_level <= 19) {
|
||||
_flightLengthFrames = 51 - _level;
|
||||
} else {
|
||||
_flightLengthFrames = 50 - _level;
|
||||
}
|
||||
|
||||
_flightLengthMs = _flightLengthFrames * 100;
|
||||
|
||||
_attractor1 = Common::Point(
|
||||
rnd.getRandomNumberRngSigned(-600, 600),
|
||||
rnd.getRandomNumberRngSigned(-600, 600));
|
||||
_attractor2 = Common::Point(
|
||||
rnd.getRandomNumberRngSigned(-600, 600),
|
||||
rnd.getRandomNumberRngSigned(-600, 600));
|
||||
|
||||
unsigned lastGoodShootFrame = 11;
|
||||
for (; (int) lastGoodShootFrame < _flightLengthFrames; lastGoodShootFrame++) {
|
||||
Common::Point p = getFlightPosition(lastGoodShootFrame / (double) _flightLengthFrames).centerPos;
|
||||
if (p.x < 50 || p.x > 550 || p.y < 50 || p.y > 350)
|
||||
break;
|
||||
}
|
||||
lastGoodShootFrame--;
|
||||
_flightShootAnimFrame = rnd.getRandomNumberRng(10, lastGoodShootFrame);
|
||||
_flightShootProjectileFrame = _flightShootAnimFrame + birdInfo[_birdType]._projectileFrame;
|
||||
_flightShootEndFrame = _flightShootAnimFrame + (birdInfo[_birdType]._projectileFrame == 6 ? 13 : 18);
|
||||
_hasShot = false;
|
||||
}
|
||||
|
||||
// 15201
|
||||
void Bird::tick(Common::SharedPtr<Bird> backRef, Common::SharedPtr<Battleground> battleground) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (!_isActive)
|
||||
return;
|
||||
LayerId flyLayer = LayerId(birdInfo[_birdType]._flyAnim, _id, "bird");
|
||||
LayerId shootLayer = LayerId(birdInfo[_birdType]._shootAnim, _id, "bird");
|
||||
_flightCounterMs = (g_vm->getCurrentTime() - _flightStart);
|
||||
if (_flightCounterMs < _flightLengthMs) {
|
||||
int frame = _flightCounterMs / 100;
|
||||
FlightPosition fp = getFlightPosition(_flightCounterMs / (double) _flightLengthMs);
|
||||
int scale = fp.scale;
|
||||
if (frame < _flightShootAnimFrame) {
|
||||
Common::Point cornerPos = fp.centerPos - (scale / 100.0)
|
||||
* birdInfo[_birdType].getBirdSize();
|
||||
room->selectFrame(flyLayer, 500, frame % 5, cornerPos);
|
||||
room->setScale(flyLayer, scale);
|
||||
room->stopAnim(shootLayer);
|
||||
} else if (frame < _flightShootEndFrame) {
|
||||
Common::Point cornerPos = fp.centerPos - (scale / 100.0)
|
||||
* birdInfo[_birdType].getBirdShootSize();
|
||||
room->selectFrame(shootLayer, 500, frame - _flightShootAnimFrame, cornerPos);
|
||||
room->setScale(shootLayer, scale);
|
||||
room->stopAnim(flyLayer);
|
||||
} else { // 15204
|
||||
Common::Point cornerPos = fp.centerPos - (scale / 100.0)
|
||||
* birdInfo[_birdType].getBirdSize();
|
||||
room->selectFrame(flyLayer, 500, (frame - _flightShootEndFrame) % 5, cornerPos);
|
||||
room->setScale(flyLayer, scale);
|
||||
room->stopAnim(shootLayer);
|
||||
}
|
||||
|
||||
if (frame >= _flightShootProjectileFrame && !_hasShot) {
|
||||
_hasShot = true;
|
||||
battleground->launchProjectile(scale / 2, fp.centerPos, _targetPos.x < _startPos.x ? -1 : +1);
|
||||
}
|
||||
} else {
|
||||
room->stopAnim(flyLayer);
|
||||
room->stopAnim(shootLayer);
|
||||
_isActive = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Bird::handleAbsoluteClick(Common::Point p) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (!_isActive || _flightCounterMs >= _flightLengthMs)
|
||||
return;
|
||||
FlightPosition fp = getFlightPosition(_flightCounterMs / (double) _flightLengthMs);
|
||||
int r = fp.scale * 40 / 100;
|
||||
if ((int) p.sqrDist(fp.centerPos) > r * r)
|
||||
return;
|
||||
room->stopAnim(LayerId(birdInfo[_birdType]._flyAnim, _id, "bird"));
|
||||
room->stopAnim(LayerId(birdInfo[_birdType]._shootAnim, _id, "bird"));
|
||||
_isActive = false;
|
||||
LayerId l = LayerId(birdInfo[_birdType]._interceptAnim, _id, "bird");
|
||||
room->playAnimWithSFX(l, "v7220ec0", 500, PlayAnimParams::disappear(),
|
||||
EventHandlerWrapper(),
|
||||
fp.centerPos - birdInfo[_birdType].getBirdSize()
|
||||
* (fp.scale / 100.0));
|
||||
}
|
||||
|
||||
Illusion::Illusion(Common::SharedPtr<Battleground> battleground) {
|
||||
_battleground = battleground;
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
_birds[i] = Common::SharedPtr<Bird>(new Bird(i));
|
||||
}
|
||||
|
||||
void Illusion::launchBird() {
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
if (!_birds[i]->_isActive) {
|
||||
_birds[i]->launch(_battleground->_level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Illusion::handleAbsoluteClick(Common::Point p) {
|
||||
for (unsigned i = 0; i < ARRAYSIZE(_birds); i++)
|
||||
_birds[i]->handleAbsoluteClick(p);
|
||||
}
|
||||
|
||||
void Illusion::movePhil() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (_illusionIsKilled || !_battleground->_isInFight)
|
||||
return;
|
||||
room->disableHotzone(Common::String::format("Phil%d", _philPosition));
|
||||
room->stopAnim(Common::String::format("v7220bt%d", _philPosition));
|
||||
_philPosition = g_vm->getRnd().getRandomNumberRng(0, 5);
|
||||
room->enableHotzone(Common::String::format("Phil%d", _philPosition));
|
||||
room->playAnim(Common::String::format("v7220bt%d", _philPosition), 600,
|
||||
PlayAnimParams::keepLastFrame().partial(0, 12), 15301);
|
||||
}
|
||||
|
||||
void Illusion::enterIllusion(int level) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
Typhoon::disableHotzones();
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
room->enableHotzone(Common::String::format("Phil%d", i));
|
||||
room->playAnimWithSpeech(Common::String::format("v7220bg%d", g_vm->getRnd().getRandomNumberRng(0, 5)),
|
||||
TranscribedSound::make("v7220xc1",
|
||||
"It's me, Phil. These beasts are all that stands between me and freedom"), 600, // unclear
|
||||
PlayAnimParams::disappear(),
|
||||
15306);
|
||||
_battleground->_level = level;
|
||||
_battleground->_leavesRemaining = 9;
|
||||
_battleground->_monsterNum = kIllusion;
|
||||
_philPosition = -1;
|
||||
_illusionIsKilled = false;
|
||||
g_vm->getHeroBelt()->setBranchOfLifeFrame(0);
|
||||
}
|
||||
|
||||
void Illusion::handleClick(const Common::String &name) {
|
||||
if (_battleground->_isInFight && _battleground->_monsterNum == kIllusion && g_vm->getHeroBelt()->getSelectedStrength() == kPowerWisdom && !_illusionIsKilled
|
||||
&& _philPosition >= 0 && name == Common::String::format("Phil%d", _philPosition)) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_illusionIsKilled = true;
|
||||
_battleground->stopFight();
|
||||
room->disableMouse();
|
||||
room->playAnimKeepLastFrame(Common::String::format("v7220bv%d", _philPosition), 600);
|
||||
room->playSFX("v7220eg0", 15307);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Illusion::handleEvent(int eventId) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
switch (eventId) {
|
||||
case 15301:
|
||||
g_vm->addTimer(15302, 3500 - (_battleground->_level - 1) * 100);
|
||||
break;
|
||||
case 15302:
|
||||
movePhil();
|
||||
break;
|
||||
case 15306:
|
||||
room->enableMouse();
|
||||
_battleground->_isInFight = true;
|
||||
movePhil();
|
||||
g_vm->addTimer(15312, g_vm->getRnd().getRandomNumberRng(2000, 4000));
|
||||
room->playAnimKeepLastFrame("v7220oa0", 600);
|
||||
g_vm->addTimer(15313, g_vm->getRnd().getRandomNumberRng(500, 5000));
|
||||
launchBird();
|
||||
break;
|
||||
case 15307:
|
||||
room->playSpeech(TranscribedSound::make("v7220wg0", "Oh no, we're gonna fry"), 15308);
|
||||
break;
|
||||
case 15308:
|
||||
room->playSpeech(TranscribedSound::make("v7220wh0", "Let's get outta here"), 15309);
|
||||
break;
|
||||
case 15309:
|
||||
g_vm->getCurrentHandler()->handleEvent(15383);
|
||||
break;
|
||||
case 15312:
|
||||
if (!_battleground->_isInFight || _illusionIsKilled || _battleground->_monsterNum != kIllusion)
|
||||
return;
|
||||
room->playSpeech(fakePhilReplics[g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(fakePhilReplics) - 1)]);
|
||||
g_vm->addTimer(15312, g_vm->getRnd().getRandomNumberRng(6000, 10000));
|
||||
break;
|
||||
case 15313:
|
||||
if (!_battleground->_isInFight || _illusionIsKilled || _battleground->_monsterNum != kIllusion)
|
||||
return;
|
||||
g_vm->addTimer(15313, g_vm->getRnd().getRandomNumberRng(500, 5000));
|
||||
launchBird();
|
||||
break;
|
||||
// TODO: 15300, 15304, 15305, 15311
|
||||
}
|
||||
}
|
||||
|
||||
void Illusion::tick() {
|
||||
if (!_battleground->_isInFight) {
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
_birds[i]->_isActive = false;
|
||||
return;
|
||||
}
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
_birds[i]->tick(_birds[i], _battleground);
|
||||
}
|
||||
}
|
||||
}
|
||||
303
engines/hadesch/rooms/monster/projectile.cpp
Normal file
303
engines/hadesch/rooms/monster/projectile.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2020 Google
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hadesch/hadesch.h"
|
||||
#include "hadesch/video.h"
|
||||
#include "hadesch/rooms/monster.h"
|
||||
|
||||
namespace Hadesch {
|
||||
|
||||
Projectile::Projectile(int id, int level, Monster monster, int startScale, Common::Point startPoint, int xmomentum) {
|
||||
_level = level;
|
||||
switch (monster) {
|
||||
case kCyclops:
|
||||
_flyAnim = "V7140BA0";
|
||||
_interceptAnim = "V7130BD0";
|
||||
_hitAnim = "V7140BD0";
|
||||
break;
|
||||
case kTyphoon:
|
||||
_flyAnim = "V7140BB0";
|
||||
_interceptAnim = "V7130BD1";
|
||||
_hitAnim = "V7140BE0";
|
||||
break;
|
||||
case kIllusion:
|
||||
_flyAnim = "V7140BC0";
|
||||
_interceptAnim = "V7130BD2";
|
||||
_hitAnim = "V7140BF0";
|
||||
break;
|
||||
}
|
||||
_isMiss = g_vm->getRnd().getRandomNumberRng(0, getProjectileHitChance()) == 0;
|
||||
_isFlightFinished = false;
|
||||
_flightCounterMs = -1;
|
||||
_projectileId = id;
|
||||
_pending = 0;
|
||||
|
||||
_flightStart = g_vm->getCurrentTime();
|
||||
_startScale = startScale;
|
||||
_start = startPoint;
|
||||
makeFlightParams(xmomentum);
|
||||
}
|
||||
|
||||
void Projectile::handleEvent(int ev) {
|
||||
switch (ev) {
|
||||
case 15053:
|
||||
g_vm->handleEvent(kHitReceived);
|
||||
// TODO: stop red
|
||||
_pending--;
|
||||
break;
|
||||
case 15054:
|
||||
_pending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Projectile::stop() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->stopAnim(LayerId(_flyAnim, _projectileId, "projectile"));
|
||||
room->stopAnim(LayerId(_hitAnim, _projectileId, "projectile"));
|
||||
room->stopAnim(LayerId(_interceptAnim, _projectileId, "projectile"));
|
||||
}
|
||||
|
||||
void Projectile::makeFlightParams(int xmomentum) {
|
||||
Common::RandomSource &rnd = g_vm->getRnd();
|
||||
_flightLengthMs = getProjectileFlightLength(_level) * 100;
|
||||
|
||||
if (_isMiss) {
|
||||
switch (rnd.getRandomNumberRng(0, 2)) {
|
||||
case 0:
|
||||
_target = Common::Point(
|
||||
-50, rnd.getRandomNumberRngSigned(-50, 400));
|
||||
break;
|
||||
case 1:
|
||||
_target = Common::Point(
|
||||
rnd.getRandomNumberRngSigned(-50, 650), -50);
|
||||
break;
|
||||
case 2:
|
||||
_target = Common::Point(
|
||||
650, rnd.getRandomNumberRngSigned(-50, 400));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_target = Common::Point(
|
||||
rnd.getRandomNumberRng(100, 500),
|
||||
rnd.getRandomNumberRng(100, 300));
|
||||
}
|
||||
|
||||
switch (xmomentum) {
|
||||
case 1:
|
||||
_attractor1 = Common::Point(
|
||||
rnd.getRandomNumberRng(0, 600),
|
||||
rnd.getRandomNumberRng(0, 300));
|
||||
break;
|
||||
case -1:
|
||||
_attractor1 = Common::Point(
|
||||
rnd.getRandomNumberRngSigned(-600, 0),
|
||||
rnd.getRandomNumberRng(0, 300));
|
||||
break;
|
||||
case 0:
|
||||
_attractor1 = Common::Point(
|
||||
rnd.getRandomNumberRngSigned(-600, 600),
|
||||
rnd.getRandomNumberRngSigned(-600, 600));
|
||||
break;
|
||||
}
|
||||
_attractor2 = Common::Point(
|
||||
rnd.getRandomNumberRngSigned(-600, 600),
|
||||
rnd.getRandomNumberRng(0, 600));
|
||||
}
|
||||
|
||||
FlightPosition Projectile::getFlightPosition(double t) {
|
||||
double t2 = t * t;
|
||||
double t3 = t2 * t;
|
||||
struct FlightPosition fp;
|
||||
|
||||
// Pseudo-Bezier
|
||||
fp.centerPos = ((2 * t3 - 3 * t2 + 1.0) * _start
|
||||
+ (t3 - 2 * t2 + t) * _attractor1
|
||||
+ (t3 - t2) * _attractor2
|
||||
+ (-2 * t3 + 3 * t2) * _target);
|
||||
fp.scale = _startScale + (120 - _startScale) * t;
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
Projectile::~Projectile() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->purgeAnim(LayerId(_flyAnim, _projectileId, "projectile"));
|
||||
room->purgeAnim(LayerId(_hitAnim, _projectileId, "projectile"));
|
||||
room->purgeAnim(LayerId(_interceptAnim, _projectileId, "projectile"));
|
||||
}
|
||||
|
||||
int Projectile::getProjectileFlightLength(int level) {
|
||||
return 41 - _level;
|
||||
}
|
||||
|
||||
int Projectile::getProjectileHitChance() {
|
||||
if (_level >= 26)
|
||||
return 6;
|
||||
if (_level >= 17)
|
||||
return 5;
|
||||
if (_level >= 12)
|
||||
return 4;
|
||||
if (_level >= 7)
|
||||
return 3;
|
||||
return 2;
|
||||
}
|
||||
|
||||
Battleground::Battleground() {
|
||||
_level = 1;
|
||||
_projectileId = 0;
|
||||
_isInFight = false;
|
||||
}
|
||||
|
||||
int Battleground::getNumOfProjectiles() {
|
||||
return (_level - 1) / 10 + 1;
|
||||
}
|
||||
|
||||
void Battleground::launchProjectile(int startScale, Common::Point startPoint, int xmomentum) {
|
||||
++_projectileId;
|
||||
Common::SharedPtr<Projectile> pj(new Projectile(_projectileId, _level, _monsterNum, startScale, startPoint, xmomentum));
|
||||
_projectiles.push_back(pj);
|
||||
pj->tick(pj);
|
||||
}
|
||||
|
||||
void Battleground::handleAbsoluteClick(Common::Point p) {
|
||||
for (auto &projectile : _projectiles) {
|
||||
projectile.operator->()->handleAbsoluteClick(projectile, p);
|
||||
}
|
||||
}
|
||||
|
||||
void Battleground::tick() {
|
||||
if (!_isInFight)
|
||||
_projectiles.clear();
|
||||
else
|
||||
for (Common::Array<Common::SharedPtr<Projectile> >::iterator it = _projectiles.begin(); it != _projectiles.end();) {
|
||||
if (it->operator->()->tick(*it)) {
|
||||
it++;
|
||||
} else {
|
||||
it = _projectiles.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Battleground::stopFight() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
_isInFight = false;
|
||||
room->stopAnim("v7040ba0");
|
||||
room->stopAnim("V7100BJ0");
|
||||
room->stopAnim("v7180ba0");
|
||||
room->stopAnim("V7180BB0");
|
||||
room->stopAnim("v7180be0");
|
||||
room->stopAnim("v7180bh0");
|
||||
room->stopAnim("v7180bh1");
|
||||
room->stopAnim("v7180bi0");
|
||||
room->stopAnim("v7180bk0");
|
||||
room->stopAnim("v7180bl0");
|
||||
room->stopAnim("v7180oa0");
|
||||
room->stopAnim("v7210bx0");
|
||||
|
||||
stopProjectiles();
|
||||
|
||||
Typhoon::stopAnims();
|
||||
Illusion::stopAnims();
|
||||
|
||||
for (unsigned i = 0; i < 6; i++) {
|
||||
room->stopAnim(Common::String::format("v7220bt%d", i));
|
||||
room->stopAnim(Common::String::format("v7220bg%d", i));
|
||||
}
|
||||
|
||||
room->dumpLayers();
|
||||
}
|
||||
|
||||
void Battleground::stopProjectiles() {
|
||||
for (auto &projectile : _projectiles)
|
||||
projectile.operator->()->stop();
|
||||
}
|
||||
|
||||
class HandlerProjectile : public EventHandler {
|
||||
public:
|
||||
void operator()() override {
|
||||
_projectile->handleEvent(_event);
|
||||
}
|
||||
|
||||
HandlerProjectile(Common::SharedPtr <Projectile> projectile,
|
||||
int event) {
|
||||
_projectile = projectile;
|
||||
_event = event;
|
||||
}
|
||||
|
||||
private:
|
||||
Common::SharedPtr <Projectile> _projectile;
|
||||
int _event;
|
||||
};
|
||||
|
||||
bool Projectile::tick(Common::SharedPtr <Projectile> backRef) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (_isFlightFinished)
|
||||
return _pending > 0;
|
||||
LayerId flyLayer = LayerId(_flyAnim, _projectileId, "projectile");
|
||||
_flightCounterMs = (g_vm->getCurrentTime() - _flightStart);
|
||||
if (_flightCounterMs < _flightLengthMs) {
|
||||
FlightPosition fp = getFlightPosition(_flightCounterMs / (double) _flightLengthMs);
|
||||
int scale = fp.scale;
|
||||
Common::Point cornerPos = fp.centerPos - (scale / 100.0)
|
||||
* Common::Point(186, 210);
|
||||
room->selectFrame(flyLayer, 400, (_flightCounterMs / 100) % 8, cornerPos);
|
||||
room->setScale(flyLayer, scale);
|
||||
} else {
|
||||
room->stopAnim(flyLayer);
|
||||
_isFlightFinished = true;
|
||||
if (_isMiss) {
|
||||
_pending = 0;
|
||||
} else {
|
||||
FlightPosition fp = getFlightPosition(_flightCounterMs / (double) _flightLengthMs);
|
||||
LayerId l = LayerId(_hitAnim, _projectileId, "projectile");
|
||||
room->playAnimWithSFX(l, "v7130ea0", 400, PlayAnimParams::disappear(),
|
||||
Common::SharedPtr<EventHandler>(new HandlerProjectile(backRef, 15053)),
|
||||
fp.centerPos - Common::Point(182, 205));
|
||||
_pending = 1;
|
||||
// TODO: fade to red, in 100 ms, callback 15055
|
||||
// TODO: shake camera for 1s
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Projectile::handleAbsoluteClick(Common::SharedPtr <Projectile> backRef, Common::Point p) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (_isFlightFinished || _flightCounterMs >= _flightLengthMs)
|
||||
return;
|
||||
FlightPosition fp = getFlightPosition(_flightCounterMs / (double) _flightLengthMs);
|
||||
int r = fp.scale * 40 / 100;
|
||||
if ((int) p.sqrDist(fp.centerPos) > r * r)
|
||||
return;
|
||||
room->stopAnim(LayerId(_flyAnim, _projectileId, "projectile"));
|
||||
_isFlightFinished = true;
|
||||
_pending = 1;
|
||||
LayerId l = LayerId(_interceptAnim, _projectileId, "projectile");
|
||||
room->playAnimWithSFX(l, "v7130eg0", 400, PlayAnimParams::disappear(),
|
||||
Common::SharedPtr<EventHandler>(new HandlerProjectile(backRef, 15054)),
|
||||
fp.centerPos - Common::Point(186, 210) * (fp.scale / 100.0));
|
||||
}
|
||||
|
||||
}
|
||||
356
engines/hadesch/rooms/monster/typhoon.cpp
Normal file
356
engines/hadesch/rooms/monster/typhoon.cpp
Normal file
@@ -0,0 +1,356 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2020 Google
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hadesch/hadesch.h"
|
||||
#include "hadesch/video.h"
|
||||
#include "hadesch/rooms/monster.h"
|
||||
|
||||
namespace Hadesch {
|
||||
|
||||
enum {
|
||||
kTyphoonZ = 500
|
||||
};
|
||||
|
||||
struct TyphoonHeadInfo {
|
||||
const char *_animDie;
|
||||
const char *_animRespawn;
|
||||
const char * _animNormal;
|
||||
const char * _hotZone;
|
||||
int _xVal;
|
||||
int _yVal;
|
||||
int _zVal;
|
||||
|
||||
Common::Point getPosition() const {
|
||||
return Common::Point(_xVal, _yVal);
|
||||
}
|
||||
};
|
||||
|
||||
static const TyphoonHeadInfo typhonHeadInfo[] = {
|
||||
{"V7210BO1", "V7210BS1", "V7210BC1", "head00c1", 275, 186, 480},
|
||||
{"V7210BO0", "V7210BS0", "V7210BC0", "head01c0", 320, 166, 481},
|
||||
{"V7210BO0", "V7210BS0", "V7210BC0", "head02c0", 313, 221, 482},
|
||||
{"V7210BO1", "V7210BS1", "V7210BC1", "head03c1", 279, 223, 483},
|
||||
{"V7210BP1", "V7210BT1", "V7210BD1", "head04d1", 237, 221, 484},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head05d0", 234, 189, 485},
|
||||
{"V7210BP1", "V7210BT1", "V7210BD1", "head06d1", 234, 160, 486},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head07d0", 289, 137, 487},
|
||||
{"V7210BO0", "V7210BS0", "V7210BC0", "head08c0", 253, 135, 488},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head09d0", 355, 219, 489},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head10d0", 368, 182, 490},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head11d0", 351, 152, 491},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head12d0", 329, 126, 492},
|
||||
{"V7210BO0", "V7210BS0", "V7210BC0", "head13c0", 289, 99, 493},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head14d0", 333, 107, 494},
|
||||
{"V7210BO0", "V7210BS0", "V7210BC0", "head15c0", 360, 135, 495},
|
||||
{"V7210BO1", "V7210BS1", "V7210BC1", "head16c1", 226, 147, 496},
|
||||
{"V7210BP0", "V7210BT0", "V7210BD0", "head17d0", 257, 107, 497}
|
||||
};
|
||||
|
||||
Typhoon::Typhoon(Common::SharedPtr<Battleground> battleground) {
|
||||
_battleground = battleground;
|
||||
_playingTyphoonRespawnSound = false;
|
||||
_playingTyphoonDieSound = false;
|
||||
for (unsigned i = 0; i < ARRAYSIZE(_headIsAlive); i++)
|
||||
_headIsAlive[i] = false;
|
||||
}
|
||||
|
||||
void Typhoon::handleEvent(int eventId) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
|
||||
switch (eventId) {
|
||||
case 15104:
|
||||
_playingTyphoonDieSound = false;
|
||||
break;
|
||||
case 15105:
|
||||
_playingTyphoonRespawnSound = false;
|
||||
break;
|
||||
case 15152:
|
||||
room->enableMouse();
|
||||
room->playAnimLoop("v7210bx0", 490);
|
||||
room->playSFX("v7210ed0");
|
||||
_battleground->_isInFight = true;
|
||||
typhoonA();
|
||||
for (unsigned i = 0; i < ARRAYSIZE(_headIsAlive); i++) {
|
||||
showHeadNormal(i);
|
||||
_headIsAlive[i] = true;
|
||||
}
|
||||
schedule15154();
|
||||
handleEvent(15163);
|
||||
break;
|
||||
case 15153:
|
||||
typhoonA();
|
||||
break;
|
||||
case 15154:
|
||||
if (!_battleground->_isInFight || _isKilled || _battleground->_monsterNum != kTyphoon)
|
||||
return;
|
||||
room->playSFX("v7050ea0");
|
||||
schedule15154();
|
||||
break;
|
||||
case 15159:
|
||||
room->playAnim("v7210bj0", 500, PlayAnimParams::disappear().partial(7, -1), 15153);
|
||||
if (!_isKilled && _battleground->_isInFight) {
|
||||
for (int y = 351, i = 0; i < _battleground->getNumOfProjectiles(); y++, i++)
|
||||
_battleground->launchProjectile(80, Common::Point(
|
||||
220, g_vm->getRnd().getRandomNumberRng(351, y)), 0);
|
||||
}
|
||||
break;
|
||||
case 15160:
|
||||
room->playAnim("v7210bi0", 500, PlayAnimParams::disappear().partial(7, -1), 15153);
|
||||
if (!_isKilled && _battleground->_isInFight) {
|
||||
for (int y = 359, i = 0; i < _battleground->getNumOfProjectiles(); y++, i++)
|
||||
_battleground->launchProjectile(80, Common::Point(
|
||||
456, g_vm->getRnd().getRandomNumberRng(359, y)), 0);
|
||||
}
|
||||
break;
|
||||
case 15163:
|
||||
if (!_battleground->_isInFight || _isKilled || _battleground->_monsterNum != kTyphoon)
|
||||
return;
|
||||
room->playSFX(g_vm->getHeroBelt()->getSelectedStrength() == kPowerStrength
|
||||
? "v7210eb0" : "v7210ea0");
|
||||
g_vm->addTimer(15163, g_vm->getRnd().getRandomNumberRng(3000, 7000));
|
||||
break;
|
||||
/*
|
||||
TODO:
|
||||
15167
|
||||
*/
|
||||
case 15168:
|
||||
g_vm->getCurrentHandler()->handleEvent(15351);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Typhoon::enterTyphoon(int level) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->playAnimKeepLastFrame("v7210oa0", 600);
|
||||
room->playAnim("v7210ba0", kTyphoonZ,
|
||||
PlayAnimParams::disappear(),
|
||||
15152);
|
||||
room->playSFX("v7050eb0");
|
||||
for (unsigned i = 0; i < ARRAYSIZE(typhonHeadInfo); i++) {
|
||||
room->enableHotzone(typhonHeadInfo[i]._hotZone);
|
||||
room->setHotZoneOffset(typhonHeadInfo[i]._hotZone, typhonHeadInfo[i].getPosition());
|
||||
}
|
||||
for (unsigned i = 0; i < 6; i++)
|
||||
room->disableHotzone(Common::String::format("Phil%d", i));
|
||||
_battleground->_level = level;
|
||||
_battleground->_leavesRemaining = 9;
|
||||
_battleground->_monsterNum = kTyphoon;
|
||||
_isKilled = false;
|
||||
_playingTyphoonDieSound = false;
|
||||
g_vm->getHeroBelt()->setBranchOfLifeFrame(0);
|
||||
}
|
||||
|
||||
void Typhoon::handleClick(Common::SharedPtr<Typhoon> backRef,
|
||||
const Common::String &name) {
|
||||
if (_battleground->_isInFight && _battleground->_monsterNum == kTyphoon
|
||||
&& g_vm->getHeroBelt()->getSelectedStrength() == kPowerStrength && !_isKilled) {
|
||||
for (unsigned i = 0; i < ARRAYSIZE(typhonHeadInfo); i++)
|
||||
if (name == typhonHeadInfo[i]._hotZone) {
|
||||
hitTyphoonHead(backRef, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Typhoon::typhoonA() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (_isKilled)
|
||||
return;
|
||||
|
||||
if (g_vm->getRnd().getRandomNumberRng(0, 3)) {
|
||||
room->playAnim("v7050ba0", 500, PlayAnimParams::disappear(), 15153);
|
||||
} else if (g_vm->getRnd().getRandomBit()) {
|
||||
room->playAnim("v7210bi0", 500, PlayAnimParams::disappear().partial(0, 6), 15160);
|
||||
room->playSFX("v7140ec0");
|
||||
}
|
||||
else {
|
||||
room->playAnim("v7210bj0", 500, PlayAnimParams::disappear().partial(0, 6), 15159);
|
||||
room->playSFX("v7140ec0");
|
||||
}
|
||||
}
|
||||
|
||||
void Typhoon::schedule15154() {
|
||||
int ha = typhonGetNumAliveHeads() * 50;
|
||||
g_vm->addTimer(15154, g_vm->getRnd().getRandomNumberRng(1100-ha, 1200 - ha));
|
||||
}
|
||||
|
||||
int Typhoon::typhonGetNumAliveHeads() {
|
||||
int v = 0;
|
||||
for (unsigned i = 0; i < ARRAYSIZE(_headIsAlive); i++)
|
||||
v += !!_headIsAlive[i];
|
||||
return v;
|
||||
}
|
||||
|
||||
void Typhoon::hideHead(int idx) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->stopAnim(LayerId(typhonHeadInfo[idx]._animNormal, idx, "head"));
|
||||
room->stopAnim(LayerId(typhonHeadInfo[idx]._animDie, idx, "head"));
|
||||
room->stopAnim(LayerId(typhonHeadInfo[idx]._animRespawn, idx, "head"));
|
||||
}
|
||||
|
||||
void Typhoon::showHeadNormal(int idx) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
hideHead(idx);
|
||||
room->playAnimLoop(LayerId(typhonHeadInfo[idx]._animNormal, idx, "head"),
|
||||
typhonHeadInfo[idx]._zVal,
|
||||
typhonHeadInfo[idx].getPosition());
|
||||
}
|
||||
|
||||
// 15103
|
||||
class TyphoonHeadRespawnComplete : public EventHandler {
|
||||
public:
|
||||
void operator()() override {
|
||||
_typhoon->showHeadNormal(_idx);
|
||||
}
|
||||
|
||||
TyphoonHeadRespawnComplete(Common::SharedPtr<Typhoon> typhoon, int idx) {
|
||||
_idx = idx;
|
||||
_typhoon = typhoon;
|
||||
}
|
||||
private:
|
||||
int _idx;
|
||||
Common::SharedPtr<Typhoon> _typhoon;
|
||||
};
|
||||
|
||||
// 15102
|
||||
class TyphoonHeadRespawnEvent : public EventHandler {
|
||||
public:
|
||||
void operator()() override {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (_typhoon->_headIsAlive[_idx] || _typhoon->_isKilled)
|
||||
return;
|
||||
room->enableHotzone(typhonHeadInfo[_idx]._hotZone);
|
||||
_typhoon->_headIsAlive[_idx] = true;
|
||||
if (!_typhoon->_playingTyphoonRespawnSound) {
|
||||
_typhoon->_playingTyphoonRespawnSound = true;
|
||||
room->playSFX("v7050ed0", 15105);
|
||||
}
|
||||
_typhoon->hideHead(_idx);
|
||||
room->playAnim(LayerId(typhonHeadInfo[_idx]._animRespawn, _idx, "head"),
|
||||
typhonHeadInfo[_idx]._zVal,
|
||||
PlayAnimParams::disappear(),
|
||||
Common::SharedPtr<EventHandler>(new TyphoonHeadRespawnComplete(_typhoon, _idx)),
|
||||
typhonHeadInfo[_idx].getPosition());
|
||||
}
|
||||
|
||||
TyphoonHeadRespawnEvent(Common::SharedPtr<Typhoon> typhoon, int idx) {
|
||||
_idx = idx;
|
||||
_typhoon = typhoon;
|
||||
}
|
||||
private:
|
||||
int _idx;
|
||||
Common::SharedPtr<Typhoon> _typhoon;
|
||||
};
|
||||
|
||||
// 15101
|
||||
class TyphoonHeadDieAnimFinishedEvent : public EventHandler {
|
||||
public:
|
||||
void operator()() override {
|
||||
int minRespawnInterval = 10000;
|
||||
int maxRespawnInterval = 10000;
|
||||
|
||||
if (_level <= 21)
|
||||
minRespawnInterval = 15000 - 500 * (_level - 1);
|
||||
else if (_level == 22)
|
||||
minRespawnInterval = 4600;
|
||||
else if (_level <= 25)
|
||||
minRespawnInterval = 4200 - 200 * (_level - 23);
|
||||
else if (_level == 26)
|
||||
minRespawnInterval = 3700;
|
||||
else
|
||||
minRespawnInterval = 3600 - 200 * (_level - 27);
|
||||
|
||||
if (_level <= 21)
|
||||
maxRespawnInterval = 20000 - 500 * (_level - 1);
|
||||
else
|
||||
maxRespawnInterval = 9600 - 200 * (_level - 22);
|
||||
|
||||
g_vm->addTimer(Common::SharedPtr<EventHandler>(new TyphoonHeadRespawnEvent(_typhoon, _idx)),
|
||||
g_vm->getRnd().getRandomNumberRng(minRespawnInterval, maxRespawnInterval));
|
||||
}
|
||||
|
||||
TyphoonHeadDieAnimFinishedEvent(Common::SharedPtr<Typhoon> typhoon, int idx, int level) {
|
||||
_idx = idx;
|
||||
_level = level;
|
||||
_typhoon = typhoon;
|
||||
}
|
||||
private:
|
||||
int _idx;
|
||||
int _level;
|
||||
Common::SharedPtr<Typhoon> _typhoon;
|
||||
};
|
||||
|
||||
void Typhoon::hitTyphoonHead(Common::SharedPtr<Typhoon> backRef, int idx) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
if (!_headIsAlive[idx])
|
||||
return;
|
||||
|
||||
if (!_playingTyphoonDieSound) {
|
||||
room->playSFX("v7050ec0", 15104);
|
||||
_playingTyphoonDieSound = true;
|
||||
}
|
||||
_headIsAlive[idx] = false;
|
||||
hideHead(idx);
|
||||
room->playAnimKeepLastFrame(LayerId(typhonHeadInfo[idx]._animDie, idx, "head"),
|
||||
typhonHeadInfo[idx]._zVal,
|
||||
Common::SharedPtr<EventHandler>(new TyphoonHeadDieAnimFinishedEvent(backRef, idx, _battleground->_level)),
|
||||
typhonHeadInfo[idx].getPosition());
|
||||
room->disableHotzone(typhonHeadInfo[idx]._hotZone);
|
||||
bool isKilled = true;
|
||||
for (unsigned i = 0; i < ARRAYSIZE(_headIsAlive); i++) {
|
||||
if (_headIsAlive[i])
|
||||
isKilled = false;
|
||||
}
|
||||
|
||||
if (!isKilled)
|
||||
return;
|
||||
_isKilled = true;
|
||||
_battleground->stopFight();
|
||||
|
||||
room->disableMouse();
|
||||
room->playAnimWithSFX("v7210bw0", "v7050ee0", 500, PlayAnimParams::disappear(), 15168);
|
||||
}
|
||||
|
||||
void Typhoon::stopAnims() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
|
||||
for (unsigned i = 0; i < ARRAYSIZE(typhonHeadInfo); i++) {
|
||||
room->stopAnim(LayerId(typhonHeadInfo[i]._animNormal, i, "head"));
|
||||
room->stopAnim(LayerId(typhonHeadInfo[i]._animDie, i, "head"));
|
||||
room->stopAnim(LayerId(typhonHeadInfo[i]._animRespawn, i, "head"));
|
||||
room->stopAnim("v7050ba0");
|
||||
room->stopAnim("v7210bi0");
|
||||
room->stopAnim("v7140ec0");
|
||||
room->stopAnim("v7210bj0");
|
||||
room->stopAnim("v7140ec0");
|
||||
}
|
||||
}
|
||||
|
||||
void Typhoon::disableHotzones() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
for (unsigned i = 0; i < ARRAYSIZE(typhonHeadInfo); i++)
|
||||
room->disableHotzone(typhonHeadInfo[i]._hotZone);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user