polserver/pol-core/pol/uopathnode.h
turleypol 6a2bd7c705 Merge remote-tracking branch 'origin/master' into vector_classes
* origin/master: (93 commits)
  Add support for dictionary creation (#277)
  Add do-while statement (#276)
  Add foreach loops (#275)
  New compiler: array initialization (#274)
  Disambiguator: figure out if label is a case statement dispatch selector, or should apply to a statement within the case dispatch group's block. (#273)
  New compiler: Add support for case statements (#272)
  Change "logical" to "bitwise". (#258)
  Fix divide-by-zero errors, and mask FormatError if it were thrown in a destructor. (#271)
  Add break and continue statements. (#270)
  New compiler: assignment to local and global variables. (#269)
  Add support for while loops (#268)
  Optimize if statements, and emit module functions in legacy order (#267)
  Optimizations: binary operators (#266)
  Add binary operators (#265)
  Add support for const declarations (#264)
  Handle default parameter values, pass-by-name, and return statements in functions. (#263)
  Add limited support for user functions (#262)
  New compiler: add return and exit statements (#261)
  Add support for if-then-else statements (#259)
  OG compiler: set module to Mod_Basic when a token is an identifier (#257)
  ...
2020-09-06 20:14:26 +02:00

206 lines
5.3 KiB
C++

/** @file
*
* @par History
* - 2005/09/03 Shinigami: GetSuccessors - added support for non-blocking doors
*/
#ifndef __UOPATHNODE_H
#define __UOPATHNODE_H
// AStar search class
#include "plib/stlastar.h"
#include "base/position.h"
#include "realms/realm.h"
#include "realms/realms.h"
namespace Pol
{
namespace Core
{
#define BORDER_SKIRT 5
class AStarBlockers
{
public:
int xLow, xHigh, yLow, yHigh; // TODO: Area2d
struct BlockNode // TODO: Pos3d
{
short x;
short y;
s8 z;
};
typedef std::vector<BlockNode*> BlockNodeVector;
public:
AStarBlockers( short xL, short xH, short yL, short yH )
{
xLow = xL;
xHigh = xH;
yLow = yL;
yHigh = yH;
}
void AddBlocker( short x, short y, s8 z )
{
BlockNode* theNode = new BlockNode;
theNode->x = x;
theNode->y = y;
theNode->z = z;
m_List.push_back( theNode );
}
~AStarBlockers()
{
for ( auto blockNode : m_List )
{
delete blockNode;
}
}
bool IsBlocking( short x, short y, s8 z )
{
for ( const auto blockNode : m_List )
{
if ( ( blockNode->x == x ) && ( blockNode->y == y ) &&
( abs( blockNode->z - z ) < settingsManager.ssopt.default_character_height ) )
return true;
}
return false;
}
BlockNodeVector m_List;
};
class UOPathState
{
public:
AStarBlockers* theBlockers;
short x; // TODO: Pos4d?
short y;
s8 z;
Realms::Realm* realm;
UOPathState()
: theBlockers( nullptr ), x( 0 ), y( 0 ), z( 0 ), realm( Core::gamestate.main_realm ){};
UOPathState( short newx, short newy, s8 newz, Realms::Realm* newrealm, AStarBlockers* blockers )
{
x = newx;
y = newy;
z = newz;
realm = newrealm;
theBlockers = blockers;
};
float GoalDistanceEstimate( UOPathState& nodeGoal );
bool IsGoal( UOPathState& nodeGoal );
bool GetSuccessors( Plib::AStarSearch<UOPathState>* astarsearch, UOPathState* parent_node,
bool doors_block );
float GetCost( UOPathState& successor );
bool IsSameState( UOPathState& rhs );
std::string Name();
};
bool UOPathState::IsSameState( UOPathState& rhs )
{
return ( ( rhs.x == x ) && ( rhs.y == y ) && ( rhs.z == z ) && ( rhs.realm == realm ) );
}
float UOPathState::GoalDistanceEstimate( UOPathState& nodeGoal )
{
return ( (float)( abs( x - nodeGoal.x ) + abs( y - nodeGoal.y ) + abs( z - nodeGoal.z ) ) );
}
bool UOPathState::IsGoal( UOPathState& nodeGoal )
{
return ( ( nodeGoal.x == x ) && ( nodeGoal.y == y ) &&
( abs( nodeGoal.z - z ) <= settingsManager.ssopt.default_character_height ) );
// return (IsSameState(nodeGoal));
}
float UOPathState::GetCost( UOPathState& successor )
{
int xdiff = abs( x - successor.x );
int ydiff = abs( y - successor.y );
if ( xdiff && ydiff )
return 1.414f;
else
return 1.0f;
}
std::string UOPathState::Name()
{
fmt::Writer writer;
writer.Format( "({},{},{})" ) << x << y << (int)z;
return writer.str();
}
bool UOPathState::GetSuccessors( Plib::AStarSearch<UOPathState>* astarsearch,
UOPathState* /*parent_node*/, bool doors_block )
{
Multi::UMulti* supporting_multi = nullptr;
Items::Item* walkon_item = nullptr;
UOPathState SolutionStartNode = ( *( astarsearch->GetSolutionStart() ) );
UOPathState SolutionEndNode = ( *( astarsearch->GetSolutionEnd() ) );
UOPathState* NewNode = new UOPathState();
for ( short i = -1; i <= 1; i++ )
{
for ( short j = -1; j <= 1; j++ )
{
if ( ( i == 0 ) && ( j == 0 ) )
continue;
short newx = x + i;
short newy = y + j;
s8 newz = z;
if ( ( newx < 0 ) || ( newx < ( theBlockers->xLow ) ) || ( newx > ( theBlockers->xHigh ) ) ||
( newx > ( (int)realm->width() ) ) )
continue;
if ( ( newy < 0 ) || ( newy < ( theBlockers->yLow ) ) || ( ( newy > theBlockers->yHigh ) ) ||
( newy > ( (int)realm->height() ) ) )
continue;
if ( realm->walkheight( Pos2d( newx, newy ), z, &newz, &supporting_multi, &walkon_item,
doors_block, Plib::MOVEMODE_LAND ) )
{
// Forbid diagonal move, if between 2 blockers - OWHorus {2011-04-26)
bool blocked = false;
if ( ( i != 0 ) && ( j != 0 ) ) // do only for diagonal moves
{
// If both neighbouring tiles are blocked, the move is illegal (diagonal move)
if ( !realm->walkheight( Pos2d( x + i, y ), z, &newz, &supporting_multi, &walkon_item,
doors_block, Plib::MOVEMODE_LAND ) )
blocked = !( realm->walkheight( Pos2d( x, y + j ), z, &newz, &supporting_multi,
&walkon_item, doors_block, Plib::MOVEMODE_LAND ) );
}
if ( !blocked )
{
NewNode->x = newx;
NewNode->y = newy;
NewNode->z = newz;
NewNode->realm = realm;
NewNode->theBlockers = theBlockers;
if ( ( !NewNode->IsSameState( SolutionStartNode ) ) &&
( !NewNode->IsSameState( SolutionEndNode ) ) )
blocked = ( theBlockers->IsBlocking( newx, newy, newz ) );
}
if ( !blocked )
{
if ( !astarsearch->AddSuccessor( *NewNode ) )
{
delete NewNode;
return false;
}
}
}
}
}
delete NewNode;
return true;
}
} // namespace Core
} // namespace Pol
#endif