Initial commit
This commit is contained in:
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));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user