Finialise the full game step
Had to rework a ton of code from bad design. NOTE: FRIENDLY FIRE IS ON >:D
This commit is contained in:
parent
6fc41914f7
commit
aee703b107
7 changed files with 379 additions and 57 deletions
171
game/game.cpp
171
game/game.cpp
|
@ -1,5 +1,6 @@
|
|||
#include "game.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// Interpret a string of orders
|
||||
int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders )
|
||||
|
@ -40,34 +41,81 @@ int CTTRTSGame::IssueOrder( player_id_t player, const COrder& order )
|
|||
if ( VerifyOrder(player,order) )
|
||||
return 1;
|
||||
|
||||
m_orders.push_back(order);
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
if ( pair.unit.getID() == order.unit )
|
||||
{
|
||||
pair.order = order;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify a position
|
||||
int CTTRTSGame::VerifyPos(uvector2 vec) const
|
||||
{
|
||||
if ( ( vec.x >= dimentions.x )
|
||||
|| ( vec.y >= dimentions.y ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Get a units new position
|
||||
uvector2 CTTRTSGame::GetNewPosition( const OrderUnitPair& pair ) const
|
||||
{
|
||||
switch ( pair.order.order )
|
||||
{
|
||||
case order_c::F:
|
||||
return pair.unit.getInFront();
|
||||
}
|
||||
|
||||
return { ucoord_invalid,ucoord_invalid };
|
||||
}
|
||||
|
||||
// Simulate and progress to the next turn
|
||||
// Returns non-zero if simulation failed
|
||||
int CTTRTSGame::SimulateToNextTurn()
|
||||
{
|
||||
int error;
|
||||
|
||||
OrderUnitPairVector orderPairs;
|
||||
|
||||
// Grab all movement orders
|
||||
for ( auto order : m_orders )
|
||||
{
|
||||
const OrderUnitPair pair = { order, GetUnitByID(order.unit) };
|
||||
orderPairs.push_back(pair);
|
||||
}
|
||||
int error = 0;
|
||||
|
||||
// Attempt all movement orders
|
||||
for ( auto pair : orderPairs )
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
switch ( pair.order.order )
|
||||
{
|
||||
case order_c::F:
|
||||
{
|
||||
// Verify new unit position will be on the board
|
||||
uvector2 newpos = GetNewPosition(pair);
|
||||
|
||||
// Verify the position is even available
|
||||
bool possible = ( VerifyPos(newpos) == 0 );
|
||||
|
||||
if ( possible )
|
||||
{
|
||||
// If any unit is in this spot, or moving unit moving to said spot, reject this
|
||||
for ( const OrderUnitPair& pair2 : m_OrderUnitPairs )
|
||||
{
|
||||
if( GetNewPosition(pair2) != newpos )
|
||||
{
|
||||
possible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the movement is still possible
|
||||
if ( possible )
|
||||
{
|
||||
pair.unit.setPos(newpos);
|
||||
pair.order = COrder();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -77,29 +125,74 @@ int CTTRTSGame::SimulateToNextTurn()
|
|||
std::vector< unit_id_t > toKill;
|
||||
|
||||
// Attempt all actions
|
||||
for ( auto pair : orderPairs )
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
switch ( pair.order.order )
|
||||
{
|
||||
case order_c::A:
|
||||
{
|
||||
// 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(pair.unit.getID());
|
||||
pair.order = COrder();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case order_c::L:
|
||||
{
|
||||
pair.unit.turnLeft();
|
||||
pair.order = COrder();
|
||||
}
|
||||
break;
|
||||
case order_c::R:
|
||||
// Nothing needed here, these orders can always be carried out
|
||||
{
|
||||
pair.unit.turnRight();
|
||||
pair.order = COrder();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort and erase all duplicates
|
||||
std::sort( toKill.begin(), toKill.end() );
|
||||
toKill.erase( std::unique( toKill.begin(), toKill.end() ), toKill.end() );
|
||||
|
||||
// Iterate through all kill orders
|
||||
for ( auto id : toKill )
|
||||
{
|
||||
// Kill the units
|
||||
for ( OrderUnitPairVector::iterator it = m_OrderUnitPairs.begin();
|
||||
it != m_OrderUnitPairs.end();
|
||||
it++ )
|
||||
{
|
||||
if( (*it).unit.getID() == id )
|
||||
{
|
||||
// Add the dead unit to our dead unit list
|
||||
m_deadUnits.push_back(std::move((*it).unit));
|
||||
|
||||
// Remove the unit from our alive unit pairs
|
||||
m_OrderUnitPairs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clear all orders
|
||||
m_orders.resize(0);
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
pair.order = COrder();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -114,10 +207,11 @@ int CTTRTSGame::AddUnit( CUnit&& unit )
|
|||
|
||||
// Verify if the unit can be placed on the current board
|
||||
const uvector2 pos = unit.getPos();
|
||||
if( (pos.x < dimentions.x) && (pos.y < dimentions.y) )
|
||||
if( (pos.x >= dimentions.x) || (pos.y >= dimentions.y) )
|
||||
return 1;
|
||||
|
||||
m_allUnits.push_back(std::move(unit));
|
||||
// Add the unit with a blank order
|
||||
m_OrderUnitPairs.push_back( OrderUnitPair(std::move(unit), COrder()) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -141,35 +235,52 @@ int CTTRTSGame::AddUnits( CUnitVector&& units )
|
|||
// Verify any order
|
||||
int CTTRTSGame::VerifyOrder( player_id_t player, const COrder& order ) const
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
// Grab the unit ID
|
||||
const unit_id_t unitID = order.unit;
|
||||
|
||||
// Attempt to find the unit
|
||||
bool unitFound = false;
|
||||
for ( const CUnit& unit : m_allUnits )
|
||||
// Attempt to find the unit
|
||||
for ( const OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
if ( unit.getID() == unitID )
|
||||
if ( pair.unit.getID() == unitID )
|
||||
{
|
||||
unitFound = true;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// for now, as long as the unit exists we can attempt the order
|
||||
return unitFound;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Get unit by unit ID
|
||||
const CUnit& CTTRTSGame::GetUnitByID( unit_id_t id ) const
|
||||
const CUnit& CTTRTSGame::GetUnitByIDConst( unit_id_t id ) const
|
||||
{
|
||||
CUnitVector::const_iterator it;
|
||||
CUnitVector::iterator it;
|
||||
|
||||
for ( const CUnit& unit : m_allUnits )
|
||||
for ( const OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
// Attempt the unit add
|
||||
if ( unit.getID() )
|
||||
return unit;
|
||||
if ( pair.unit.getID() )
|
||||
return pair.unit;
|
||||
}
|
||||
|
||||
// Return an invalid unit
|
||||
static CUnit invalid_unit;
|
||||
return invalid_unit;
|
||||
}
|
||||
|
||||
// Get unit by unit ID
|
||||
CUnit& CTTRTSGame::GetUnitByID( unit_id_t id )
|
||||
{
|
||||
CUnitVector::iterator it;
|
||||
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
// Attempt the unit add
|
||||
if ( pair.unit.getID() )
|
||||
return pair.unit;
|
||||
}
|
||||
|
||||
// Return an invalid unit
|
||||
|
|
55
game/game.h
55
game/game.h
|
@ -12,8 +12,27 @@ typedef std::vector< CUnit > CUnitVector;
|
|||
// Type for order and unit pairs
|
||||
struct OrderUnitPair
|
||||
{
|
||||
const COrder& order;
|
||||
const CUnit& unit;
|
||||
// Straight up move constructor
|
||||
OrderUnitPair( OrderUnitPair&& other )
|
||||
: unit ( std::move(other.unit) )
|
||||
, order ( other.order )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Multi parameter constructor
|
||||
OrderUnitPair( CUnit&& u, COrder o )
|
||||
: unit ( std::move(u) )
|
||||
, order ( o )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Move asignment operator
|
||||
inline OrderUnitPair& operator=( OrderUnitPair&& rhs ) { *this = std::move(rhs); return *this; }
|
||||
|
||||
CUnit unit;
|
||||
COrder order;
|
||||
};
|
||||
|
||||
typedef std::vector< OrderUnitPair > OrderUnitPairVector;
|
||||
|
@ -48,36 +67,42 @@ public:
|
|||
int AddUnits( CUnitVector&& units );
|
||||
|
||||
// Get the number of units
|
||||
inline unsigned int GetNumUnits() const { return m_allUnits.size(); }
|
||||
inline unsigned int GetNumUnits() const { return m_OrderUnitPairs.size(); }
|
||||
|
||||
// Get unit by index as above (not unit ID)
|
||||
inline const CUnit& GetUnitByIndex( unsigned int i ) const { return m_allUnits[i]; }
|
||||
inline const CUnit& GetUnitByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].unit; }
|
||||
|
||||
// Get unit by unit ID
|
||||
const CUnit& GetUnitByID( unit_id_t id ) const;
|
||||
|
||||
// Get the number of order
|
||||
inline unsigned int GetNumOrders() const { return m_orders.size(); }
|
||||
const CUnit& GetUnitByIDConst( unit_id_t id ) const;
|
||||
|
||||
// Get orders by index as above
|
||||
inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_orders[i]; }
|
||||
inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].order; }
|
||||
|
||||
// Get dimentions
|
||||
inline const uvector2& GetDimentions() const { return dimentions; }
|
||||
|
||||
private:
|
||||
|
||||
// Verify any order
|
||||
// Verify any order - non-zero is error
|
||||
int VerifyOrder( player_id_t player, const COrder& order ) const;
|
||||
|
||||
// Verify any order
|
||||
// Verify any order - non-zero is error
|
||||
int VerifyUnit( const CUnit& unit ) const;
|
||||
|
||||
// Vector to store points to all units
|
||||
CUnitVector m_allUnits;
|
||||
// Verify Position - non-zero is error
|
||||
int VerifyPos( uvector2 vec ) const;
|
||||
|
||||
// Orders to execute this turn
|
||||
COrderVector m_orders;
|
||||
// Get a units new position after an order
|
||||
uvector2 GetNewPosition( const OrderUnitPair& pair ) const;
|
||||
|
||||
// Get unit by unit ID
|
||||
CUnit& GetUnitByID( unit_id_t id );
|
||||
|
||||
// Vector to store points to all units
|
||||
OrderUnitPairVector m_OrderUnitPairs;
|
||||
|
||||
// List of dead units
|
||||
CUnitVector m_deadUnits;
|
||||
|
||||
// Dimensions of the game
|
||||
uvector2 dimentions;
|
||||
|
|
|
@ -14,7 +14,8 @@ enum class order_c : char
|
|||
F = 'F',
|
||||
L = 'L',
|
||||
R = 'R',
|
||||
A = 'A'
|
||||
A = 'A',
|
||||
INVALID
|
||||
};
|
||||
|
||||
// Movement orders
|
||||
|
@ -34,6 +35,13 @@ static const order_c sk_actionOrders[] =
|
|||
// Container for an order
|
||||
struct COrder
|
||||
{
|
||||
COrder()
|
||||
: unit ( unit_id_invalid )
|
||||
, order ( order_c::INVALID )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Unit order is for
|
||||
unit_id_t unit;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ CUnit::CUnit()
|
|||
, player_id ( player_id_invalid )
|
||||
, unit_vis ( unitVis_invalid )
|
||||
, dir ( dir_t::S )
|
||||
, pos ( { ucoord_invalid, ucoord_invalid } )
|
||||
{
|
||||
updateMyVisual();
|
||||
};
|
||||
|
@ -47,6 +48,7 @@ CUnit::CUnit(CUnit&& unit)
|
|||
, player_id ( std::move(unit.player_id) )
|
||||
, unit_vis ( std::move(unit.unit_vis) )
|
||||
, dir ( std::move(unit.dir) )
|
||||
, pos ( std::move(unit.pos) )
|
||||
{
|
||||
updateMyVisual();
|
||||
}
|
||||
|
@ -81,7 +83,7 @@ bool CUnit::setFromVisual( const unitVis_c& vis )
|
|||
{
|
||||
if( it->second == vis )
|
||||
{
|
||||
dir == it->first;
|
||||
dir = it->first;
|
||||
updateMyVisual();
|
||||
return true;
|
||||
}
|
||||
|
@ -90,3 +92,91 @@ bool CUnit::setFromVisual( const unitVis_c& vis )
|
|||
// No matching direction to visual
|
||||
return false;
|
||||
}
|
||||
|
||||
// Turn unit left
|
||||
dir_t CUnit::turnLeft()
|
||||
{
|
||||
switch( dir )
|
||||
{
|
||||
case dir_t::N:
|
||||
dir = dir_t::W;
|
||||
break;
|
||||
|
||||
case dir_t::E:
|
||||
dir = dir_t::N;
|
||||
break;
|
||||
|
||||
case dir_t::S:
|
||||
dir = dir_t::E;
|
||||
break;
|
||||
|
||||
case dir_t::W:
|
||||
dir = dir_t::S;
|
||||
break;
|
||||
}
|
||||
|
||||
updateMyVisual();
|
||||
|
||||
return getDir();
|
||||
}
|
||||
|
||||
// Turn unit right
|
||||
dir_t CUnit::turnRight()
|
||||
{
|
||||
switch( dir )
|
||||
{
|
||||
case dir_t::N:
|
||||
dir = dir_t::E;
|
||||
break;
|
||||
|
||||
case dir_t::E:
|
||||
dir = dir_t::S;
|
||||
break;
|
||||
|
||||
case dir_t::S:
|
||||
dir = dir_t::W;
|
||||
break;
|
||||
|
||||
case dir_t::W:
|
||||
dir = dir_t::N;
|
||||
break;
|
||||
}
|
||||
|
||||
updateMyVisual();
|
||||
|
||||
return getDir();
|
||||
}
|
||||
|
||||
// Turn unit around
|
||||
dir_t CUnit::turnAround()
|
||||
{
|
||||
switch( dir )
|
||||
{
|
||||
case dir_t::N:
|
||||
dir = dir_t::S;
|
||||
break;
|
||||
|
||||
case dir_t::E:
|
||||
dir = dir_t::W;
|
||||
break;
|
||||
|
||||
case dir_t::S:
|
||||
dir = dir_t::N;
|
||||
break;
|
||||
|
||||
case dir_t::W:
|
||||
dir = dir_t::E;
|
||||
break;
|
||||
}
|
||||
|
||||
updateMyVisual();
|
||||
|
||||
return getDir();
|
||||
}
|
||||
|
||||
// Get the co-ordinate infront of the unit
|
||||
uvector2 CUnit::getInFront() const
|
||||
{
|
||||
vector2 delta = vecFromDir(dir);
|
||||
return pos + delta;
|
||||
}
|
||||
|
|
18
game/unit.h
18
game/unit.h
|
@ -13,22 +13,28 @@ class CUnit
|
|||
public:
|
||||
|
||||
CUnit();
|
||||
CUnit(CUnit&& unit);
|
||||
CUnit(CUnit&& unit);
|
||||
CUnit& operator=(CUnit&& unit) { *this = std::move(unit); return *this; }
|
||||
~CUnit() = default;
|
||||
|
||||
inline const unit_id_t& getID() const { return unit_id; }
|
||||
inline const team_id_t& getTeam() const { return team_id; }
|
||||
inline const player_id_t& getPlayer() const { return player_id; }
|
||||
inline const unitVis_c& getVisual() const { return unit_vis; }
|
||||
inline const dir_t& getDir() const { return dir; }
|
||||
|
||||
// Return non-zero values on error
|
||||
inline int setTeam(const team_id_t& v) { return (v == team_id_invalid) ? -1 : (( team_id = v ), 0); }
|
||||
inline int setPlayer(const player_id_t& v) { return (v == player_id_invalid) ? -1 : (( player_id = v ), 0); }
|
||||
inline int setVisual(const unitVis_c& v) { return (v == unitVis_invalid) ? -1 : (( unit_vis = v ), 0); }
|
||||
inline int setTeam(const team_id_t& v) { return (v == team_id_invalid) ? -1 : (( team_id = v ), 0); }
|
||||
inline int setPlayer(const player_id_t& v) { return (v == player_id_invalid) ? -1 : (( player_id = v ), 0); }
|
||||
inline int setVisual(const unitVis_c& v) { return (v == unitVis_invalid) ? -1 : (( unit_vis = v ), 0); }
|
||||
inline dir_t setDir(const dir_t& v) { return (dir = v); }
|
||||
|
||||
inline const uvector2& getPos() const { return pos; }
|
||||
inline void setPos(const uvector2& v) { pos = v; }
|
||||
|
||||
// Get the co-ordinate infront of the unit
|
||||
uvector2 getInFront() const;
|
||||
|
||||
// Check unit is valid
|
||||
inline bool valid() const;
|
||||
|
||||
|
@ -38,6 +44,10 @@ public:
|
|||
// Factory function for creating units from a visual
|
||||
static CUnit getUnitFromVis( unitVis_c vis );
|
||||
|
||||
dir_t turnLeft();
|
||||
dir_t turnRight();
|
||||
dir_t turnAround();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -3,16 +3,73 @@
|
|||
|
||||
#include "mathtypes.h"
|
||||
|
||||
struct uvector2;
|
||||
|
||||
struct vector2
|
||||
{
|
||||
coord_t x;
|
||||
coord_t y;
|
||||
|
||||
inline vector2 operator-() const { return { (coord_t)-x, (coord_t)-y }; }
|
||||
|
||||
inline operator uvector2() const;
|
||||
|
||||
// vec
|
||||
inline vector2 operator+(const vector2& rhs) const { return { (coord_t)(rhs.x + x) , (coord_t)(rhs.y + y) }; }
|
||||
inline vector2 operator-(const vector2& rhs) const { return *this + (-rhs); }
|
||||
|
||||
inline const vector2& operator+=(const vector2& rhs) { *this = *this+rhs; return *this; }
|
||||
inline const vector2& operator-=(const vector2& rhs) { return *this+=(-rhs); }
|
||||
|
||||
inline bool operator==(const vector2& rhs) const { return ( rhs.x == x) && ( rhs.y == y); }
|
||||
inline bool operator!=(const vector2& rhs) const { return !(*this==rhs); }
|
||||
};
|
||||
|
||||
struct uvector2
|
||||
{
|
||||
ucoord_t x;
|
||||
ucoord_t y;
|
||||
|
||||
// Implicit conversion to vector 2 if needed
|
||||
inline operator vector2() const { return { (coord_t)x, (coord_t)y }; }
|
||||
|
||||
inline uvector2 operator-() const { return { (ucoord_t)-x, (ucoord_t)-y }; }
|
||||
|
||||
// uvec
|
||||
inline uvector2 operator+(const uvector2& rhs) const { return { (ucoord_t)(rhs.x + x) , (ucoord_t)(rhs.y + y) }; }
|
||||
inline uvector2 operator-(const uvector2& rhs) const { return *this + (-rhs); }
|
||||
|
||||
inline const uvector2& operator+=(const uvector2& rhs) { *this = *this+rhs; return *this; }
|
||||
inline const uvector2& operator-=(const uvector2& rhs) { return *this+=(-rhs); }
|
||||
|
||||
inline bool operator==(const uvector2& rhs) const { return ( rhs.x == x) && ( rhs.y == y); }
|
||||
inline bool operator!=(const uvector2& rhs) const { return !(*this==rhs); }
|
||||
};
|
||||
|
||||
inline vector2::operator uvector2() const { return { (ucoord_t)x, (ucoord_t)y }; }
|
||||
|
||||
inline vector2 vecFromDir( dir_t dir )
|
||||
{
|
||||
switch( dir )
|
||||
{
|
||||
case dir_t::N:
|
||||
return { 0,1 };
|
||||
break;
|
||||
|
||||
case dir_t::E:
|
||||
return { 1,0 };
|
||||
break;
|
||||
|
||||
case dir_t::S:
|
||||
return { 0,-1 };
|
||||
break;
|
||||
|
||||
case dir_t::W:
|
||||
return { -1,0 };
|
||||
break;
|
||||
}
|
||||
|
||||
return { 0,0 };
|
||||
}
|
||||
|
||||
#endif //_VECTOR2_H_
|
|
@ -68,13 +68,34 @@ const char* tests()
|
|||
if( game.SimulateToNextTurn() )
|
||||
return "Failed to simulate a blank game";
|
||||
|
||||
if( game.GetNumOrders() )
|
||||
return "Game started with non-zero order number";
|
||||
|
||||
if( game.GetNumUnits() )
|
||||
return "Game started with non-zero unit number";
|
||||
if( game.GetNumUnits() )
|
||||
return "Game started with non-zero unit number";
|
||||
}
|
||||
|
||||
{
|
||||
CTTRTSGame game( 5, 5 );
|
||||
|
||||
CUnit unit = CUnit::getUnitFromVis('>');
|
||||
const unit_id_t id = unit.getID();
|
||||
COrder order;
|
||||
|
||||
unit.setPos( {2,2} );
|
||||
unit.setPlayer(0);
|
||||
|
||||
game.AddUnit(std::move(unit));
|
||||
|
||||
order.unit = id;
|
||||
order.order = order_c::F;
|
||||
|
||||
game.IssueOrder(0,order);
|
||||
|
||||
game.SimulateToNextTurn();
|
||||
|
||||
if( game.GetUnitByIDConst(id).getPos() != uvector2{3,2} )
|
||||
return "Simple movement order failed";
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue