Change unit Attack behaviour to a charge

All charges on a turn are evaluated at the same time, step by step
This commit is contained in:
Marc Di Luzio 2014-12-17 13:38:06 +00:00
parent 4b37246e53
commit 3fc1f5ee5d
4 changed files with 156 additions and 59 deletions

View file

@ -108,14 +108,12 @@ int CTTRTSGame::VerifyPos(uvector2 vec) const
// Get a units new position // Get a units new position
uvector2 CTTRTSGame::GetNewPosition( const OrderUnitPair& pair ) const uvector2 CTTRTSGame::GetNewPosition( const OrderUnitPair& pair ) const
{ {
// Grab the order // Grab the order
switch ( pair.order.command) switch ( pair.order.command)
{ {
// For forward orders, grab in front // For forward orders, grab in front
case command_c::F: case command_c::F:
return pair.unit.getInFront(); return pair.unit.getInFront();
break;
// For all other orders, just grab the old position // For all other orders, just grab the old position
default: default:
return pair.unit.getPos(); return pair.unit.getPos();
@ -158,7 +156,6 @@ int CTTRTSGame::SimulateToNextTurn()
if ( possible ) if ( possible )
{ {
pair.unit.setPos(newpos); pair.unit.setPos(newpos);
pair.order = COrder();
} }
} }
break; break;
@ -167,60 +164,115 @@ int CTTRTSGame::SimulateToNextTurn()
} }
} }
// Vector of units to kill // Turn all units that need turning
std::vector< unit_id_t > toKill;
// Attempt all actions
for ( OrderUnitPair& pair : m_OrderUnitPairs ) for ( OrderUnitPair& pair : m_OrderUnitPairs )
{ {
switch ( pair.order.command) switch ( pair.order.command)
{ {
case command_c::A: case command_c::L:
{
// Verify that there's a unit in front to attack
uvector2 infront = pair.unit.getInFront();
// Check if there's any unit in front
// FRIENDLY FIRE IS ENABLED
for ( const OrderUnitPair& pair2 : m_OrderUnitPairs )
{
// if the unit is infront of our unit, then add it to the kill list
if( pair2.unit.getPos() == infront )
{
toKill.push_back(pair2.unit.getID());
pair.order = COrder();
break;
}
}
}
break;
case command_c::L:
{ {
// Simply turn left // Simply turn left
pair.unit.turnLeft(); pair.unit.turnLeft();
pair.order = COrder();
} }
break; break;
case command_c::R: case command_c::R:
{ {
// Simply turn right // Simply turn right
pair.unit.turnRight(); pair.unit.turnRight();
pair.order = COrder();
} }
break; break;
default: default:
break; break;
} }
} }
// Sort and erase all duplicates // Iterate through all charge states
std::sort( toKill.begin(), toKill.end() ); bool charging = true;
toKill.erase( std::unique( toKill.begin(), toKill.end() ), toKill.end() ); while(charging)
{
// Iterate through all kill orders // Assume no more charging
for ( auto id : toKill ) charging = false;
// Initially move all units
for ( OrderUnitPair& pair : m_OrderUnitPairs )
{
if ( pair.order.command == command_c::A )
{
uvector2 newpos = pair.unit.getInFront();
// If move would be within the arena
if ( ( newpos.x <= dimensions.x-1 ) && ( newpos.y <= dimensions.y-1 ) )
{
pair.unit.setPos(newpos);
// Unit moved, so more charging needs to be done
charging = true;
}
}
}
std::vector< unit_id_t > toKill; // Vector to store which units to kill
// Initially move all units to check for pass through
for ( OrderUnitPair& pair1 : m_OrderUnitPairs )
if ( pair1.order.command == command_c::A )
for ( OrderUnitPair& pair2 : m_OrderUnitPairs )
if ( pair1.unit.getID() != pair2.unit.getID() // Don't check the same units
&& pair2.order.command == command_c::A )
{
if( CheckForPassThrough(pair1.unit,pair2.unit) )
{
toKill.push_back(pair1.unit.getID());
toKill.push_back(pair2.unit.getID());
}
}
// Kill all units to kill
KillAll(toKill);
toKill.clear();
// Check for all matching spots
for ( OrderUnitPair& pair1 : m_OrderUnitPairs )
for ( OrderUnitPair& pair2 : m_OrderUnitPairs )
{
if( pair1.unit.getID() == pair2.unit.getID() ) continue; // Don't check the same units
if( pair1.unit.getPos() == pair2.unit.getPos() )
{
if( pair1.order.command == command_c::A )
{
toKill.push_back(pair2.unit.getID());
}
if( pair2.order.command == command_c::A )
{
toKill.push_back(pair1.unit.getID());
}
}
}
// Kill all units to kill
KillAll(toKill);
toKill.clear();
}
// Clear all orders
for ( OrderUnitPair& pair : m_OrderUnitPairs )
pair.order = COrder();
// Increment the current turn
turn++;
return error;
}
// Kill all units in list
void CTTRTSGame::KillAll( std::vector< unit_id_t >& vec )
{
// Sort and erase all duplicates
std::sort( vec.begin(), vec.end() );
vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() );
for ( auto id : vec )
{ {
// Kill the units
for ( OrderUnitPairVector::iterator it = m_OrderUnitPairs.begin(); for ( OrderUnitPairVector::iterator it = m_OrderUnitPairs.begin();
it != m_OrderUnitPairs.end(); it != m_OrderUnitPairs.end();
it++ ) it++ )
@ -230,21 +282,42 @@ int CTTRTSGame::SimulateToNextTurn()
// Remove the unit from our alive unit pairs // Remove the unit from our alive unit pairs
m_OrderUnitPairs.erase(it); m_OrderUnitPairs.erase(it);
break; break;
} }
} }
}
}
// Check if two units passed through each other
bool CTTRTSGame::CheckForPassThrough( const CUnit& one, const CUnit& two )
{
uvector2 pos1 = one.getPos();
uvector2 pos2 = two.getPos();
dir_t dir1 = one.getDir();
dir_t dir2 = two.getDir();
if( pos1.x == pos2.x ) { // Same col
if (pos1.y == (pos2.y + 1)) {
if (dir1 == dir_t::N && dir2 == dir_t::S)
return true;
}
else if (pos1.y == (pos2.y - 1)) {
if (dir1 == dir_t::S && dir2 == dir_t::N)
return true;
}
}
else if( pos1.y == pos2.y ) { // Same row
if( pos1.x == (pos2.x+1) ) {
if( dir1 == dir_t::E && dir2 == dir_t::W )
return true;
}
else if( pos1.x == (pos2.x-1) ) {
if( dir1 == dir_t::E && dir2 == dir_t::W )
return true;
}
} }
// Clear all orders return false;
for ( OrderUnitPair& pair : m_OrderUnitPairs )
{
pair.order = COrder();
}
// Increment the current turn
turn++;
return error;
} }
// Add a unit, nonzero return value indicates error // Add a unit, nonzero return value indicates error
@ -301,7 +374,8 @@ int CTTRTSGame::VerifyOrder( Team team, const COrder& order ) const
for ( const OrderUnitPair& pair : m_OrderUnitPairs ) for ( const OrderUnitPair& pair : m_OrderUnitPairs )
{ {
// Accept if we have the unit // Accept if we have the unit
if ( pair.unit.getID() == unitID ) if ( pair.unit.getID() == unitID
&& pair.unit.getTeam() == team )
{ {
ret = 0; ret = 0;
break; break;
@ -318,7 +392,7 @@ const CUnit& CTTRTSGame::GetUnitByIDConst( unit_id_t id ) const
for ( const OrderUnitPair& pair : m_OrderUnitPairs ) for ( const OrderUnitPair& pair : m_OrderUnitPairs )
{ {
// Attempt the unit add // Attempt the unit add
if ( pair.unit.getID() ) if ( pair.unit.getID() == id )
return pair.unit; return pair.unit;
} }
@ -327,13 +401,28 @@ const CUnit& CTTRTSGame::GetUnitByIDConst( unit_id_t id ) const
return invalid_unit; return invalid_unit;
} }
// Get an order by unit ID
const COrder& CTTRTSGame::GetOrderByIDConst( unit_id_t id ) const
{
for ( const OrderUnitPair& pair : m_OrderUnitPairs )
{
// Attempt the unit add
if ( pair.unit.getID() == id )
return pair.order;
}
// Return an invalid unit
static COrder invalid_order;
return invalid_order;
}
// Get unit by unit ID // Get unit by unit ID
CUnit& CTTRTSGame::GetUnitByID( unit_id_t id ) CUnit& CTTRTSGame::GetUnitByID( unit_id_t id )
{ {
for ( OrderUnitPair& pair : m_OrderUnitPairs ) for ( OrderUnitPair& pair : m_OrderUnitPairs )
{ {
// Attempt the unit add // Attempt the unit add
if ( pair.unit.getID() ) if ( pair.unit.getID() == id )
return pair.unit; return pair.unit;
} }

View file

@ -85,6 +85,7 @@ public:
// Get a unit by it's ID // Get a unit by it's ID
const CUnit& GetUnitByIDConst( unit_id_t id ) const; const CUnit& GetUnitByIDConst( unit_id_t id ) const;
const COrder& GetOrderByIDConst( unit_id_t id ) const;
// Get dimensions // Get dimensions
inline const uvector2 &GetDimensions() const { return dimensions; } inline const uvector2 &GetDimensions() const { return dimensions; }
@ -100,7 +101,7 @@ public:
// Get a vector of the teams in the current game // Get a vector of the teams in the current game
std::vector<Team> GetTeams() const; std::vector<Team> GetTeams() const;
private: private:
// Verify any order or position - non-zero is error // Verify any order or position - non-zero is error
@ -110,6 +111,12 @@ private:
// Get a units new position after an order // Get a units new position after an order
uvector2 GetNewPosition( const OrderUnitPair& pair ) const; uvector2 GetNewPosition( const OrderUnitPair& pair ) const;
// Check for a pass through
static bool CheckForPassThrough( const CUnit& one, const CUnit& two );
// Kill all units in list
void KillAll( std::vector< unit_id_t >& vec );
// Get unit by unit ID // Get unit by unit ID
CUnit& GetUnitByID( unit_id_t id ); CUnit& GetUnitByID( unit_id_t id );

View file

@ -11,10 +11,10 @@
// Type for all orders ( as a char ) // Type for all orders ( as a char )
enum class command_c : char enum class command_c : char
{ {
F = 'F', F = 'F', // Move forward one square
L = 'L', L = 'L', // Turn left
R = 'R', R = 'R', // Turn right
A = 'A', A = 'A', // Attack forwards until a unit or edge of the arena is hit
NUM_INVALID NUM_INVALID
}; };

View file

@ -87,6 +87,7 @@ private:
// Typedef for a vector of units // Typedef for a vector of units
typedef std::vector< CUnit > CUnitVector; typedef std::vector< CUnit > CUnitVector;
typedef std::vector< unit_id_t > CUnitIDVector;
// Simple validation // Simple validation
inline bool CUnit::valid() const inline bool CUnit::valid() const