mirror of
https://github.com/1dot13/source.git
synced 2026-09-09 14:46:05 +02:00
Readded AStar code, see email for more details.
Fixed bug in AStar code. Fixed night combat chance to hit Optimized worst case scenario pathing to be faster. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1438 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -0,0 +1,358 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef BINARY_HEAP_HPP
|
||||||
|
#define BINARY_HEAP_HPP
|
||||||
|
|
||||||
|
template <typename KEY = int, class T = int>
|
||||||
|
class HEAP
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KEY key;
|
||||||
|
T data;
|
||||||
|
|
||||||
|
HEAP<KEY, T>(void){return;};
|
||||||
|
HEAP<KEY, T>(T data, int key) {HEAP::data = data; HEAP::key = key; return;};
|
||||||
|
|
||||||
|
bool operator==(HEAP<KEY, T> &compare) {
|
||||||
|
if (this->key == compare.key && this->data == compare.data) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename KEY = int, class T = int>
|
||||||
|
class CBinaryHeap
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
CBinaryHeap ();
|
||||||
|
CBinaryHeap (int size);
|
||||||
|
~CBinaryHeap ();
|
||||||
|
|
||||||
|
HEAP<KEY, T> popTopHeap ();
|
||||||
|
HEAP<KEY, T> popTopHeap (int& returnSize);
|
||||||
|
HEAP<KEY, T> peekTopHeap () const;
|
||||||
|
HEAP<KEY, T> peekElement (int index) const;
|
||||||
|
int size () const;
|
||||||
|
int getMaxSize () const;
|
||||||
|
int insertElement (const T data, const KEY key);
|
||||||
|
HEAP<KEY, T> removeElement (const T data, const KEY key);
|
||||||
|
HEAP<KEY, T> removeElement (const T data);
|
||||||
|
bool editElement (const T oldData, const T newData,
|
||||||
|
const KEY oldKey, const KEY newKey);
|
||||||
|
bool editElement (const T data, const KEY key);
|
||||||
|
int findData (const T data) const;
|
||||||
|
int findData (const T data, const KEY key) const;
|
||||||
|
void clear (){heapCount = 1; return;};
|
||||||
|
|
||||||
|
private:
|
||||||
|
int moveUp (int index, KEY newKey);
|
||||||
|
int moveDown (int index, KEY newKey);
|
||||||
|
|
||||||
|
int heapCount;
|
||||||
|
int maxSize;
|
||||||
|
HEAP<KEY, T>* BinaryHeap;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
void clear ()
|
||||||
|
{
|
||||||
|
heapCount = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBinaryHeap(int size)
|
||||||
|
{
|
||||||
|
if (size <= 0) {
|
||||||
|
size = WORLD_MAX;
|
||||||
|
}
|
||||||
|
//size must be maxSize + 1, because 1 element is unused.
|
||||||
|
BinaryHeap = new HEAP<KEY, T>[size+1];
|
||||||
|
maxSize = size;
|
||||||
|
heapCount = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBinaryHeap()
|
||||||
|
{
|
||||||
|
//size must be maxSize + 1, because 1 element is unused.
|
||||||
|
BinaryHeap = new HEAP<KEY, T>[WORLD_MAX+1];
|
||||||
|
maxSize = WORLD_MAX;
|
||||||
|
heapCount = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
~CBinaryHeap()
|
||||||
|
{
|
||||||
|
delete BinaryHeap;
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP<KEY, T> removeElement(const T data)
|
||||||
|
{
|
||||||
|
HEAP<KEY, T> returnHeap;
|
||||||
|
int index = findData(data);
|
||||||
|
if (index) {
|
||||||
|
returnHeap = BinaryHeap[index];
|
||||||
|
--heapCount;
|
||||||
|
BinaryHeap[moveDown(index, BinaryHeap[heapCount].key)] = BinaryHeap[heapCount];
|
||||||
|
}
|
||||||
|
return (returnHeap);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP<KEY, T> removeElement(const T data, const KEY key)
|
||||||
|
{
|
||||||
|
HEAP<KEY, T> returnHeap;
|
||||||
|
int index = findData(data, key);
|
||||||
|
if (index) {
|
||||||
|
returnHeap = BinaryHeap[index];
|
||||||
|
--heapCount;
|
||||||
|
BinaryHeap[moveDown(index, BinaryHeap[heapCount].key)] = BinaryHeap[heapCount];
|
||||||
|
}
|
||||||
|
return (returnHeap);
|
||||||
|
}
|
||||||
|
|
||||||
|
int moveUp(register int index, KEY newKey)
|
||||||
|
{
|
||||||
|
while (index > 1) {
|
||||||
|
int current2 = index>>1;//divided by 2
|
||||||
|
if (BinaryHeap[current2].key > newKey) {
|
||||||
|
//move parent down
|
||||||
|
BinaryHeap[index] = BinaryHeap[current2];
|
||||||
|
index = current2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int moveDown(int index, KEY currentKey)
|
||||||
|
{
|
||||||
|
register int current2 = index+index;
|
||||||
|
while (current2 < heapCount) {
|
||||||
|
if (current2+1 < heapCount) {
|
||||||
|
//choose child to possibly move
|
||||||
|
current2 += (BinaryHeap[current2].key > BinaryHeap[current2+1].key);
|
||||||
|
if (currentKey > BinaryHeap[current2].key) {
|
||||||
|
//move child up
|
||||||
|
BinaryHeap[index] = BinaryHeap[current2];
|
||||||
|
index = current2;
|
||||||
|
current2 += current2;//times 2
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (currentKey > BinaryHeap[current2].key) {
|
||||||
|
BinaryHeap[index] = BinaryHeap[current2];
|
||||||
|
index = current2;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool editElement(const T oldData, const T newData, const KEY oldKey, const KEY newKey)
|
||||||
|
{
|
||||||
|
int index = findData(oldData, oldKey);
|
||||||
|
if (index) {
|
||||||
|
if (oldKey < newKey) {
|
||||||
|
index = moveDown(index, newKey);
|
||||||
|
BinaryHeap[index].key = newKey;
|
||||||
|
}
|
||||||
|
else if (oldKey > newKey) {
|
||||||
|
index = moveUp(index, newKey);
|
||||||
|
BinaryHeap[index].key = newKey;
|
||||||
|
}
|
||||||
|
BinaryHeap[index].data = newData;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool editElement(const T data, const KEY key)
|
||||||
|
{
|
||||||
|
int index = findData(data);
|
||||||
|
if (index) {
|
||||||
|
int oldKey = BinaryHeap[index].key;
|
||||||
|
if (oldKey < key) {
|
||||||
|
index = moveDown(index, key);
|
||||||
|
BinaryHeap[index].data = data;
|
||||||
|
BinaryHeap[index].key = key;
|
||||||
|
}
|
||||||
|
else if (oldKey > key) {
|
||||||
|
index = moveUp(index, key);
|
||||||
|
BinaryHeap[index].data = data;
|
||||||
|
BinaryHeap[index].key = key;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int insertElement(const T data, const KEY key)
|
||||||
|
{
|
||||||
|
if (heapCount > maxSize) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int index = heapCount;
|
||||||
|
while (index > 1) {
|
||||||
|
int current2 = index>>1;//divided by 2
|
||||||
|
if (BinaryHeap[current2].key > key) {
|
||||||
|
//move parent down
|
||||||
|
BinaryHeap[index] = BinaryHeap[current2];
|
||||||
|
index = current2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BinaryHeap[index].data = data;
|
||||||
|
BinaryHeap[index].key = key;
|
||||||
|
return (heapCount++);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (heapCount > maxSize) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
__asm {
|
||||||
|
mov ecx, [this]
|
||||||
|
mov eax, [ecx]CBinaryHeap.heapCount
|
||||||
|
mov ecx, [ecx]CBinaryHeap.BinaryHeap
|
||||||
|
mov edx, key
|
||||||
|
cmp eax, 1
|
||||||
|
jle short insert
|
||||||
|
|
||||||
|
moveParentDown:
|
||||||
|
mov esi, eax
|
||||||
|
sar esi, 1
|
||||||
|
cmp [ecx+esi*8], edx
|
||||||
|
jle short insert//if parent key is higher, insert at current index
|
||||||
|
cmp esi, 1
|
||||||
|
mov ebx, [ecx+esi*8]
|
||||||
|
mov [ecx+eax*8], ebx
|
||||||
|
mov ebx, [ecx+esi*8+4]
|
||||||
|
mov [ecx+eax*8+4], ebx
|
||||||
|
mov eax, esi
|
||||||
|
jg short moveParentDown
|
||||||
|
|
||||||
|
insert:
|
||||||
|
mov esi, data
|
||||||
|
mov [ecx+eax*8+4], esi
|
||||||
|
mov [ecx+eax*8], edx
|
||||||
|
mov ecx, [this]
|
||||||
|
mov eax, [ecx]CBinaryHeap.heapCount//++heapCount
|
||||||
|
mov edx, eax
|
||||||
|
inc edx
|
||||||
|
mov [ecx]CBinaryHeap.heapCount, edx//BinaryHeap.heapCount = heapCount
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP<KEY, T> popTopHeap(int& returnSize)
|
||||||
|
{
|
||||||
|
returnSize = heapCount-1;
|
||||||
|
if (heapCount != 1) {
|
||||||
|
return (popTopHeap());
|
||||||
|
}
|
||||||
|
return (BinaryHeap[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP<KEY, T> popTopHeap()
|
||||||
|
{
|
||||||
|
HEAP<KEY, T> returnHeap;
|
||||||
|
if (heapCount != 1) {
|
||||||
|
returnHeap = BinaryHeap[1];
|
||||||
|
--heapCount;
|
||||||
|
KEY currentKey = BinaryHeap[heapCount].key;
|
||||||
|
int current2 = 2;
|
||||||
|
int index = 1;
|
||||||
|
while (current2 < heapCount) {
|
||||||
|
if (current2+1 < heapCount) {
|
||||||
|
current2 += (BinaryHeap[current2].key > BinaryHeap[current2+1].key);
|
||||||
|
//choose child to possibly move
|
||||||
|
if (currentKey > BinaryHeap[current2].key) {
|
||||||
|
//move child up
|
||||||
|
BinaryHeap[index] = BinaryHeap[current2];
|
||||||
|
index = current2;
|
||||||
|
current2 += current2;//times 2
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (currentKey > BinaryHeap[current2].key) {
|
||||||
|
BinaryHeap[index] = BinaryHeap[current2];
|
||||||
|
index = current2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BinaryHeap[index] = BinaryHeap[heapCount];
|
||||||
|
}
|
||||||
|
return (returnHeap);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP<KEY, T> peekTopHeap() const
|
||||||
|
{
|
||||||
|
return (BinaryHeap[(heapCount != 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEAP<KEY, T> peekElement(int index) const
|
||||||
|
{
|
||||||
|
if (index < heapCount) {
|
||||||
|
return (BinaryHeap[index]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (BinaryHeap[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return (heapCount-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMaxSize() const
|
||||||
|
{
|
||||||
|
return (maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int findData(const T data) const
|
||||||
|
{
|
||||||
|
register int current;
|
||||||
|
for (current = heapCount-1; current > 0; --current) {
|
||||||
|
if (BinaryHeap[current].data == data) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findData(const T data, const KEY key) const
|
||||||
|
{
|
||||||
|
register int current;
|
||||||
|
if ((BinaryHeap[1].key + BinaryHeap[heapCount-1].key)>>1 > key) {
|
||||||
|
for (current = 1; current <= heapCount-1; ++current) {
|
||||||
|
if (BinaryHeap[current].data == data && BinaryHeap[current].key == key) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (current = heapCount-1; current > 0; --current) {
|
||||||
|
if (BinaryHeap[current].data == data && BinaryHeap[current].key == key) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int heapCount;
|
||||||
|
int maxSize;
|
||||||
|
HEAP<KEY, T>* BinaryHeap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+16
-16
@@ -640,7 +640,7 @@ BOOLEAN ResolveHitOnWall( STRUCTURE * pStructure, INT32 iGridNo, INT8 bLOSIndexX
|
|||||||
* - stops at other obstacles
|
* - stops at other obstacles
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, int iTileSightLimit, UINT8 ubTreeSightReduction, INT8 bAware, INT32 bCamouflage, BOOLEAN fSmell, INT16 * psWindowGridNo )
|
INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, int iTileSightLimit, UINT8 ubTreeSightReduction, INT8 bAware, INT32 bCamouflage, BOOLEAN fSmell, INT16 * psWindowGridNo, bool adjustForSight = true )
|
||||||
{
|
{
|
||||||
// Parameters...
|
// Parameters...
|
||||||
// the X,Y,Z triplets should be obvious
|
// the X,Y,Z triplets should be obvious
|
||||||
@@ -1384,21 +1384,21 @@ INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX,
|
|||||||
//without stopping when my eyes stop, but also including my sight limit!
|
//without stopping when my eyes stop, but also including my sight limit!
|
||||||
//so iTileSightLimit has 255 added to it if the line is supposed to be infinite
|
//so iTileSightLimit has 255 added to it if the line is supposed to be infinite
|
||||||
|
|
||||||
int scalar = iSightLimit;
|
int distanceWithCover = (iDistance + (iSightLimit - iAdjSightLimit));
|
||||||
if (iTileSightLimit >= 255) {
|
if (adjustForSight == false) {
|
||||||
//I know I am doing a CTGT calc, so don't get carried away
|
//I know I am doing a CTGT calc, so don't get carried away
|
||||||
//just because I can see 999 tiles doesn't mean I can shoot it!
|
//just because I can see 999 tiles doesn't mean I can shoot it!
|
||||||
//this preserves the original intent of the scalar, but makes it less likely iAdjSightLimit
|
//this preserves the original intent of the scalar, but makes it less likely iAdjSightLimit
|
||||||
//is less than zero, which if it were the function would return, which we don't want if our sight is good
|
//is less than zero, which if it were the function would return, which we don't want if our sight is good
|
||||||
scalar = min(MaxNormalDistanceVisible() * CELL_X_SIZE, iSightLimit);
|
return distanceWithCover;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
//I know that my sight could be over the average distance, but I am not going to clamp it
|
|
||||||
//because I do not think the actual value matters, and if it does,
|
//I know that my sight could be over the average distance, but I am not going to clamp it
|
||||||
//then using the real value is closer to the original intent
|
//because I do not think the actual value matters, and if it does,
|
||||||
//AFAIK all instances that aren't CTGT just use this as a boolean test
|
//then using the real value is closer to the original intent
|
||||||
}
|
//AFAIK all instances that aren't CTGT just use this as a boolean test
|
||||||
return( (iDistance + (iSightLimit - iAdjSightLimit)) * (MaxNormalDistanceVisible() * CELL_X_SIZE) / scalar );
|
return( distanceWithCover * (MaxNormalDistanceVisible() * CELL_X_SIZE) / iSightLimit );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN CalculateSoldierZPos( SOLDIERTYPE * pSoldier, UINT8 ubPosType, FLOAT * pdZPos )
|
BOOLEAN CalculateSoldierZPos( SOLDIERTYPE * pSoldier, UINT8 ubPosType, FLOAT * pdZPos )
|
||||||
@@ -1587,7 +1587,7 @@ BOOLEAN CalculateSoldierZPos( SOLDIERTYPE * pSoldier, UINT8 ubPosType, FLOAT * p
|
|||||||
return( TRUE );
|
return( TRUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit, UINT8 ubAimLocation )
|
INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit, UINT8 ubAimLocation, bool adjustForSight )
|
||||||
{
|
{
|
||||||
FLOAT dStartZPos, dEndZPos;
|
FLOAT dStartZPos, dEndZPos;
|
||||||
BOOLEAN fOk;
|
BOOLEAN fOk;
|
||||||
@@ -1766,7 +1766,7 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE
|
|||||||
iTileSightLimit = 255 + pStartSoldier->GetMaxDistanceVisible( pEndSoldier->sGridNo, pEndSoldier->bLevel, CALC_FROM_ALL_DIRS );
|
iTileSightLimit = 255 + pStartSoldier->GetMaxDistanceVisible( pEndSoldier->sGridNo, pEndSoldier->bLevel, CALC_FROM_ALL_DIRS );
|
||||||
}
|
}
|
||||||
|
|
||||||
return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, iTileSightLimit, ubTreeReduction, bAware, bEffectiveCamo + bEffectiveStealth, fSmell, NULL ) );
|
return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, iTileSightLimit, ubTreeReduction, bAware, bEffectiveCamo + bEffectiveStealth, fSmell, NULL, adjustForSight ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
INT16 SoldierToLocationWindowTest( SOLDIERTYPE * pStartSoldier, INT16 sEndGridNo )
|
INT16 SoldierToLocationWindowTest( SOLDIERTYPE * pStartSoldier, INT16 sEndGridNo )
|
||||||
@@ -1797,7 +1797,7 @@ INT16 SoldierToLocationWindowTest( SOLDIERTYPE * pStartSoldier, INT16 sEndGridNo
|
|||||||
return( sWindowGridNo );
|
return( sWindowGridNo );
|
||||||
}
|
}
|
||||||
|
|
||||||
INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bCubeLevel, INT8 bAware, int iTileSightLimit )
|
INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bCubeLevel, INT8 bAware, int iTileSightLimit, bool adjustForSight )
|
||||||
{
|
{
|
||||||
FLOAT dStartZPos, dEndZPos;
|
FLOAT dStartZPos, dEndZPos;
|
||||||
INT16 sXPos, sYPos;
|
INT16 sXPos, sYPos;
|
||||||
@@ -1821,7 +1821,7 @@ INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGr
|
|||||||
if (ubTargetID != NOBODY)
|
if (ubTargetID != NOBODY)
|
||||||
{
|
{
|
||||||
// there's a merc there; do a soldier-to-soldier test
|
// there's a merc there; do a soldier-to-soldier test
|
||||||
return( SoldierToSoldierLineOfSightTest( pStartSoldier, MercPtrs[ubTargetID], bAware, iTileSightLimit) );
|
return( SoldierToSoldierLineOfSightTest( pStartSoldier, MercPtrs[ubTargetID], bAware, iTileSightLimit, LOS_POS, adjustForSight) );
|
||||||
}
|
}
|
||||||
// else... assume standing height
|
// else... assume standing height
|
||||||
dEndZPos = STANDING_LOS_POS + bLevel * HEIGHT_UNITS;
|
dEndZPos = STANDING_LOS_POS + bLevel * HEIGHT_UNITS;
|
||||||
@@ -1840,7 +1840,7 @@ INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGr
|
|||||||
iTileSightLimit = 255 + pStartSoldier->GetMaxDistanceVisible( sGridNo, bLevel, CALC_FROM_ALL_DIRS );
|
iTileSightLimit = 255 + pStartSoldier->GetMaxDistanceVisible( sGridNo, bLevel, CALC_FROM_ALL_DIRS );
|
||||||
}
|
}
|
||||||
|
|
||||||
return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) sXPos, (FLOAT) sYPos, dEndZPos, iTileSightLimit, gubTreeSightReduction[ANIM_STAND], bAware, 0, HasThermalOptics( pStartSoldier), NULL ) );
|
return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) sXPos, (FLOAT) sYPos, dEndZPos, iTileSightLimit, gubTreeSightReduction[ANIM_STAND], bAware, 0, HasThermalOptics( pStartSoldier), NULL, adjustForSight ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
INT32 SoldierToVirtualSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bStance, INT8 bAware, int iTileSightLimit )
|
INT32 SoldierToVirtualSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bStance, INT8 bAware, int iTileSightLimit )
|
||||||
|
|||||||
+2
-2
@@ -65,8 +65,8 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA
|
|||||||
#define CALC_FROM_WANTED_DIR -2
|
#define CALC_FROM_WANTED_DIR -2
|
||||||
#define NO_DISTANCE_LIMIT -3
|
#define NO_DISTANCE_LIMIT -3
|
||||||
|
|
||||||
INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS, UINT8 ubAimLocation = LOS_POS );
|
INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS, UINT8 ubAimLocation = LOS_POS, bool adjustForSight = true );
|
||||||
INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bCubeLevel, INT8 bAware, int ubSightLimit = CALC_FROM_ALL_DIRS );
|
INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bCubeLevel, INT8 bAware, int ubSightLimit = CALC_FROM_ALL_DIRS, bool adjustForSight = true );
|
||||||
INT32 SoldierToVirtualSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bStance, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS );
|
INT32 SoldierToVirtualSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT16 sGridNo, INT8 bLevel, INT8 bStance, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS );
|
||||||
UINT8 SoldierToSoldierChanceToGetThrough( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier );
|
UINT8 SoldierToSoldierChanceToGetThrough( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier );
|
||||||
UINT8 SoldierToSoldierBodyPartChanceToGetThrough( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, UINT8 ubAimLocation );
|
UINT8 SoldierToSoldierBodyPartChanceToGetThrough( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, UINT8 ubAimLocation );
|
||||||
|
|||||||
@@ -10,6 +10,181 @@
|
|||||||
#define _PATHAI_H
|
#define _PATHAI_H
|
||||||
#include "isometric utils.h"
|
#include "isometric utils.h"
|
||||||
|
|
||||||
|
#define USE_ASTAR_PATHS
|
||||||
|
|
||||||
|
#ifdef USE_ASTAR_PATHS
|
||||||
|
|
||||||
|
namespace ASTAR {
|
||||||
|
#include "BinaryHeap.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum eAStar
|
||||||
|
{
|
||||||
|
AStar_Init,
|
||||||
|
AStar_Open,
|
||||||
|
AStar_Closed
|
||||||
|
};
|
||||||
|
|
||||||
|
class AStar_Data
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AStar_Data()
|
||||||
|
{
|
||||||
|
cost = f = APCost = direction = prevCost = 0;
|
||||||
|
#ifdef ASTAR_USING_EXTRACOVER
|
||||||
|
extraGCoverCost = -1;//-1 means we have not stopped at this node
|
||||||
|
#endif
|
||||||
|
wasBackwards = false;
|
||||||
|
status = AStar_Init;
|
||||||
|
parent = GridNode(-1,-1);
|
||||||
|
};
|
||||||
|
//no H
|
||||||
|
int cost;//G
|
||||||
|
int f;//F
|
||||||
|
int APCost;//the APs spent to get here
|
||||||
|
#ifdef ASTAR_USING_EXTRACOVER
|
||||||
|
int extraGCoverCost;//an extra cost that makes stopping in midpath at a node with little cover worse
|
||||||
|
#endif
|
||||||
|
GridNode parent;
|
||||||
|
eAStar status;
|
||||||
|
int prevCost;
|
||||||
|
bool wasBackwards;
|
||||||
|
int direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef HEAP<int, GridNode> AStarHeap;
|
||||||
|
|
||||||
|
class AStarPathfinder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AStarPathfinder ();
|
||||||
|
static AStarPathfinder& GetInstance();
|
||||||
|
int GetPath (SOLDIERTYPE *s ,
|
||||||
|
INT16 dest,
|
||||||
|
INT8 ubLevel,
|
||||||
|
INT16 usMovementMode,
|
||||||
|
INT8 bCopy,
|
||||||
|
UINT8 fFlags );
|
||||||
|
|
||||||
|
private:
|
||||||
|
static AStarPathfinder* pThis;
|
||||||
|
std::vector<GridNode> ClosedList;
|
||||||
|
CBinaryHeap<int, GridNode> OpenHeap;
|
||||||
|
|
||||||
|
int direction;//current direction
|
||||||
|
int startDir;
|
||||||
|
int endDir;
|
||||||
|
int lastDir;
|
||||||
|
bool startingLoop;
|
||||||
|
|
||||||
|
SOLDIERTYPE* pSoldier;
|
||||||
|
INT8 onRooftop;//aka ubLevel, not sure if this bool is logically reversed yet
|
||||||
|
bool fNonFenceJumper;
|
||||||
|
bool fNonSwimmer;
|
||||||
|
bool fPathingForPlayer;
|
||||||
|
bool fPathAroundPeople;
|
||||||
|
bool fGoingThroughDoor;
|
||||||
|
int bOKToAddStructID;
|
||||||
|
int bLoopState;
|
||||||
|
bool bWaterToWater;
|
||||||
|
bool fVisitSpotsOnlyOnce;
|
||||||
|
bool fCheckedBehind;
|
||||||
|
bool fTurnBased;
|
||||||
|
bool fCloseGoodEnough;
|
||||||
|
bool fContinuousTurnNeeded;
|
||||||
|
bool fConsiderPersonAtDestAsObstacle;
|
||||||
|
bool fCopyReachable;
|
||||||
|
bool fCopyPathCosts;
|
||||||
|
|
||||||
|
int maxAPBudget;//the gubNPCAPBudget
|
||||||
|
int mercsMaxAPs;//the merc only has so many points to move with
|
||||||
|
int movementMode;
|
||||||
|
int sClosePathLimit;
|
||||||
|
|
||||||
|
int PATHAI_VISIBLE_DEBUG_Counter;
|
||||||
|
|
||||||
|
//vehicle defined in cpp
|
||||||
|
//#ifdef VEHICLE
|
||||||
|
BOOLEAN fMultiTile;
|
||||||
|
STRUCTURE_FILE_REF * pStructureFileRef;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
// member variables to prevent passing them around
|
||||||
|
GridNode StartNode;
|
||||||
|
GridNode DestNode;
|
||||||
|
GridNode CurrentNode;
|
||||||
|
GridNode ParentNode;
|
||||||
|
INT16 ParentNodeIndex;
|
||||||
|
INT16 CurrentNodeIndex;
|
||||||
|
|
||||||
|
AStar_Data AStarData[WORLD_COLS][WORLD_ROWS];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AStarHeap AStar ();
|
||||||
|
|
||||||
|
void ExecuteAStarLogic();
|
||||||
|
|
||||||
|
void ResetAStarList ();
|
||||||
|
|
||||||
|
int TerrainCostToAStarG(int const terrainCost);
|
||||||
|
int CalcG (int* pPrevCost);
|
||||||
|
int CalcAP (int const terrainCost);
|
||||||
|
int CalcH ();
|
||||||
|
int CalcGCover (int const NodeIndex,
|
||||||
|
int const APCost);
|
||||||
|
int CalcStartingAP ();
|
||||||
|
|
||||||
|
//including THREATTYPE was a pain, so pass by value
|
||||||
|
int CalcCoverValue (INT16 sMyGridNo, INT32 iMyThreat, INT32 iMyAPsLeft,
|
||||||
|
INT32 myThreatsiOrigRange, INT16 myThreatssGridNo, SOLDIERTYPE* myThreatspOpponent,
|
||||||
|
INT32 myThreatsiValue, INT32 myThreatsiAPs, INT32 myThreatsiCertainty);
|
||||||
|
|
||||||
|
eAStar GetAStarStatus (const GridNode node) const {return AStarData[node.x][node.y].status;};
|
||||||
|
GridNode GetAStarParent (const GridNode node) const {return AStarData[node.x][node.y].parent;};
|
||||||
|
int GetAStarG (const GridNode node) const {return AStarData[node.x][node.y].cost;};
|
||||||
|
int GetAStarF (const GridNode node) const {return AStarData[node.x][node.y].f;};
|
||||||
|
int GetActionPoints (const GridNode node) const {return AStarData[node.x][node.y].APCost;};
|
||||||
|
bool GetLoopState (const GridNode node) const {return AStarData[node.x][node.y].wasBackwards;};
|
||||||
|
int GetPrevCost (const GridNode node) const {return AStarData[node.x][node.y].prevCost;};
|
||||||
|
int GetDirection (const GridNode node) const {return AStarData[node.x][node.y].direction;};
|
||||||
|
#ifdef ASTAR_USING_EXTRACOVER
|
||||||
|
int GetExtraGCover (const GridNode node) const {return AStarData[node.x][node.y].extraGCoverCost;};
|
||||||
|
|
||||||
|
void SetExtraGCover (const GridNode node, const int extraGCoverCost) {AStarData[node.x][node.y].extraGCoverCost = extraGCoverCost;};
|
||||||
|
#endif
|
||||||
|
void SetAStarStatus (const GridNode node, const eAStar status) {AStarData[node.x][node.y].status = status;};
|
||||||
|
void SetAStarParent (const GridNode node, const GridNode parent) {AStarData[node.x][node.y].parent = parent;};
|
||||||
|
void SetAStarG (const GridNode node, const int cost) {AStarData[node.x][node.y].cost = cost;};
|
||||||
|
void SetAStarF (const GridNode node, const int f) {AStarData[node.x][node.y].f = f;};
|
||||||
|
void SetActionPoints (const GridNode node, const int APCost) {AStarData[node.x][node.y].APCost = APCost;};
|
||||||
|
void SetLoopState (const GridNode node, const int loopState);
|
||||||
|
void SetPrevCost (const GridNode node, const int prevCost) {AStarData[node.x][node.y].prevCost = prevCost;};
|
||||||
|
void SetDirection (const GridNode node, const int direction) {AStarData[node.x][node.y].direction = direction;};
|
||||||
|
|
||||||
|
INT16 PythSpacesAway (GridNode const node1,
|
||||||
|
GridNode const node2);
|
||||||
|
INT16 SpacesAway (GridNode const node1,
|
||||||
|
GridNode const node2);
|
||||||
|
//bool IsDiagonal (GridNode const node1,
|
||||||
|
// GridNode const node2) {return (abs(node1.x - node2.x) && abs(node1.y - node2.y));};
|
||||||
|
bool IsDiagonal (int const direction) {return (direction & 1);};
|
||||||
|
void InitVehicle ();
|
||||||
|
int VehicleObstacleCheck();
|
||||||
|
bool CanTraverse ();
|
||||||
|
bool IsSomeoneInTheWay();
|
||||||
|
void IncrementLoop ();
|
||||||
|
void InitLoop ();
|
||||||
|
bool ContinueLoop ();
|
||||||
|
};
|
||||||
|
|
||||||
|
};//end namespace ASTAR
|
||||||
|
|
||||||
|
#endif//end #ifdef USE_ASTAR_PATHS
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN InitPathAI( void );
|
BOOLEAN InitPathAI( void );
|
||||||
void ShutDownPathAI( void );
|
void ShutDownPathAI( void );
|
||||||
INT16 PlotPath( SOLDIERTYPE *pSold, INT16 sDestGridno, INT8 bCopyRoute, INT8 bPlot, INT8 bStayOn, UINT16 usMovementMode, INT8 bStealth, INT8 bReverse , INT16 sAPBudget);
|
INT16 PlotPath( SOLDIERTYPE *pSold, INT16 sDestGridno, INT8 bCopyRoute, INT8 bPlot, INT8 bStayOn, UINT16 usMovementMode, INT8 bStealth, INT8 bReverse , INT16 sAPBudget);
|
||||||
|
|||||||
+1509
-6
File diff suppressed because it is too large
Load Diff
@@ -3699,11 +3699,11 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, UINT16 sGridNo, UINT8 ubAimTime
|
|||||||
//We are firing a gun, and so the gun will be pointed and the scope will be used, even if it isn't now, so don't forget that we are in a firing animation
|
//We are firing a gun, and so the gun will be pointed and the scope will be used, even if it isn't now, so don't forget that we are in a firing animation
|
||||||
if (ubTargetID != NOBODY && pSoldier->bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY)
|
if (ubTargetID != NOBODY && pSoldier->bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY)
|
||||||
{
|
{
|
||||||
iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation );
|
iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false );
|
||||||
}
|
}
|
||||||
if (iSightRange == -1) // didn't do a bodypart-based test
|
if (iSightRange == -1) // didn't do a bodypart-based test
|
||||||
{
|
{
|
||||||
iSightRange = SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, pSoldier->bTargetLevel, pSoldier->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT );
|
iSightRange = SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, pSoldier->bTargetLevel, pSoldier->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
//restore old flag
|
//restore old flag
|
||||||
|
|||||||
@@ -20,6 +20,27 @@
|
|||||||
#define WORLD_BASE_HEIGHT 0
|
#define WORLD_BASE_HEIGHT 0
|
||||||
#define WORLD_CLIFF_HEIGHT 80
|
#define WORLD_CLIFF_HEIGHT 80
|
||||||
|
|
||||||
|
//ADB I'm tired of seeing a 5 digit number when looking at something's gridno.
|
||||||
|
//I need to see an x and y. I created this class for the AStar,
|
||||||
|
//but moved it here as you can convert a regular INT16 gridno to a GridNode then print it out for debugging.
|
||||||
|
//Don't switch between the 2 types too often, IntToGridNode is especially slow
|
||||||
|
class GridNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GridNode () {x = -1; y = -1;};
|
||||||
|
GridNode (INT16 const loc) {this->x = loc % WORLD_COLS; this->y = loc / WORLD_COLS;};
|
||||||
|
GridNode (int x, int y) {GridNode::x = x; GridNode::y = y;};
|
||||||
|
GridNode operator + (const GridNode& point) const {return GridNode(this->x + point.x, this->y + point.y);};
|
||||||
|
bool operator == (const GridNode& point) const {return this->x == point.x && this->y == point.y;};
|
||||||
|
bool operator != (const GridNode& point) const {return !(*this == point);};
|
||||||
|
INT16 GridNodeToInt() {return (this->x + this->y * WORLD_COLS);};
|
||||||
|
void IntToGridNode(INT16 const loc) {this->x = loc % WORLD_COLS; this->y = loc / WORLD_COLS;};
|
||||||
|
bool isInWorld() {return (this->x < WORLD_COLS && this->x >= 0 &&
|
||||||
|
this->y < WORLD_ROWS && this->y >= 0);};
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
//A macro that actually memcpy's over data and increments the pointer automatically
|
//A macro that actually memcpy's over data and increments the pointer automatically
|
||||||
//based on the size. Works like a FileRead except with a buffer instead of a file pointer.
|
//based on the size. Works like a FileRead except with a buffer instead of a file pointer.
|
||||||
//Used by LoadWorld() and child functions.
|
//Used by LoadWorld() and child functions.
|
||||||
|
|||||||
Reference in New Issue
Block a user