Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,568 @@
/* 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.h"
#include "scumm/he/basketball/geo_translations.h"
namespace Scumm {
int LogicHEBasketball::u32_userInitCourt(int courtID) {
static const char *courtNames[] = {
"",
"Dobbaguchi", "Jocindas", "SandyFlats", "Queens",
"Park", "Scheffler", "Polk", "McMillan",
"CrownHill", "Memorial", "TechState", "Garden",
"Moon", "Barn"
};
// Make sure nothing on the court is currently initialized.
_vm->_basketball->_court->_objectTree.~CCollisionObjectTree();
_vm->_basketball->_court->_objectList.clear();
_vm->_basketball->_court->_homePlayerList.clear();
_vm->_basketball->_court->_awayPlayerList.clear();
// Initialize the shot spots
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].center.x = BASKET_X;
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].center.y = BASKET_Y;
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].center.z = BASKET_Z;
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].radius = SHOT_SPOT_RADIUS;
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].center.x = MAX_WORLD_X - BASKET_X;
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].center.y = BASKET_Y;
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].center.z = BASKET_Z;
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].radius = SHOT_SPOT_RADIUS;
// Get the name and object file for this court.
_vm->_basketball->_court->_name = Common::String(courtNames[courtID]);
// Put together to relative path and filename.
Common::Path objectFileName = Common::Path(Common::String::format("data/courts/%s.cof", courtNames[courtID]));
// Create a file stream to the collision object file
Common::File objectFile;
if (!objectFile.open(objectFileName))
error("LogicHEBasketball::u32_userInitCourt(): Could not open file '%s'", objectFileName.toString(Common::Path::kNativeSeparator).c_str());
// Read in the object file version
char fileVersion[32];
int versionStringLength = objectFile.readUint32LE();
if (versionStringLength <= 0 || versionStringLength > ARRAYSIZE(fileVersion) - 1)
error("LogicHEBasketball::u32_userInitCourt(): Read from stream did not read the version string length correctly.");
objectFile.read(fileVersion, versionStringLength);
fileVersion[versionStringLength] = '\0';
if (strcmp(fileVersion, "01.05"))
error("LogicHEBasketball::u32_userInitCourt(): Invalid court version field: %s", fileVersion);
// Read in the total number of objects
_vm->_basketball->_court->_objectCount = objectFile.readUint32LE();
_vm->_basketball->_court->_objectList.resize(_vm->_basketball->_court->_objectCount);
// Keep a list of pointers to the court objects...
CCollisionObjectVector objectPtrList;
objectPtrList.resize(_vm->_basketball->_court->_objectCount);
// Read in each court object...
for (int i = 0; i < _vm->_basketball->_court->_objectCount; i++) {
CCollisionBox *currentObject = &_vm->_basketball->_court->_objectList[i];
// Read in this object's description...
int descriptionStringLength = objectFile.readUint32LE();
char *tmp = (char *)malloc(descriptionStringLength + 1);
assert(tmp);
objectFile.read(tmp, descriptionStringLength);
tmp[descriptionStringLength] = '\0';
Common::String tmp2(tmp);
_vm->_basketball->_court->_objectList[i]._description = Common::move(tmp2);
free(tmp);
// Read in all other object attributes...
currentObject->_objectType = (EObjectType)objectFile.readUint32LE();
currentObject->_collisionEfficiency = objectFile.readFloatLE();
currentObject->_friction = objectFile.readFloatLE();
currentObject->_soundNumber = objectFile.readUint32LE();
currentObject->_objectID = objectFile.readUint32LE();
currentObject->minPoint.x = objectFile.readUint32LE();
currentObject->minPoint.y = objectFile.readUint32LE();
currentObject->minPoint.z = objectFile.readUint32LE();
currentObject->maxPoint.x = objectFile.readUint32LE();
currentObject->maxPoint.y = objectFile.readUint32LE();
currentObject->maxPoint.z = objectFile.readUint32LE();
objectPtrList[i] = currentObject;
// Decide if this is a backboard, and keep track of it if it is...
if (currentObject->_objectType == kBackboard) {
// See which backboard it is...
if (((currentObject->minPoint.x + currentObject->maxPoint.x) / 2) < (MAX_WORLD_X / 2)) {
_vm->_basketball->_court->_backboardIndex[LEFT_BASKET] = i;
} else {
_vm->_basketball->_court->_backboardIndex[RIGHT_BASKET] = i;
}
}
}
_vm->_basketball->_court->_objectTree.initialize(objectPtrList);
// Lower all the shields...
u32_userLowerShields(ALL_SHIELD_ID);
return 1;
}
int LogicHEBasketball::u32_userDeinitCourt() {
// Make sure the collision object tree has been cleared...
_vm->_basketball->_court->_objectTree.~CCollisionObjectTree();
// Lower all the shields...
u32_userLowerShields(ALL_SHIELD_ID);
return 1;
}
int LogicHEBasketball::u32_userInitBall(U32FltPoint3D &ballLocation, U32FltVector3D &bellVelocity, int radius, int ballID) {
_vm->_basketball->_court->_basketBall._description = "Basketball";
_vm->_basketball->_court->_basketBall._objectType = kBall;
_vm->_basketball->_court->_basketBall._objectID = ballID;
_vm->_basketball->_court->_basketBall.center = ballLocation;
_vm->_basketball->_court->_basketBall._velocity = bellVelocity;
_vm->_basketball->_court->_basketBall.radius = radius;
_vm->_basketball->_court->_basketBall._collisionEfficiency = 1.0F;
_vm->_basketball->_court->_basketBall._friction = 0.0F;
_vm->_basketball->_court->_basketBall._ignore = false;
_vm->_basketball->_court->_basketBall.save();
return 1;
}
int LogicHEBasketball::u32_userInitVirtualBall(U32FltPoint3D &ballLocation, U32FltVector3D &bellVelocity, int radius, int ballID) {
_vm->_basketball->_court->_virtualBall._description = "Virtual Basketball";
_vm->_basketball->_court->_virtualBall._objectType = kBall;
_vm->_basketball->_court->_virtualBall._objectID = ballID;
_vm->_basketball->_court->_virtualBall.center = ballLocation;
_vm->_basketball->_court->_virtualBall._velocity = bellVelocity;
_vm->_basketball->_court->_virtualBall.radius = radius;
_vm->_basketball->_court->_virtualBall._collisionEfficiency = 1.0F;
_vm->_basketball->_court->_virtualBall._friction = 0.0F;
_vm->_basketball->_court->_virtualBall._ignore = false;
_vm->_basketball->_court->_virtualBall.save();
return 1;
}
int LogicHEBasketball::u32_userDeinitBall() {
_vm->_basketball->_court->_basketBall._ignore = true;
return 1;
}
int LogicHEBasketball::u32_userDeinitVirtualBall() {
_vm->_basketball->_court->_virtualBall._ignore = true;
return 1;
}
int LogicHEBasketball::u32_userInitPlayer(int playerID, U32FltPoint3D &playerLocation, int height, int radius, bool playerIsInGame) {
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
error("LogicHEBasketball::u32_userInitPlayer(): Passed in invalid player ID");
// Cycle through all of the player slots until an empty one is found...
Common::Array<CCollisionPlayer> *playerList = _vm->_basketball->_court->getPlayerListPtr(playerID);
if (playerList->size() < MAX_PLAYERS_ON_TEAM) {
CCollisionPlayer newPlayer;
newPlayer._objectType = kPlayer;
newPlayer._objectID = playerID;
newPlayer.height = height;
newPlayer._catchHeight = PLAYER_CATCH_HEIGHT;
newPlayer.radius = radius;
newPlayer.center = playerLocation;
newPlayer.center.z = playerLocation.z + (height / 2);
newPlayer._collisionEfficiency = 0.5F;
newPlayer._friction = 0.5F;
newPlayer._playerIsInGame = playerIsInGame;
newPlayer.save();
playerList->push_back(newPlayer);
return 1;
} else {
warning("LogicHEBasketball::u32_userInitPlayer(): There were no empty player slots. You can't initialize a new player until you deinit one.");
return 0;
}
}
int LogicHEBasketball::u32_userDeinitPlayer(int playerID) {
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
error("LogicHEBasketball::u32_userDeinitPlayer(): Passed in invalid player ID");
int index = _vm->_basketball->_court->getPlayerIndex(playerID);
Common::Array<CCollisionPlayer> *playerList = _vm->_basketball->_court->getPlayerListPtr(playerID);
playerList->remove_at(index);
return 1;
}
int LogicHEBasketball::u32_userPlayerOff(int playerID) {
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
error("LogicHEBasketball::u32_userPlayerOff(): Passed in invalid player ID");
_vm->_basketball->_court->getPlayerPtr(playerID)->_ignore = true;
return 1;
}
int LogicHEBasketball::u32_userPlayerOn(int playerID) {
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
error("LogicHEBasketball::u32_userPlayerOn(): Passed in invalid player ID");
_vm->_basketball->_court->getPlayerPtr(playerID)->_ignore = false;
return 1;
}
static void trackCollisionObject(const ICollisionObject &sourceObject, const ICollisionObject &targetObject, CCollisionObjectVector *objectVector) {
float currentDist = sourceObject.getObjectDistance(targetObject);
// As an object moves backwards along its velocity vector and new collisions
// are detected, older collisions may become invalid. Here, we go through prior
// collisions, and see which ones are invalidated by this new collision.
for (CCollisionObjectVector::const_iterator objectIt = objectVector->begin();
objectIt != objectVector->end();
++objectIt) {
float pastDist = sourceObject.getObjectDistance(**objectIt);
// If the distance between the source object and the current target object
// is less than or equal to the distance between the source object and the last
// target object, then the current target object is stored along side the last
// target object. Otherwise, the current object replaces the last object.
if ((fabs(pastDist - currentDist) < COLLISION_EPSILON) ||
(!sourceObject.isCollisionHandled(targetObject)) ||
(!sourceObject.isCollisionHandled(**objectIt))) {
break;
}
}
// Make sure that we aren't keeping track of the same object twice...
if (!objectVector->contains(targetObject)) {
objectVector->push_back(&targetObject);
}
}
int LogicHEBasketball::u32_userDetectBallCollision(U32FltPoint3D &ballLocation, U32FltVector3D &ballVector, int recordCollision, int ballID) {
bool ballIsClear = false; // Flag that indicates if the ball collided with any objects on its current vector
bool errorOccurred = false;
U32Distance3D distance; // The distance between the ball and a collision object candidate
CCollisionObjectVector targetList; // All potential collision candidates
CCollisionObjectVector collisionVector; // All objects that have been collided with
CCollisionObjectVector rollingVector; // All objects that have been rolled on
int collisionOccurred = 0;
int rollingHappened = 0;
// Determine which ball we're dealing with...
CCollisionBasketball *sourceBall = _vm->_basketball->_court->getBallPtr(ballID);
// Update the position and vector of the basketball...
sourceBall->center = ballLocation;
sourceBall->_velocity = ballVector;
// Clear the ball's collision stack...
sourceBall->_objectCollisionHistory.clear();
sourceBall->_objectRollingHistory.clear();
// Find out who our potential collision candidates are...
_vm->_basketball->fillBallTargetList(sourceBall, &targetList);
// See if there was an error while traversing the object tree,
// if there was put the player in the last known safe position...
if (_vm->_basketball->_court->_objectTree.checkErrors()) {
sourceBall->restore();
}
for (int i = 0; (i < MAX_BALL_COLLISION_PASSES) && (!ballIsClear); i++) {
float totalTime = 0.0F; // The time it takes to back out of all objects we have intersected while on the current vector
ballIsClear = true;
// Go through all of the collision candidates....
for (size_t j = 0; j < targetList.size(); ++j) {
const ICollisionObject *targetObject = targetList[j];
assert(targetObject);
// See if we intersect the current object...
bool intersectionResult = sourceBall->testObjectIntersection(*targetObject, &distance);
if (intersectionResult) {
// If we are intersecting a moving object, make sure that we actually
// ran into them, and they didn't just run into us...
if (sourceBall->validateCollision(*targetObject, &distance)) {
// If we are intersecting the object, back out of it...
if (sourceBall->backOutOfObject(*targetObject, &distance, &totalTime)) {
// Move in to the exact point of collision...
if (sourceBall->nudgeObject(*targetObject, &distance, &totalTime)) {
// Keep track of this object so we can respond to the collision later...
trackCollisionObject(*sourceBall, *targetObject, &sourceBall->_objectCollisionHistory);
if (sourceBall->isCollisionHandled(*targetObject)) {
trackCollisionObject(*sourceBall, *targetObject, &collisionVector);
ballIsClear = false;
}
collisionOccurred = 1;
} else {
errorOccurred = true;
}
} else {
errorOccurred = true;
}
}
} else {
// See if we are passing over a player...
if (sourceBall->testCatch(*targetObject, &distance, _vm->_basketball->_court)) {
trackCollisionObject(*sourceBall, *targetObject, &sourceBall->_objectCollisionHistory);
collisionOccurred = true;
}
}
// See if we are rolling on the current object...
if (sourceBall->isOnObject(*targetObject, distance)) {
rollingHappened = 1;
if (!intersectionResult) {
// This is not really a collision, but the ball is rolling, so we want to slow it down...
trackCollisionObject(*sourceBall, *targetObject, &rollingVector);
trackCollisionObject(*sourceBall, *targetObject, &sourceBall->_objectRollingHistory);
}
}
}
// Adjust the ball's velocity and position due to any collisions...
sourceBall->handleCollisions(&rollingVector, &totalTime, false);
sourceBall->handleCollisions(&collisionVector, &totalTime, true);
}
// Keep track of how long we've been rolling...
if (rollingHappened) {
++sourceBall->_rollingCount;
} else {
sourceBall->_rollingCount = 0;
}
// If there were no errors this frame, save the position...
if (!errorOccurred) {
sourceBall->save();
}
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(sourceBall->center.x));
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(sourceBall->center.y));
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(sourceBall->center.z));
writeScummVar(_vm1->VAR_U32_USER_VAR_D, _vm->_basketball->u32FloatToInt(sourceBall->_velocity.x));
writeScummVar(_vm1->VAR_U32_USER_VAR_E, _vm->_basketball->u32FloatToInt(sourceBall->_velocity.y));
writeScummVar(_vm1->VAR_U32_USER_VAR_F, _vm->_basketball->u32FloatToInt(sourceBall->_velocity.z));
writeScummVar(_vm1->VAR_U32_USER_VAR_G, collisionOccurred);
writeScummVar(_vm1->VAR_U32_USER_VAR_H, rollingHappened != 0 ? 0 : 1);
return 1;
}
int LogicHEBasketball::u32_userDetectPlayerCollision(int playerID, U32FltPoint3D &playerLocation, U32FltVector3D &playerVector, bool playerHasBall) {
U32Distance3D distance; // The distance between the ball and a collision object candidate
CCollisionObjectVector collisionVector; // All objects that have been collided with
int playerIsOnObject = 0;
int collisionOccurred = 0;
bool playerIsClear = false;
bool errorOccurred = false;
float totalTime = 0.0F; // The time it takes to back out of all objects we have intersected on this frame
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
error("LogicHEBasketball::u32_userDetectPlayerCollision(): Passed in invalid player ID");
// Get the player who is being tested...
CCollisionPlayer *sourcePlayer = _vm->_basketball->_court->getPlayerPtr(playerID);
// Update the player's status...
sourcePlayer->_playerHasBall = playerHasBall;
// In SCUMM code, the center of a player in the z dimension is at their feet.
// In U32 code, it is in the middle of the cylinder, so make the translation...
playerLocation.z += (sourcePlayer->height / 2);
// Update the player's position and velocity...
sourcePlayer->center = playerLocation;
sourcePlayer->_velocity = playerVector;
sourcePlayer->_movementType = kStraight;
// Clear the player's collision stack...
sourcePlayer->_objectCollisionHistory.clear();
sourcePlayer->_objectRollingHistory.clear();
// Find out who our potential collision candidates are...
CCollisionObjectVector targetList;
_vm->_basketball->fillPlayerTargetList(sourcePlayer, &targetList);
// See if there was an error while traversing the object tree,
// if there was put the player in the last known safe position...
if (_vm->_basketball->_court->_objectTree.checkErrors()) {
sourcePlayer->restore();
}
for (int i = 0; (i < MAX_PLAYER_COLLISION_PASSES) && (!playerIsClear); i++) {
playerIsClear = 1;
// Check all of the collision candidates...
for (size_t j = 0; j < targetList.size(); ++j) {
const ICollisionObject *targetObject = targetList[j];
assert(targetObject);
// See if we intersect the current object...
bool intersectionResult = sourcePlayer->testObjectIntersection(*targetObject, &distance);
if (intersectionResult) {
// If we are intersecting a moving object, make sure that we actually
// ran into them, and they didn't just run into us...
if (sourcePlayer->validateCollision(*targetObject, &distance)) {
// If we are intersecting an object, back out to the exact point of collision...
if (sourcePlayer->backOutOfObject(*targetObject, &distance, &totalTime)) {
// Move in to the exact point of collision...
if (sourcePlayer->nudgeObject(*targetObject, &distance, &totalTime)) {
trackCollisionObject(*sourcePlayer, *targetObject, &sourcePlayer->_objectCollisionHistory);
collisionOccurred = true;
if (sourcePlayer->isCollisionHandled(*targetObject)) {
trackCollisionObject(*sourcePlayer, *targetObject, &collisionVector);
playerIsClear = false;
}
} else {
errorOccurred = true;
}
} else {
errorOccurred = true;
}
}
} else {
// See if the virtual ball is passing over us...
if (sourcePlayer->testCatch(*targetObject, &distance, _vm->_basketball->_court)) {
trackCollisionObject(*sourcePlayer, *targetObject, &sourcePlayer->_objectCollisionHistory);
collisionOccurred = true;
}
}
// See if we are standing on the current object...
if (sourcePlayer->isOnObject(*targetObject, distance)) {
playerIsOnObject = true;
}
}
sourcePlayer->handleCollisions(&collisionVector, &totalTime, true);
}
// If there were no errors this frame, save the position...
if (!errorOccurred) {
sourcePlayer->save();
}
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(sourcePlayer->center.x));
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(sourcePlayer->center.y));
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(sourcePlayer->center.z - (sourcePlayer->height / 2)));
writeScummVar(_vm1->VAR_U32_USER_VAR_D, _vm->_basketball->u32FloatToInt(sourcePlayer->_velocity.x));
writeScummVar(_vm1->VAR_U32_USER_VAR_E, _vm->_basketball->u32FloatToInt(sourcePlayer->_velocity.y));
writeScummVar(_vm1->VAR_U32_USER_VAR_F, _vm->_basketball->u32FloatToInt(sourcePlayer->_velocity.z));
writeScummVar(_vm1->VAR_U32_USER_VAR_G, collisionOccurred);
writeScummVar(_vm1->VAR_U32_USER_VAR_H, playerIsOnObject != 0 ? 0 : 1);
return 1;
}
int LogicHEBasketball::u32_userGetLastBallCollision(int ballID) {
EObjectType lastObjectType = kNoObjectType;
int objectID = 0;
// Determine which ball we're dealing with
CCollisionSphere *sourceBall;
if (ballID == _vm->_basketball->_court->_basketBall._objectID) {
sourceBall = (CCollisionSphere *)&_vm->_basketball->_court->_basketBall;
} else if (ballID == _vm->_basketball->_court->_virtualBall._objectID) {
sourceBall = (CCollisionSphere *)&_vm->_basketball->_court->_virtualBall;
} else {
warning("LogicHEBasketball::u32_userGetLastBallCollision(): Invalid ball ID %d.", ballID);
sourceBall = (CCollisionSphere *)&_vm->_basketball->_court->_basketBall;
}
if (!sourceBall->_objectCollisionHistory.empty()) {
lastObjectType = sourceBall->_objectCollisionHistory.back()->_objectType;
objectID = sourceBall->_objectCollisionHistory.back()->_objectID;
sourceBall->_objectCollisionHistory.pop_back();
} else if (!sourceBall->_objectRollingHistory.empty()) {
lastObjectType = sourceBall->_objectRollingHistory.back()->_objectType;
objectID = sourceBall->_objectRollingHistory.back()->_objectID;
sourceBall->_objectRollingHistory.pop_back();
}
writeScummVar(_vm1->VAR_U32_USER_VAR_A, lastObjectType);
writeScummVar(_vm1->VAR_U32_USER_VAR_B, objectID);
return 1;
}
int LogicHEBasketball::u32_userGetLastPlayerCollision(int playerID) {
EObjectType lastObjectType = kNoObjectType;
int objectID = 0;
bool playerIsOnObject = false;
CCollisionPlayer *pPlayer = _vm->_basketball->_court->getPlayerPtr(playerID);
if (!pPlayer->_objectCollisionHistory.empty()) {
const ICollisionObject *targetObject = pPlayer->_objectCollisionHistory.back();
lastObjectType = targetObject->_objectType;
objectID = targetObject->_objectID;
// See if we are standing on the current object
U32Distance3D distance;
pPlayer->testObjectIntersection(*targetObject, &distance);
if (pPlayer->isOnObject(*targetObject, distance)) {
playerIsOnObject = true;
}
pPlayer->_objectCollisionHistory.pop_back();
}
writeScummVar(_vm1->VAR_U32_USER_VAR_A, lastObjectType);
writeScummVar(_vm1->VAR_U32_USER_VAR_B, objectID);
writeScummVar(_vm1->VAR_U32_USER_VAR_C, playerIsOnObject);
return 1;
}
} // End of namespace Scumm

View File

@@ -0,0 +1,48 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
namespace Scumm {
#define RIM_CE 0.4F
#define BACKBOARD_CE 0.3F
#define FLOOR_CE 0.65F
#define LEFT_BASKET 0
#define RIGHT_BASKET 1
#define RIM_WIDTH (WORLD_UNIT_MULTIPLIER / 11)
#define RIM_RADIUS ((3 * WORLD_UNIT_MULTIPLIER) / 4)
#define MAX_BALL_COLLISION_PASSES 10
#define MAX_PLAYER_COLLISION_PASSES 3
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_H

View File

@@ -0,0 +1,45 @@
/* 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/basketball/court.h"
#include "scumm/he/basketball/collision/bball_collision_basketball.h"
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
bool CCollisionBasketball::testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court) {
if (targetObject._objectType == kPlayer) {
ICollisionObject *object = const_cast<ICollisionObject *>(&targetObject);
CCollisionPlayer *player = static_cast<CCollisionPlayer *>(object);
return (player->testCatch(*this, distance, court));
} else {
return false;
}
}
} // End of namespace Scumm

View File

@@ -0,0 +1,47 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BASKETBALL_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BASKETBALL_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/court.h"
#include "scumm/he/basketball/basketball.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
namespace Scumm {
class CBBallCourt;
class CCollisionBasketball : public CCollisionSphere {
public:
CCollisionBasketball() {}
~CCollisionBasketball() {}
bool testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court);
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BASKETBALL_H

View File

@@ -0,0 +1,59 @@
/* 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/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
U32FltPoint3D CCollisionBox::findNearestPoint(const U32FltPoint3D &testPoint) const {
U32FltPoint3D boxPoint;
for (int i = X_INDEX; i <= Z_INDEX; i++) {
EDimension dimension = (EDimension)i;
if (testPoint[dimension] < minPoint[dimension]) {
boxPoint[dimension] = minPoint[dimension];
} else if (testPoint[dimension] > maxPoint[dimension]) {
boxPoint[dimension] = maxPoint[dimension];
} else {
boxPoint[dimension] = testPoint[dimension];
}
}
return boxPoint;
}
U32BoundingBox CCollisionBox::getBoundingBox() const {
return *this;
}
U32BoundingBox CCollisionBox::getBigBoundingBox() const {
return *this;
}
} // End of namespace Scumm

View File

@@ -0,0 +1,46 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BOX_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BOX_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_object.h"
namespace Scumm {
class CCollisionBox : public ICollisionObject, public U32BoundingBox {
public:
CCollisionBox() : ICollisionObject(kBox) {}
~CCollisionBox() {}
U32FltPoint3D findNearestPoint(const U32FltPoint3D &testPoint) const override;
U32BoundingBox getBoundingBox() const override;
U32BoundingBox getBigBoundingBox() const override;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BOX_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_CYLINDER_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_CYLINDER_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
namespace Scumm {
#define MAX_STEP_HEIGHT 50
// An object's velocity can either be carried
// out as straight or circular movement...
enum EMovementType {
kStraight = 0,
kCircular = 1 // 2D circular motion along the horizon plane
};
class CCollisionCylinder : public ICollisionObject, public U32Cylinder {
public:
CCollisionCylinder() : ICollisionObject(kCylinder),
height(0),
_shieldRadius(0),
_movementType(EMovementType::kStraight),
_revCenter(nullptr),
_positionSaved(false) {}
~CCollisionCylinder() {}
using ICollisionObject::getObjectDistance;
float getObjectDistance(const CCollisionSphere &targetObject) const override;
float getObjectDistance(const CCollisionBox &targetObject) const override;
float getObjectDistance(const CCollisionCylinder &targetObject) const override;
using ICollisionObject::testObjectIntersection;
bool testObjectIntersection(const CCollisionSphere &targetObject, U32Distance3D *distance) const override;
bool testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *distance) const override;
bool testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *distance) const override;
using ICollisionObject::validateCollision;
bool validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *distance) override;
using ICollisionObject::backOutOfObject;
bool backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) override;
bool backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) override;
using ICollisionObject::nudgeObject;
bool nudgeObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) override;
bool nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) override;
using ICollisionObject::isCollisionHandled;
bool isCollisionHandled(const CCollisionSphere &targetObject) const override { return false; };
void handleCollisions(CCollisionObjectVector *collisionVector, float *timeUsed, bool advanceObject) override;
void handleCollision(const CCollisionCylinder &targetCylinder, float *timeUsed, U32Distance3D *distance, bool advanceObject) override;
void handleCollision(const CCollisionBox &targetBox, float *pTimeUsed, U32Distance3D *distance, bool advanceObject) override;
using ICollisionObject::isOnObject;
bool isOnObject(const CCollisionSphere &targetObject, const U32Distance3D &distance) const override;
bool isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const override;
bool isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const override;
U32FltPoint3D findNearestPoint(const U32FltPoint3D &testPoint) const override;
int getEquidistantPoint(U32FltPoint2D inPoint1, float distance1, U32FltPoint2D inPoint2, float distance2, U32FltPoint2D *outPoint1, U32FltPoint2D *outPoint2);
U32BoundingBox getBoundingBox() const override;
U32BoundingBox getBigBoundingBox() const override;
void save() override;
void restore() override;
float height;
float _shieldRadius; // Sometimes we may want ot temporarily increase a player's
// effective collision radius. This value keeps track of
// how much their radius has been increased by.
EMovementType _movementType;
const ICollisionObject *_revCenter; // If an object is moving with circular motion,
// this is the object it is revolving around.
U32FltPoint2D _revCenterPt; // This is the center of the _revCenter.
protected:
float getDimensionDistance(const CCollisionBox &targetObject, EDimension dimension) const;
float getDimensionDistance(const CCollisionSphere &targetObject, EDimension dimension) const;
float getDimensionDistance(const CCollisionCylinder &targetObject, EDimension dimension) const;
private:
bool _positionSaved;
U32FltPoint3D _safetyPoint;
U32FltVector3D _safetyVelocity;
bool backStraightOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed);
bool circleOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed);
bool circleOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed);
ERevDirection getRevDirection() const;
using ICollisionObject::getPenetrationTime;
float getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
float getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
float getPointOfCollision(const CCollisionBox &targetBox, U32Distance3D distance, EDimension dimension) const;
void forceOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance);
bool getCornerIntersection(const CCollisionBox &targetObject, const U32Distance3D &distance, U32FltPoint2D *intersection);
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_CYLINDER_H

View File

@@ -0,0 +1,135 @@
/* 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/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
CCollisionNode::CCollisionNode() {
for (int i = 0; i < NUM_CHILDREN_NODES; i++) {
_child[i] = nullptr;
}
_quadrant.setMinPoint(0, 0);
_quadrant.setMaxPoint(0, 0);
_isExternal = false;
}
CCollisionNode::CCollisionNode(const CCollisionObjectVector &initObjects) : _objectList(initObjects) {
for (int i = 0; i < NUM_CHILDREN_NODES; i++) {
_child[i] = nullptr;
}
_quadrant.setMinPoint(0, 0);
_quadrant.setMaxPoint(0, 0);
_isExternal = false;
}
CCollisionNode::~CCollisionNode() {
if (!_isExternal) {
for (int i = 0; i < NUM_CHILDREN_NODES; i++) {
assert(_child[i]);
delete _child[i];
_child[i] = nullptr;
}
}
}
U32BoundingBox CCollisionNode::getChildQuadrant(const U32BoundingBox &parentQuadrant, EChildID childID) {
int minX, minY;
int maxX, maxY;
int centerX = ((parentQuadrant.getMinPoint().x + parentQuadrant.getMaxPoint().x) / 2);
int centerY = ((parentQuadrant.getMinPoint().y + parentQuadrant.getMaxPoint().y) / 2);
switch (childID) {
case kChild1:
minX = centerX;
minY = parentQuadrant.getMinPoint().y;
maxX = parentQuadrant.getMaxPoint().x;
maxY = centerY;
break;
case kChild2:
minX = centerX;
minY = centerY;
maxX = parentQuadrant.getMaxPoint().x;
maxY = parentQuadrant.getMaxPoint().y;
break;
case kChild3:
minX = parentQuadrant.getMinPoint().x;
minY = centerY;
maxX = centerX;
maxY = parentQuadrant.getMaxPoint().y;
break;
case kChild4:
minX = parentQuadrant.getMinPoint().x;
minY = parentQuadrant.getMinPoint().y;
maxX = centerX;
maxY = centerY;
break;
default:
warning("CCollisionNode::getChildQuadrant(): Invalid childID passed to getChildQuadrant");
minX = 0;
minY = 0;
maxX = 0;
maxY = 0;
}
U32BoundingBox childQuadrant;
childQuadrant.setMinPoint(minX, minY);
childQuadrant.setMaxPoint(maxX, maxY);
return childQuadrant;
}
void CCollisionNode::searchTree(const U32BoundingBox &searchRange, CCollisionObjectVector *targetList) const {
if (searchRange.intersect(_quadrant)) {
if (_isExternal) {
// Search through and add points that are within bounds...
for (CCollisionObjectVector::size_type objectIndex = 0; objectIndex < _objectList.size(); ++objectIndex) {
if (!_objectList[objectIndex]->_ignore) {
const ICollisionObject *currentObject = _objectList[objectIndex];
targetList->push_back(currentObject);
}
}
} else {
// Search all of the children...
for (int childID = 0; childID < NUM_CHILDREN_NODES; childID++) {
_child[childID]->searchTree(searchRange, targetList);
}
}
}
}
} // End of namespace Scumm

View File

@@ -0,0 +1,70 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_NODE_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_NODE_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
namespace Scumm {
#define NUM_CHILDREN_NODES 4
enum EChildID {
kChild1 = 0,
kChild2 = 1,
kChild3 = 2,
kChild4 = 3
};
class CCollisionNode {
public:
CCollisionNode();
CCollisionNode(const CCollisionObjectVector &initObjects);
~CCollisionNode();
friend class CCollisionObjectTree;
private:
void searchTree(const U32BoundingBox &searchRange, CCollisionObjectVector *targetList) const;
static U32BoundingBox getChildQuadrant(const U32BoundingBox &parentQuadrant, EChildID childID);
// Children nodes to this node
CCollisionNode *_child[NUM_CHILDREN_NODES];
// A list of object pointers that are contained within this node
CCollisionObjectVector _objectList;
// The area that is handled by this node
U32BoundingBox _quadrant;
// Whether or not this is a leaf node
bool _isExternal;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_NODE_H

View File

@@ -0,0 +1,334 @@
/* 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/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
ICollisionObject::ICollisionObject(EObjectShape shape) : _objectShape(shape),
_objectID(0),
_objectType(kNoObjectType),
_description(""),
_collisionEfficiency(0.0F),
_friction(0.0F),
_soundNumber(0),
_ignore(false) {
_velocity.x = 0.0F;
_velocity.y = 0.0F;
_velocity.z = 0.0F;
}
bool ICollisionObject::operator==(const ICollisionObject &otherObject) const {
return ((otherObject._objectShape == _objectShape) &&
(otherObject._objectType == _objectType) &&
(otherObject._objectID == _objectID));
}
float ICollisionObject::getObjectDistance(const ICollisionObject &targetObject) const {
float result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::getObjectDistance(): Tried to interact with an object of undefined type");
result = 0.0F;
break;
case kSphere:
result = getObjectDistance(dynamic_cast<const CCollisionSphere &>(targetObject));
break;
case kBox:
result = getObjectDistance(dynamic_cast<const CCollisionBox &>(targetObject));
break;
case kCylinder:
result = getObjectDistance(dynamic_cast<const CCollisionCylinder &>(targetObject));
break;
default:
warning("ICollisionObject::getObjectDistance(): Tried to interact with an object of undefined type");
result = 0.0F;
}
return result;
}
bool ICollisionObject::testObjectIntersection(const ICollisionObject &targetObject, U32Distance3D *distance) const {
bool result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::testObjectIntersection(): Tried to interact with an object of undefined type");
result = false;
break;
case kSphere:
result = testObjectIntersection(dynamic_cast<const CCollisionSphere &>(targetObject), distance);
break;
case kBox:
result = testObjectIntersection(dynamic_cast<const CCollisionBox &>(targetObject), distance);
break;
case kCylinder:
result = testObjectIntersection(dynamic_cast<const CCollisionCylinder &>(targetObject), distance);
break;
default:
warning("ICollisionObject::testObjectIntersection(): Tried to interact with an object of undefined type");
result = false;
}
return result;
}
bool ICollisionObject::validateCollision(const ICollisionObject &targetObject, U32Distance3D *distance) {
if (_ignore)
return true;
bool result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::validateCollision(): Tried to interact with an object of undefined type");
result = false;
break;
case kSphere:
result = validateCollision(dynamic_cast<const CCollisionSphere &>(targetObject), distance);
break;
case kBox:
result = validateCollision(dynamic_cast<const CCollisionBox &>(targetObject), distance);
break;
case kCylinder:
result = validateCollision(dynamic_cast<const CCollisionCylinder &>(targetObject), distance);
break;
default:
warning("ICollisionObject::validateCollision(): Tried to interact with an object of undefined type");
result = false;
}
return result;
}
bool ICollisionObject::backOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed) {
if (_ignore)
return true;
bool result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::backOutOfObject(): Tried to interact with an object of undefined type");
result = false;
break;
case kSphere:
result = backOutOfObject(dynamic_cast<const CCollisionSphere &>(targetObject), distance, timeUsed);
break;
case kBox:
result = backOutOfObject(dynamic_cast<const CCollisionBox &>(targetObject), distance, timeUsed);
break;
case kCylinder:
result = backOutOfObject(dynamic_cast<const CCollisionCylinder &>(targetObject), distance, timeUsed);
break;
default:
warning("ICollisionObject::backOutOfObject(): Tried to interact with an object of undefined type");
result = false;
}
return result;
}
bool ICollisionObject::nudgeObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed) {
if (_velocity.magnitude() == 0)
return true;
if (_ignore)
return true;
if (*timeUsed == 0)
return true;
bool result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::nudgeObject(): Tried to interact with an object of undefined type");
result = false;
break;
case kSphere:
result = nudgeObject(dynamic_cast<const CCollisionSphere &>(targetObject), distance, timeUsed);
break;
case kBox:
result = nudgeObject(dynamic_cast<const CCollisionBox &>(targetObject), distance, timeUsed);
break;
case kCylinder:
result = nudgeObject(dynamic_cast<const CCollisionCylinder &>(targetObject), distance, timeUsed);
break;
default:
warning("ICollisionObject::nudgeObject(): Tried to interact with an object of undefined type");
result = false;
}
return result;
}
bool ICollisionObject::isCollisionHandled(const ICollisionObject &targetObject) const {
bool result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::isCollisionHandled(): Tried to interact with an object of undefined type");
result = false;
break;
case kSphere:
result = isCollisionHandled(dynamic_cast<const CCollisionSphere &>(targetObject));
break;
case kBox:
result = isCollisionHandled(dynamic_cast<const CCollisionBox &>(targetObject));
break;
case kCylinder:
result = isCollisionHandled(dynamic_cast<const CCollisionCylinder &>(targetObject));
break;
default:
warning("ICollisionObject::isCollisionHandled(): Tried to interact with an object of undefined type");
result = false;
}
return result;
}
void ICollisionObject::handleCollisions(CCollisionObjectVector *collisionVector, float *timeUsed, bool advanceObject) {
if (_velocity.magnitude() == 0)
return;
if (_ignore)
return;
for (CCollisionObjectVector::const_iterator objectIt = collisionVector->begin(); objectIt != collisionVector->end(); ++objectIt) {
const ICollisionObject *pTargetObject = *objectIt;
U32Distance3D distance;
testObjectIntersection(*pTargetObject, &distance);
switch (pTargetObject->_objectShape) {
case kNoObjectShape:
warning("ICollisionObject::handleCollisions(): Tried to interact with an object of undefined type");
break;
case kSphere:
handleCollision(*static_cast<const CCollisionSphere *>(pTargetObject), timeUsed, &distance, advanceObject);
break;
case kBox:
handleCollision(*static_cast<const CCollisionBox *>(pTargetObject), timeUsed, &distance, advanceObject);
break;
case kCylinder:
handleCollision(*static_cast<const CCollisionCylinder *>(pTargetObject), timeUsed, &distance, advanceObject);
break;
default:
warning("ICollisionObject::handleCollisions(): Tried to interact with an object of undefined type");
}
}
}
bool ICollisionObject::isOnObject(const ICollisionObject &targetObject, const U32Distance3D &distance) const {
bool result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::isOnObject(): Tried to interact with an object of undefined type");
result = false;
break;
case kSphere:
result = isOnObject(static_cast<const CCollisionSphere &>(targetObject), distance);
break;
case kBox:
result = isOnObject(static_cast<const CCollisionBox &>(targetObject), distance);
break;
case kCylinder:
result = isOnObject(static_cast<const CCollisionCylinder &>(targetObject), distance);
break;
default:
warning("ICollisionObject::isOnObject(): Tried to interact with an object of undefined type");
result = false;
}
return result;
}
U32FltPoint3D ICollisionObject::findNearestPoint(const U32FltPoint3D &testPoint) const {
return testPoint;
}
float ICollisionObject::getPenetrationTime(const ICollisionObject &targetObject, const U32Distance3D &distance, EDimension dimension) const {
float result;
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::getPenetrationTime(): Tried to interact with an object of undefined type");
result = 0.0F;
break;
case kSphere:
result = getPenetrationTime(*static_cast<const CCollisionSphere *>(&targetObject), distance, dimension);
break;
case kBox:
result = getPenetrationTime(*static_cast<const CCollisionBox *>(&targetObject), distance, dimension);
break;
case kCylinder:
result = getPenetrationTime(*static_cast<const CCollisionCylinder *>(&targetObject), distance, dimension);
break;
default:
warning("ICollisionObject::getPenetrationTime(): Tried to interact with an object of undefined type");
result = 0.0F;
}
return result;
}
void ICollisionObject::defineReflectionPlane(const ICollisionObject &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
switch (targetObject._objectShape) {
case kNoObjectShape:
warning("ICollisionObject::defineReflectionPlane(): Tried to interact with an object of undefined type");
break;
case kSphere:
defineReflectionPlane(dynamic_cast<const CCollisionSphere &>(targetObject), distance, collisionPlane);
break;
case kBox:
defineReflectionPlane(dynamic_cast<const CCollisionBox &>(targetObject), distance, collisionPlane);
break;
case kCylinder:
defineReflectionPlane(dynamic_cast<const CCollisionCylinder &>(targetObject), distance, collisionPlane);
break;
default:
warning("ICollisionObject::defineReflectionPlane(): Tried to interact with an object of undefined type");
}
}
void ICollisionObject::defineReflectionPlane(const CCollisionSphere &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
collisionPlane->clear();
}
void ICollisionObject::defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
collisionPlane->clear();
}
void ICollisionObject::defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
collisionPlane->clear();
}
} // End of namespace Scumm

View File

@@ -0,0 +1,193 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_OBJECT_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_OBJECT_H
#ifdef ENABLE_HE
#include "common/str.h"
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
namespace Scumm {
#define COLLISION_EPSILON 0.5F
#define COLLISION_SMALL_TIME_INCREMENT 0.05F
#define COLLISION_BACK_OUT_TIME_LIMIT 20.0F
class CCollisionSphere;
class CCollisionBox;
class CCollisionCylinder;
class CCollisionObjectStack;
class CCollisionObjectVector;
enum EObjectShape {
kNoObjectShape = 0,
kSphere = 1,
kBox = 2,
kCylinder = 3
};
enum EObjectType {
kNoObjectType = 0,
kBackboard = 1,
kRim = 2,
kOtherType = 3,
kFloor = 4,
kBall = 5,
kPlayer = 6
};
class ICollisionObject {
public:
ICollisionObject(EObjectShape shape = kNoObjectShape);
virtual ~ICollisionObject() {}
// Comparison operator
bool operator==(const ICollisionObject &otherObject) const;
// Get the distance between the outside of this object and the outside of a target object
virtual float getObjectDistance(const ICollisionObject &targetObject) const;
virtual float getObjectDistance(const CCollisionSphere &targetObject) const { return 0.0F; }
virtual float getObjectDistance(const CCollisionBox &targetObject) const { return 0.0F; }
virtual float getObjectDistance(const CCollisionCylinder &targetObject) const { return 0.0F; }
// testObjectIntersection is used to determine if this object is intersecting a target object
virtual bool testObjectIntersection(const ICollisionObject &targetObject, U32Distance3D *distance) const;
virtual bool testObjectIntersection(const CCollisionSphere &targetObject, U32Distance3D *distance) const { return false; }
virtual bool testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *distance) const { return false; }
virtual bool testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *distance) const { return false; }
// Just because this object is intersecting another, doesn't mean that it collided with
// that object. That object could have collided with us. This function verifies, that
// we collided with another object...
virtual bool validateCollision(const ICollisionObject &targetObject, U32Distance3D *distance);
virtual bool validateCollision(const CCollisionSphere &targetObject, U32Distance3D *distance) { return true; }
virtual bool validateCollision(const CCollisionBox &targetObject, U32Distance3D *distance) { return true; }
virtual bool validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *distance) { return true; }
// backOutOfObject moves this object backwards along its velocity vector to a point
// where it is guaranteed not to be intersecting a target object
virtual bool backOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed);
virtual bool backOutOfObject(const CCollisionSphere &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
virtual bool backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
virtual bool backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
// nudgeObject moves this object forward along its velocity vector to a point
// where it is guaranteed to be touching the target object at the exact point
// of collision
virtual bool nudgeObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed);
virtual bool nudgeObject(const CCollisionSphere &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
virtual bool nudgeObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
virtual bool nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
// Some collisions between objects are recorded, but not handled physically. This
// function determines whether a collision gets handled or not...
virtual bool isCollisionHandled(const ICollisionObject &targetObject) const;
virtual bool isCollisionHandled(const CCollisionSphere &targetObject) const { return true; }
virtual bool isCollisionHandled(const CCollisionBox &targetObject) const { return true; }
virtual bool isCollisionHandled(const CCollisionCylinder &targetObject) const { return true; }
// handleCollisions alters this objects velocity and position as a result of
// a collision with one or more target objects
virtual void handleCollisions(CCollisionObjectVector *pCollisionVector, float *timeUsed, bool advanceObject);
virtual void handleCollision(const CCollisionSphere &targetObject, float *timeUsed, U32Distance3D *distance, bool advanceObject) {}
virtual void handleCollision(const CCollisionBox &targetObject, float *timeUsed, U32Distance3D *distance, bool advanceObject) {}
virtual void handleCollision(const CCollisionCylinder &targetObject, float *timeUsed, U32Distance3D *distance, bool advanceObject) {}
// Determine if this object is resting, running, or rolling on another object.
// An object doing this would not necessarily trigger an intersection...
virtual bool isOnObject(const ICollisionObject &targetObject, const U32Distance3D &distance) const;
virtual bool isOnObject(const CCollisionSphere &targetObject, const U32Distance3D &distance) const { return false; }
virtual bool isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const { return false; }
virtual bool isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const { return false; }
// Return a 3-dimensional bounding box for this object
virtual U32BoundingBox getBoundingBox() const = 0;
virtual U32BoundingBox getBigBoundingBox() const = 0;
// Return the point on the surface of the object that is closest to the input point
virtual U32FltPoint3D findNearestPoint(const U32FltPoint3D &testPoint) const;
// Call this function when it is known that the object is at a legal location and is
// not intersecting any other objects
virtual void save() {}
// Put the object at the last place that it was guaranteed to not be intersecting any
// other objects, and negate it's velocity vector
virtual void restore() {}
Common::String _description;
EObjectShape _objectShape;
EObjectType _objectType;
int _objectID; // An identifier that uniquely identifies this object
U32FltVector3D _velocity;
float _collisionEfficiency; // A multiplier (range 0 to 1) that represents
// the percentage of velocity (perpendicular with
// the collision) that a target object retains
// when it collides with this object
float _friction; // A multiplier (range 0 to 1) that represents
// the percentage of velocity (parallel with
// the collision) that a target object loses
// when it collides with this object
int _soundNumber;
bool _ignore; // There could be times when you want to ignore
// an object for collision purposes. This flag
// determines that.
CCollisionObjectVector _objectCollisionHistory; // Stack with pointers to all the
// objects that this object collided
// with this frame
CCollisionObjectVector _objectRollingHistory; // Stack with pointers to all the
// objects that this object rolled
// on this frame
protected:
// Get the amount of time it took this sphere to penetrate whatever object it is
// currently intersecting in the given dimension
virtual float getPenetrationTime(const ICollisionObject &targetObject, const U32Distance3D &distance, EDimension dimension) const;
virtual float getPenetrationTime(const CCollisionSphere &targetObject, const U32Distance3D &distance, EDimension dimension) const { return 0.0F; }
virtual float getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const { return 0.0F; }
virtual float getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const { return 0.0F; }
// Sometimes when this object collides with another object, it may want to treat
// the object at the point of collision like a plane. This can help simplify the
// collision. defineReflectionPlane defines a plane between this object and the
// target object at the point of collision...
virtual void defineReflectionPlane(const ICollisionObject &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
virtual void defineReflectionPlane(const CCollisionSphere &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
virtual void defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
virtual void defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_OBJECT_H

View File

@@ -0,0 +1,95 @@
/* 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/basketball/court.h"
#include "scumm/he/basketball/collision/bball_collision_player.h"
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
void CCollisionPlayer::startBlocking(int blockHeight, int blockTime) {
assert(blockTime != 0);
_maxBlockHeight = blockHeight;
_blockTime = blockTime;
int blockIncrement = _maxBlockHeight / _blockTime;
_blockHeight += blockIncrement;
height += blockIncrement;
}
void CCollisionPlayer::holdBlocking() {
int blockIncrement = _maxBlockHeight / _blockTime;
if (_velocity.z > 0) {
if ((_blockHeight + blockIncrement) <= _maxBlockHeight) {
_blockHeight += blockIncrement;
height += blockIncrement;
} else {
blockIncrement = _maxBlockHeight - _blockHeight;
_blockHeight += blockIncrement;
height += blockIncrement;
assert(_blockHeight == _maxBlockHeight);
}
} else if (_velocity.z < 0) {
if ((_blockHeight - blockIncrement) >= 0) {
_blockHeight -= blockIncrement;
height -= blockIncrement;
} else {
blockIncrement = _blockHeight;
_blockHeight -= blockIncrement;
height -= blockIncrement;
assert(_blockHeight == 0);
}
}
}
void CCollisionPlayer::endBlocking() {
height -= _blockHeight;
_blockHeight = 0;
}
bool CCollisionPlayer::testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court) {
if (&targetObject == (ICollisionObject *)&court->_virtualBall) {
int oldHeight = height;
height += _catchHeight;
bool retVal = testObjectIntersection(targetObject, distance);
height = oldHeight;
return retVal;
} else {
return false;
}
}
} // End of namespace Scumm

View File

@@ -0,0 +1,68 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_PLAYER_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_PLAYER_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/court.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
namespace Scumm {
#define PLAYER_CATCH_HEIGHT 250
class CBBallCourt;
class CCollisionPlayer : public CCollisionCylinder {
public:
CCollisionPlayer() : _playerHasBall(false),
_playerIsInGame(true),
_blockHeight(0),
_blockTime(0),
_catchHeight(0),
_maxBlockHeight(0) {}
~CCollisionPlayer() {}
void startBlocking(int blockHeight, int blockTime);
void holdBlocking();
void endBlocking();
bool _playerHasBall;
bool _playerIsInGame;
int _catchHeight; // The extra height that a player gets for detecting the ball.
bool testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court);
private:
int _blockHeight = 0; // The extra height that a player gets when blocking.
int _maxBlockHeight = 0; // The max extra height that a player gets when blocking.
int _blockTime = 0; // The time it takes from the start of a block, to the apex of the block.
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_PLAYER_H

View File

@@ -0,0 +1,250 @@
/* 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/geo_translations.h"
#include "scumm/he/basketball/court.h"
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
#include "scumm/he/basketball/collision/bball_collision_shields.h"
namespace Scumm {
CCollisionShieldVector::CCollisionShieldVector() : _shieldUpCount(0) {
CCollisionBox westShield;
CCollisionBox northShield;
CCollisionBox eastShield;
CCollisionBox southShield;
CCollisionBox topShield;
CCollisionBox westShield2;
CCollisionBox northShield2;
CCollisionBox eastShield2;
CCollisionBox southShield2;
westShield.minPoint.x = 0 - SHIELD_DEPTH;
westShield.maxPoint.x = 0;
westShield.minPoint.y = 0 - SHIELD_EXTENSION;
westShield.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
westShield.minPoint.z = 0;
westShield.maxPoint.z = SHIELD_HEIGHT;
westShield._description = "West Shield";
westShield._collisionEfficiency = 0.5F;
westShield._friction = 0.3F;
westShield._objectID = WEST_SHIELD_ID;
westShield._ignore = true;
westShield2.minPoint.x = 0 - SHIELD_DEPTH - BUFFER_WIDTH;
westShield2.maxPoint.x = 0 - BUFFER_WIDTH;
westShield2.minPoint.y = 0 - SHIELD_EXTENSION;
westShield2.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
westShield2.minPoint.z = 0;
westShield2.maxPoint.z = SHIELD_HEIGHT;
westShield2._description = "West Shield 2";
westShield2._collisionEfficiency = 0.5F;
westShield2._friction = 0.3F;
westShield2._objectID = BACKUP_WEST_SHIELD_ID;
westShield2._ignore = true;
northShield.minPoint.x = 0 - SHIELD_EXTENSION;
northShield.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
northShield.minPoint.y = MAX_WORLD_Y;
northShield.maxPoint.y = MAX_WORLD_Y + SHIELD_DEPTH;
northShield.minPoint.z = 0;
northShield.maxPoint.z = SHIELD_HEIGHT;
northShield._description = "North Shield";
northShield._collisionEfficiency = 0.5F;
northShield._friction = 0.3F;
northShield._objectID = NORTH_SHIELD_ID;
northShield._ignore = true;
northShield2.minPoint.x = 0 - SHIELD_EXTENSION;
northShield2.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
northShield2.minPoint.y = MAX_WORLD_Y + BUFFER_WIDTH;
northShield2.maxPoint.y = MAX_WORLD_Y + SHIELD_DEPTH + BUFFER_WIDTH;
northShield2.minPoint.z = 0;
northShield2.maxPoint.z = SHIELD_HEIGHT;
northShield2._description = "North Shield 2";
northShield2._collisionEfficiency = 0.5F;
northShield2._friction = 0.3F;
northShield2._objectID = BACKUP_NORTH_SHIELD_ID;
northShield2._ignore = true;
eastShield.minPoint.x = MAX_WORLD_X;
eastShield.maxPoint.x = MAX_WORLD_X + SHIELD_DEPTH;
eastShield.minPoint.y = 0 - SHIELD_EXTENSION;
eastShield.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
eastShield.minPoint.z = 0;
eastShield.maxPoint.z = SHIELD_HEIGHT;
eastShield._description = "East Shield";
eastShield._collisionEfficiency = 0.5F;
eastShield._friction = 0.3F;
eastShield._objectID = EAST_SHIELD_ID;
eastShield._ignore = true;
eastShield2.minPoint.x = MAX_WORLD_X + BUFFER_WIDTH;
eastShield2.maxPoint.x = MAX_WORLD_X + SHIELD_DEPTH + BUFFER_WIDTH;
eastShield2.minPoint.y = 0 - SHIELD_EXTENSION;
eastShield2.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
eastShield2.minPoint.z = 0;
eastShield2.maxPoint.z = SHIELD_HEIGHT;
eastShield2._description = "East Shield 2";
eastShield2._collisionEfficiency = 0.5F;
eastShield2._friction = 0.3F;
eastShield2._objectID = BACKUP_EAST_SHIELD_ID;
eastShield2._ignore = true;
southShield.minPoint.x = 0 - SHIELD_EXTENSION;
southShield.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
southShield.minPoint.y = 0 - SHIELD_DEPTH;
southShield.maxPoint.y = 0;
southShield.minPoint.z = 0;
southShield.maxPoint.z = SHIELD_HEIGHT;
southShield._description = "South Shield";
southShield._collisionEfficiency = 0.5F;
southShield._friction = 0.3F;
southShield._objectID = SOUTH_SHIELD_ID;
southShield._ignore = true;
southShield2.minPoint.x = 0 - SHIELD_EXTENSION;
southShield2.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
southShield2.minPoint.y = 0 - SHIELD_DEPTH - BUFFER_WIDTH;
southShield2.maxPoint.y = 0 - BUFFER_WIDTH;
southShield2.minPoint.z = 0;
southShield2.maxPoint.z = SHIELD_HEIGHT;
southShield2._description = "South Shield 2";
southShield2._collisionEfficiency = 0.5F;
southShield2._friction = 0.3F;
southShield2._objectID = BACKUP_SOUTH_SHIELD_ID;
southShield2._ignore = true;
topShield.minPoint.x = 0 - SHIELD_EXTENSION;
topShield.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
topShield.minPoint.y = 0 - SHIELD_EXTENSION;
topShield.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
topShield.minPoint.z = SHIELD_HEIGHT;
topShield.maxPoint.z = SHIELD_HEIGHT + SHIELD_DEPTH;
topShield._description = "Top Shield";
topShield._collisionEfficiency = 0.5F;
topShield._friction = 0.3F;
topShield._objectID = TOP_SHIELD_ID;
topShield._ignore = true;
push_back(westShield);
push_back(northShield);
push_back(eastShield);
push_back(southShield);
push_back(topShield);
push_back(westShield2);
push_back(northShield2);
push_back(eastShield2);
push_back(southShield2);
}
CCollisionShieldVector::~CCollisionShieldVector() {
CCollisionShieldVector::iterator shieldIt;
for (shieldIt = begin(); shieldIt != end(); ++shieldIt) {
shieldIt->_ignore = true;
}
}
int LogicHEBasketball::u32_userRaiseShields(int shieldID) {
assert(shieldID < MAX_SHIELD_COUNT || shieldID == ALL_SHIELD_ID);
CCollisionShieldVector::iterator shieldIt;
for (shieldIt = _vm->_basketball->_shields->begin(); shieldIt != _vm->_basketball->_shields->end(); ++shieldIt) {
// Make sure we don't mess with the backup shields...
if (shieldIt->_objectID < MAX_SHIELD_COUNT) {
if (((shieldIt->_objectID == shieldID) || (shieldID == ALL_SHIELD_ID)) &&
(shieldIt->_ignore == true)) {
shieldIt->_ignore = false;
++_vm->_basketball->_shields->_shieldUpCount;
}
}
}
if (shieldID == ALL_SHIELD_ID) {
assert(_vm->_basketball->_shields->_shieldUpCount == MAX_SHIELD_COUNT);
}
return 1;
}
int LogicHEBasketball::u32_userLowerShields(int shieldID) {
assert(shieldID < MAX_SHIELD_COUNT || shieldID == ALL_SHIELD_ID);
CCollisionShieldVector::iterator shieldIt;
for (shieldIt = _vm->_basketball->_shields->begin(); shieldIt != _vm->_basketball->_shields->end(); ++shieldIt) {
// Make sure we don't mess with the backup shields...
if (shieldIt->_objectID < MAX_SHIELD_COUNT) {
if (((shieldIt->_objectID == shieldID) || (shieldID == ALL_SHIELD_ID)) &&
(shieldIt->_ignore == false)) {
shieldIt->_ignore = true;
--_vm->_basketball->_shields->_shieldUpCount;
}
}
}
if (shieldID == ALL_SHIELD_ID) {
assert(_vm->_basketball->_shields->_shieldUpCount == 0);
}
return 1;
}
int LogicHEBasketball::u32_userAreShieldsClear() {
int shieldsAreClear = (_vm->_basketball->_shields->_shieldUpCount != MAX_SHIELD_COUNT);
writeScummVar(_vm1->VAR_U32_USER_VAR_A, shieldsAreClear);
return 1;
}
int LogicHEBasketball::u32_userShieldPlayer(int playerID, int shieldRadius) {
CCollisionPlayer *player = _vm->_basketball->_court->getPlayerPtr(playerID);
if (player->_shieldRadius < shieldRadius) {
player->_shieldRadius += PLAYER_SHIELD_INCREMENT_VALUE;
player->radius += PLAYER_SHIELD_INCREMENT_VALUE;
}
return 1;
}
int LogicHEBasketball::u32_userClearPlayerShield(int playerID) {
CCollisionPlayer *player = _vm->_basketball->_court->getPlayerPtr(playerID);
player->radius -= player->_shieldRadius;
player->_shieldRadius = 0.0F;
return 1;
}
} // End of namespace Scumm

View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SHIELDS_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SHIELDS_H
#ifdef ENABLE_HE
#include "scumm/he/intern_he.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
namespace Scumm {
#define WEST_SHIELD_ID 0
#define NORTH_SHIELD_ID 1
#define EAST_SHIELD_ID 2
#define SOUTH_SHIELD_ID 3
#define TOP_SHIELD_ID 4
#define ALL_SHIELD_ID 5
#define MAX_SHIELD_COUNT 5
#define BACKUP_WEST_SHIELD_ID 6
#define BACKUP_NORTH_SHIELD_ID 7
#define BACKUP_EAST_SHIELD_ID 8
#define BACKUP_SOUTH_SHIELD_ID 9
#define PLAYER_SHIELD_INCREMENT_VALUE 25
#define SHIELD_DEPTH 1000
#define SHIELD_HEIGHT 50000
#define SHIELD_EXTENSION 20000
#define BUFFER_WIDTH 800
class CCollisionShieldVector : public Common::Array<CCollisionBox> {
public:
CCollisionShieldVector();
~CCollisionShieldVector();
int _shieldUpCount;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SHIELDS_H

View File

@@ -0,0 +1,662 @@
/* 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/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
float CCollisionSphere::getDimensionDistance(const CCollisionBox &targetObject, EDimension dimension) const {
if (center[dimension] < targetObject.minPoint[dimension]) {
return (center[dimension] - targetObject.minPoint[dimension]);
} else if (center[dimension] > targetObject.maxPoint[dimension]) {
return (center[dimension] - targetObject.maxPoint[dimension]);
} else {
return 0;
}
}
float CCollisionSphere::getDimensionDistance(const CCollisionCylinder &targetObject, EDimension dimension) const {
float centerDistance = center[dimension] - targetObject.center[dimension];
if (dimension == Z_INDEX) {
if (centerDistance < -(targetObject.height / 2)) {
return (centerDistance + (targetObject.height / 2));
} else if (centerDistance > (targetObject.height / 2)) {
return (centerDistance - (targetObject.height / 2));
} else {
return 0;
}
} else {
return centerDistance;
}
}
float CCollisionSphere::getObjectDistance(const CCollisionBox &targetObject) const {
U32Distance3D distance;
distance.x = getDimensionDistance(targetObject, X_INDEX);
distance.y = getDimensionDistance(targetObject, Y_INDEX);
distance.z = getDimensionDistance(targetObject, Z_INDEX);
float totalDistance = distance.magnitude() - radius;
if (totalDistance < 0)
totalDistance = 0;
return totalDistance;
}
float CCollisionSphere::getObjectDistance(const CCollisionCylinder &targetObject) const {
U32Distance3D distance;
distance.x = getDimensionDistance(targetObject, X_INDEX);
distance.y = getDimensionDistance(targetObject, Y_INDEX);
distance.z = getDimensionDistance(targetObject, Z_INDEX);
float xyDistance = distance.xyMagnitude() - radius - targetObject.radius;
if (xyDistance < 0)
xyDistance = 0;
float zDistance = fabs(distance.z) - radius - (targetObject.height / 2);
if (zDistance < 0)
zDistance = 0;
float totalDistance = sqrt((xyDistance * xyDistance) + (zDistance * zDistance));
return totalDistance;
}
bool CCollisionSphere::testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *distance) const {
// Get the distance between the ball and the bounding box...
distance->x = getDimensionDistance(targetObject, X_INDEX);
distance->y = getDimensionDistance(targetObject, Y_INDEX);
distance->z = getDimensionDistance(targetObject, Z_INDEX);
// Determine if the ball intersects the bounding box.
return (distance->magnitude() < radius);
}
bool CCollisionSphere::testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *distance) const {
// Get the distance between the ball and the cylinder...
distance->x = getDimensionDistance(targetObject, X_INDEX);
distance->y = getDimensionDistance(targetObject, Y_INDEX);
distance->z = getDimensionDistance(targetObject, Z_INDEX);
if (distance->xyMagnitude() < (radius + targetObject.radius)) {
return (fabs(distance->z) < radius);
} else {
return false;
}
}
bool CCollisionSphere::validateCollision(const CCollisionBox &targetObject, U32Distance3D *distance) {
U32FltPoint3D targetPoint = targetObject.findNearestPoint(center);
U32FltVector3D centerVector = targetPoint - center;
float aMag = _velocity.magnitude();
float bMag = centerVector.magnitude();
float aDotb = _velocity * centerVector;
if (aMag == 0) {
// If this object isn't moving, this can't be a valid collision...
return false;
}
if (bMag == 0) {
// bMag is 0, it is possible that this sphere penetrated too far into the target
// object. If this is the case, we'll go ahead and validate the collision...
return true;
}
double angleCosine = aDotb / (aMag * bMag);
if (angleCosine > 1) {
angleCosine = 1;
} else if (angleCosine < -1) {
angleCosine = -1;
}
float sourceMovementAngle = acos(angleCosine);
if (sourceMovementAngle < (BBALL_M_PI / 2)) {
return true;
} else {
return false;
}
}
bool CCollisionSphere::validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *distance) {
// Create a vector from the center of the target cylinder to the center of
// this sphere. If the sphere is not hitting above or below the cylinder,
// negate any z component of the center vector...
U32FltVector3D centerVector = targetObject.center - center;
if (center.z > (targetObject.center.z + targetObject.height / 2)) {
centerVector.z = targetObject.center.z + (targetObject.height / 2) - center.z;
} else if (center.z < (targetObject.center.z - targetObject.height / 2)) {
centerVector.z = targetObject.center.z - (targetObject.height / 2) - center.z;
} else if (_velocity.xyMagnitude() != 0) {
centerVector.z = 0;
}
float aMag = _velocity.magnitude();
float bMag = centerVector.magnitude();
float aDotb = _velocity * centerVector;
if (aMag == 0) {
// If this object isn't moving, this can't be a valid collision...
return false;
}
if (bMag == 0) {
// bMag is 0, it is possible that this sphere penetrated too far into the target
// object. If this is the case, we'll go ahead and validate the collision...
return true;
}
// Calculate the angle between this object's velocity and the vector from the target
// objects center to our center. If the angle between the two is greater than
// 90 degrees, then the target object is not colliding with us...
double angleCosine = aDotb / (aMag * bMag);
if (angleCosine > 0) {
return true;
} else {
return false;
}
}
float CCollisionSphere::getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const {
float collisionDepth1;
float collisionDepth2;
float boxWidth = targetObject.maxPoint[dimension] - targetObject.minPoint[dimension];
if (distance[dimension] > 0) {
collisionDepth1 = (radius - distance[dimension]);
collisionDepth2 = (-radius + distance[dimension] - boxWidth);
} else if (distance[dimension] < 0) {
collisionDepth1 = (-radius - distance[dimension]);
collisionDepth2 = (radius - distance[dimension] + boxWidth);
} else {
return 0;
}
float time1 = (_velocity[dimension] == 0) ? 0 : collisionDepth1 / -_velocity[dimension];
float time2 = (_velocity[dimension] == 0) ? 0 : collisionDepth2 / -_velocity[dimension];
float tFinal = MIN_GREATER_THAN_ZERO(time1, time2);
return tFinal;
}
float CCollisionSphere::getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const {
float collisionDepth;
if (dimension == Z_INDEX) {
if (distance[dimension] > 0) {
collisionDepth = (radius - distance[dimension]);
} else if (distance[dimension] < 0) {
collisionDepth = (-radius - distance[dimension]);
} else {
collisionDepth = 0;
}
} else {
if (distance[dimension] > 0) {
collisionDepth = (radius + targetObject.radius - distance[dimension]);
} else if (distance[dimension] < 0) {
collisionDepth = (-radius - targetObject.radius - distance[dimension]);
} else {
collisionDepth = 0;
}
}
float tFinal = (_velocity[dimension] == 0) ? 0 : (collisionDepth / -_velocity[dimension]);
return tFinal;
}
bool CCollisionSphere::backStraightOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed) {
if (_velocity.magnitude() == 0)
return true;
U32FltPoint3D startPosition = center;
int loopCounter = 0;
while (testObjectIntersection(targetObject, distance)) {
float collisionTimes[3];
collisionTimes[X_INDEX] = getPenetrationTime(targetObject, *distance, X_INDEX);
collisionTimes[Y_INDEX] = getPenetrationTime(targetObject, *distance, Y_INDEX);
collisionTimes[Z_INDEX] = getPenetrationTime(targetObject, *distance, Z_INDEX);
Std::sort(collisionTimes, collisionTimes + Z_INDEX + 1);
float collisionTime = COLLISION_SMALL_TIME_INCREMENT;
if (collisionTimes[2] > 0)
collisionTime = collisionTimes[2];
if (collisionTimes[1] > 0)
collisionTime = collisionTimes[1];
if (collisionTimes[0] > 0)
collisionTime = collisionTimes[0];
*timeUsed += collisionTime;
// If we take too long to back out, something is wrong.
// Restore the object to an ok state...
if ((*timeUsed > COLLISION_BACK_OUT_TIME_LIMIT) && (*timeUsed != collisionTime)) {
warning("CCollisionSphere::backStraightOutOfObject(): It took too long for one object to back out of another. Ignore and U32 will attempt to correct.");
center = startPosition;
restore();
return false;
}
center.x -= (collisionTime * _velocity.x);
center.y -= (collisionTime * _velocity.y);
center.z -= (collisionTime * _velocity.z);
// Make doubly sure we don't loop forever...
if (++loopCounter > 500)
return false;
}
return true;
}
bool CCollisionSphere::backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) {
return backStraightOutOfObject(targetObject, distance, timeUsed);
}
bool CCollisionSphere::backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) {
return backStraightOutOfObject(targetObject, distance, timeUsed);
}
bool CCollisionSphere::nudgeObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) {
// To nudge the sphere precisely against the box, we need to calculate when the
// square root of the sum of the squared distances between the sphere and the three
// planes equals the radius of the sphere. Here we will construct a quadratic
// equation to solve for time....
double a = 0;
double b = 0;
double c = -(radius * radius);
for (int i = X_INDEX; i <= Z_INDEX; ++i) {
EDimension dim = (EDimension)i;
// If the ball is already within the boundaries of the box in a certain dimension,
// we don't want to include that dimension in the equation...
if ((*distance)[dim] != 0) {
a += (_velocity[dim] * _velocity[dim]);
b += (2 * _velocity[dim] * (*distance)[dim]);
c += ((*distance)[dim] * (*distance)[dim]);
}
}
if (((b * b) < (4 * a * c)) || (a == 0)) {
warning("CCollisionSphere::nudgeObject(): Tried to use sqrt on a negative number");
return false;
}
// Now we have two answer candidates. We want the smallest of the two that is
// greater than 0...
double t1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
double t2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
double tFinal = 0;
if ((0 <= t1) && (t1 <= t2)) {
tFinal = t1;
} else if ((0 <= t2) && (t2 <= t1)) {
tFinal = t2;
}
// Update the position of the ball...
center.x += _velocity.x * tFinal;
center.y += _velocity.y * tFinal;
center.z += _velocity.z * tFinal;
*timeUsed -= tFinal;
testObjectIntersection(targetObject, distance);
return true;
}
bool CCollisionSphere::nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) {
float collisionTimeFinal;
U32FltVector3D xyVelocity = _velocity;
xyVelocity.z = 0;
// Find the distance between the two centers that would indicate an exact collision...
float intersectionDist = radius + targetObject.radius;
// Set up a vector pointing from the center of this sphere to the center of
// the target cylinder...
U32FltVector3D centerVector;
centerVector.x = targetObject.center.x - center.x;
centerVector.y = targetObject.center.y - center.y;
float centerDistance = centerVector.xyMagnitude();
if (centerDistance > intersectionDist) {
// Project the center vector onto the velocity vector.
// This is the distance along the velocity vector from the
// center of the sphere to the point that is parallel with the center
// of the cylinder...
float parallelDistance = centerVector.projectScalar(xyVelocity);
// Find the distance between the center of the target object to the point that
// that is distance2 units along the the velocity vector...
parallelDistance = ((centerDistance * centerDistance) >=
(parallelDistance * parallelDistance))
? parallelDistance
: COPY_SIGN(centerDistance, parallelDistance);
// Make sure we don't try to sqrt by negative number...
if (parallelDistance > centerDistance) {
warning("CCollisionSphere::nudgeObject(): Tried to sqrt by negative number.");
centerDistance = parallelDistance;
}
float perdistance = sqrt(centerDistance * centerDistance - parallelDistance * parallelDistance);
// Now we need to find the point along the velocity vector where the distance
// between that point and the center of the target cylinder equals intersectionDist.
// We calculate using distance 2, distance3 and intersectionDist...
perdistance = ((intersectionDist * intersectionDist) >=
(perdistance * perdistance))
? perdistance
: COPY_SIGN(intersectionDist, perdistance);
// Make sure we don't try to sqrt by negative number...
if (perdistance > intersectionDist) {
warning("CCollisionSphere::nudgeObject(): Tried to sqrt by negative number.");
intersectionDist = perdistance;
}
float xyCollisionDist = parallelDistance - sqrt(intersectionDist * intersectionDist - perdistance * perdistance);
collisionTimeFinal = (_velocity.xyMagnitude() == 0) ? 0 : (xyCollisionDist / _velocity.xyMagnitude());
} else {
collisionTimeFinal = -getPenetrationTime(targetObject, *distance, Z_INDEX);
}
center.x += collisionTimeFinal * _velocity.x;
center.y += collisionTimeFinal * _velocity.y;
center.z += collisionTimeFinal * _velocity.z;
*timeUsed -= collisionTimeFinal;
testObjectIntersection(targetObject, distance);
// We may still have a little ways to go in the z direction...
if (fabs(distance->z) >= (radius + COLLISION_EPSILON)) {
collisionTimeFinal = -getPenetrationTime(targetObject, *distance, Z_INDEX);
center.x += collisionTimeFinal * _velocity.x;
center.y += collisionTimeFinal * _velocity.y;
center.z += collisionTimeFinal * _velocity.z;
*timeUsed -= collisionTimeFinal;
testObjectIntersection(targetObject, distance);
}
return true;
}
void CCollisionSphere::defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
// Find the point of collision...
collisionPlane->point = targetObject.findNearestPoint(center);
// Find the normal of the collision plane...
collisionPlane->normal.x = (distance.magnitude() == 0) ? 0 : distance.x / distance.magnitude();
collisionPlane->normal.y = (distance.magnitude() == 0) ? 0 : distance.y / distance.magnitude();
collisionPlane->normal.z = (distance.magnitude() == 0) ? 0 : distance.z / distance.magnitude();
collisionPlane->friction = targetObject._friction;
collisionPlane->collisionEfficiency = targetObject._collisionEfficiency;
}
void CCollisionSphere::defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
// Find the point of collision...
collisionPlane->point = targetObject.findNearestPoint(center);
// Find the normal of the collision plane...
collisionPlane->normal.x = (distance.magnitude() == 0) ? 0 : distance.x / distance.magnitude();
collisionPlane->normal.y = (distance.magnitude() == 0) ? 0 : distance.y / distance.magnitude();
collisionPlane->normal.z = (distance.magnitude() == 0) ? 0 : distance.z / distance.magnitude();
collisionPlane->friction = targetObject._friction;
collisionPlane->collisionEfficiency = targetObject._collisionEfficiency;
}
void CCollisionSphere::reboundOffPlane(const U32Plane &collisionPlane, bool isOnObject) {
U32FltVector3D normalVector;
U32FltVector3D reflectionVector;
U32FltVector3D parallelVector;
U32FltVector3D perpendicularVector;
// Calculate the reflection vector...
normalVector = _velocity.projectVector(collisionPlane.normal) * -1;
reflectionVector = (normalVector * 2) + _velocity;
// Break down the components of the refelction vector that are perpendicular
// and parallel to the collision plane. This way we can account for drag and
// inelastic collisions...
perpendicularVector = normalVector;
perpendicularVector *= collisionPlane.collisionEfficiency * _collisionEfficiency;
parallelVector = reflectionVector - normalVector;
if ((!isOnObject) || ((_rollingCount % ROLL_SLOWDOWN_FREQUENCY) == 0)) {
parallelVector -= ((parallelVector * collisionPlane.friction) + (parallelVector * _friction));
}
// Now put the reflection vector back together again...
reflectionVector = parallelVector + perpendicularVector;
_velocity = reflectionVector;
}
void CCollisionSphere::increaseVelocity(float minSpeed) {
if (_velocity.magnitude() < minSpeed) {
// Make sure we're moving along the XY plane...
if (_velocity.xyMagnitude() == 0) {
// Randomly add some velocity...
int random = (g_scumm->_rnd.getRandomNumber(0x7FFF) * 4) / 0x7FFF;
switch (random) {
case 0:
_velocity.x = minSpeed;
break;
case 1:
_velocity.x = -minSpeed;
break;
case 2:
_velocity.y = minSpeed;
break;
case 3:
case 4:
_velocity.y = -minSpeed;
break;
default:
warning("CCollisionSphere::increaseVelocity(): Invalid random number.");
}
} else {
// Increase the current velocity...
float oldVelocity = _velocity.magnitude();
_velocity.x = (_velocity.x / oldVelocity) * minSpeed;
_velocity.y = (_velocity.y / oldVelocity) * minSpeed;
_velocity.z = (_velocity.z / oldVelocity) * minSpeed;
}
}
}
void CCollisionSphere::handleCollisions(CCollisionObjectVector *collisionVector, float *timeUsed, bool advanceObject) {
Common::Array<U32Plane> planeVector;
Common::Array<bool> rollingRecord;
U32Plane collisionPlane;
U32Distance3D distance;
bool isRollingOnObject;
for (CCollisionObjectVector::const_iterator objectIt = collisionVector->begin();
objectIt != collisionVector->end();
++objectIt) {
const ICollisionObject *currentObject = *objectIt;
testObjectIntersection(*currentObject, &distance);
// See if we are rolling on this object...
isRollingOnObject = isOnObject(*currentObject, distance);
if (isRollingOnObject) {
// See if rolling has slowed to the point that we are stopped.
// Never stop on the backboard or rim...
if ((currentObject->_objectType == kBackboard) ||
(currentObject->_objectType == kRim)) {
increaseVelocity(ROLL_SPEED_LIMIT);
} else {
if (_velocity.xyMagnitude() < ROLL_SPEED_LIMIT) {
_velocity.x = 0;
_velocity.y = 0;
}
}
_velocity.z = 0;
} else {
// See if rolling has slowed to the point that we are stopped.
// Never stop on the backboard or rim...
if ((currentObject->_objectType == kBackboard) ||
(currentObject->_objectType == kRim)) {
increaseVelocity(ROLL_SPEED_LIMIT);
}
}
defineReflectionPlane(*currentObject, distance, &collisionPlane);
planeVector.push_back(collisionPlane);
rollingRecord.push_back(isRollingOnObject);
}
collisionVector->clear();
if (!planeVector.empty()) {
collisionPlane = planeVector[0];
isRollingOnObject = rollingRecord[0];
Common::Array<U32Plane>::const_iterator planeIt;
Common::Array<bool>::const_iterator recordIt;
for (planeIt = planeVector.begin(), recordIt = rollingRecord.begin();
planeIt != planeVector.end();
++planeIt, ++recordIt) {
collisionPlane.average(*planeIt);
isRollingOnObject = isRollingOnObject || *recordIt;
}
reboundOffPlane(collisionPlane, isRollingOnObject);
}
if (advanceObject) {
// Move the ball for the amount of time remaining...
center.x += (_velocity.x * *timeUsed);
center.y += (_velocity.y * *timeUsed);
center.z += (_velocity.z * *timeUsed);
*timeUsed = 0;
}
}
bool CCollisionSphere::isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const {
float distancePercentage = fabs(distance.z - radius) / radius;
// See if bouncing has slowed to the point that we are rolling...
return ((distancePercentage < .1) &&
(distance.xyMagnitude() == 0) &&
(fabs(_velocity.z) <= BOUNCE_SPEED_LIMIT));
}
bool CCollisionSphere::isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const {
float distancePercentage = fabs(distance.z - radius) / radius;
// See if bouncing has slowed to the point that we are rolling...
return ((distancePercentage < .1) &&
(distance.xyMagnitude() <= targetObject.radius) &&
(fabs(_velocity.z) <= BOUNCE_SPEED_LIMIT));
}
U32BoundingBox CCollisionSphere::getBoundingBox() const {
U32BoundingBox outBox;
outBox.minPoint.x = center.x - radius;
outBox.minPoint.y = center.y - radius;
outBox.minPoint.z = center.z - radius;
outBox.maxPoint.x = center.x + radius;
outBox.maxPoint.y = center.y + radius;
outBox.maxPoint.z = center.z + radius;
return outBox;
}
U32BoundingBox CCollisionSphere::getBigBoundingBox() const {
U32BoundingBox outBox;
float velocity = _velocity.magnitude();
outBox.minPoint.x = center.x - (radius + velocity);
outBox.minPoint.y = center.y - (radius + velocity);
outBox.minPoint.z = center.z - (radius + velocity);
outBox.maxPoint.x = center.x + (radius + velocity);
outBox.maxPoint.y = center.y + (radius + velocity);
outBox.maxPoint.z = center.z + (radius + velocity);
return outBox;
}
void CCollisionSphere::save() {
_positionSaved = true;
_safetyPoint = center;
_safetyVelocity = _velocity;
}
void CCollisionSphere::restore() {
if (_positionSaved) {
if (_safetyVelocity.magnitude() != 0) {
debug("CCollisionSphere::Restore(): Restoring");
center = _safetyPoint;
_velocity.x = 0;
_velocity.y = 0;
_velocity.z = 0;
}
} else {
warning("CCollisionSphere::Restore(): No save point.");
}
}
} // End of namespace Scumm

View File

@@ -0,0 +1,108 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SPHERE_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SPHERE_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
namespace Scumm {
const int BOUNCE_SPEED_LIMIT = 20; // If the z-direction speed of the ball falls below this limit during a bounce, then the ball will begin to roll.
const int ROLL_SPEED_LIMIT = 20; // If the xy-direction speed of the ball falls below this limit during a roll, then the ball will stop.
const int ROLL_SLOWDOWN_FREQUENCY = 10; // The ball slows down every x frames while rolling.
class CCollisionSphere : public ICollisionObject, public U32Sphere {
public:
CCollisionSphere() : ICollisionObject(kSphere),
_rollingCount(0),
_positionSaved(false) {}
~CCollisionSphere() {}
using ICollisionObject::getObjectDistance;
float getObjectDistance(const CCollisionBox &targetObject) const override;
float getObjectDistance(const CCollisionCylinder &targetObject) const override;
using ICollisionObject::testObjectIntersection;
bool testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *pDistance) const override;
bool testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *pDistance) const override;
using ICollisionObject::validateCollision;
bool validateCollision(const CCollisionBox &targetObject, U32Distance3D *pDistance) override;
bool validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *pDistance) override;
using ICollisionObject::backOutOfObject;
bool backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
bool backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
using ICollisionObject::nudgeObject;
bool nudgeObject(const CCollisionBox &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
bool nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
void handleCollisions(CCollisionObjectVector *pCollisionVector, float *pTimeUsed, bool advanceObject) override;
using ICollisionObject::isOnObject;
bool isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const override;
bool isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const override;
U32BoundingBox getBoundingBox() const override;
U32BoundingBox getBigBoundingBox() const override;
void save() override;
void restore() override;
int _rollingCount;
protected:
float getDimensionDistance(const CCollisionBox &targetObject, EDimension dimension) const;
float getDimensionDistance(const CCollisionCylinder &targetObject, EDimension dimension) const;
private:
bool _positionSaved;
U32FltPoint3D _safetyPoint;
U32FltVector3D _safetyVelocity;
bool backStraightOutOfObject(const ICollisionObject &targetObject, U32Distance3D *pDistance, float *pTimeUsed);
using ICollisionObject::defineReflectionPlane;
void defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const override;
void defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const override;
void reboundOffPlane(const U32Plane &collisionPlane, bool isOnPlane);
using ICollisionObject::getPenetrationTime;
float getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
float getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
void increaseVelocity(float minSpeed);
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SPHERE_H

View File

@@ -0,0 +1,73 @@
/* 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/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
void CCollisionObjectStack::clear() {
while (!empty()) {
pop_back();
}
}
int CCollisionObjectVector::getMinPoint(EDimension dimension) const {
int min = 1000000;
for (size_type i = 0; i < size(); i++) {
int current = ((*this)[i])->getBoundingBox().minPoint[dimension];
if (current < min) {
min = current;
}
}
return min;
}
int CCollisionObjectVector::getMaxPoint(EDimension dimension) const {
int max = 0;
for (uint i = 0; i < size(); i++) {
int current = ((*this)[i])->getBoundingBox().minPoint[dimension];
if (current > max) {
max = current;
}
}
return max;
}
bool CCollisionObjectVector::contains(const ICollisionObject &object) const {
for (CCollisionObjectVector::const_iterator objectIt = begin(); objectIt != end(); ++objectIt) {
if (object == **objectIt) {
return true;
}
}
return false;
}
} // End of namespace Scumm

View File

@@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_STACK_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_STACK_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
#include "common/array.h"
namespace Scumm {
class ICollisionObject;
class CCollisionObjectStack : public Common::Array<const ICollisionObject *> {
public:
void clear();
};
class CCollisionObjectVector : public Common::Array<const ICollisionObject *> {
public:
int getMinPoint(EDimension dimension) const;
int getMaxPoint(EDimension dimension) const;
bool contains(const ICollisionObject &object) const;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_STACK_H

View File

@@ -0,0 +1,716 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SUPPORT_OBJ_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SUPPORT_OBJ_H
#ifdef ENABLE_HE
#include "common/std/algorithm.h"
namespace Scumm {
#define BBALL_M_PI 3.14159265358979
#define COPY_SIGN(x, y) ((x < 0) == (y < 0)) ? x : -x
#define MIN_GREATER_THAN_ZERO(a, b) ((a < 0) ? ((b < 0) ? ((a > b) ? a : b) : b) : ((b < 0) ? a : ((a > b) ? b : a)))
enum EDimension {
X_INDEX = 0,
Y_INDEX = 1,
Z_INDEX = 2
};
enum ERevDirection {
kClockwise = -1,
kNone = 0,
kCounterClockwise = 1
};
template<class Type>
class U32Construct2D {
public:
Type x;
Type y;
U32Construct2D() : x(0), y(0) {}
U32Construct2D(Type xIn, Type yIn) : x(xIn), y(yIn) {}
bool operator==(const U32Construct2D<Type> &other) const {
return ((other.x == x) && (other.y == y));
}
U32Construct2D<Type> operator-(const U32Construct2D<Type> &other) const {
U32Construct2D<Type> newConstruct;
newConstruct.x = x - other.x;
newConstruct.y = y - other.y;
return newConstruct;
}
U32Construct2D<Type> operator+(const U32Construct2D<Type> &other) const {
U32Construct2D<Type> newConstruct;
newConstruct.x = x + other.x;
newConstruct.y = y + other.y;
return newConstruct;
}
Type operator*(const U32Construct2D<Type> &multiplier) const {
return (x * multiplier.x + y * multiplier.y);
}
Type &operator[](EDimension dimension) {
assert(dimension <= Y_INDEX);
return *(&x + dimension);
}
const Type &operator[](EDimension dimension) const {
assert(dimension <= Y_INDEX);
return *(&x + dimension);
}
Type magnitude(void) const {
return (Type)(sqrt(x * x + y * y));
}
};
template<class Type>
class U32Construct3D {
public:
Type x;
Type y;
Type z;
U32Construct3D() : x(0), y(0), z(0) {}
U32Construct3D(Type xIn, Type yIn, Type zIn) : x(xIn), y(yIn), z(zIn) {}
Type magnitude(void) const {
return (Type)(sqrt(x * x + y * y + z * z));
}
Type xyMagnitude(void) const {
return (Type)(sqrt(x * x + y * y));
}
bool operator==(const U32Construct3D<Type> &other) const {
return ((other.x == x) && (other.y == y) && (other.z == z));
}
bool operator!=(const U32Construct2D<Type> &other) const {
return ((other.x != x) || (other.y != y));
}
Type &operator[](EDimension dimension) {
assert(dimension <= Z_INDEX);
return *(&x + dimension);
}
const Type &operator[](EDimension dimension) const {
assert(dimension <= Z_INDEX);
return *(&x + dimension);
}
U32Construct3D<Type> operator+(const U32Construct3D<Type> &other) const {
U32Construct3D<Type> newConstruct;
newConstruct.x = x + other.x;
newConstruct.y = y + other.y;
newConstruct.z = z + other.z;
return newConstruct;
}
Type operator*(const U32Construct3D<Type> &multiplier) const {
return (x * multiplier.x + y * multiplier.y + z * multiplier.z);
}
friend U32Construct3D<Type> operator*(const Type multiplier1[4][4], U32Construct3D<Type> multiplier2) {
U32Construct3D<Type> newPoint;
Type h = 0;
int column, row;
for (row = X_INDEX; row <= Z_INDEX; ++row) {
for (column = X_INDEX; column <= Z_INDEX; ++column) {
newPoint[(EDimension)row] += multiplier1[row][column] * multiplier2[(EDimension)column];
}
newPoint[(EDimension)row] += multiplier1[row][column];
}
for (column = X_INDEX; column <= Z_INDEX; ++column) {
h += multiplier1[row][column] * multiplier2[(EDimension)column];
}
h += multiplier1[row][column];
(h == 0) ? 0 : newPoint.x /= h;
(h == 0) ? 0 : newPoint.y /= h;
(h == 0) ? 0 : newPoint.z /= h;
return newPoint;
}
};
template<class Type>
class U32Point3D;
template<class Type>
class U32Point2D : public U32Construct2D<Type> {
public:
U32Point2D() : U32Construct2D<Type>() {}
U32Point2D(Type xx, Type yy) : U32Construct2D<Type>(xx, yy) {}
U32Point2D(const U32Construct2D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {}
U32Point2D(const U32Construct3D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {} // For 3D
U32Point2D<Type> operator=(const U32Construct3D<Type> &other) {
this->x = other.x;
this->y = other.y;
return *this;
}
U32Construct2D<Type> operator-(const U32Construct3D<Type> &other) const {
U32Construct2D<Type> newPoint;
newPoint.x = this->x - other.x;
newPoint.y = this->y - other.y;
return newPoint;
}
U32Construct2D<Type> operator-(const U32Construct2D<Type> &other) const {
U32Construct2D<Type> newPoint;
newPoint.x = this->x - other.x;
newPoint.y = this->y - other.y;
return newPoint;
}
};
typedef U32Point2D<int> U32IntPoint2D;
typedef U32Point2D<float> U32FltPoint2D;
template<class Type>
class U32Point3D : public U32Construct3D<Type> {
public:
U32Point3D() : U32Construct3D<Type>() {}
U32Point3D(Type xIn, Type yIn, Type zIn) : U32Construct3D<Type>(xIn, yIn, zIn) {}
U32Point3D(const U32Construct3D<Type> &other) : U32Construct3D<Type>(other.x, other.y, other.z) {}
bool operator==(const U32Construct2D<Type> &other) const {
return ((other.x == this->x) && (other.y == this->y));
}
bool operator==(const U32Construct3D<Type> &other) const {
return ((other.x == this->x) && (other.y == this->y) && (other.z == this->z));
}
U32Construct3D<Type> operator-(const U32Construct2D<Type> &other) const {
U32Construct3D<Type> newPoint;
newPoint.x = this->x - other.x;
newPoint.y = this->y - other.y;
newPoint.z = this->z;
return newPoint;
}
U32Construct3D<Type> operator-(const U32Construct3D<Type> &other) const {
U32Construct3D<Type> newPoint;
newPoint.x = this->x - other.x;
newPoint.y = this->y - other.y;
newPoint.z = this->z - other.z;
return newPoint;
}
};
typedef U32Point3D<int> U32IntPoint3D;
typedef U32Point3D<float> U32FltPoint3D;
template<class Type>
class U32Vector2D : public U32Construct2D<Type> {
public:
U32Vector2D() : U32Construct2D<Type>() {}
U32Vector2D(Type xx, Type yy) : U32Construct2D<Type>(xx, yy) {}
U32Vector2D(const U32Construct2D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {}
U32Vector2D(const U32Construct3D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {}
U32Vector2D<Type> normalize() const {
Type magnitude = this->magnitude();
assert(magnitude > 0);
U32Vector2D<Type> newVector;
newVector.x = this->x / magnitude;
newVector.y = this->y / magnitude;
return newVector;
}
U32Vector2D<Type> operator*(Type multiplier) const {
U32Vector2D<Type> newVector;
newVector.x = multiplier * this->x;
newVector.y = multiplier * this->y;
return newVector;
}
Type operator*(const U32Vector2D<Type> &multiplier) const {
return (this->x * multiplier.x + this->y * multiplier.y);
}
const U32Vector2D<Type> &operator*=(Type multiplier) {
*this = *this * multiplier;
return *this;
}
const U32Vector2D<Type> &rotate(ERevDirection whichDirection, double radians) {
U32Point2D<Type> newPoint;
if (whichDirection == kCounterClockwise) {
newPoint.x = this->x * cos(radians) - this->y * sin(radians);
newPoint.y = this->x * sin(radians) + this->y * cos(radians);
} else {
newPoint.x = this->x * cos(radians) + this->y * sin(radians);
newPoint.y = this->y * cos(radians) - this->x * sin(radians);
}
this->x = newPoint.x;
this->y = newPoint.y;
return *this;
}
U32Construct3D<Type> cross(const U32Vector2D<Type> &otherVector) const {
U32Construct3D<Type> newVector;
newVector.x = 0;
newVector.y = 0;
newVector.z = this->x * otherVector.y - this->y * otherVector.x;
return newVector;
}
U32Vector2D<Type> transpose(void) const {
U32Vector2D<Type> newVector;
newVector.x = -this->y;
newVector.y = this->x;
return newVector;
}
Type distance2(const U32Vector2D<Type> &otherVector) const {
return ((this->x - otherVector.x) * (this->x - otherVector.x) +
(this->y - otherVector.y) * (this->y - otherVector.y));
}
Type distance(const U32Vector2D<Type> &otherVector) const {
return (Type)(sqrt((double)(distance2(otherVector))));
}
ERevDirection getRevDirection(const U32Vector2D<Type> &otherVector) const {
U32Construct3D<Type> vector3 = this->cross(otherVector);
if (vector3.z > 0) {
return kCounterClockwise;
} else if (vector3.z < 0) {
return kClockwise;
} else {
return kNone;
}
}
// Project this vector onto otherVector, and return the resulting vector's magnitude.
Type projectScalar(const U32Vector2D<Type> &otherVector) const {
Type projectionScalar;
if (otherVector.magnitude() == 0) {
projectionScalar = 0;
} else {
float otherMagnitude = otherVector.magnitude();
projectionScalar = (*this * otherVector) / otherMagnitude;
}
return projectionScalar;
}
};
typedef U32Vector2D<int> U32IntVector2D;
typedef U32Vector2D<float> U32FltVector2D;
template<class Type>
class U32Vector3D : public U32Construct3D<Type> {
public:
U32Vector3D() : U32Construct3D<Type>() {}
U32Vector3D(Type xx, Type yy, Type zz) : U32Construct3D<Type>(xx, yy, zz) {}
U32Vector3D(const U32Construct2D<Type> &other) : U32Construct3D<Type>(other.x, other.y, 0) {}
U32Vector3D(const U32Construct3D<Type> &other) : U32Construct3D<Type>(other.x, other.y, other.z) {}
U32Vector3D<Type> operator-(const U32Construct2D<Type> &other) const {
U32Vector3D<Type> newVector;
newVector.x = this->x - other.x;
newVector.y = this->y - other.y;
newVector.z = this->z;
return newVector;
}
U32Vector3D<Type> operator-(const U32Construct3D<Type> &other) const {
U32Vector3D<Type> newVector;
newVector.x = this->x - other.x;
newVector.y = this->y - other.y;
newVector.z = this->z - other.z;
return newVector;
}
Type operator*(const U32Construct3D<Type> &multiplier) const {
return (this->x * multiplier.x + this->y * multiplier.y + this->z * multiplier.z);
}
U32Vector3D<Type> &operator+=(const U32Construct3D<Type> &adder) const {
*this = *this + adder;
return *this;
}
U32Vector3D<Type> &operator-=(const U32Construct3D<Type> &subtractor) {
*this = *this - subtractor;
return *this;
}
U32Vector3D<Type> operator*(Type multiplier) const {
U32Vector3D<Type> newVector;
newVector.x = multiplier * this->x;
newVector.y = multiplier * this->y;
newVector.z = multiplier * this->z;
return newVector;
}
const U32Vector3D<Type> &operator*=(Type multiplier) {
*this = *this * multiplier;
return *this;
}
U32Vector3D<Type> operator/(Type divider) const {
U32Vector3D<Type> newVector;
newVector.x = (divider == 0) ? 0 : this->x / divider;
newVector.y = (divider == 0) ? 0 : this->y / divider;
newVector.z = (divider == 0) ? 0 : this->z / divider;
return newVector;
}
const U32Vector3D<Type> &operator/=(Type multiplier) {
*this = *this / multiplier;
return *this;
}
U32Vector3D<Type> cross(const U32Vector3D<Type> &otherVector) const {
U32Vector3D<Type> newVector;
newVector.x = this->y * otherVector.z - this->z * otherVector.y;
newVector.y = this->z * otherVector.x - this->x * otherVector.z;
newVector.z = this->x * otherVector.y - this->y * otherVector.x;
return newVector;
}
bool operator>(const U32Vector3D<Type> &otherVector) const {
return (this->magnitude() > otherVector.magnitude());
}
bool operator<(const U32Vector3D<Type> &otherVector) const {
return (this->magnitude() < otherVector.magnitude());
}
// Project this vector onto otherVector, and return the resulting vector
U32Vector3D<Type> projectVector(const U32Vector3D<Type> &otherVector) const {
Type projectionScalar;
if (otherVector.magnitude() == 0)
projectionScalar = 0;
else
projectionScalar = (*this * otherVector) / (otherVector.magnitude() * otherVector.magnitude());
U32Vector3D<Type> newVector = otherVector * projectionScalar;
return newVector;
}
// Project this vector onto otherVector, and return the resulting vector's magnitude
Type projectScalar(const U32Vector3D<Type> &otherVector) const {
Type projectionScalar;
if (otherVector.magnitude() == 0) {
projectionScalar = 0;
} else {
float otherMagnitude = otherVector.magnitude();
projectionScalar = (*this * otherVector) / otherMagnitude;
}
return projectionScalar;
}
U32Vector3D<Type> normalize() const {
Type magnitude = this->magnitude();
assert(magnitude > 0);
U32Vector3D<Type> newVector;
if (magnitude != 0) {
newVector.x = this->x / magnitude;
newVector.y = this->y / magnitude;
newVector.z = this->z / magnitude;
}
return newVector;
}
};
typedef U32Vector3D<int> U32IntVector3D;
typedef U32Vector3D<float> U32FltVector3D;
class U32Distance3D : public U32Construct3D<float> {
public:
U32Distance3D() : U32Construct3D<float>() {}
U32Distance3D(const U32Construct2D<float> &other) : U32Construct3D<float>(other.x, other.y, 0) {}
U32Distance3D(const U32Construct3D<float> &other) : U32Construct3D<float>(other.x, other.y, other.z) {}
U32Distance3D operator-(int subtractor) const {
U32Distance3D newDistance;
if (magnitude() != 0) {
newDistance.x = x - ((x * subtractor) / magnitude());
newDistance.y = y - ((y * subtractor) / magnitude());
newDistance.z = z - ((z * subtractor) / magnitude());
}
return newDistance;
}
U32Distance3D operator-=(int subtractor) {
*this = *this - subtractor;
return *this;
}
};
struct U32Circle {
U32FltPoint2D center;
float radius;
};
struct U32Sphere {
U32FltPoint3D center;
float radius;
};
struct U32Cylinder : public U32Sphere {
float height;
};
struct U32BoundingBox {
U32IntPoint3D minPoint;
U32IntPoint3D maxPoint;
void setMinPoint(int x, int y) {
minPoint.x = x;
minPoint.y = y;
}
void setMaxPoint(int x, int y) {
maxPoint.x = x;
maxPoint.y = y;
}
const U32IntPoint3D &getMinPoint(void) const {
return minPoint;
}
const U32IntPoint3D &getMaxPoint(void) const {
return maxPoint;
}
bool intersect(const U32BoundingBox &targetBox) const {
return ((((minPoint.x <= targetBox.minPoint.x) &&
(maxPoint.x >= targetBox.minPoint.x)) ||
((minPoint.x <= targetBox.maxPoint.x) &&
(maxPoint.x >= targetBox.maxPoint.x)) ||
((targetBox.minPoint.x <= minPoint.x) &&
(targetBox.maxPoint.x >= minPoint.x)) ||
((targetBox.minPoint.x <= maxPoint.x) &&
(targetBox.maxPoint.x >= maxPoint.x)))
&&
(((minPoint.y <= targetBox.minPoint.y) &&
(maxPoint.y >= targetBox.minPoint.y)) ||
((minPoint.y <= targetBox.maxPoint.y) &&
(maxPoint.y >= targetBox.maxPoint.y)) ||
((targetBox.minPoint.y <= minPoint.y) &&
(targetBox.maxPoint.y >= minPoint.y)) ||
((targetBox.minPoint.y <= maxPoint.y) &&
(targetBox.maxPoint.y >= maxPoint.y))));
}
const U32IntPoint3D &operator[](int point) const {
assert(point <= 1);
return ((point == 0) ? minPoint : maxPoint);
}
U32IntPoint3D &operator[](int point) {
assert(point <= 1);
return ((point == 0) ? minPoint : maxPoint);
}
bool isPointWithin(U32FltPoint2D point) const {
return ((minPoint.x <= point.x) && (point.x <= maxPoint.x) &&
(minPoint.y <= point.y) && (point.y <= maxPoint.y));
}
};
struct U32Plane {
U32FltPoint3D point;
U32FltVector3D normal;
float collisionEfficiency;
float friction;
// Average this plane with another plane
U32Plane &average(const U32Plane &otherPlane) {
point.x = (point.x + otherPlane.point.x) / 2;
point.y = (point.y + otherPlane.point.y) / 2;
point.z = (point.z + otherPlane.point.z) / 2;
normal.x = (normal.x + otherPlane.normal.x) / 2;
normal.y = (normal.y + otherPlane.normal.y) / 2;
normal.z = (normal.z + otherPlane.normal.z) / 2;
float normalMag = normal.magnitude();
normal.x = (normalMag == 0) ? 0 : normal.x / normalMag;
normal.y = (normalMag == 0) ? 0 : normal.y / normalMag;
normal.z = (normalMag == 0) ? 0 : normal.z / normalMag;
collisionEfficiency = (collisionEfficiency + otherPlane.collisionEfficiency) / 2;
friction = (friction + otherPlane.friction) / 2;
return *this;
}
void clear() {
point = U32FltPoint3D();
normal = U32FltVector3D();
collisionEfficiency = 0.0F;
friction = 0.0F;
}
};
class U32Ray2D {
public:
U32FltPoint2D _origin;
U32FltVector2D _direction;
bool intersection(const U32Ray2D &otherRay, U32FltPoint2D *intersection) const {
float numerator = ((otherRay._origin - _origin) * otherRay._direction.transpose());
float denominator = _direction * otherRay._direction.transpose();
if ((denominator == 0) ||
(denominator < 0) != (numerator < 0)) {
return false;
} else {
float s = numerator / denominator;
assert(s >= 0);
intersection->x = _origin.x + (_direction.x * s);
intersection->y = _origin.y + (_direction.y * s);
return true;
}
}
bool nearIntersection(const U32Circle &circle, U32FltPoint2D *intersection) const {
U32FltVector2D coVector = _origin - circle.center;
double b = _direction.normalize() * coVector;
double c = (coVector * coVector) - (circle.radius * circle.radius);
double d = (b * b) - c;
if (d < 0) {
return false;
} else {
double t = -b - sqrt(d);
if (t < 0) {
return false;
} else {
*intersection = _origin + (_direction.normalize() * t);
return true;
}
}
}
bool farIntersection(const U32Circle &circle, U32FltPoint2D *intersection) const {
U32FltVector2D coVector = _origin - circle.center;
double b = _direction.normalize() * coVector;
double c = (coVector * coVector) - (circle.radius * circle.radius);
double d = (b * b) - c;
if (d < 0) {
return false;
} else {
double t = -b + sqrt(d);
if (t < 0) {
return false;
} else {
*intersection = _origin + (_direction.normalize() * t);
return true;
}
}
}
};
class U32Ray3D {
public:
U32FltPoint3D _origin;
U32FltVector3D _direction;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SUPPORT_OBJ_H

View File

@@ -0,0 +1,128 @@
/* 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/basketball/collision/bball_collision_support_obj.h"
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
#include "scumm/he/basketball/collision/bball_collision_box.h"
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
#include "scumm/he/basketball/collision/bball_collision_tree.h"
namespace Scumm {
CCollisionObjectTree::CCollisionObjectTree(const CCollisionObjectVector &inputObjects) : _maxHeight(INIT_MAX_HEIGHT),
_maxObjectsInNode(INIT_MAX_OBJECTS),
_root(nullptr),
_errorFlag(false) {
initialize(inputObjects);
}
CCollisionObjectTree::~CCollisionObjectTree() {
if (_root) {
delete _root;
_root = nullptr;
}
}
void CCollisionObjectTree::initialize(const CCollisionObjectVector &inputObjects) {
if (_root) {
delete _root;
_root = nullptr;
}
U32BoundingBox buildRange;
buildRange.setMinPoint(inputObjects.getMinPoint(X_INDEX), inputObjects.getMinPoint(Y_INDEX));
buildRange.setMaxPoint(inputObjects.getMaxPoint(X_INDEX), inputObjects.getMaxPoint(Y_INDEX));
_root = buildSelectionStructure(inputObjects, 0, buildRange);
}
void CCollisionObjectTree::selectObjectsInBound(const U32BoundingBox &bound, CCollisionObjectVector *targetVector) {
_root->searchTree(bound, targetVector);
if (targetVector->size() <= 0) {
warning("CCollisionObjectTree::selectObjectsInBound(): (targetVector->size() <= 0) Something went really wrong with a collision, ignore and U32 will attempt to correct.");
_errorFlag = true;
return;
}
// Here we make sure that we don't have any duplicate objects in our target stack...
Std::sort(targetVector->begin(), targetVector->end());
CCollisionObjectVector::iterator newEnd = Std::unique(targetVector->begin(), targetVector->end());
targetVector->erase(newEnd, targetVector->end());
}
bool CCollisionObjectTree::checkErrors() {
if (_errorFlag) {
_errorFlag = false;
return true;
} else {
return false;
}
}
CCollisionNode *CCollisionObjectTree::buildSelectionStructure(const CCollisionObjectVector &inputObjects, int currentLevel, const U32BoundingBox &nodeRange) {
// Create a new node, containing all of the input points...
CCollisionNode *newNode = new CCollisionNode(inputObjects);
newNode->_quadrant = nodeRange;
// See if we are at the final level, or if we have reached our target occupancy...
if ((currentLevel == _maxHeight) ||
(inputObjects.size() <= _maxObjectsInNode)) {
newNode->_isExternal = true;
} else {
newNode->_isExternal = false;
// Otherwise, break the inputPoints into 4 new point lists...
CCollisionObjectVector newList[NUM_CHILDREN_NODES];
U32BoundingBox newRange[NUM_CHILDREN_NODES];
int childID;
for (childID = 0; childID < NUM_CHILDREN_NODES; childID++) {
newRange[childID] = CCollisionNode::getChildQuadrant(nodeRange, (EChildID)childID);
}
// Go through each point in the list...
for (size_t i = 0; i < inputObjects.size(); i++) {
const ICollisionObject *currentObject = inputObjects[i];
// Figure out which child each point belongs to...
for (childID = 0; childID < NUM_CHILDREN_NODES; ++childID) {
if (newRange[childID].intersect(currentObject->getBoundingBox())) {
newList[childID].push_back(currentObject);
}
}
}
// Make recursive calls...
for (childID = 0; childID < NUM_CHILDREN_NODES; ++childID) {
newNode->_child[childID] = buildSelectionStructure(newList[childID],
currentLevel + 1,
newRange[childID]);
}
}
return newNode;
}
} // End of namespace Scumm

View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_TREE_H
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_TREE_H
#ifdef ENABLE_HE
#include "scumm/he/basketball/collision/bball_collision_object.h"
#include "scumm/he/basketball/collision/bball_collision_stack.h"
#include "scumm/he/basketball/collision/bball_collision_node.h"
namespace Scumm {
#define INIT_MAX_HEIGHT 10
#define INIT_MAX_OBJECTS 5
class CCollisionObjectTree {
public:
CCollisionObjectTree() : _maxHeight(INIT_MAX_HEIGHT),
_maxObjectsInNode(INIT_MAX_OBJECTS),
_root(nullptr),
_errorFlag(false) {}
CCollisionObjectTree(const CCollisionObjectVector &inputObjects);
~CCollisionObjectTree();
void initialize(const CCollisionObjectVector &inputObjects);
void selectObjectsInBound(const U32BoundingBox &bound, CCollisionObjectVector *targetVector);
bool checkErrors();
private:
CCollisionNode *buildSelectionStructure(const CCollisionObjectVector &inputObjects, int currentLevel, const U32BoundingBox &nodeRange);
int _maxHeight;
size_t _maxObjectsInNode;
CCollisionNode *_root;
bool _errorFlag;
};
} // End of namespace Scumm
#endif // ENABLE_HE
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_TREE_H