#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() ); } }