knightonline/server/AIServer/PathFind.cpp

339 lines
6.4 KiB
C++

#include "stdafx.h"
#include "MAP.h"
#include "PathFind.h"
#include "ServerDlg.h"
#define LEVEL_ONE_FIND_CROSS 2
#define LEVEL_ONE_FIND_DIAGONAL 3
#define LEVEL_TWO_FIND_CROSS 11
#define LEVEL_TWO_FIND_DIAGONAL 10
CPathFind::CPathFind()
{
m_pStack = (STACK *)calloc(1, sizeof(STACK));
m_pOpen = nullptr;
m_pClosed = nullptr;
m_pMap = nullptr;
m_lMapUse = 0;
}
CPathFind::~CPathFind()
{
ClearData();
free(m_pStack);
}
void CPathFind::ClearData()
{
_PathNode *t_node1, *t_node2;
if(m_pOpen)
{
t_node1 = m_pOpen->NextNode;
while(t_node1)
{
t_node2 = t_node1->NextNode;
free(t_node1);
t_node1 = t_node2;
}
free(m_pOpen);
m_pOpen = nullptr;
}
if(m_pClosed)
{
t_node1 = m_pClosed->NextNode;
while(t_node1)
{
t_node2 = t_node1->NextNode;
free(t_node1);
t_node1 = t_node2;
}
free(m_pClosed);
m_pClosed = nullptr;
}
}
void CPathFind::SetMap(int x, int y, MAP * pMap, int16 min_x, int16 min_y)
{
m_vMapSize.cx = x;
m_vMapSize.cy = y;
m_pMap = pMap;
m_min_x = min_x;
m_min_y = min_y;
}
_PathNode *CPathFind::FindPath(int start_x, int start_y, int dest_x, int dest_y)
{
_PathNode *t_node, *r_node = nullptr;
// if(!m_pMap) return nullptr;
ClearData();
m_pOpen = (_PathNode *)calloc(1, sizeof(_PathNode));
m_pClosed = (_PathNode *)calloc(1, sizeof(_PathNode));
t_node = (_PathNode *)calloc(1, sizeof(_PathNode));
t_node->g = 0;
t_node->h = (int)sqrt((double)((start_x-dest_x)*(start_x-dest_x) + (start_y-dest_y)*(start_y-dest_y)));
// t_node->h = (int)std::max( start_x-dest_x, start_y-dest_y );
t_node->f = t_node->g + t_node->h;
t_node->x = start_x;
t_node->y = start_y;
int maxtry = abs(start_x-dest_x)*m_vMapSize.cx + abs(start_y-dest_y)*m_vMapSize.cy + 1;
int count = 0;
m_pOpen->NextNode = t_node;
while (1)
{
if (count++ > maxtry * 2)
return nullptr;
r_node = (_PathNode *)ReturnBestNode();
if (r_node == nullptr) return r_node;
if (r_node->x == dest_x && r_node->y == dest_y)
return r_node;
FindChildPath(r_node, dest_x, dest_y);
}
return r_node;
}
_PathNode *CPathFind::ReturnBestNode()
{
_PathNode *tmp;
if(m_pOpen->NextNode == nullptr) {
return nullptr;
}
tmp=m_pOpen->NextNode; // point to first node on m_pOpen
m_pOpen->NextNode=tmp->NextNode; // Make m_pOpen point to nextnode or nullptr.
tmp->NextNode=m_pClosed->NextNode;
m_pClosed->NextNode=tmp;
return(tmp);
}
void CPathFind::FindChildPath(_PathNode *node, int dx, int dy)
{
int x, y;
// UpperLeft
if(IsBlankMap(x=node->x-1,y=node->y-1))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_CROSS );
// Upper
if(IsBlankMap(x=node->x,y=node->y-1))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_DIAGONAL );
// UpperRight
if(IsBlankMap(x=node->x+1,y=node->y-1))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_CROSS );
// Right
if(IsBlankMap(x=node->x+1,y=node->y))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_DIAGONAL );
// LowerRight
if(IsBlankMap(x=node->x+1,y=node->y+1))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_CROSS );
// Lower
if(IsBlankMap(x=node->x,y=node->y+1))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_DIAGONAL );
// LowerLeft
if(IsBlankMap(x=node->x-1,y=node->y+1))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_CROSS );
// Left
if(IsBlankMap(x=node->x-1,y=node->y))
FindChildPathSub(node, x, y, dx, dy, LEVEL_TWO_FIND_DIAGONAL );
}
void CPathFind::FindChildPathSub(_PathNode *node, int x, int y, int dx, int dy, int arg)
{
int g, c=0;
_PathNode *old_node,*t_node;
g = node->g + arg;
if((old_node = CheckOpen(x, y)) != nullptr)
{
for(c = 0; c < 8; c++)
{
if(node->Child[c] == nullptr)
{
break;
}
}
node->Child[c] = old_node;
if(g < old_node->g)
{
old_node->Parent = node;
old_node->g = g;
old_node->f = g + old_node->h;
}
}
else if((old_node = CheckClosed(x, y)) != nullptr)
{
for(c = 0; c < 8; c++)
{
if(node->Child[c] == nullptr)
{
break;
}
}
node->Child[c] = old_node;
if(g < old_node->g)
{
old_node->Parent = node;
old_node->g = g;
old_node->f = g + old_node->h;
PropagateDown(old_node);
}
}
else
{
t_node = (_PathNode *)calloc(1, sizeof(_PathNode));
t_node->Parent = node;
t_node->g = g;
// t_node->h = (int)sqrt((x-dx)*(x-dx) + (y-dy)*(y-dy));
t_node->h = (int)std::max( x-dx, y-dy );
t_node->f = g + t_node->h;
t_node->x = x;
t_node->y = y;
Insert(t_node);
for(c = 0; c < 8; c++)
{
if(node->Child[c] == nullptr)
{
break;
}
}
node->Child[c] = t_node;
}
}
_PathNode *CPathFind::CheckOpen(int x, int y)
{
_PathNode *tmp = m_pOpen->NextNode;
while (tmp != nullptr)
{
if (tmp->x == x && tmp->y == y)
return tmp;
tmp = tmp->NextNode;
}
return nullptr;
}
_PathNode *CPathFind::CheckClosed(int x, int y)
{
_PathNode *tmp;
tmp = m_pClosed->NextNode;
while(tmp != nullptr)
{
if(tmp->x == x && tmp->y == y)
{
return tmp;
}
else
{
tmp = tmp->NextNode;
}
}
return nullptr;
}
void CPathFind::Insert(_PathNode *node)
{
_PathNode *tmp1, *tmp2;
int f;
if(m_pOpen->NextNode == nullptr)
{
m_pOpen->NextNode = node;
return;
}
f = node->f;
tmp1 = m_pOpen;
tmp2 = m_pOpen->NextNode;
while((tmp2 != nullptr) && (tmp2->f < f))
{
tmp1 = tmp2;
tmp2 = tmp2->NextNode;
}
node->NextNode = tmp2;
tmp1->NextNode = node;
}
void CPathFind::PropagateDown(_PathNode *old)
{
int c, g;
_PathNode *child, *parent;
g = old->g;
for(c = 0; c < 8; c++)
{
if((child = old->Child[c]) == nullptr)
{
break;
}
if(g+1 < child->g)
{
child->g = g+1;
child->f = child->g + child->h;
child->Parent = old;
Push(child);
}
}
while (m_pStack->NextStackPtr != nullptr)
{
parent = Pop();
for(c = 0; c < 8; c++)
{
if((child = parent->Child[c])==nullptr)
{
break;
}
if(parent->g+1 < child->g)
{
child->g = parent->g+1;
child->f = parent->g + parent->h;
child->Parent = parent;
Push(child);
}
}
}
}
void CPathFind::Push(_PathNode *node)
{
STACK *tmp;
tmp = (STACK *)calloc(1, sizeof(STACK));
tmp->NodePtr = node;
tmp->NextStackPtr = m_pStack->NextStackPtr;
m_pStack->NextStackPtr = tmp;
}
_PathNode *CPathFind::Pop()
{
_PathNode *t_node;
STACK *t_stack;
t_stack = m_pStack->NextStackPtr;
t_node = t_stack->NodePtr;
m_pStack->NextStackPtr = t_stack->NextStackPtr;
free(t_stack);
return t_node;
}
bool CPathFind::IsBlankMap(int x, int y)
{
return m_pMap->IsMovable(m_min_x + x, m_min_y + y);
}