1
0
forked from 0ad/0ad
0ad/source/simulation/Formation.cpp
janwas 73683b6109 # SwEng
. the massive renaming undertaking: camelCase functions -> PascalCase.
. add some cppdoc.
. minor additional renaming improvements: e.g. GetIsClosed -> IsClosed
. in entity code, replace constructs like "pvec = new vector; return
pvec; use *pvec; delete pvec" with a simple stack variable passed as
output parameter (avoid unnecessary dynamic allocs)
. timer: simpler handling of raw ticks vs normal timer (less #if)

This was SVN commit r5017.
2007-05-02 12:07:08 +00:00

210 lines
5.7 KiB
C++

#include "precompiled.h"
#include "Formation.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "maths/MathUtil.h"
#define LOG_CATEGORY "Formation"
CFormation::CFormation()
{
m_numSlots = 0;
}
bool CFormation::LoadXml(const CStr& filename)
{
CXeromyces XeroFile;
if (XeroFile.Load(filename) != PSRETURN_OK)
return false;
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
EL(formation);
EL(fl);
EL(rk);
EL(blank);
AT(tag);
AT(bonus);
AT(bonusbase);
AT(bonustype);
AT(bonusval);
AT(penalty);
AT(penaltybase);
AT(penaltytype);
AT(penaltyval);
AT(anglepenalty);
AT(anglepenaltydivs);
AT(anglepenaltytype);
AT(anglepenaltyval);
AT(required);
AT(next);
AT(prior);
AT(movement);
AT(filespacing);
AT(rankspacing);
AT(category);
AT(order);
#undef AT
#undef EL
XMBElement Root = XeroFile.GetRoot();
if( Root.GetNodeName() != el_formation )
{
LOG( ERROR, LOG_CATEGORY, "CFormation::LoadXml: XML root was not \"Formation\" in file %s. Load failed.", filename.c_str() );
return( false );
}
//Load in single attributes
XMBAttributeList Attributes = Root.GetAttributes();
for ( int i=0; i<Attributes.Count; ++i )
{
XMBAttribute Attr = Attributes.Item(i);
if ( Attr.Name == at_tag )
m_tag = CStr(Attr.Value);
else if ( Attr.Name == at_bonus )
m_bonus = CStr(Attr.Value);
else if ( Attr.Name == at_bonusbase )
m_bonusBase = CStr(Attr.Value);
else if ( Attr.Name == at_bonustype )
m_bonusType = CStr(Attr.Value);
else if ( Attr.Name == at_bonusval )
m_bonusVal = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_penalty )
m_penalty = CStr(Attr.Value);
else if ( Attr.Name == at_penaltybase )
m_penaltyBase = CStr(Attr.Value);
else if ( Attr.Name == at_penaltytype )
m_penaltyType = CStr(Attr.Value);
else if ( Attr.Name == at_penaltyval )
m_penaltyVal = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_anglepenalty )
m_anglePenalty = CStr(Attr.Value);
else if ( Attr.Name == at_anglepenaltydivs )
m_anglePenaltyDivs = CStr(Attr.Value).ToInt();
else if ( Attr.Name == at_anglepenaltytype )
m_anglePenaltyType = CStr(Attr.Value);
else if ( Attr.Name == at_anglepenaltyval )
m_anglePenaltyVal = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_required)
m_required = CStr(Attr.Value).ToInt();
else if ( Attr.Name == at_next )
m_next = CStr(Attr.Value);
else if ( Attr.Name == at_prior )
m_prior = CStr(Attr.Value);
else if ( Attr.Name == at_movement )
m_movement = CStr(Attr.Value);
else if ( Attr.Name == at_rankspacing )
m_rankSpacing = CStr(Attr.Value).ToFloat();
else if ( Attr.Name == at_filespacing )
m_fileSpacing = CStr(Attr.Value).ToFloat();
else
{
const char* invAttr = XeroFile.GetAttributeString(Attr.Name).c_str();
LOG( ERROR, LOG_CATEGORY, "CFormation::LoadXml: Invalid attribute %s defined in formation file %s. Load failed.", invAttr, filename.c_str() );
return( false );
}
}
XMBElementList RootChildren = Root.GetChildNodes();
int file=0;
int rank=0;
int maxrank=0;
//Read in files and ranks
for (int i = 0; i < RootChildren.Count; ++i)
{
XMBElement RootChild = RootChildren.Item(i);
int ChildName = RootChild.GetNodeName();
if ( ChildName == el_fl )
{
rank = 0;
XMBAttributeList FileAttribList = RootChild.GetAttributes();
//Load default category
CStr FileCatValue = FileAttribList.GetNamedItem(at_category);
//Specific slots in this file (row)
XMBElementList RankNodes = RootChild.GetChildNodes();
for ( int r=0; r<RankNodes.Count; ++r )
{
XMBElement Rank = RankNodes.Item(r);
if ( Rank.GetNodeName() == el_blank )
{
++rank;
continue;
}
else if ( Rank.GetNodeName() != el_rk )
return false;
//error
XMBAttributeList RankAttribList = Rank.GetAttributes();
int order = CStr( RankAttribList.GetNamedItem(at_order) ).ToInt();
CStr category = CStr( RankAttribList.GetNamedItem(at_category) );
if( order <= 0 )
{
LOG( ERROR, LOG_CATEGORY, "CFormation::LoadXml: Invalid (negative number or 0) order defined in formation file %s. The game will try to continue anyway.", filename.c_str() );
continue;
}
--order; //We need this to be in line with arrays, so start at 0
//if ( category.Length() )
//AssignCategory(order, category);
//else
AssignCategory(order, FileCatValue);
m_slots[order].fileOff = file * m_fileSpacing;
m_slots[order].rankOff = rank * m_rankSpacing;
++m_numSlots;
++rank;
}
if ( rank > maxrank )
maxrank = rank;
++file;
} //if el_fl
else if ( ChildName == el_blank )
++file;
}
float centerx = maxrank * m_rankSpacing / 2.0f;
float centery = file * m_fileSpacing / 2.0f;
//Here we check to make sure no order was skipped over. If so, failure, because we rely
//on a linearly accessible slots in entityformation.cpp.
for ( int i=0; i<m_numSlots; ++i )
{
if ( m_slots.find(i) == m_slots.end() )
{
LOG( ERROR, LOG_CATEGORY, "CFormation::LoadXml: Missing orders in %s. Load failed.", filename.c_str() );
return false;
}
else
{
m_slots[i].rankOff = m_slots[i].rankOff - centerx;
m_slots[i].fileOff = m_slots[i].fileOff - centery;
}
}
return true;
}
void CFormation::AssignCategory(int order, CStr category)
{
category.Remove( CStr(",") );
category = category + " "; //So the final word will be pushed as well
CStr temp;
//Push categories until last space
while ( ( temp = category.BeforeFirst(" ") ) != "" )
{
m_slots[order].category.push_back(temp);
//Don't use remove because certain categories could be substrings of others
size_t off = category.find(temp);
category.erase( off, temp.length() );
}
}