239 lines
6.5 KiB
C++
239 lines
6.5 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 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/>.
|
|
*
|
|
*/
|
|
|
|
#include "scumm/he/intern_he.h"
|
|
#include "scumm/he/basketball/basketball.h"
|
|
#include "scumm/he/basketball/collision/bball_collision_shields.h"
|
|
|
|
namespace Scumm {
|
|
|
|
Basketball::Basketball(ScummEngine_v100he *vm) {
|
|
_vm = vm;
|
|
_court = new CBBallCourt();
|
|
_shields = new CCollisionShieldVector();
|
|
}
|
|
|
|
Basketball::~Basketball() {
|
|
delete _court;
|
|
delete _shields;
|
|
}
|
|
|
|
int Basketball::u32FloatToInt(float input) {
|
|
int output = 0;
|
|
|
|
if (input < 0)
|
|
output = (int)(input - 0.5F);
|
|
else if (input > 0)
|
|
output = (int)(input + 0.5F);
|
|
|
|
return output;
|
|
}
|
|
|
|
int Basketball::u32DoubleToInt(double input) {
|
|
int output = 0;
|
|
|
|
if (input < 0)
|
|
output = (int)(input - 0.5);
|
|
else if (input > 0)
|
|
output = (int)(input + 0.5);
|
|
|
|
return output;
|
|
}
|
|
|
|
void Basketball::fillBallTargetList(const CCollisionSphere *sourceObject, CCollisionObjectVector *targetList) {
|
|
// Add all of the court objects...
|
|
_court->_objectTree.selectObjectsInBound(sourceObject->getBigBoundingBox(), targetList);
|
|
|
|
// Add the shields...
|
|
CCollisionShieldVector::const_iterator shieldIt;
|
|
|
|
for (shieldIt = _shields->begin(); shieldIt != _shields->end(); ++shieldIt) {
|
|
if (!shieldIt->_ignore) {
|
|
targetList->push_back(&(*shieldIt));
|
|
}
|
|
}
|
|
|
|
// Add all of the home players...
|
|
Common::Array<CCollisionPlayer>::const_iterator homePlayerIt;
|
|
|
|
for (homePlayerIt = _court->_homePlayerList.begin();
|
|
homePlayerIt != _court->_homePlayerList.end();
|
|
++homePlayerIt) {
|
|
if (!homePlayerIt->_ignore) {
|
|
targetList->push_back(&(*homePlayerIt));
|
|
}
|
|
}
|
|
|
|
// Add all of the away players...
|
|
Common::Array<CCollisionPlayer>::const_iterator awayPlayerIt;
|
|
|
|
for (awayPlayerIt = _court->_awayPlayerList.begin();
|
|
awayPlayerIt != _court->_awayPlayerList.end();
|
|
++awayPlayerIt) {
|
|
if (!awayPlayerIt->_ignore) {
|
|
targetList->push_back(&(*awayPlayerIt));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Basketball::fillPlayerTargetList(const CCollisionPlayer *sourceObject, CCollisionObjectVector *targetList) {
|
|
// Add all of the court objects...
|
|
_court->_objectTree.selectObjectsInBound(sourceObject->getBigBoundingBox(), targetList);
|
|
|
|
// Add the shields if the player has the ball...
|
|
if (sourceObject->_playerHasBall) {
|
|
CCollisionShieldVector::const_iterator shieldIt;
|
|
|
|
for (shieldIt = _shields->begin(); shieldIt != _shields->end(); ++shieldIt) {
|
|
if (!shieldIt->_ignore) {
|
|
targetList->push_back(&(*shieldIt));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the basketball...
|
|
if (!_court->_basketBall._ignore) {
|
|
targetList->push_back((ICollisionObject *)&_court->_basketBall);
|
|
}
|
|
|
|
// Add the virtual basketball...
|
|
if (!_court->_virtualBall._ignore) {
|
|
targetList->push_back((ICollisionObject *)&_court->_virtualBall);
|
|
}
|
|
|
|
// Add all of the home players...
|
|
Common::Array<CCollisionPlayer>::const_iterator homePlayerIt;
|
|
|
|
for (homePlayerIt = _court->_homePlayerList.begin();
|
|
homePlayerIt != _court->_homePlayerList.end();
|
|
++homePlayerIt) {
|
|
if ((sourceObject != &(*homePlayerIt)) &&
|
|
(!homePlayerIt->_ignore)) {
|
|
targetList->push_back(&(*homePlayerIt));
|
|
}
|
|
}
|
|
|
|
// Add all of the away players...
|
|
Common::Array<CCollisionPlayer>::const_iterator awayPlayerIt;
|
|
|
|
for (awayPlayerIt = _court->_awayPlayerList.begin();
|
|
awayPlayerIt != _court->_awayPlayerList.end();
|
|
++awayPlayerIt) {
|
|
if ((sourceObject != &(*awayPlayerIt)) &&
|
|
(!awayPlayerIt->_ignore)) {
|
|
targetList->push_back(&(*awayPlayerIt));
|
|
}
|
|
}
|
|
}
|
|
|
|
double Basketball::getLaunchAngle(int velocity, int hDist, int vDist, int gravity) {
|
|
double theta;
|
|
double bestTheta;
|
|
double tempTheta;
|
|
double thetaMin, thetaMax;
|
|
|
|
double answer;
|
|
double bestAnswer;
|
|
double hiAnswer, loAnswer;
|
|
|
|
double time;
|
|
double bestTime;
|
|
|
|
double targetAngle;
|
|
int counter;
|
|
|
|
assert(hDist > 0);
|
|
|
|
// Set the search limits, and get a first guess...
|
|
targetAngle = atan2(vDist, hDist);
|
|
|
|
// The minimum angle of the pass is the angle directly between us and the target...
|
|
thetaMin = targetAngle;
|
|
|
|
// The maximum angle is straight up...
|
|
thetaMax = BBALL_M_PI / 4;
|
|
|
|
theta = (thetaMin + thetaMax) / 2;
|
|
bestTheta = theta;
|
|
bestTime = hDist / (velocity * cos(theta));
|
|
if (bestTime < 0)
|
|
bestTime *= -1;
|
|
|
|
// Start binary searching for a close answer...
|
|
counter = 0;
|
|
answer = (2 * velocity * velocity * hDist * sin(theta) * cos(theta)) - (2 * velocity * velocity * vDist * cos(theta) * cos(theta)) - (gravity * hDist * hDist);
|
|
if (answer < 0)
|
|
answer *= -1;
|
|
bestAnswer = answer;
|
|
|
|
while ((fabs(answer * 1000.0) > 10.0) && (++counter <= 100)) {
|
|
if (theta < 0)
|
|
targetAngle += (2 * BBALL_M_PI);
|
|
|
|
// Get a theta above and below the current one and see which one gets us closer
|
|
// to satisfying the equation...
|
|
tempTheta = (thetaMin + theta) / 2;
|
|
loAnswer = (2 * velocity * velocity * hDist * sin(tempTheta) * cos(tempTheta)) - (2 * velocity * velocity * vDist * cos(tempTheta) * cos(tempTheta)) - (gravity * hDist * hDist);
|
|
if (loAnswer < 0)
|
|
loAnswer = 0 - loAnswer;
|
|
|
|
tempTheta = (thetaMax + theta) / 2;
|
|
hiAnswer = (2 * velocity * velocity * hDist * sin(tempTheta) * cos(tempTheta)) - (2 * velocity * velocity * vDist * cos(tempTheta) * cos(tempTheta)) - (gravity * hDist * hDist);
|
|
if (hiAnswer < 0)
|
|
hiAnswer = 0 - hiAnswer;
|
|
|
|
if (loAnswer < hiAnswer) {
|
|
thetaMax = theta;
|
|
answer = loAnswer;
|
|
} else {
|
|
thetaMin = theta;
|
|
answer = hiAnswer;
|
|
}
|
|
theta = (thetaMin + thetaMax) / 2;
|
|
if (answer < 0)
|
|
answer *= -1;
|
|
|
|
if (answer <= bestAnswer) {
|
|
if (answer == bestAnswer) {
|
|
time = hDist / (velocity * cos(theta));
|
|
if (time < 0)
|
|
time *= -1;
|
|
if (time < bestTime) {
|
|
bestTheta = theta;
|
|
bestTime = time;
|
|
bestAnswer = answer;
|
|
}
|
|
} else {
|
|
bestTheta = theta;
|
|
bestTime = hDist / (velocity * cos(theta));
|
|
if (bestTime < 0)
|
|
bestTime *= -1;
|
|
bestAnswer = answer;
|
|
}
|
|
}
|
|
}
|
|
|
|
bestTheta = (bestTheta * 180) / BBALL_M_PI;
|
|
return bestTheta;
|
|
}
|
|
|
|
} // End of namespace Scumm
|