Team.cpp 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Team.cpp /////////////////////////////////////////////////////////////////////////////////
  24. // Team interface implementation
  25. // Author: Michael S. Booth, March 2001
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/GameState.h"
  30. #include "Common/Team.h"
  31. #include "Common/ThingFactory.h"
  32. #include "Common/PerfTimer.h"
  33. #include "Common/Player.h"
  34. #include "Common/PlayerList.h"
  35. #include "Common/PlayerTemplate.h"
  36. #include "Common/ThingTemplate.h"
  37. #include "Common/WellKnownKeys.h"
  38. #include "Common/Xfer.h"
  39. #include "GameClient/Drawable.h"
  40. #include "GameLogic/SidesList.h"
  41. #include "GameLogic/Object.h"
  42. #include "GameLogic/Module/BodyModule.h"
  43. #include "GameLogic/Module/ContainModule.h"
  44. #include "GameLogic/PolygonTrigger.h"
  45. #include "GameLogic/Module/AIUpdate.h"
  46. #include "GameLogic/PartitionManager.h"
  47. #include "GameLogic/ScriptActions.h"
  48. #include "GameLogic/ScriptEngine.h"
  49. #ifdef _INTERNAL
  50. // for occasional debugging...
  51. //#pragma optimize("", off)
  52. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  53. #endif
  54. ///@todo - do delayed script evaluations for team scripts. jba.
  55. // GLOBALS ////////////////////////////////////////////////////////////////////
  56. TeamFactory *TheTeamFactory = NULL;
  57. // ------------------------------------------------------------------------------------------------
  58. // ------------------------------------------------------------------------------------------------
  59. TeamRelationMap::TeamRelationMap( void )
  60. {
  61. } // end TeamRelationMap
  62. // ------------------------------------------------------------------------------------------------
  63. // ------------------------------------------------------------------------------------------------
  64. TeamRelationMap::~TeamRelationMap( void )
  65. {
  66. // maek sure the data is clear
  67. m_map.clear();
  68. } // end ~TeamRelationMap
  69. // ------------------------------------------------------------------------------------------------
  70. /** CRC */
  71. // ------------------------------------------------------------------------------------------------
  72. void TeamRelationMap::crc( Xfer *xfer )
  73. {
  74. } // end crc
  75. // ------------------------------------------------------------------------------------------------
  76. /** Xfer method
  77. * Version Info;
  78. * 1: Initial version */
  79. // ------------------------------------------------------------------------------------------------
  80. void TeamRelationMap::xfer( Xfer *xfer )
  81. {
  82. // version
  83. XferVersion currentVersion = 1;
  84. XferVersion version = currentVersion;
  85. xfer->xferVersion( &version, currentVersion );
  86. // team relation count
  87. TeamRelationMapType::iterator teamRelationIt;
  88. UnsignedShort teamRelationCount = m_map.size();
  89. xfer->xferUnsignedShort( &teamRelationCount );
  90. // team relations
  91. TeamID teamID;
  92. Relationship r;
  93. if( xfer->getXferMode() == XFER_SAVE )
  94. {
  95. // go through all team relations
  96. for( teamRelationIt = m_map.begin(); teamRelationIt != m_map.end(); ++teamRelationIt )
  97. {
  98. // write team ID
  99. teamID = (*teamRelationIt).first;
  100. xfer->xferUser( &teamID, sizeof( TeamID ) );
  101. // write relationship
  102. r = (*teamRelationIt).second;
  103. xfer->xferUser( &r, sizeof( Relationship ) );
  104. } // end for
  105. } // end if, save
  106. else
  107. {
  108. for( UnsignedShort i = 0; i < teamRelationCount; ++i )
  109. {
  110. // read team ID
  111. xfer->xferUser( &teamID, sizeof( TeamID ) );
  112. // read relationship
  113. xfer->xferUser( &r, sizeof( Relationship ) );
  114. // assign relationship
  115. m_map[teamID] = r;
  116. } // end for, i
  117. } // end else load
  118. } // end xfer
  119. // ------------------------------------------------------------------------------------------------
  120. /** Load post process */
  121. // ------------------------------------------------------------------------------------------------
  122. void TeamRelationMap::loadPostProcess( void )
  123. {
  124. } // end loadPostProcess
  125. ///////////////////////////////////////////////////////////////////////////////////////////////////
  126. ///////////////////////////////////////////////////////////////////////////////////////////////////
  127. ///////////////////////////////////////////////////////////////////////////////////////////////////
  128. // ------------------------------------------------------------------------
  129. // ------------------------------------------------------------------------
  130. // ------------------------------------------------------------------------
  131. // STATIC FUNCTIONS ///////////////////////////////////////////////////////////
  132. static Bool locoSetMatches(LocomotorSurfaceTypeMask lstm, UnsignedInt surfaceBitFlags)
  133. {
  134. surfaceBitFlags = surfaceBitFlags & 0x01 | ((surfaceBitFlags & 0x02) << 2);
  135. return (surfaceBitFlags & lstm) != 0;
  136. }
  137. // ------------------------------------------------------------------------
  138. // ------------------------------------------------------------------------
  139. TeamFactory::TeamFactory()
  140. {
  141. m_uniqueTeamPrototypeID = TEAM_PROTOTYPE_ID_INVALID;
  142. m_uniqueTeamID = TEAM_ID_INVALID;
  143. }
  144. // ------------------------------------------------------------------------
  145. TeamFactory::~TeamFactory()
  146. {
  147. clear();
  148. }
  149. // ------------------------------------------------------------------------
  150. void TeamFactory::init( void )
  151. {
  152. clear();
  153. }
  154. // ------------------------------------------------------------------------
  155. void TeamFactory::reset( void )
  156. {
  157. m_uniqueTeamPrototypeID = TEAM_PROTOTYPE_ID_INVALID;
  158. m_uniqueTeamID = TEAM_ID_INVALID;
  159. clear();
  160. }
  161. // ------------------------------------------------------------------------
  162. void TeamFactory::update( void )
  163. {
  164. }
  165. // ------------------------------------------------------------------------
  166. void TeamFactory::clear()
  167. {
  168. // must remove it from the map before deleting the TeamProto, since
  169. // the TeamProto will try to remove itself from the list when it goes away
  170. TeamPrototypeMap tmp = m_prototypes;
  171. m_prototypes.clear();
  172. for (TeamPrototypeMap::iterator it = tmp.begin(); it != tmp.end(); ++it)
  173. {
  174. it->second->deleteInstance();
  175. }
  176. }
  177. // ------------------------------------------------------------------------
  178. void TeamFactory::initFromSides(SidesList *sides)
  179. {
  180. clear();
  181. // create the teams we need.
  182. for(Int i = 0; i < sides->getNumTeams(); i++)
  183. {
  184. Dict *d = sides->getTeamInfo(i)->getDict();
  185. AsciiString tname = d->getAsciiString(TheKey_teamName);
  186. AsciiString oname = d->getAsciiString(TheKey_teamOwner);
  187. Bool singleton = d->getBool(TheKey_teamIsSingleton);
  188. initTeam(tname, oname, singleton, d);
  189. }
  190. }
  191. // ------------------------------------------------------------------------
  192. void TeamFactory::initTeam(const AsciiString& name, const AsciiString& owner, Bool isSingleton, Dict *d)
  193. {
  194. DEBUG_ASSERTCRASH(findTeamPrototype(name)==NULL,("team already exists"));
  195. Player *pOwner = ThePlayerList->findPlayerWithNameKey(NAMEKEY(owner));
  196. DEBUG_ASSERTCRASH(pOwner, ("no owner found for team %s (%s)\n",name.str(),owner.str()));
  197. if (!pOwner)
  198. pOwner = ThePlayerList->getNeutralPlayer();
  199. /*TeamPrototype *tp =*/ newInstance(TeamPrototype)(this, name, pOwner, isSingleton, d, ++m_uniqueTeamPrototypeID);
  200. if (isSingleton) {
  201. // Create the singleton team.
  202. createInactiveTeam(name);
  203. }
  204. }
  205. //=============================================================================
  206. void TeamFactory::addTeamPrototypeToList(TeamPrototype* team)
  207. {
  208. NameKeyType nk = NAMEKEY(team->getName());
  209. TeamPrototypeMap::iterator it = m_prototypes.find(nk);
  210. if (it != m_prototypes.end())
  211. {
  212. DEBUG_ASSERTCRASH((*it).second==team, ("uh oh, mismatch"));
  213. return; // already present
  214. }
  215. m_prototypes[nk] = team;
  216. }
  217. //=============================================================================
  218. void TeamFactory::removeTeamPrototypeFromList(TeamPrototype* team)
  219. {
  220. NameKeyType nk = NAMEKEY(team->getName());
  221. TeamPrototypeMap::iterator it = m_prototypes.find(nk);
  222. if (it != m_prototypes.end())
  223. m_prototypes.erase(it);
  224. }
  225. // ------------------------------------------------------------------------
  226. TeamPrototype *TeamFactory::findTeamPrototype(const AsciiString& name)
  227. {
  228. NameKeyType nk = NAMEKEY(name);
  229. TeamPrototypeMap::iterator it = m_prototypes.find(nk);
  230. if (it != m_prototypes.end())
  231. return it->second;
  232. return NULL;
  233. }
  234. // ------------------------------------------------------------------------
  235. TeamPrototype *TeamFactory::findTeamPrototypeByID( TeamPrototypeID id )
  236. {
  237. TeamPrototypeMap::iterator it;
  238. TeamPrototype *prototype = NULL;
  239. for( it = m_prototypes.begin(); it != m_prototypes.end(); ++it )
  240. {
  241. prototype = it->second;
  242. if( prototype->getID() == id )
  243. return prototype;
  244. } // end for
  245. // not found
  246. return NULL;
  247. }
  248. // ------------------------------------------------------------------------
  249. Team *TeamFactory::findTeamByID( TeamID teamID )
  250. {
  251. // simple case
  252. if( teamID == TEAM_ID_INVALID )
  253. return NULL;
  254. // search all prototypes for the matching team ID
  255. TeamPrototype *tp;
  256. TeamPrototypeMap::iterator it;
  257. Team *team;
  258. for( it = m_prototypes.begin(); it != m_prototypes.end(); ++it )
  259. {
  260. tp = (*it).second;
  261. team = tp->findTeamByID( teamID );
  262. if( team )
  263. return team;
  264. }
  265. return NULL;
  266. }
  267. // ------------------------------------------------------------------------
  268. /** Creates an inactive team, suitable for adding members to as they are built.
  269. Call team->setActive() when all members are added. */
  270. Team *TeamFactory::createInactiveTeam(const AsciiString& name)
  271. {
  272. TeamPrototype *tp = findTeamPrototype(name);
  273. if (!tp)
  274. throw ERROR_BAD_ARG;
  275. Team *t = NULL;
  276. if (tp->getIsSingleton())
  277. {
  278. t = tp->getFirstItemIn_TeamInstanceList();
  279. if (t) {
  280. if (tp->getTemplateInfo()->m_executeActions) {
  281. const Script *script = TheScriptEngine->findScriptByName(tp->getTemplateInfo()->m_productionCondition);
  282. if (script) {
  283. TheScriptEngine->friend_executeAction(script->getAction());
  284. }
  285. }
  286. return t;
  287. }
  288. }
  289. t = newInstance(Team)(tp, ++m_uniqueTeamID );
  290. if (tp->getTemplateInfo()->m_executeActions) {
  291. const Script *script = TheScriptEngine->findScriptByName(tp->getTemplateInfo()->m_productionCondition);
  292. if (script) {
  293. TheScriptEngine->friend_executeAction(script->getAction());
  294. }
  295. }
  296. return t;
  297. }
  298. // ------------------------------------------------------------------------
  299. Team *TeamFactory::createTeam(const AsciiString& name)
  300. {
  301. Team *t = NULL;
  302. t = createInactiveTeam(name);
  303. t->setActive();
  304. return t;
  305. }
  306. // ------------------------------------------------------------------------
  307. Team *TeamFactory::createTeamOnPrototype( TeamPrototype *prototype )
  308. {
  309. if( prototype == NULL )
  310. throw ERROR_BAD_ARG;
  311. Team *t = NULL;
  312. if( prototype->getIsSingleton() )
  313. {
  314. t = prototype->getFirstItemIn_TeamInstanceList();
  315. if( t )
  316. return t;
  317. }
  318. t = newInstance(Team)( prototype, ++m_uniqueTeamID );
  319. t->setActive();
  320. return t;
  321. }
  322. // ------------------------------------------------------------------------
  323. Team* TeamFactory::findTeam(const AsciiString& name)
  324. {
  325. TeamPrototype *tp = findTeamPrototype(name);
  326. if (tp)
  327. {
  328. Team *t = tp->getFirstItemIn_TeamInstanceList();
  329. if (t == NULL && !tp->getIsSingleton())
  330. {
  331. t = createInactiveTeam(name);
  332. }
  333. return t;
  334. }
  335. return NULL;
  336. }
  337. // ------------------------------------------------------------------------
  338. void TeamFactory::teamAboutToBeDeleted(Team* team)
  339. {
  340. for (TeamPrototypeMap::iterator it = m_prototypes.begin(); it != m_prototypes.end(); ++it)
  341. {
  342. it->second->teamAboutToBeDeleted(team);
  343. }
  344. if (ThePlayerList)
  345. ThePlayerList->teamAboutToBeDeleted(team);
  346. }
  347. // ------------------------------------------------------------------------
  348. /** CRC */
  349. // ------------------------------------------------------------------------
  350. void TeamFactory::crc( Xfer *xfer )
  351. {
  352. } // end crc
  353. // ------------------------------------------------------------------------
  354. /** Xfer method
  355. * Version Info:
  356. * 1: Initial version */
  357. // ------------------------------------------------------------------------
  358. void TeamFactory::xfer( Xfer *xfer )
  359. {
  360. // version
  361. XferVersion currentVersion = 1;
  362. XferVersion version = currentVersion;
  363. xfer->xferVersion( &version, currentVersion );
  364. // unique team ID counter
  365. xfer->xferUser( &m_uniqueTeamID, sizeof( TeamID ) );
  366. // how many team prototypes of data do we have to write
  367. UnsignedShort prototypeCount = m_prototypes.size();
  368. xfer->xferUnsignedShort( &prototypeCount );
  369. //
  370. // prototypes cannot change in number during run time so the count should be the
  371. // same as that already loaded into us from a map load
  372. //
  373. if( prototypeCount != m_prototypes.size() )
  374. {
  375. DEBUG_CRASH(( "TeamFactory::xfer - Prototype count mismatch '%d should be '%d'\n",
  376. prototypeCount, m_prototypes.size() ));
  377. throw SC_INVALID_DATA;
  378. } // end if
  379. // xfer each of the prototype information
  380. TeamPrototypeMap::iterator it;
  381. TeamPrototypeID teamPrototypeID;
  382. TeamPrototype *teamPrototype;
  383. AsciiString prototypeName;
  384. if( xfer->getXferMode() == XFER_SAVE )
  385. {
  386. // iterate each prototype and xfer if it needs to be in the save file
  387. for( it = m_prototypes.begin(); it != m_prototypes.end(); ++it )
  388. {
  389. // get prototype
  390. teamPrototype = it->second;
  391. // xfer prototype id
  392. teamPrototypeID = teamPrototype->getID();
  393. xfer->xferUser( &teamPrototypeID, sizeof( TeamPrototypeID ) );
  394. // xfer prototype data
  395. xfer->xferSnapshot( teamPrototype );
  396. } //end for, it
  397. } // end if, saving
  398. else
  399. {
  400. // read all the team prototype info
  401. for( UnsignedShort i = 0; i < prototypeCount; ++i )
  402. {
  403. // read prototype ID
  404. xfer->xferUser( &teamPrototypeID, sizeof( TeamPrototypeID ) );
  405. // find the prototype
  406. teamPrototype = findTeamPrototypeByID( teamPrototypeID );
  407. // sanity
  408. if( teamPrototype == NULL )
  409. {
  410. DEBUG_CRASH(( "TeamFactory::xfer - Unable to find team prototype by id\n" ));
  411. throw SC_INVALID_DATA;
  412. } // end if
  413. // xfer prototype data
  414. xfer->xferSnapshot( teamPrototype );
  415. } // end for, i
  416. } // end else, loading
  417. /*
  418. // SAVE_LOAD_DEBUG
  419. if( xfer->getXferMode() == XFER_SAVE )
  420. {
  421. FILE *fp = fopen( "TeamCheckSave.txt", "w+t" );
  422. if( fp == NULL )
  423. return;
  424. Object *obj;
  425. TeamPrototypeMap::iterator prototypeIt;
  426. TeamPrototype *prototype;
  427. Team *team;
  428. for( prototypeIt = m_prototypes.begin(); prototypeIt != m_prototypes.end(); ++prototypeIt )
  429. {
  430. prototype = prototypeIt->second;
  431. fprintf( fp, "Prototype '%s' for player index '%d'\n", prototype->getName().str(), prototype->getControllingPlayer()->getPlayerIndex() );
  432. for( DLINK_ITERATOR<Team> teamIt = prototype->iterate_TeamInstanceList(); !teamIt.done(); teamIt.advance() )
  433. {
  434. team = teamIt.cur();
  435. fprintf( fp, " Team Instance '%s', id is '%d'\n", team->getName().str(), team->getID() );
  436. for( DLINK_ITERATOR<Object> objIt = team->iterate_TeamMemberList(); !objIt.done(); objIt.advance() )
  437. {
  438. obj = objIt.cur();
  439. fprintf( fp, " Member '%s', id '%d'\n", obj->getTemplate()->getName().str(), obj->getID() );
  440. }
  441. } // end for
  442. } // end for
  443. fclose( fp );
  444. } // end if, save
  445. */
  446. } // end xfer
  447. // ------------------------------------------------------------------------
  448. /** Load post process */
  449. // ------------------------------------------------------------------------
  450. void TeamFactory::loadPostProcess( void )
  451. {
  452. // set the next unique team and prototype ID to just over the highest one in use
  453. m_uniqueTeamID = 0;
  454. m_uniqueTeamPrototypeID = 0;
  455. TeamPrototypeMap::iterator prototypeIt;
  456. TeamPrototype *prototype;
  457. Team *team;
  458. for( prototypeIt = m_prototypes.begin(); prototypeIt != m_prototypes.end(); ++prototypeIt )
  459. {
  460. // get prototype
  461. prototype = prototypeIt->second;
  462. // do protype ID check
  463. if( prototype->getID() >= m_uniqueTeamPrototypeID )
  464. m_uniqueTeamPrototypeID = prototype->getID() + 1;
  465. // iterate team instances on each prototype and do the team ID check
  466. for( DLINK_ITERATOR<Team> iter = prototype->iterate_TeamInstanceList(); !iter.done(); iter.advance() )
  467. {
  468. team = iter.cur();
  469. if( team->getID() >= m_uniqueTeamID )
  470. m_uniqueTeamID = team->getID() + 1;
  471. } // end for
  472. } // end for, it
  473. /*
  474. // SAVE_LOAD_DEBUG
  475. FILE *fp = fopen( "TeamCheckLoad.txt", "w+t" );
  476. if( fp == NULL )
  477. return;
  478. Object *obj;
  479. for( prototypeIt = m_prototypes.begin(); prototypeIt != m_prototypes.end(); ++prototypeIt )
  480. {
  481. prototype = prototypeIt->second;
  482. fprintf( fp, "Prototype '%s' for player index '%d'\n", prototype->getName().str(), prototype->getControllingPlayer()->getPlayerIndex() );
  483. for( DLINK_ITERATOR<Team> teamIt = prototype->iterate_TeamInstanceList(); !teamIt.done(); teamIt.advance() )
  484. {
  485. team = teamIt.cur();
  486. fprintf( fp, " Team Instance '%s', id is '%d'\n", team->getName().str(), team->getID() );
  487. team->reverse_TeamMemberList();
  488. for( DLINK_ITERATOR<Object> objIt = team->iterate_TeamMemberList(); !objIt.done(); objIt.advance() )
  489. {
  490. obj = objIt.cur();
  491. fprintf( fp, " Member '%s', id '%d'\n", obj->getTemplate()->getName().str(), obj->getID() );
  492. }
  493. } // end for
  494. } // end for
  495. fclose( fp );
  496. */
  497. } // end loadPostProcess
  498. // ------------------------------------------------------------------------
  499. // ------------------------------------------------------------------------
  500. // ------------------------------------------------------------------------
  501. TeamTemplateInfo::TeamTemplateInfo(Dict *d) :
  502. m_numUnitsInfo(0)
  503. {
  504. Bool exists;
  505. Int min, max;
  506. AsciiString templateName;
  507. min = d->getInt(TheKey_teamUnitMinCount1, &exists);
  508. max = d->getInt(TheKey_teamUnitMaxCount1, &exists);
  509. templateName = d->getAsciiString(TheKey_teamUnitType1, &exists);
  510. if (max>0 && exists) {
  511. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  512. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  513. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  514. m_numUnitsInfo++;
  515. }
  516. min = d->getInt(TheKey_teamUnitMinCount2, &exists);
  517. max = d->getInt(TheKey_teamUnitMaxCount2, &exists);
  518. templateName = d->getAsciiString(TheKey_teamUnitType2, &exists);
  519. if (max>0 && exists) {
  520. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  521. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  522. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  523. m_numUnitsInfo++;
  524. }
  525. min = d->getInt(TheKey_teamUnitMinCount3, &exists);
  526. max = d->getInt(TheKey_teamUnitMaxCount3, &exists);
  527. templateName = d->getAsciiString(TheKey_teamUnitType3, &exists);
  528. if (max>0 && exists) {
  529. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  530. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  531. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  532. m_numUnitsInfo++;
  533. }
  534. min = d->getInt(TheKey_teamUnitMinCount4, &exists);
  535. max = d->getInt(TheKey_teamUnitMaxCount4, &exists);
  536. templateName = d->getAsciiString(TheKey_teamUnitType4, &exists);
  537. if (max>0 && exists) {
  538. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  539. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  540. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  541. m_numUnitsInfo++;
  542. }
  543. min = d->getInt(TheKey_teamUnitMinCount5, &exists);
  544. max = d->getInt(TheKey_teamUnitMaxCount5, &exists);
  545. templateName = d->getAsciiString(TheKey_teamUnitType5, &exists);
  546. if (max>0 && exists) {
  547. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  548. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  549. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  550. m_numUnitsInfo++;
  551. }
  552. min = d->getInt(TheKey_teamUnitMinCount6, &exists);
  553. max = d->getInt(TheKey_teamUnitMaxCount6, &exists);
  554. templateName = d->getAsciiString(TheKey_teamUnitType6, &exists);
  555. if (max>0 && exists) {
  556. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  557. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  558. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  559. m_numUnitsInfo++;
  560. }
  561. min = d->getInt(TheKey_teamUnitMinCount7, &exists);
  562. max = d->getInt(TheKey_teamUnitMaxCount7, &exists);
  563. templateName = d->getAsciiString(TheKey_teamUnitType7, &exists);
  564. if (max>0 && exists) {
  565. m_unitsInfo[m_numUnitsInfo].minUnits = min;
  566. m_unitsInfo[m_numUnitsInfo].maxUnits = max;
  567. m_unitsInfo[m_numUnitsInfo].unitThingName = templateName;
  568. m_numUnitsInfo++;
  569. }
  570. AsciiString waypoint = d->getAsciiString(TheKey_teamHome, &exists);
  571. m_homeLocation.x = m_homeLocation.y = 0;
  572. m_homeLocation.z = 0;
  573. m_hasHomeLocation = false;
  574. if (exists) {
  575. for (Waypoint *way = TheTerrainLogic->getFirstWaypoint(); way; way = way->getNext()) {
  576. if (way->getName() == waypoint) {
  577. m_homeLocation = *way->getLocation();
  578. m_hasHomeLocation = true;
  579. }
  580. }
  581. }
  582. m_scriptOnCreate = d->getAsciiString(TheKey_teamOnCreateScript, &exists);
  583. m_isAIRecruitable = d->getBool(TheKey_teamIsAIRecruitable, &exists);
  584. if (!exists) {
  585. m_isAIRecruitable = false;
  586. }
  587. m_isBaseDefense = d->getBool(TheKey_teamIsBaseDefense, &exists);
  588. m_isPerimeterDefense = d->getBool(TheKey_teamIsPerimeterDefense, &exists);
  589. m_automaticallyReinforce = d->getBool(TheKey_teamAutoReinforce, &exists);
  590. Int interact = d->getInt(TheKey_teamAggressiveness, &exists);
  591. m_initialTeamAttitude = AI_NORMAL;
  592. if (exists) {
  593. m_initialTeamAttitude = (AttitudeType) interact;
  594. }
  595. m_transportsReturn = d->getBool(TheKey_teamTransportsReturn, &exists);
  596. m_avoidThreats = d->getBool(TheKey_teamAvoidThreats, &exists);
  597. m_attackCommonTarget = d->getBool(TheKey_teamAttackCommonTarget, &exists);
  598. m_maxInstances = d->getInt(TheKey_teamMaxInstances, &exists);
  599. m_scriptOnIdle = d->getAsciiString(TheKey_teamOnIdleScript, &exists);
  600. m_initialIdleFrames = d->getInt(TheKey_teamInitialIdleFrames, &exists);
  601. m_scriptOnEnemySighted = d->getAsciiString(TheKey_teamEnemySightedScript, &exists);
  602. m_scriptOnAllClear = d->getAsciiString(TheKey_teamAllClearScript, &exists);
  603. m_scriptOnDestroyed = d->getAsciiString(TheKey_teamOnDestroyedScript, &exists);
  604. m_destroyedThreshold = d->getReal(TheKey_teamDestroyedThreshold, &exists);
  605. m_scriptOnUnitDestroyed = d->getAsciiString(TheKey_teamOnUnitDestroyedScript, &exists);
  606. m_productionPriority = d->getInt(TheKey_teamProductionPriority, &exists);
  607. m_productionPrioritySuccessIncrease = d->getInt(TheKey_teamProductionPrioritySuccessIncrease, &exists);
  608. m_productionPriorityFailureDecrease = d->getInt(TheKey_teamProductionPriorityFailureDecrease, &exists);
  609. // Production scripts stuff
  610. m_productionCondition = d->getAsciiString(TheKey_teamProductionCondition, &exists);
  611. m_executeActions = d->getBool(TheKey_teamExecutesActionsOnCreate, &exists);
  612. // Which scripts to attempt during run?
  613. for (int i = 0; i < MAX_GENERIC_SCRIPTS; ++i) {
  614. AsciiString keyName;
  615. keyName.format("%s%d", TheNameKeyGenerator->keyToName(TheKey_teamGenericScriptHook).str(), i);
  616. m_teamGenericScripts[i] = d->getAsciiString(NAMEKEY(keyName), &exists);
  617. if (!exists) {
  618. m_teamGenericScripts[i].clear();
  619. }
  620. }
  621. // reinforcement team info.
  622. m_transportUnitType = d->getAsciiString(TheKey_teamTransport, &exists);
  623. m_transportsExit = d->getBool(TheKey_teamTransportsExit, &exists);
  624. m_teamStartsFull = d->getBool(TheKey_teamStartsFull, &exists);
  625. m_startReinforceWaypoint = d->getAsciiString(TheKey_teamReinforcementOrigin, &exists);
  626. m_veterancy = (VeterancyLevel)d->getInt(TheKey_teamVeterancy, &exists);
  627. }
  628. // ------------------------------------------------------------------------
  629. /** CRC */
  630. // ------------------------------------------------------------------------
  631. void TeamTemplateInfo::crc( Xfer *xfer )
  632. {
  633. } // end crc
  634. // ------------------------------------------------------------------------
  635. /** Xfer method
  636. * Version Info:
  637. * 1: Initial version */
  638. // ------------------------------------------------------------------------
  639. void TeamTemplateInfo::xfer( Xfer *xfer )
  640. {
  641. // version
  642. XferVersion currentVersion = 1;
  643. XferVersion version = currentVersion;
  644. xfer->xferVersion( &version, currentVersion );
  645. // xfer the production priority
  646. xfer->xferInt( &m_productionPriority );
  647. } // end xfer
  648. // ------------------------------------------------------------------------
  649. /** Load post process */
  650. // ------------------------------------------------------------------------
  651. void TeamTemplateInfo::loadPostProcess( void )
  652. {
  653. } // end loadPostProcess
  654. // ------------------------------------------------------------------------
  655. // ------------------------------------------------------------------------
  656. // ------------------------------------------------------------------------
  657. // ------------------------------------------------------------------------
  658. // ------------------------------------------------------------------------
  659. TeamPrototype::TeamPrototype( TeamFactory *tf,
  660. const AsciiString &name,
  661. Player *ownerPlayer,
  662. Bool isSingleton,
  663. Dict *d,
  664. TeamPrototypeID id ) :
  665. m_id(id),
  666. m_factory(tf),
  667. m_name(name),
  668. m_owningPlayer(ownerPlayer),
  669. m_flags(isSingleton ? TeamPrototype::TEAM_SINGLETON : 0),
  670. m_teamTemplate(d),
  671. m_productionConditionAlwaysFalse(false),
  672. m_productionConditionScript(NULL)
  673. {
  674. DEBUG_ASSERTCRASH(!(m_owningPlayer == NULL), ("bad args to TeamPrototype ctor"));
  675. if (m_factory)
  676. m_factory->addTeamPrototypeToList(this);
  677. if (m_owningPlayer)
  678. m_owningPlayer->addTeamToList(this);
  679. m_retrievedGenericScripts = false;
  680. for (Int i = 0; i < MAX_GENERIC_SCRIPTS; ++i) {
  681. m_genericScriptsToRun[i] = NULL;
  682. }
  683. }
  684. // ------------------------------------------------------------------------
  685. static void deleteTeamCallback(Team* o)
  686. {
  687. if (o)
  688. {
  689. TheTeamFactory->teamAboutToBeDeleted(o);
  690. o->deleteInstance();
  691. }
  692. }
  693. TeamPrototype::~TeamPrototype()
  694. {
  695. removeAll_TeamInstanceList(deleteTeamCallback);
  696. if (m_owningPlayer)
  697. m_owningPlayer->removeTeamFromList(this);
  698. if (m_factory)
  699. m_factory->removeTeamPrototypeFromList(this);
  700. if (m_productionConditionScript)
  701. {
  702. m_productionConditionScript->deleteInstance();
  703. }
  704. m_productionConditionScript = NULL;
  705. for (Int i = 0; i < MAX_GENERIC_SCRIPTS; ++i)
  706. {
  707. if (m_genericScriptsToRun[i])
  708. {
  709. m_genericScriptsToRun[i]->deleteInstance();
  710. m_genericScriptsToRun[i] = NULL;
  711. }
  712. }
  713. }
  714. // ------------------------------------------------------------------------
  715. Player *TeamPrototype::getControllingPlayer() const
  716. {
  717. return m_owningPlayer;
  718. }
  719. // ------------------------------------------------------------------------
  720. Team *TeamPrototype::findTeamByID( TeamID teamID )
  721. {
  722. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  723. {
  724. if( iter.cur()->getID() == teamID )
  725. return iter.cur();
  726. }
  727. return NULL;
  728. }
  729. // ------------------------------------------------------------------------
  730. void TeamPrototype::setControllingPlayer(Player *newController)
  731. {
  732. DEBUG_ASSERTCRASH(newController, ("Attempted to set NULL player as team-owner, illegal."));
  733. if (!newController) {
  734. return;
  735. }
  736. if (m_owningPlayer)
  737. m_owningPlayer->removeTeamFromList(this);
  738. m_owningPlayer = newController;
  739. // impossible to get here with a NULL pointer.
  740. m_owningPlayer->addTeamToList(this);
  741. }
  742. // ------------------------------------------------------------------------
  743. void TeamPrototype::countObjectsByThingTemplate(Int numTmplates, const ThingTemplate* const* things, Bool ignoreDead, Int *counts, Bool ignoreUnderConstruction) const
  744. {
  745. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  746. {
  747. iter.cur()->countObjectsByThingTemplate(numTmplates, things, ignoreDead, counts, ignoreUnderConstruction);
  748. }
  749. }
  750. // ------------------------------------------------------------------------
  751. void TeamPrototype::teamAboutToBeDeleted(Team* team)
  752. {
  753. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  754. {
  755. // iter.cur()->removeOverrideTeamRelationship(team);
  756. iter.cur()->removeOverrideTeamRelationship(team ? team->getID() : TEAM_ID_INVALID );
  757. }
  758. }
  759. // ------------------------------------------------------------------------
  760. Script *TeamPrototype::getGenericScript(Int scriptToRetrieve)
  761. {
  762. if (!m_retrievedGenericScripts) {
  763. m_retrievedGenericScripts = TRUE; // set this to true so we won't do the lookup again.
  764. // Go get them from the script engine, and duplicate each one.
  765. for (Int i = 0; i < MAX_GENERIC_SCRIPTS; ++i) {
  766. const Script *tmpScript = NULL;
  767. Script *scriptToSave = NULL;
  768. if (!m_teamTemplate.m_teamGenericScripts[i].isEmpty()) {
  769. tmpScript = TheScriptEngine->findScriptByName(m_teamTemplate.m_teamGenericScripts[i]);
  770. if (tmpScript) {
  771. scriptToSave = tmpScript->duplicate();
  772. } else {
  773. DEBUG_CRASH(("We attempted to find a generic script, but couldn't. ('%s')", m_teamTemplate.m_teamGenericScripts[i].str()));
  774. }
  775. }
  776. // I now own this one. I'm responsible for cleaning it up on destruction.
  777. m_genericScriptsToRun[i] = scriptToSave;
  778. }
  779. }
  780. return m_genericScriptsToRun[scriptToRetrieve];
  781. }
  782. // ------------------------------------------------------------------------
  783. // Make a team more likely to be selected by the ai for building due to success.
  784. void TeamPrototype::increaseAIPriorityForSuccess(void) const
  785. {
  786. m_teamTemplate.m_productionPriority += m_teamTemplate.m_productionPrioritySuccessIncrease;
  787. }
  788. // ------------------------------------------------------------------------
  789. // Make a team more likely to be selected by the ai for building due to success.
  790. void TeamPrototype::decreaseAIPriorityForFailure(void) const
  791. {
  792. m_teamTemplate.m_productionPriority -= m_teamTemplate.m_productionPriorityFailureDecrease;
  793. }
  794. // ------------------------------------------------------------------------
  795. Int TeamPrototype::countBuildings(void)
  796. {
  797. int retVal = 0;
  798. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance()) {
  799. retVal += iter.cur()->countBuildings();
  800. }
  801. return retVal;
  802. }
  803. // ------------------------------------------------------------------------
  804. Int TeamPrototype::countObjects(KindOfMaskType setMask, KindOfMaskType clearMask)
  805. {
  806. int retVal = 0;
  807. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance()) {
  808. retVal += iter.cur()->countObjects(setMask, clearMask);
  809. }
  810. return retVal;
  811. }
  812. // ------------------------------------------------------------------------
  813. void TeamPrototype::healAllObjects(void)
  814. {
  815. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  816. {
  817. iter.cur()->healAllObjects();
  818. }
  819. }
  820. // ------------------------------------------------------------------------
  821. void TeamPrototype::iterateObjects( ObjectIterateFunc func, void *userData )
  822. {
  823. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  824. {
  825. iter.cur()->iterateObjects( func, userData );
  826. }
  827. }
  828. // ------------------------------------------------------------------------
  829. /**
  830. * Count the number of teams that have been instanced by this prototype
  831. */
  832. Int TeamPrototype::countTeamInstances( void )
  833. {
  834. Int count = 0;
  835. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  836. count++;
  837. return count;
  838. }
  839. // ------------------------------------------------------------------------
  840. Bool TeamPrototype::hasAnyBuildings() const
  841. {
  842. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  843. {
  844. if (iter.cur()->hasAnyBuildings()) return true;
  845. }
  846. return false;
  847. }
  848. // ------------------------------------------------------------------------
  849. Bool TeamPrototype::hasAnyBuildings(KindOfMaskType kindOf) const
  850. {
  851. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  852. {
  853. if (iter.cur()->hasAnyBuildings(kindOf)) return true;
  854. }
  855. return false;
  856. }
  857. // ------------------------------------------------------------------------
  858. Bool TeamPrototype::hasAnyUnits() const
  859. {
  860. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  861. {
  862. if (iter.cur()->hasAnyUnits()) return true;
  863. }
  864. return false;
  865. }
  866. // ------------------------------------------------------------------------
  867. Bool TeamPrototype::hasAnyObjects() const
  868. {
  869. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  870. {
  871. if (iter.cur()->hasAnyObjects()) return true;
  872. }
  873. return false;
  874. }
  875. // ------------------------------------------------------------------------
  876. void TeamPrototype::updateState(void)
  877. {
  878. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  879. {
  880. iter.cur()->updateState();
  881. }
  882. /* remove empty teams. */
  883. Bool done = false;
  884. while (!done) {
  885. done = true;
  886. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  887. {
  888. if (iter.cur()->getFirstItemIn_TeamMemberList() == NULL)
  889. {
  890. // Team has no members.
  891. if (this->getIsSingleton())
  892. {
  893. continue; // Don't delete singleton teams, even if they are empty.
  894. }
  895. if (iter.cur()->getControllingPlayer() && iter.cur()->getControllingPlayer()->getDefaultTeam() == iter.cur())
  896. {
  897. // This is the player's default team, so don't remove it.
  898. continue;
  899. }
  900. // don't delete inactive teams - they are under construction
  901. if (iter.cur()->isActive() == false)
  902. {
  903. continue;
  904. }
  905. // So remove it
  906. TheTeamFactory->teamAboutToBeDeleted(iter.cur());
  907. iter.cur()->deleteInstance();
  908. done = false;
  909. break; // Not sure what state the iterator is in after deleting a member of the list. jba
  910. }
  911. }
  912. }
  913. }
  914. // ------------------------------------------------------------------------
  915. Bool TeamPrototype::hasAnyBuildFacility() const
  916. {
  917. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  918. {
  919. if (iter.cur()->hasAnyBuildFacility()) return true;
  920. }
  921. return false;
  922. }
  923. // ------------------------------------------------------------------------
  924. void TeamPrototype::damageTeamMembers(Real amount)
  925. {
  926. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  927. {
  928. iter.cur()->damageTeamMembers(amount);
  929. }
  930. }
  931. // ------------------------------------------------------------------------
  932. void TeamPrototype::moveTeamTo(Coord3D destination)
  933. {
  934. for (DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance())
  935. {
  936. iter.cur()->moveTeamTo(destination);
  937. }
  938. }
  939. // ------------------------------------------------------------------------
  940. Bool TeamPrototype::evaluateProductionCondition(void)
  941. {
  942. if (m_productionConditionAlwaysFalse) {
  943. // Set if we don't have a script.
  944. return false;
  945. }
  946. if (m_productionConditionScript) {
  947. // If we are doing peridic evaluation, check the frame.
  948. if (TheGameLogic->getFrame()<m_productionConditionScript->getFrameToEvaluate()) {
  949. return false;
  950. }
  951. Int delaySeconds = m_productionConditionScript->getDelayEvalSeconds();
  952. if (delaySeconds>0) {
  953. m_productionConditionScript->setFrameToEvaluate(TheGameLogic->getFrame()+delaySeconds*LOGICFRAMES_PER_SECOND);
  954. }
  955. return TheScriptEngine->evaluateConditions(m_productionConditionScript, NULL, getControllingPlayer());
  956. }
  957. // We don't have a script yet, so check for one.
  958. if (m_teamTemplate.m_productionCondition.isEmpty()) {
  959. // No script defined.
  960. m_productionConditionAlwaysFalse = true;
  961. return false;
  962. }
  963. const Script *pScript = TheScriptEngine->findScriptByName(m_teamTemplate.m_productionCondition);
  964. if (pScript) {
  965. // Check difficulty.
  966. switch (getControllingPlayer()->getPlayerDifficulty() ) {
  967. case DIFFICULTY_EASY:
  968. if (!pScript->isEasy()) {
  969. m_productionConditionAlwaysFalse = true;
  970. return false;
  971. }
  972. break;
  973. case DIFFICULTY_NORMAL:
  974. if (!pScript->isNormal()) {
  975. m_productionConditionAlwaysFalse = true;
  976. return false;
  977. }
  978. break;
  979. case DIFFICULTY_HARD:
  980. if (!pScript->isHard()) {
  981. m_productionConditionAlwaysFalse = true;
  982. return false;
  983. }
  984. break;
  985. }
  986. // Make a copy of the script locally, just for paranoia's sake. We can't be sure
  987. // exactly what order the teams & scripts will get reset, so be safe.
  988. m_productionConditionScript = pScript->duplicate();
  989. return TheScriptEngine->evaluateConditions(m_productionConditionScript, NULL, getControllingPlayer());
  990. }
  991. // Couldn't find a script.
  992. m_productionConditionAlwaysFalse = true;
  993. return false;
  994. }
  995. // ------------------------------------------------------------------------
  996. /** CRC */
  997. // ------------------------------------------------------------------------
  998. void TeamPrototype::crc( Xfer *xfer )
  999. {
  1000. } // end crc
  1001. // ------------------------------------------------------------------------
  1002. /** Xfer method
  1003. * Version Info:
  1004. * 1: Initial version */
  1005. // ------------------------------------------------------------------------
  1006. void TeamPrototype::xfer( Xfer *xfer )
  1007. {
  1008. // version
  1009. XferVersion currentVersion = 2;
  1010. XferVersion version = currentVersion;
  1011. xfer->xferVersion( &version, currentVersion );
  1012. // owning player index
  1013. Int owningPlayerIndex;
  1014. if( xfer->getXferMode() == XFER_SAVE )
  1015. owningPlayerIndex = m_owningPlayer->getPlayerIndex();
  1016. xfer->xferInt( &owningPlayerIndex );
  1017. m_owningPlayer = ThePlayerList->getNthPlayer( owningPlayerIndex );
  1018. if (version>=2) {
  1019. xfer->xferAsciiString(&m_attackPriorityName);
  1020. }
  1021. // production condition
  1022. xfer->xferBool( &m_productionConditionAlwaysFalse );
  1023. // team template information
  1024. xfer->xferSnapshot( &m_teamTemplate );
  1025. // xfer team instance count
  1026. UnsignedShort teamInstanceCount = 0;
  1027. for( DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance() )
  1028. teamInstanceCount++;
  1029. xfer->xferUnsignedShort( &teamInstanceCount );
  1030. // xfer team instances
  1031. Team *teamInstance;
  1032. TeamID teamID;
  1033. if( xfer->getXferMode() == XFER_SAVE )
  1034. {
  1035. // xfer each team instance
  1036. for( DLINK_ITERATOR<Team> iter = iterate_TeamInstanceList(); !iter.done(); iter.advance() )
  1037. {
  1038. // get the team
  1039. teamInstance = iter.cur();
  1040. // write team id
  1041. teamID = teamInstance->getID();
  1042. xfer->xferUser( &teamID, sizeof( TeamID ) );
  1043. // write team data
  1044. xfer->xferSnapshot( teamInstance );
  1045. } // end for
  1046. } // end if, save
  1047. else
  1048. {
  1049. //
  1050. // there is no need to check to make sure the instance list is empty here ... see
  1051. // the large bock comment below where we find a team given an id
  1052. //
  1053. // read each block
  1054. for( UnsignedShort i = 0; i < teamInstanceCount; ++i )
  1055. {
  1056. // read team id
  1057. xfer->xferUser( &teamID, sizeof( TeamID ) );
  1058. //
  1059. // find this team, if it's not there create it ... note that there will in fact
  1060. // be some teams in the instance when were are loading as they are creating during
  1061. // the map load. But since the team ids are reset on the map load, they are
  1062. // created with exactly the same team IDs they had before
  1063. //
  1064. teamInstance = TheTeamFactory->findTeamByID( teamID );
  1065. if( teamInstance == NULL )
  1066. {
  1067. // create team
  1068. teamInstance = TheTeamFactory->createTeamOnPrototype( this );
  1069. // restore original ID we read from the file
  1070. teamInstance->setID( teamID );
  1071. } // end if
  1072. // xfer team data
  1073. xfer->xferSnapshot( teamInstance );
  1074. } // end for, i
  1075. } // end else, load
  1076. } // end xfer
  1077. // ------------------------------------------------------------------------
  1078. /** Load post process */
  1079. // ------------------------------------------------------------------------
  1080. void TeamPrototype::loadPostProcess( void )
  1081. {
  1082. } // end loadPostProcess
  1083. // ------------------------------------------------------------------------
  1084. // ------------------------------------------------------------------------
  1085. // ------------------------------------------------------------------------
  1086. // ------------------------------------------------------------------------
  1087. // ------------------------------------------------------------------------
  1088. // ------------------------------------------------------------------------
  1089. // ------------------------------------------------------------------------
  1090. Team::Team(TeamPrototype *proto, TeamID id ) :
  1091. m_id( id ),
  1092. m_proto(proto),
  1093. m_enteredOrExited(false),
  1094. m_active(false),
  1095. m_seeEnemy(false),
  1096. m_prevSeeEnemy(false),
  1097. m_checkEnemySighted(false),
  1098. m_isRecruitablitySet(false),
  1099. m_isRecruitable(false),
  1100. m_destroyThreshold(0),
  1101. m_curUnits(0),
  1102. m_wasIdle(false)
  1103. {
  1104. //Added By Sadullah Nader
  1105. //Initialization(s) inserted
  1106. m_created = FALSE;
  1107. //
  1108. m_commonAttackTarget = INVALID_ID;
  1109. // allocate new relation map pools
  1110. m_playerRelations = newInstance(PlayerRelationMap);
  1111. m_teamRelations = newInstance(TeamRelationMap);
  1112. if (proto)
  1113. {
  1114. proto->prependTo_TeamInstanceList(this);
  1115. if (!proto->getTemplateInfo()->m_scriptOnAllClear.isEmpty() ||
  1116. !proto->getTemplateInfo()->m_scriptOnEnemySighted.isEmpty())
  1117. {
  1118. m_checkEnemySighted = true; // Only keep track of enemy sighted if there is a script that cares.
  1119. }
  1120. AsciiString teamName = proto->getName();
  1121. teamName.concat(" - creating team instance.");
  1122. TheScriptEngine->AppendDebugMessage(teamName, false);
  1123. }
  1124. for (Int i = 0; i < MAX_GENERIC_SCRIPTS; ++i)
  1125. {
  1126. m_shouldAttemptGenericScript[i] = true;
  1127. }
  1128. }
  1129. // ------------------------------------------------------------------------
  1130. Team::~Team()
  1131. {
  1132. // DEBUG_ASSERTCRASH(getFirstItemIn_TeamMemberList() == NULL, ("Team still has members in existence"));
  1133. TheScriptEngine->notifyOfTeamDestruction(this);
  1134. // Tell the players a team is going away.
  1135. Int i;
  1136. for (i=0; i<ThePlayerList->getPlayerCount(); i++) {
  1137. Player *plyr = ThePlayerList->getNthPlayer(i);
  1138. if (plyr) {
  1139. plyr->preTeamDestroy(this);
  1140. }
  1141. }
  1142. Object* tm;
  1143. while ((tm = getFirstItemIn_TeamMemberList()) != NULL)
  1144. {
  1145. tm->setTeam(NULL);
  1146. }
  1147. //this test is valid, but will generate a 'false positive' during game teardown
  1148. //DEBUG_ASSERTCRASH(!(getControllingPlayer() && getControllingPlayer()->getDefaultTeam()==this),("I am still someones default team -- sure you want to delete me?"));
  1149. DEBUG_ASSERTCRASH(m_proto, ("proto should not be null"));
  1150. if (m_proto && m_proto->isInList_TeamInstanceList(this))
  1151. m_proto->removeFrom_TeamInstanceList(this);
  1152. // delete the relation maps (the destructor clears the actual map if any data is present)
  1153. m_teamRelations->deleteInstance();
  1154. m_playerRelations->deleteInstance();
  1155. // make sure the xfer list is clear
  1156. m_xferMemberIDList.clear();
  1157. }
  1158. // ------------------------------------------------------------------------
  1159. Player *Team::getControllingPlayer() const
  1160. {
  1161. return m_proto->getControllingPlayer();
  1162. }
  1163. // ------------------------------------------------------------------------
  1164. void Team::setControllingPlayer(Player *newController)
  1165. {
  1166. // NULL is not allowed, but is caught by TeamPrototype::setControllingPlayer()
  1167. m_proto->setControllingPlayer(newController);
  1168. // This function is used by one script, and it is kind of odd. The actual units
  1169. // are not getting captured, the team they are on is being reassigned to a new player.
  1170. // The Team doesn't change, it just starts to return a different answer when you ask for
  1171. // the controlling player. I don't want to make the major change of onCapture on everyone,
  1172. // so I will do the minor fix for the specific bug, which is harmless even when misused.
  1173. // Tell all members to redo their looking status, as their Player has changed, but they don't know.
  1174. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1175. {
  1176. Object *obj = iter.cur();
  1177. if (!obj)
  1178. continue;
  1179. obj->handlePartitionCellMaintenance();
  1180. }
  1181. }
  1182. // ------------------------------------------------------------------------
  1183. void Team::setAttackPriorityName(AsciiString name)
  1184. {
  1185. if (m_proto) m_proto->setAttackPriorityName(name);
  1186. }
  1187. // ------------------------------------------------------------------------
  1188. void Team::getTeamAsAIGroup(AIGroup *pAIGroup)
  1189. {
  1190. if (!pAIGroup) {
  1191. return;
  1192. }
  1193. // Should this clear out the pAIGroup that it receives? I don't think so, but that
  1194. // would go here if so. jkmcd
  1195. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  1196. if (iter.cur()) {
  1197. pAIGroup->add(iter.cur());
  1198. }
  1199. }
  1200. }
  1201. // ------------------------------------------------------------------------
  1202. Int Team::getTargetableCount() const
  1203. {
  1204. Int retVal = 0;
  1205. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  1206. Object *obj = iter.cur();
  1207. if (!obj) {
  1208. continue;
  1209. }
  1210. if (obj->isEffectivelyDead() || (obj->getAIUpdateInterface() == NULL && !obj->isKindOf(KINDOF_STRUCTURE))) {
  1211. continue;
  1212. }
  1213. ++retVal;
  1214. }
  1215. return retVal;
  1216. }
  1217. // ------------------------------------------------------------------------
  1218. Relationship Team::getRelationship(const Team *that) const
  1219. {
  1220. // do we have an override for that particular team? if so, return it.
  1221. if (!m_teamRelations->m_map.empty() && that != NULL)
  1222. {
  1223. TeamRelationMapType::const_iterator it = m_teamRelations->m_map.find(that->getID());
  1224. if (it != m_teamRelations->m_map.end())
  1225. {
  1226. return (*it).second;
  1227. }
  1228. }
  1229. // hummm... well, do we have an override for that team's player?
  1230. if (!m_playerRelations->m_map.empty() && that != NULL)
  1231. {
  1232. Player* thatPlayer = that->getControllingPlayer();
  1233. if (thatPlayer != NULL)
  1234. {
  1235. PlayerRelationMapType::const_iterator it = m_playerRelations->m_map.find(thatPlayer->getPlayerIndex());
  1236. if (it != m_playerRelations->m_map.end())
  1237. {
  1238. return (*it).second;
  1239. }
  1240. }
  1241. }
  1242. // nope -- go with our Player's view on the matter.
  1243. return getControllingPlayer()->getRelationship(that);
  1244. }
  1245. // ------------------------------------------------------------------------
  1246. void Team::setTeamTargetObject(const Object *target)
  1247. {
  1248. if (target==NULL) {
  1249. m_commonAttackTarget = INVALID_ID;
  1250. return;
  1251. }
  1252. // Only ai players do common attack.
  1253. if (getControllingPlayer()->getPlayerType() == PLAYER_COMPUTER) {
  1254. if (getControllingPlayer()->getPlayerDifficulty() == DIFFICULTY_EASY) {
  1255. return; // we don't do this for easy. jba.
  1256. }
  1257. m_commonAttackTarget = target->getID();
  1258. }
  1259. }
  1260. // ------------------------------------------------------------------------
  1261. Object *Team::getTeamTargetObject(void)
  1262. {
  1263. if (m_commonAttackTarget == INVALID_ID) {
  1264. return NULL;
  1265. }
  1266. Object *target = TheGameLogic->findObjectByID(m_commonAttackTarget);
  1267. if (target) {
  1268. //If the enemy unit is stealthed and not detected, then we can't attack it!
  1269. UnsignedInt status = target->getStatusBits();
  1270. if( (status & OBJECT_STATUS_STEALTHED) && !(status & OBJECT_STATUS_DETECTED) ) {
  1271. target = NULL;
  1272. }
  1273. }
  1274. if (target && target->isEffectivelyDead()) {
  1275. target = NULL;
  1276. }
  1277. if (target && target->getContainedBy()) {
  1278. target = NULL; // target entered a building or vehicle, so stop targeting.
  1279. }
  1280. if (target == NULL) {
  1281. m_commonAttackTarget = INVALID_ID;
  1282. }
  1283. return target;
  1284. }
  1285. // ------------------------------------------------------------------------
  1286. void Team::setOverrideTeamRelationship( TeamID teamID, Relationship r)
  1287. {
  1288. if (teamID != TEAM_ID_INVALID )
  1289. {
  1290. // note that this creates the entry if it doesn't exist.
  1291. m_teamRelations->m_map[teamID] = r;
  1292. }
  1293. }
  1294. // ------------------------------------------------------------------------
  1295. Bool Team::removeOverrideTeamRelationship( TeamID teamID )
  1296. {
  1297. if (!m_teamRelations->m_map.empty())
  1298. {
  1299. if (teamID == TEAM_ID_INVALID)
  1300. {
  1301. m_teamRelations->m_map.clear();
  1302. return true;
  1303. }
  1304. else
  1305. {
  1306. TeamRelationMapType::iterator it = m_teamRelations->m_map.find(teamID);
  1307. if (it != m_teamRelations->m_map.end())
  1308. {
  1309. m_teamRelations->m_map.erase(it);
  1310. return true;
  1311. }
  1312. }
  1313. }
  1314. return false;
  1315. }
  1316. // ------------------------------------------------------------------------
  1317. void Team::setOverridePlayerRelationship( Int playerIndex, Relationship r )
  1318. {
  1319. if (playerIndex != PLAYER_INDEX_INVALID)
  1320. {
  1321. // note that this creates the entry if it doesn't exist.
  1322. m_playerRelations->m_map[playerIndex] = r;
  1323. }
  1324. }
  1325. // ------------------------------------------------------------------------
  1326. Bool Team::removeOverridePlayerRelationship( Int playerIndex )
  1327. {
  1328. if (!m_playerRelations->m_map.empty())
  1329. {
  1330. if (playerIndex == PLAYER_INDEX_INVALID)
  1331. {
  1332. m_playerRelations->m_map.clear();
  1333. return true;
  1334. }
  1335. else
  1336. {
  1337. PlayerRelationMapType::iterator it = m_playerRelations->m_map.find(playerIndex);
  1338. if (it != m_playerRelations->m_map.end())
  1339. {
  1340. m_playerRelations->m_map.erase(it);
  1341. return true;
  1342. }
  1343. }
  1344. }
  1345. return false;
  1346. }
  1347. // ------------------------------------------------------------------------
  1348. void Team::countObjectsByThingTemplate(Int numTmplates, const ThingTemplate* const* things, Bool ignoreDead, Int *counts, Bool ignoreUnderConstruction) const
  1349. {
  1350. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1351. {
  1352. const ThingTemplate *objtmpl = iter.cur()->getTemplate();
  1353. for (Int i = 0; i < numTmplates; ++i)
  1354. {
  1355. //Kris: Compare
  1356. if( !objtmpl->isEquivalentTo( things[i] ) )
  1357. {
  1358. continue;
  1359. }
  1360. if (ignoreDead && iter.cur()->isEffectivelyDead())
  1361. continue;
  1362. if( ignoreUnderConstruction && (BitTest(iter.cur()->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION) == TRUE) )
  1363. continue;
  1364. counts[i] += 1;
  1365. break; // from 'next i', NOT 'next object'
  1366. }
  1367. }
  1368. }
  1369. // ------------------------------------------------------------------------
  1370. Int Team::countBuildings(void)
  1371. {
  1372. int retVal = 0;
  1373. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  1374. const ThingTemplate* objtmpl = iter.cur()->getTemplate();
  1375. if (!objtmpl) {
  1376. continue;
  1377. }
  1378. if (objtmpl->isKindOf(KINDOF_STRUCTURE)) {
  1379. ++retVal;
  1380. }
  1381. }
  1382. return retVal;
  1383. }
  1384. // ------------------------------------------------------------------------
  1385. Int Team::countObjects(KindOfMaskType setMask, KindOfMaskType clearMask)
  1386. {
  1387. int retVal = 0;
  1388. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  1389. const ThingTemplate* objtmpl = iter.cur()->getTemplate();
  1390. if (!objtmpl) {
  1391. continue;
  1392. }
  1393. if (objtmpl->isKindOfMulti(setMask, clearMask)) {
  1394. ++retVal;
  1395. }
  1396. }
  1397. return retVal;
  1398. }
  1399. // ------------------------------------------------------------------------
  1400. void Team::healAllObjects(void)
  1401. {
  1402. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1403. {
  1404. iter.cur()->healCompletely();
  1405. }
  1406. }
  1407. // ------------------------------------------------------------------------
  1408. void Team::iterateObjects( ObjectIterateFunc func, void *userData )
  1409. {
  1410. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1411. {
  1412. func( iter.cur(), userData );
  1413. }
  1414. }
  1415. // ------------------------------------------------------------------------
  1416. Bool Team::hasAnyBuildings() const
  1417. {
  1418. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1419. {
  1420. if (iter.cur()->isEffectivelyDead())
  1421. continue;
  1422. if (iter.cur()->isDestroyed())
  1423. continue;
  1424. if (iter.cur()->isKindOf(KINDOF_STRUCTURE))
  1425. return true;
  1426. }
  1427. return false;
  1428. }
  1429. // ------------------------------------------------------------------------
  1430. Bool Team::hasAnyBuildings(KindOfMaskType kindOf) const
  1431. {
  1432. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1433. {
  1434. if (iter.cur()->isEffectivelyDead())
  1435. continue;
  1436. if (iter.cur()->isDestroyed())
  1437. continue;
  1438. kindOf.set(KINDOF_STRUCTURE);
  1439. if (iter.cur()->isKindOfMulti(kindOf, KINDOFMASK_NONE))
  1440. return true;
  1441. }
  1442. return false;
  1443. }
  1444. // ------------------------------------------------------------------------
  1445. Bool Team::hasAnyUnits() const
  1446. {
  1447. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1448. {
  1449. if (iter.cur()->isEffectivelyDead())
  1450. continue;
  1451. if (iter.cur()->isDestroyed())
  1452. continue;
  1453. // If it's a structure, it's not a unit.
  1454. if (iter.cur()->isKindOf(KINDOF_STRUCTURE)) continue;
  1455. // If it's a projectile, it's not a unit.
  1456. if (iter.cur()->isKindOf(KINDOF_PROJECTILE)) continue;
  1457. // If it's a mine, it's not a unit.
  1458. if (iter.cur()->isKindOf(KINDOF_MINE)) continue;
  1459. return true;
  1460. }
  1461. return false;
  1462. }
  1463. // ------------------------------------------------------------------------
  1464. Bool Team::isIdle() const
  1465. {
  1466. Bool idle = true; // assume idle.
  1467. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1468. {
  1469. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1470. if (!ai) continue; // Non-ai things are idle.
  1471. if (iter.cur()->isEffectivelyDead())
  1472. continue;
  1473. if (!ai->isIdle())
  1474. {
  1475. idle = false;
  1476. break;
  1477. }
  1478. }
  1479. return idle;
  1480. }
  1481. // ------------------------------------------------------------------------
  1482. Bool Team::hasAnyObjects() const
  1483. {
  1484. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1485. {
  1486. if (iter.cur()->isEffectivelyDead())
  1487. continue;
  1488. if (iter.cur()->isDestroyed())
  1489. continue;
  1490. if (iter.cur()->isKindOf(KINDOF_PROJECTILE)) {
  1491. continue; // shell & missiles don't count. jba.
  1492. }
  1493. if (iter.cur()->isKindOf(KINDOF_INERT)) {
  1494. // inert stuff doesn't count. This is for radiation fields, which are living
  1495. // so they can be attacked by ambulances.
  1496. continue;
  1497. }
  1498. if (iter.cur()->isKindOf(KINDOF_MINE)) {
  1499. // Mines don't count.
  1500. continue;
  1501. }
  1502. return true;
  1503. }
  1504. return false;
  1505. }
  1506. // ------------------------------------------------------------------------
  1507. /** Clears m_enteredExited, checks & clears m_created. */
  1508. void Team::updateState(void)
  1509. {
  1510. m_enteredOrExited = false;
  1511. if (!m_active) {
  1512. return;
  1513. }
  1514. const TeamTemplateInfo *pInfo = m_proto->getTemplateInfo();
  1515. if (m_created)
  1516. {
  1517. m_created = false;
  1518. // Run the on create script, if any.
  1519. if (!pInfo->m_scriptOnCreate.isEmpty())
  1520. {
  1521. TheScriptEngine->runScript(pInfo->m_scriptOnCreate, this);
  1522. }
  1523. // Set up info for the onDestroyed script, if needed.
  1524. if (!pInfo->m_scriptOnDestroyed.isEmpty() )
  1525. {
  1526. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1527. {
  1528. m_curUnits++;
  1529. }
  1530. m_destroyThreshold = m_curUnits - (m_curUnits * pInfo->m_destroyedThreshold);
  1531. if (m_destroyThreshold>m_curUnits-1) m_destroyThreshold = m_curUnits-1;
  1532. if (m_destroyThreshold<0) m_destroyThreshold = 0;
  1533. }
  1534. }
  1535. // Do enemy sighted/on clear checks.
  1536. if (m_checkEnemySighted) {
  1537. m_prevSeeEnemy = m_seeEnemy;
  1538. m_seeEnemy = false;
  1539. Bool anyAliveInTeam = false; // If we're all dead, don't do all clear.
  1540. // only consider enemies.
  1541. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1542. {
  1543. if (iter.cur()->isEffectivelyDead())
  1544. continue;
  1545. PartitionFilterRelationship filterTeam(iter.cur(), PartitionFilterRelationship::ALLOW_ENEMIES);
  1546. // and only stuff that is not dead
  1547. PartitionFilterAlive filterAlive;
  1548. PartitionFilterSameMapStatus filterMapStatus(iter.cur());
  1549. PartitionFilter *filters[] = { &filterTeam, &filterAlive, &filterMapStatus, NULL };
  1550. Real visionRange = iter.cur()->getVisionRange();
  1551. anyAliveInTeam = true;
  1552. Object *pObj = ThePartitionManager->getClosestObject( iter.cur(), visionRange,
  1553. FROM_CENTER_2D, filters );
  1554. if (pObj) {
  1555. m_seeEnemy = true;
  1556. break;
  1557. }
  1558. }
  1559. if (anyAliveInTeam) {
  1560. if (m_prevSeeEnemy != m_seeEnemy)
  1561. {
  1562. if (m_seeEnemy)
  1563. {
  1564. // fire onEnemySighted
  1565. TheScriptEngine->runScript(pInfo->m_scriptOnEnemySighted, this);
  1566. } else {
  1567. // fire on all clear.
  1568. TheScriptEngine->runScript(pInfo->m_scriptOnAllClear, this);
  1569. }
  1570. }
  1571. }
  1572. }
  1573. // Do onDestroyed checks.
  1574. if (!pInfo->m_scriptOnDestroyed.isEmpty())
  1575. {
  1576. Int prevUnits = m_curUnits;
  1577. m_curUnits = 0;
  1578. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1579. {
  1580. if (iter.cur()->isEffectivelyDead())
  1581. continue;
  1582. m_curUnits++;
  1583. }
  1584. if (m_curUnits != prevUnits && m_curUnits <= m_destroyThreshold)
  1585. {
  1586. TheScriptEngine->runScript(pInfo->m_scriptOnDestroyed, this);
  1587. m_destroyThreshold = -1; // don't trigger again.
  1588. }
  1589. }
  1590. // Do onIdle checks.
  1591. if (!pInfo->m_scriptOnIdle.isEmpty())
  1592. {
  1593. Bool isIdle = true;
  1594. Bool anyAliveInTeam = false; // If we're all dead, don't do all clear.
  1595. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1596. {
  1597. if (iter.cur()->isEffectivelyDead()) {
  1598. continue;
  1599. }
  1600. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1601. if (!ai) continue;
  1602. anyAliveInTeam = true;
  1603. if (!ai->isIdle()) {
  1604. isIdle = false;
  1605. }
  1606. }
  1607. if (anyAliveInTeam && isIdle && m_wasIdle)
  1608. {
  1609. TheScriptEngine->runScript(pInfo->m_scriptOnIdle, this);
  1610. }
  1611. m_wasIdle = isIdle;
  1612. }
  1613. }
  1614. // ------------------------------------------------------------------------
  1615. void Team::notifyTeamOfObjectDeath( void )
  1616. {
  1617. const TeamTemplateInfo *pInfo = m_proto->getTemplateInfo();
  1618. if (!pInfo) {
  1619. return;
  1620. }
  1621. if (pInfo->m_scriptOnUnitDestroyed.isEmpty()) {
  1622. return;
  1623. }
  1624. TheScriptEngine->runScript(pInfo->m_scriptOnUnitDestroyed, this);
  1625. }
  1626. // ------------------------------------------------------------------------
  1627. Bool Team::didAllEnter(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1628. {
  1629. // If any units entered or exited, they set this flag.
  1630. if (!m_enteredOrExited) return false;
  1631. Bool anyConsidered = false;
  1632. Bool entered = false;
  1633. Bool outside = false;
  1634. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1635. {
  1636. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1637. if (ai) {
  1638. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1639. {
  1640. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1641. continue;
  1642. }
  1643. }
  1644. } else {
  1645. // things without ai should consider themselves ground units
  1646. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1647. continue;
  1648. }
  1649. }
  1650. if (iter.cur()->isEffectivelyDead())
  1651. continue;
  1652. if (iter.cur()->isKindOf(KINDOF_INERT))
  1653. continue;
  1654. if (iter.cur()->didEnter(pTrigger)) {
  1655. entered = true;
  1656. } else {
  1657. if (!iter.cur()->isInside(pTrigger)) {
  1658. outside = true;
  1659. }
  1660. }
  1661. // We need this in order to prevent this from returning a false positive
  1662. anyConsidered = true;
  1663. }
  1664. return entered && !outside;
  1665. }
  1666. // ------------------------------------------------------------------------
  1667. Bool Team::didPartialEnter(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1668. {
  1669. // If any units entered or exited, they set this flag.
  1670. if (!m_enteredOrExited) return false;
  1671. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1672. {
  1673. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1674. if (ai) {
  1675. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1676. {
  1677. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1678. continue;
  1679. }
  1680. }
  1681. } else {
  1682. // things without ai should consider themselves ground units
  1683. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1684. continue;
  1685. }
  1686. }
  1687. if (iter.cur()->isEffectivelyDead())
  1688. continue;
  1689. if (iter.cur()->isKindOf(KINDOF_INERT))
  1690. continue;
  1691. if (iter.cur()->didEnter(pTrigger)) {
  1692. return true;
  1693. }
  1694. }
  1695. return false;
  1696. }
  1697. // ------------------------------------------------------------------------
  1698. Bool Team::didPartialExit(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1699. {
  1700. // If any units entered or exited, they set this flag.
  1701. if (!m_enteredOrExited) return false;
  1702. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1703. {
  1704. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1705. if (ai) {
  1706. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1707. {
  1708. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1709. continue;
  1710. }
  1711. }
  1712. } else {
  1713. // things without ai should consider themselves ground units
  1714. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1715. continue;
  1716. }
  1717. }
  1718. if (iter.cur()->isEffectivelyDead())
  1719. continue;
  1720. if (iter.cur()->isKindOf(KINDOF_INERT))
  1721. continue;
  1722. if (iter.cur()->didExit(pTrigger)) {
  1723. return true;
  1724. }
  1725. }
  1726. return false;
  1727. }
  1728. // ------------------------------------------------------------------------
  1729. Bool Team::didAllExit(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1730. {
  1731. // If any units entered or exited, they set this flag.
  1732. if (!m_enteredOrExited)
  1733. return false;
  1734. Bool anyConsidered = false;
  1735. Bool exited = false;
  1736. Bool inside = false;
  1737. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1738. {
  1739. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1740. if (ai) {
  1741. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1742. {
  1743. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1744. continue;
  1745. }
  1746. }
  1747. } else {
  1748. // things without ai should consider themselves ground units
  1749. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1750. continue;
  1751. }
  1752. }
  1753. if (iter.cur()->isEffectivelyDead())
  1754. continue;
  1755. if (iter.cur()->isKindOf(KINDOF_INERT))
  1756. continue;
  1757. if (iter.cur()->didExit(pTrigger)) {
  1758. exited = true;
  1759. } else {
  1760. if (iter.cur()->isInside(pTrigger)) {
  1761. inside = true;
  1762. }
  1763. }
  1764. // We need this in order to prevent this from returning a false positive
  1765. anyConsidered = true;
  1766. }
  1767. return anyConsidered && exited && !inside;
  1768. }
  1769. // ------------------------------------------------------------------------
  1770. Bool Team::allInside(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1771. {
  1772. // empty teams are not inside.
  1773. if (!hasAnyObjects()) {
  1774. return false;
  1775. }
  1776. Bool anyConsidered = false;
  1777. Bool anyOutside = false;
  1778. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1779. {
  1780. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1781. if (ai) {
  1782. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1783. {
  1784. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1785. continue;
  1786. }
  1787. }
  1788. } else {
  1789. // things without ai should consider themselves ground units
  1790. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1791. continue;
  1792. }
  1793. }
  1794. if (iter.cur()->isEffectivelyDead()) {
  1795. continue;
  1796. }
  1797. if (iter.cur()->isKindOf(KINDOF_INERT))
  1798. continue;
  1799. if (!iter.cur()->isInside(pTrigger)) {
  1800. anyOutside = true;
  1801. }
  1802. // We need this in order to prevent this from returning a false positive
  1803. anyConsidered = true;
  1804. }
  1805. return anyConsidered && !anyOutside;
  1806. }
  1807. // ------------------------------------------------------------------------
  1808. Bool Team::noneInside(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1809. {
  1810. Bool anyConsidered = false;
  1811. Bool anyInside = false;
  1812. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1813. {
  1814. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1815. if (ai) {
  1816. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1817. {
  1818. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1819. continue;
  1820. }
  1821. }
  1822. } else {
  1823. // things without ai should consider themselves ground units
  1824. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1825. continue;
  1826. }
  1827. }
  1828. // don't consider dead things.
  1829. if (iter.cur()->isEffectivelyDead()) {
  1830. continue;
  1831. }
  1832. if (iter.cur()->isKindOf(KINDOF_INERT))
  1833. continue;
  1834. if (iter.cur()->isInside(pTrigger)) {
  1835. anyInside = true;
  1836. }
  1837. // We need this in order to prevent this from returning a false positive
  1838. anyConsidered = true;
  1839. }
  1840. return anyConsidered && !anyInside;
  1841. }
  1842. // ------------------------------------------------------------------------
  1843. Bool Team::someInsideSomeOutside(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1844. {
  1845. Bool anyConsidered = false;
  1846. Bool anyInside = false;
  1847. Bool anyOutside = false;
  1848. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1849. {
  1850. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1851. if (ai) {
  1852. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1853. {
  1854. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1855. continue;
  1856. }
  1857. }
  1858. } else {
  1859. // things without ai should consider themselves ground units
  1860. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1861. continue;
  1862. }
  1863. }
  1864. // don't consider dead things.
  1865. if (iter.cur()->isEffectivelyDead()) {
  1866. continue;
  1867. }
  1868. if (iter.cur()->isKindOf(KINDOF_INERT))
  1869. continue;
  1870. if (iter.cur()->isInside(pTrigger)) {
  1871. anyInside = true;
  1872. } else {
  1873. anyOutside = true;
  1874. }
  1875. // In this particular case, this is unnecessary. However, unless it is a performance hit, please
  1876. // leave it.
  1877. anyConsidered = true;
  1878. }
  1879. return anyConsidered && anyInside && anyOutside;
  1880. }
  1881. const Coord3D* Team::getEstimateTeamPosition(void)
  1882. {
  1883. // this doesn't actually calculate the team position, but rather estimates it by
  1884. // returning the position of the first member of the team
  1885. DLINK_ITERATOR<Object> iter = iterate_TeamMemberList();
  1886. Object *obj = iter.cur();
  1887. if (!obj)
  1888. return NULL;
  1889. const Coord3D *pos = iter.cur()->getPosition();
  1890. if (!pos)
  1891. return NULL;
  1892. return pos;
  1893. }
  1894. // ------------------------------------------------------------------------
  1895. void Team::deleteTeam(Bool ignoreDead)
  1896. {
  1897. // First off, if this Team is the Player's default team, we need to Evacuate everyone or else
  1898. // Garrisoned buildings will fall victim to this deletion as well, since they were added to the
  1899. // Default when captured. Design intends with this script to kill the people out from inside.
  1900. // If the thing is a transport, everything will still work, as the issue at hand is the container's
  1901. // wanting to change sides when emptied. The bug is that the people in the Garrisoned building
  1902. // are deleted, and that changes the Team of the building, and then the DLink walks down the new team
  1903. // and deletes the wrong stuff. Like every tree and civialian building on the map.
  1904. // Of course, to prevent the exact same DLINK jumping bug, I must first record what guys I am going to
  1905. // Evacuate, or else after the first occupied building is emptied, he will move his Next into the
  1906. // same damn wrong team.
  1907. if( this == getControllingPlayer()->getDefaultTeam() )
  1908. {
  1909. std::list<Object *> guysToMakeEvacuate;
  1910. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1911. {
  1912. Object *obj = iter.cur();
  1913. if (!obj)
  1914. continue;
  1915. if( obj->getContain() && (obj->getContain()->getContainCount() > 0) )
  1916. {
  1917. // Write them all down, so the DLINK track jumping doesn't screw me up here as well.
  1918. guysToMakeEvacuate.push_back( obj );
  1919. }
  1920. }
  1921. for( std::list<Object *>::iterator it = guysToMakeEvacuate.begin(); it != guysToMakeEvacuate.end(); /*nothing*/ )
  1922. {
  1923. Object *obj = *it;
  1924. it++;
  1925. if( obj->getContain() )
  1926. {
  1927. obj->getContain()->removeAllContained();
  1928. }
  1929. }
  1930. }
  1931. // this doesn't actually delete the team, it deletes the members of the team.
  1932. // the team itself will be deleted in updateState.
  1933. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1934. {
  1935. Object *obj = iter.cur();
  1936. if (!obj) {
  1937. continue;
  1938. }
  1939. // The reason the comment says the team will be deleted is because it will see that it is empty.
  1940. // So yes, the Team will survive for a while, but it was going to anyway. This is a script flag, so if
  1941. // they use it on a team with things that can't die, then yeah, the Team will last forever. But then it is
  1942. // user error.
  1943. if( ignoreDead && obj->isEffectivelyDead() )
  1944. continue;
  1945. TheGameLogic->destroyObject(obj);
  1946. }
  1947. }
  1948. // ------------------------------------------------------------------------
  1949. /* Transfer our units to new team. */
  1950. void Team::transferUnitsTo(Team *newTeam)
  1951. {
  1952. if (this == newTeam) return;
  1953. if (newTeam == NULL) return;
  1954. Object *obj;
  1955. while ((obj = getFirstItemIn_TeamMemberList()) != 0)
  1956. {
  1957. obj->setTeam(newTeam);
  1958. }
  1959. }
  1960. // ------------------------------------------------------------------------
  1961. static Bool isInBuildVariations(const ThingTemplate* ttWithVariations, const ThingTemplate* b)
  1962. {
  1963. const std::vector<AsciiString>& bv = ttWithVariations->getBuildVariations();
  1964. if (bv.empty())
  1965. return false;
  1966. for (std::vector<AsciiString>::const_iterator it = bv.begin(); it != bv.end(); ++it)
  1967. {
  1968. if (b->getName() == *it)
  1969. return true;
  1970. }
  1971. return false;
  1972. }
  1973. // ------------------------------------------------------------------------
  1974. /* Try to recruit a unit from other teams of this player. */
  1975. Object *Team::tryToRecruit(const ThingTemplate *tTemplate, const Coord3D *teamHome, Real maxDist)
  1976. {
  1977. Player *myPlayer = getControllingPlayer();
  1978. Object *obj=NULL;
  1979. Real distSqr = maxDist*maxDist;
  1980. Object *recruit = NULL;
  1981. for( obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() )
  1982. {
  1983. if (!obj->getTemplate()->isEquivalentTo(tTemplate))
  1984. {
  1985. // it might be ok, if tTemplate is really just a "build-variations" template...
  1986. if (!isInBuildVariations(tTemplate, obj->getTemplate()))
  1987. continue;
  1988. }
  1989. if (obj->getControllingPlayer() != myPlayer)
  1990. continue;
  1991. Team *team = obj->getTeam();
  1992. Bool isDefaultTeam = false;
  1993. if (team == myPlayer->getDefaultTeam()) {
  1994. isDefaultTeam = true;
  1995. }
  1996. if (!team->isActive()) {
  1997. continue; // Team is building, so don't steal it's members yet.
  1998. }
  1999. if (team->getPrototype()->getTemplateInfo()->m_productionPriority>=getPrototype()->getTemplateInfo()->m_productionPriority) {
  2000. continue;
  2001. }
  2002. Bool teamIsRecruitable = isDefaultTeam; // Default team always recruitable.
  2003. if (team->getPrototype()->getTemplateInfo()->m_isAIRecruitable) {
  2004. teamIsRecruitable = true;
  2005. }
  2006. // Check & see if individual team has been marked for recruitability.
  2007. if (team->m_isRecruitablitySet) {
  2008. teamIsRecruitable = team->m_isRecruitable;
  2009. }
  2010. if (!teamIsRecruitable) {
  2011. continue;
  2012. }
  2013. if (obj->getAIUpdateInterface() && !obj->getAIUpdateInterface()->isRecruitable()) {
  2014. continue; // can't recruit this unit.
  2015. }
  2016. if( obj->isDisabledByType( DISABLED_HELD ) )
  2017. {
  2018. continue; // Don't recruit held units.
  2019. }
  2020. Real dx, dy;
  2021. dx = teamHome->x - obj->getPosition()->x;
  2022. dy = teamHome->y - obj->getPosition()->y;
  2023. if (isDefaultTeam && recruit == NULL) {
  2024. recruit = obj;
  2025. distSqr = dx*dx+dy*dy;
  2026. }
  2027. if (dx*dx+dy*dy > distSqr) {
  2028. continue;
  2029. }
  2030. distSqr = dx*dx+dy*dy;
  2031. recruit = obj;
  2032. }
  2033. if (recruit!=NULL) {
  2034. return recruit;
  2035. }
  2036. return NULL;
  2037. }
  2038. // ------------------------------------------------------------------------
  2039. void Team::evacuateTeam(void)
  2040. {
  2041. std::list<Object *> objectsToProcess;
  2042. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  2043. Object *obj = iter.cur();
  2044. if (!obj || obj->isDestroyed() || obj->isEffectivelyDead()) {
  2045. continue;
  2046. }
  2047. ContainModuleInterface *cmi = obj->getContain();
  2048. UnsignedInt numContained = 0;
  2049. if (cmi != NULL) {
  2050. numContained = cmi->getContainCount();
  2051. }
  2052. if (numContained > 0) {
  2053. objectsToProcess.push_back(obj);
  2054. }
  2055. }
  2056. // evacuate any containers
  2057. std::list<Object *>::iterator objIt;
  2058. for (objIt = objectsToProcess.begin(); objIt != objectsToProcess.end(); ++objIt)
  2059. {
  2060. Object *obj = *objIt;
  2061. ContainModuleInterface *cmi = obj->getContain();
  2062. if (cmi)
  2063. {
  2064. cmi->removeAllContained();
  2065. }
  2066. }
  2067. objectsToProcess.clear();
  2068. }
  2069. // ------------------------------------------------------------------------
  2070. void Team::killTeam(void)
  2071. {
  2072. std::list<Object *> objectsToProcess;
  2073. evacuateTeam();
  2074. // beacons are effectively dead, so we need to destroy via a non-kill() method
  2075. const ThingTemplate *beaconTemplate = TheThingFactory->findTemplate( getControllingPlayer()->getPlayerTemplate()->getBeaconTemplate() );
  2076. // now find objects to kill
  2077. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  2078. Object *obj = iter.cur();
  2079. if (!obj || obj->isDestroyed() || (obj->isEffectivelyDead() && !obj->getTemplate()->isEquivalentTo(beaconTemplate)))
  2080. {
  2081. continue;
  2082. }
  2083. Team *objTeam = obj->getTeam();
  2084. // the object's team could change after having all the passengers get out.
  2085. if (objTeam == this) {
  2086. objectsToProcess.push_back(obj);
  2087. }
  2088. }
  2089. // and finally, kill things
  2090. std::list<Object *>::iterator objIt;
  2091. for (objIt = objectsToProcess.begin(); objIt != objectsToProcess.end(); ++objIt)
  2092. {
  2093. Object *obj = *objIt;
  2094. if (obj->isKindOf(KINDOF_TECH_BUILDING))
  2095. obj->setTeam(ThePlayerList->getNeutralPlayer()->getDefaultTeam());
  2096. else
  2097. obj->kill();
  2098. }
  2099. objectsToProcess.clear();
  2100. }
  2101. // ------------------------------------------------------------------------
  2102. Bool Team::damageTeamMembers(Real amount)
  2103. {
  2104. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  2105. {
  2106. if (iter.cur()->isEffectivelyDead())
  2107. continue;
  2108. if (iter.cur()->isDestroyed())
  2109. continue;
  2110. // do max amount of damage to object
  2111. if (amount < 0.0) {
  2112. iter.cur()->kill();
  2113. } else {
  2114. DamageInfo damageInfo;
  2115. damageInfo.in.m_damageType = DAMAGE_UNRESISTABLE;
  2116. damageInfo.in.m_deathType = DEATH_NORMAL;
  2117. damageInfo.in.m_sourceID = INVALID_ID;
  2118. damageInfo.in.m_amount = amount;
  2119. iter.cur()->attemptDamage( &damageInfo );
  2120. }
  2121. }
  2122. return false;
  2123. }
  2124. // ------------------------------------------------------------------------
  2125. /// @todo This should give a "team move" command, not individual move orders (MSB)
  2126. void Team::moveTeamTo(Coord3D destination)
  2127. {
  2128. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  2129. {
  2130. if (iter.cur()->isEffectivelyDead())
  2131. continue;
  2132. if (iter.cur()->isDestroyed())
  2133. continue;
  2134. }
  2135. }
  2136. // ------------------------------------------------------------------------
  2137. Bool Team::hasAnyBuildFacility() const
  2138. {
  2139. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  2140. {
  2141. const ThingTemplate *objtmpl = iter.cur()->getTemplate();
  2142. if (objtmpl->isBuildFacility())
  2143. return true;
  2144. }
  2145. return false;
  2146. }
  2147. // ------------------------------------------------------------------------
  2148. //DECLARE_PERF_TIMER(updateGenericScripts)
  2149. void Team::updateGenericScripts(void)
  2150. {
  2151. //USE_PERF_TIMER(updateGenericScripts)
  2152. for (Int i = 0; i < MAX_GENERIC_SCRIPTS; ++i) {
  2153. if (m_shouldAttemptGenericScript[i]) {
  2154. // Does the condition succeed? If so, run it. If it is a run once script, also mark that we
  2155. // shouldn't run it again.
  2156. Script *script = m_proto->getGenericScript(i);
  2157. if (script) {
  2158. if (TheScriptEngine->evaluateConditions(script, this)) {
  2159. // It was successful.
  2160. if (script->isOneShot()) {
  2161. m_shouldAttemptGenericScript[i] = false;
  2162. }
  2163. TheScriptEngine->friend_executeAction(script->getAction(), this);
  2164. AsciiString msg = "Generic script '";
  2165. msg.concat(script->getName());
  2166. msg.concat("' run on team ");
  2167. msg.concat(getName());
  2168. TheScriptEngine->AppendDebugMessage(msg, false);
  2169. }
  2170. } else {
  2171. m_shouldAttemptGenericScript[i] = false;
  2172. }
  2173. }
  2174. }
  2175. }
  2176. // ------------------------------------------------------------------------------------------------
  2177. /** CRC */
  2178. // ------------------------------------------------------------------------------------------------
  2179. void Team::crc( Xfer *xfer )
  2180. {
  2181. } // end crc
  2182. // ------------------------------------------------------------------------------------------------
  2183. /** Xfer Method
  2184. * Version Info:
  2185. * 1: Initial version */
  2186. // ------------------------------------------------------------------------------------------------
  2187. void Team::xfer( Xfer *xfer )
  2188. {
  2189. // version
  2190. XferVersion currentVersion = 1;
  2191. XferVersion version = currentVersion;
  2192. xfer->xferVersion( &version, currentVersion );
  2193. // xfer id, this is a sanity check as team id m_id should always be valid at this point
  2194. TeamID teamID = m_id;
  2195. xfer->xferUser( &teamID, sizeof( TeamID ) );
  2196. if( teamID != m_id )
  2197. {
  2198. DEBUG_CRASH(( "Team::xfer - TeamID mismatch. Xfered '%d' but should be '%d'\n",
  2199. teamID, m_id ));
  2200. throw SC_INVALID_DATA;
  2201. } // end if
  2202. // member list count and data
  2203. ObjectID memberID;
  2204. UnsignedShort memberCount = 0;
  2205. for( DLINK_ITERATOR< Object > objIt = iterate_TeamMemberList();
  2206. objIt.done() == FALSE;
  2207. objIt.advance() )
  2208. memberCount++;
  2209. xfer->xferUnsignedShort( &memberCount );
  2210. if( xfer->getXferMode() == XFER_SAVE )
  2211. {
  2212. Object *obj;
  2213. // save all member info
  2214. for( DLINK_ITERATOR< Object > objIt = iterate_TeamMemberList();
  2215. objIt.done() == FALSE;
  2216. objIt.advance() )
  2217. {
  2218. // get object
  2219. obj = objIt.cur();
  2220. // save id
  2221. memberID = obj->getID();
  2222. xfer->xferObjectID( &memberID );
  2223. } // end for
  2224. } // end if, save
  2225. else
  2226. {
  2227. // load all members
  2228. for( UnsignedShort i = 0; i < memberCount; ++i )
  2229. {
  2230. // read ID
  2231. xfer->xferObjectID( &memberID );
  2232. // put on pending list for later processing
  2233. m_xferMemberIDList.push_back( memberID );
  2234. } // end for, i
  2235. } // end else, load
  2236. // state
  2237. xfer->xferAsciiString( &m_state );
  2238. // entered or exited
  2239. xfer->xferBool( &m_enteredOrExited );
  2240. // active status
  2241. xfer->xferBool( &m_active );
  2242. // created flag
  2243. xfer->xferBool( &m_created );
  2244. // check enemy sighted
  2245. xfer->xferBool( &m_checkEnemySighted );
  2246. // see enemy
  2247. xfer->xferBool( &m_seeEnemy );
  2248. // previous see enemy
  2249. xfer->xferBool( &m_prevSeeEnemy );
  2250. // was idle
  2251. xfer->xferBool( &m_wasIdle );
  2252. // destroy threshold
  2253. xfer->xferInt( &m_destroyThreshold );
  2254. // current units
  2255. xfer->xferInt( &m_curUnits );
  2256. // waypoint
  2257. UnsignedInt currentWaypointID = m_currentWaypoint ? m_currentWaypoint->getID() : 0;
  2258. xfer->xferUnsignedInt( &currentWaypointID );
  2259. if( xfer->getXferMode() == XFER_LOAD )
  2260. m_currentWaypoint = TheTerrainLogic->getWaypointByID( currentWaypointID );
  2261. UnsignedShort shouldAttemptGenericScriptCount = MAX_GENERIC_SCRIPTS;
  2262. xfer->xferUnsignedShort( &shouldAttemptGenericScriptCount );
  2263. if ( shouldAttemptGenericScriptCount != MAX_GENERIC_SCRIPTS )
  2264. {
  2265. DEBUG_CRASH(("Team::xfer - The number of allowable Generic scripts has changed, and this chunk needs to be versioned."));
  2266. throw SC_INVALID_DATA;
  2267. }
  2268. for (Int i = 0; i < shouldAttemptGenericScriptCount; ++i)
  2269. xfer->xferBool(&m_shouldAttemptGenericScript[i]);
  2270. // recruitability set
  2271. xfer->xferBool( &m_isRecruitablitySet );
  2272. // is recruitable
  2273. xfer->xferBool( &m_isRecruitable );
  2274. // Common attack target.
  2275. xfer->xferObjectID( &m_commonAttackTarget );
  2276. // team relations
  2277. xfer->xferSnapshot( m_teamRelations );
  2278. // player relations
  2279. xfer->xferSnapshot( m_playerRelations );
  2280. } // ene xfer
  2281. // ------------------------------------------------------------------------------------------------
  2282. /** Load post process */
  2283. // ------------------------------------------------------------------------------------------------
  2284. void Team::loadPostProcess( void )
  2285. {
  2286. //
  2287. // now that all objects have actually been loaded, populate the member list with
  2288. // real object pointers
  2289. //
  2290. Object *obj;
  2291. std::list< ObjectID >::const_iterator it;
  2292. for( it = m_xferMemberIDList.begin(); it != m_xferMemberIDList.end(); ++it )
  2293. {
  2294. // find object
  2295. obj = TheGameLogic->findObjectByID( *it );
  2296. if( obj == NULL )
  2297. {
  2298. DEBUG_CRASH(( "Team::loadPostProcess - Unable to post process object to member list, object ID = '%d'\n", *it ));
  2299. throw SC_INVALID_DATA;
  2300. } // end if
  2301. //
  2302. // we are now disabling this code since the objects set their team during their
  2303. // own xfer function which will actually put it on the team ... however, we will sanity
  2304. // check everything here to make sure that all the objects that should be on the team,
  2305. // are in fact on the team
  2306. //
  2307. if( isInList_TeamMemberList( obj ) == FALSE )
  2308. {
  2309. DEBUG_CRASH(( "Team::loadPostProcess - Object '%s'(%d) should be in team list but is not\n",
  2310. obj->getTemplate()->getName().str(), obj->getID() ));
  2311. throw SC_INVALID_DATA;
  2312. } // end if
  2313. } // end for
  2314. // since we prepended the object member pointers, reverse that list so it's just like before
  2315. // reverse_TeamMemberList();
  2316. // we're done with the xfer list now
  2317. m_xferMemberIDList.clear();
  2318. } // end loadPostProcess
  2319. // ------------------------------------------------------------------------
  2320. // ------------------------------------------------------------------------
  2321. // ------------------------------------------------------------------------