Initial commit
This commit is contained in:
250
engines/scumm/he/basketball/ai.cpp
Normal file
250
engines/scumm/he/basketball/ai.cpp
Normal 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/ai.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/geo_translations.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "math/utils.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int LogicHEBasketball::u32_userGetPlayerClosestToBall(int teamIndex) {
|
||||
assert((TEAM_HOME <= teamIndex) && (teamIndex <= TEAM_AWAY));
|
||||
|
||||
int finalPlayerIndex = NO_PLAYER;
|
||||
int shortestDistance2 = 0x7FFFFFFF;
|
||||
|
||||
// Go through all of the players on the team and calculate the distance between
|
||||
// them and the ball...
|
||||
Common::Array<CCollisionPlayer> *playerList =
|
||||
(teamIndex == TEAM_HOME) ?
|
||||
&_vm->_basketball->_court->_homePlayerList : &_vm->_basketball->_court->_awayPlayerList;
|
||||
|
||||
for (size_t playerIndex = 0; playerIndex < playerList->size(); ++playerIndex) {
|
||||
CCollisionPlayer *currentPlayer = &((*playerList)[playerIndex]);
|
||||
|
||||
if (currentPlayer->_playerIsInGame) {
|
||||
|
||||
int distance2 = (
|
||||
((currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x) *
|
||||
(currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x)) +
|
||||
((currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y) *
|
||||
(currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y)));
|
||||
|
||||
// Keep track of the player closest to the ball...
|
||||
if (distance2 < shortestDistance2) {
|
||||
finalPlayerIndex = playerIndex;
|
||||
shortestDistance2 = distance2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(finalPlayerIndex != NO_PLAYER);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, (*playerList)[finalPlayerIndex]._objectID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetPlayerClosestToBall() {
|
||||
int finalPlayerIndex = NO_PLAYER;
|
||||
int shortestDistance2 = 0x7FFFFFFF;
|
||||
Common::Array<CCollisionPlayer> *playerList = nullptr;
|
||||
|
||||
// Go through all of the players on both teams and calculate the distance between
|
||||
// them and the ball...
|
||||
for (size_t playerIndex = 0; playerIndex < _vm->_basketball->_court->_homePlayerList.size(); ++playerIndex) {
|
||||
CCollisionPlayer *currentPlayer = &_vm->_basketball->_court->_homePlayerList[playerIndex];
|
||||
|
||||
if (currentPlayer->_playerIsInGame) {
|
||||
int distance2 = (
|
||||
((currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x) *
|
||||
(currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x)) +
|
||||
((currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y) *
|
||||
(currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y)));
|
||||
|
||||
// Keep track of the player closest to the ball...
|
||||
if (distance2 < shortestDistance2) {
|
||||
finalPlayerIndex = playerIndex;
|
||||
shortestDistance2 = distance2;
|
||||
playerList = &_vm->_basketball->_court->_homePlayerList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t playerIndex = 0; playerIndex < _vm->_basketball->_court->_awayPlayerList.size(); ++playerIndex) {
|
||||
CCollisionPlayer *currentPlayer = &_vm->_basketball->_court->_awayPlayerList[playerIndex];
|
||||
|
||||
if (currentPlayer->_playerIsInGame) {
|
||||
int distance2 = (
|
||||
((currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x) *
|
||||
(currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x)) +
|
||||
((currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y) *
|
||||
(currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y)));
|
||||
|
||||
// Keep track of the player closest to the ball...
|
||||
if (distance2 < shortestDistance2) {
|
||||
finalPlayerIndex = playerIndex;
|
||||
shortestDistance2 = distance2;
|
||||
playerList = &_vm->_basketball->_court->_awayPlayerList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(finalPlayerIndex != NO_PLAYER);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, (*playerList)[finalPlayerIndex]._objectID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Basketball::numOpponentsInCone(int team, float widthDistanceRatio, const U32FltVector2D &end, const U32FltVector2D &focus) {
|
||||
// The end out parameter is the end point of the center line of the cone,
|
||||
// and widthDistanceRatio defines the width of the cone = width at dist 1
|
||||
int count = 0;
|
||||
|
||||
Line2D line(focus, end);
|
||||
|
||||
Common::Array<CCollisionPlayer> *playerList = (team == TEAM_HOME) ? &_vm->_basketball->_court->_homePlayerList : &_vm->_basketball->_court->_awayPlayerList;
|
||||
|
||||
for (Common::Array<CCollisionPlayer>::iterator currentPlayer = playerList->begin(); currentPlayer != playerList->end(); ++currentPlayer) {
|
||||
U32FltVector2D point = line.projectPoint(currentPlayer->center);
|
||||
|
||||
if (focus.distance2(currentPlayer->center) < (point.distance2(focus) * widthDistanceRatio * widthDistanceRatio) && line.inBetween(point, focus, end)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool isPointInBounds(const U32FltVector2D &point) {
|
||||
return ((point.x > 0) &&
|
||||
(point.x < MAX_WORLD_X) &&
|
||||
(point.y > 0) &&
|
||||
(point.y < MAX_WORLD_Y));
|
||||
}
|
||||
|
||||
float Basketball::congestion(U32FltVector2D pos, bool ignore, int whichPlayer) {
|
||||
float congestion = 0.0F;
|
||||
|
||||
for (int team = TEAM_HOME; team <= TEAM_AWAY; ++team) {
|
||||
Common::Array<CCollisionPlayer> *playerList = (team == TEAM_HOME) ? &_court->_homePlayerList : &_court->_awayPlayerList;
|
||||
|
||||
for (Common::Array<CCollisionPlayer>::iterator currentPlayer = playerList->begin(); currentPlayer != playerList->end(); ++currentPlayer) {
|
||||
if (currentPlayer->_playerIsInGame && (ignore && !(currentPlayer->_objectID == whichPlayer))) {
|
||||
float distance2 = pos.distance2(currentPlayer->center);
|
||||
|
||||
if (distance2 == 0.0F)
|
||||
return FLT_MAX;
|
||||
|
||||
congestion += (1 / distance2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return congestion;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetOpenSpot(int whichPlayer, U32FltVector2D upperLeft, U32FltVector2D lowerRight, U32FltVector2D passer, bool attract, U32FltVector2D attractPoint) {
|
||||
int xGranularity = 5;
|
||||
int yGranularity = 5;
|
||||
|
||||
int rectWidth = fabs(upperLeft.x - lowerRight.x);
|
||||
int rectHeight = fabs(upperLeft.y - lowerRight.y);
|
||||
|
||||
// Integer operation cast to float, this is intended!
|
||||
float xMesh = (float)(rectWidth / (xGranularity + 1));
|
||||
float yMesh = (float)(rectHeight / (yGranularity + 1));
|
||||
|
||||
float startX = upperLeft.x + xMesh / 2;
|
||||
float startY = upperLeft.y + yMesh / 2;
|
||||
|
||||
float x = startX, y = startY;
|
||||
|
||||
float bestCongestion = FLT_MAX;
|
||||
|
||||
U32FltVector2D bestPoint, point;
|
||||
|
||||
float tmp;
|
||||
|
||||
for (int ii = 0; ii < xGranularity; ii++) {
|
||||
for (int jj = 0; jj < yGranularity; jj++) {
|
||||
tmp = _vm->_basketball->congestion(point = U32FltVector2D(x, y), true, whichPlayer);
|
||||
|
||||
if (attract) {
|
||||
tmp -= (4 * (1 / point.distance2(attractPoint)));
|
||||
}
|
||||
|
||||
if (tmp < bestCongestion &&
|
||||
isPointInBounds(point)) {
|
||||
bestCongestion = tmp;
|
||||
bestPoint = point;
|
||||
}
|
||||
|
||||
y += yMesh;
|
||||
}
|
||||
|
||||
x += xMesh;
|
||||
y = startY;
|
||||
}
|
||||
|
||||
if (bestCongestion == FLT_MAX) {
|
||||
return 0;
|
||||
} else {
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, bestPoint.x);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, bestPoint.y);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int isPlayerInBounds(U32Sphere *player) {
|
||||
assert(player);
|
||||
|
||||
return (((player->center.x - player->radius) > -COLLISION_EPSILON) &&
|
||||
((player->center.x + player->radius) < (MAX_WORLD_X + COLLISION_EPSILON)) &&
|
||||
((player->center.y - player->radius) > -COLLISION_EPSILON) &&
|
||||
((player->center.y + player->radius) < (MAX_WORLD_Y + COLLISION_EPSILON)));
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userIsPlayerInBounds(int playerID) {
|
||||
U32Cylinder *player = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
int isPlayerInBoundsRes = isPlayerInBounds(player);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, isPlayerInBoundsRes);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userIsBallInBounds() {
|
||||
int isBallInBounds = isPlayerInBounds(&_vm->_basketball->_court->_basketBall);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, isBallInBounds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
Reference in New Issue
Block a user