Team.cpp 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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, ("TeamFactory::addTeamPrototypeToList: Team %s already exists... skipping.", team->getName().str()));
  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. if( target->testStatus( OBJECT_STATUS_STEALTHED ) &&
  1270. !target->testStatus( OBJECT_STATUS_DETECTED ) &&
  1271. !target->testStatus( OBJECT_STATUS_DISGUISED ) )
  1272. {
  1273. target = NULL;
  1274. }
  1275. }
  1276. if (target && target->isEffectivelyDead()) {
  1277. target = NULL;
  1278. }
  1279. if (target && target->getContainedBy()) {
  1280. target = NULL; // target entered a building or vehicle, so stop targeting.
  1281. }
  1282. if (target && target->isKindOf(KINDOF_AIRCRAFT)) {
  1283. // It is just generally bad to have an aircraft as the team target.
  1284. // Let team members acquire aircraft individually. jba. [8/27/2003]
  1285. target = NULL;
  1286. }
  1287. if (target == NULL) {
  1288. m_commonAttackTarget = INVALID_ID;
  1289. }
  1290. return target;
  1291. }
  1292. // ------------------------------------------------------------------------
  1293. void Team::setOverrideTeamRelationship( TeamID teamID, Relationship r)
  1294. {
  1295. if (teamID != TEAM_ID_INVALID )
  1296. {
  1297. // note that this creates the entry if it doesn't exist.
  1298. m_teamRelations->m_map[teamID] = r;
  1299. }
  1300. }
  1301. // ------------------------------------------------------------------------
  1302. Bool Team::removeOverrideTeamRelationship( TeamID teamID )
  1303. {
  1304. if (!m_teamRelations->m_map.empty())
  1305. {
  1306. if (teamID == TEAM_ID_INVALID)
  1307. {
  1308. m_teamRelations->m_map.clear();
  1309. return true;
  1310. }
  1311. else
  1312. {
  1313. TeamRelationMapType::iterator it = m_teamRelations->m_map.find(teamID);
  1314. if (it != m_teamRelations->m_map.end())
  1315. {
  1316. m_teamRelations->m_map.erase(it);
  1317. return true;
  1318. }
  1319. }
  1320. }
  1321. return false;
  1322. }
  1323. // ------------------------------------------------------------------------
  1324. void Team::setOverridePlayerRelationship( Int playerIndex, Relationship r )
  1325. {
  1326. if (playerIndex != PLAYER_INDEX_INVALID)
  1327. {
  1328. // note that this creates the entry if it doesn't exist.
  1329. m_playerRelations->m_map[playerIndex] = r;
  1330. }
  1331. }
  1332. // ------------------------------------------------------------------------
  1333. Bool Team::removeOverridePlayerRelationship( Int playerIndex )
  1334. {
  1335. if (!m_playerRelations->m_map.empty())
  1336. {
  1337. if (playerIndex == PLAYER_INDEX_INVALID)
  1338. {
  1339. m_playerRelations->m_map.clear();
  1340. return true;
  1341. }
  1342. else
  1343. {
  1344. PlayerRelationMapType::iterator it = m_playerRelations->m_map.find(playerIndex);
  1345. if (it != m_playerRelations->m_map.end())
  1346. {
  1347. m_playerRelations->m_map.erase(it);
  1348. return true;
  1349. }
  1350. }
  1351. }
  1352. return false;
  1353. }
  1354. // ------------------------------------------------------------------------
  1355. void Team::countObjectsByThingTemplate(Int numTmplates, const ThingTemplate* const* things, Bool ignoreDead, Int *counts, Bool ignoreUnderConstruction) const
  1356. {
  1357. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1358. {
  1359. const ThingTemplate *objtmpl = iter.cur()->getTemplate();
  1360. for (Int i = 0; i < numTmplates; ++i)
  1361. {
  1362. //Kris: Compare
  1363. if( !objtmpl->isEquivalentTo( things[i] ) )
  1364. {
  1365. continue;
  1366. }
  1367. if (ignoreDead && iter.cur()->isEffectivelyDead())
  1368. continue;
  1369. if( ignoreUnderConstruction && iter.cur()->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  1370. continue;
  1371. counts[i] += 1;
  1372. break; // from 'next i', NOT 'next object'
  1373. }
  1374. }
  1375. }
  1376. // ------------------------------------------------------------------------
  1377. Int Team::countBuildings(void)
  1378. {
  1379. int retVal = 0;
  1380. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  1381. const ThingTemplate* objtmpl = iter.cur()->getTemplate();
  1382. if (!objtmpl) {
  1383. continue;
  1384. }
  1385. if (objtmpl->isKindOf(KINDOF_STRUCTURE)) {
  1386. ++retVal;
  1387. }
  1388. }
  1389. return retVal;
  1390. }
  1391. // ------------------------------------------------------------------------
  1392. Int Team::countObjects(KindOfMaskType setMask, KindOfMaskType clearMask)
  1393. {
  1394. int retVal = 0;
  1395. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  1396. const ThingTemplate* objtmpl = iter.cur()->getTemplate();
  1397. if (!objtmpl) {
  1398. continue;
  1399. }
  1400. if (objtmpl->isKindOfMulti(setMask, clearMask)) {
  1401. ++retVal;
  1402. }
  1403. }
  1404. return retVal;
  1405. }
  1406. // ------------------------------------------------------------------------
  1407. void Team::healAllObjects(void)
  1408. {
  1409. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1410. {
  1411. iter.cur()->healCompletely();
  1412. }
  1413. }
  1414. // ------------------------------------------------------------------------
  1415. void Team::iterateObjects( ObjectIterateFunc func, void *userData )
  1416. {
  1417. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1418. {
  1419. func( iter.cur(), userData );
  1420. }
  1421. }
  1422. // ------------------------------------------------------------------------
  1423. Bool Team::hasAnyBuildings() const
  1424. {
  1425. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1426. {
  1427. if (iter.cur()->isEffectivelyDead())
  1428. continue;
  1429. if (iter.cur()->isDestroyed())
  1430. continue;
  1431. if (iter.cur()->isKindOf(KINDOF_STRUCTURE))
  1432. return true;
  1433. }
  1434. return false;
  1435. }
  1436. // ------------------------------------------------------------------------
  1437. Bool Team::hasAnyBuildings(KindOfMaskType kindOf) const
  1438. {
  1439. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1440. {
  1441. if (iter.cur()->isEffectivelyDead())
  1442. continue;
  1443. if (iter.cur()->isDestroyed())
  1444. continue;
  1445. kindOf.set(KINDOF_STRUCTURE);
  1446. if (iter.cur()->isKindOfMulti(kindOf, KINDOFMASK_NONE))
  1447. return true;
  1448. }
  1449. return false;
  1450. }
  1451. // ------------------------------------------------------------------------
  1452. Bool Team::hasAnyUnits() const
  1453. {
  1454. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1455. {
  1456. if (iter.cur()->isEffectivelyDead())
  1457. continue;
  1458. if (iter.cur()->isDestroyed())
  1459. continue;
  1460. // If it's a structure, it's not a unit.
  1461. if (iter.cur()->isKindOf(KINDOF_STRUCTURE)) continue;
  1462. // If it's a projectile, it's not a unit.
  1463. if (iter.cur()->isKindOf(KINDOF_PROJECTILE)) continue;
  1464. // If it's a mine, it's not a unit.
  1465. if (iter.cur()->isKindOf(KINDOF_MINE)) continue;
  1466. return true;
  1467. }
  1468. return false;
  1469. }
  1470. // ------------------------------------------------------------------------
  1471. Bool Team::isIdle() const
  1472. {
  1473. Bool idle = true; // assume idle.
  1474. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1475. {
  1476. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1477. if (!ai) continue; // Non-ai things are idle.
  1478. if (iter.cur()->isEffectivelyDead())
  1479. continue;
  1480. if (!ai->isIdle())
  1481. {
  1482. idle = false;
  1483. break;
  1484. }
  1485. }
  1486. return idle;
  1487. }
  1488. // ------------------------------------------------------------------------
  1489. Bool Team::hasAnyObjects() const
  1490. {
  1491. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1492. {
  1493. if (iter.cur()->isEffectivelyDead())
  1494. continue;
  1495. if (iter.cur()->isDestroyed())
  1496. continue;
  1497. if (iter.cur()->isKindOf(KINDOF_PROJECTILE)) {
  1498. continue; // shell & missiles don't count. jba.
  1499. }
  1500. if (iter.cur()->isKindOf(KINDOF_INERT)) {
  1501. // inert stuff doesn't count. This is for radiation fields, which are living
  1502. // so they can be attacked by ambulances.
  1503. continue;
  1504. }
  1505. if (iter.cur()->isKindOf(KINDOF_MINE)) {
  1506. // Mines don't count.
  1507. continue;
  1508. }
  1509. return true;
  1510. }
  1511. return false;
  1512. }
  1513. // ------------------------------------------------------------------------
  1514. /** Clears m_enteredExited, checks & clears m_created. */
  1515. void Team::updateState(void)
  1516. {
  1517. m_enteredOrExited = false;
  1518. if (!m_active) {
  1519. return;
  1520. }
  1521. const TeamTemplateInfo *pInfo = m_proto->getTemplateInfo();
  1522. if (m_created)
  1523. {
  1524. m_created = false;
  1525. // Run the on create script, if any.
  1526. if (!pInfo->m_scriptOnCreate.isEmpty())
  1527. {
  1528. TheScriptEngine->runScript(pInfo->m_scriptOnCreate, this);
  1529. }
  1530. // Set up info for the onDestroyed script, if needed.
  1531. if (!pInfo->m_scriptOnDestroyed.isEmpty() )
  1532. {
  1533. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1534. {
  1535. m_curUnits++;
  1536. }
  1537. m_destroyThreshold = m_curUnits - (m_curUnits * pInfo->m_destroyedThreshold);
  1538. if (m_destroyThreshold>m_curUnits-1) m_destroyThreshold = m_curUnits-1;
  1539. if (m_destroyThreshold<0) m_destroyThreshold = 0;
  1540. }
  1541. }
  1542. // Do enemy sighted/on clear checks.
  1543. if (m_checkEnemySighted) {
  1544. m_prevSeeEnemy = m_seeEnemy;
  1545. m_seeEnemy = false;
  1546. Bool anyAliveInTeam = false; // If we're all dead, don't do all clear.
  1547. // only consider enemies.
  1548. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1549. {
  1550. if (iter.cur()->isEffectivelyDead())
  1551. continue;
  1552. PartitionFilterRelationship filterTeam(iter.cur(), PartitionFilterRelationship::ALLOW_ENEMIES);
  1553. // and only stuff that is not dead
  1554. PartitionFilterAlive filterAlive;
  1555. PartitionFilterSameMapStatus filterMapStatus(iter.cur());
  1556. PartitionFilter *filters[] = { &filterTeam, &filterAlive, &filterMapStatus, NULL };
  1557. Real visionRange = iter.cur()->getVisionRange();
  1558. anyAliveInTeam = true;
  1559. Object *pObj = ThePartitionManager->getClosestObject( iter.cur(), visionRange,
  1560. FROM_CENTER_2D, filters );
  1561. if (pObj) {
  1562. m_seeEnemy = true;
  1563. break;
  1564. }
  1565. }
  1566. if (anyAliveInTeam) {
  1567. if (m_prevSeeEnemy != m_seeEnemy)
  1568. {
  1569. if (m_seeEnemy)
  1570. {
  1571. // fire onEnemySighted
  1572. TheScriptEngine->runScript(pInfo->m_scriptOnEnemySighted, this);
  1573. } else {
  1574. // fire on all clear.
  1575. TheScriptEngine->runScript(pInfo->m_scriptOnAllClear, this);
  1576. }
  1577. }
  1578. }
  1579. }
  1580. // Do onDestroyed checks.
  1581. if (!pInfo->m_scriptOnDestroyed.isEmpty())
  1582. {
  1583. Int prevUnits = m_curUnits;
  1584. m_curUnits = 0;
  1585. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1586. {
  1587. if (iter.cur()->isEffectivelyDead())
  1588. continue;
  1589. m_curUnits++;
  1590. }
  1591. if (m_curUnits != prevUnits && m_curUnits <= m_destroyThreshold)
  1592. {
  1593. TheScriptEngine->runScript(pInfo->m_scriptOnDestroyed, this);
  1594. m_destroyThreshold = -1; // don't trigger again.
  1595. }
  1596. }
  1597. // Do onIdle checks.
  1598. if (!pInfo->m_scriptOnIdle.isEmpty())
  1599. {
  1600. Bool isIdle = true;
  1601. Bool anyAliveInTeam = false; // If we're all dead, don't do all clear.
  1602. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1603. {
  1604. if (iter.cur()->isEffectivelyDead()) {
  1605. continue;
  1606. }
  1607. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1608. if (!ai) continue;
  1609. anyAliveInTeam = true;
  1610. if (!ai->isIdle()) {
  1611. isIdle = false;
  1612. }
  1613. }
  1614. if (anyAliveInTeam && isIdle && m_wasIdle)
  1615. {
  1616. TheScriptEngine->runScript(pInfo->m_scriptOnIdle, this);
  1617. }
  1618. m_wasIdle = isIdle;
  1619. }
  1620. }
  1621. // ------------------------------------------------------------------------
  1622. void Team::notifyTeamOfObjectDeath( void )
  1623. {
  1624. const TeamTemplateInfo *pInfo = m_proto->getTemplateInfo();
  1625. if (!pInfo) {
  1626. return;
  1627. }
  1628. if (pInfo->m_scriptOnUnitDestroyed.isEmpty()) {
  1629. return;
  1630. }
  1631. TheScriptEngine->runScript(pInfo->m_scriptOnUnitDestroyed, this);
  1632. }
  1633. // ------------------------------------------------------------------------
  1634. Bool Team::didAllEnter(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1635. {
  1636. // If any units entered or exited, they set this flag.
  1637. if (!m_enteredOrExited) return false;
  1638. Bool anyConsidered = false;
  1639. Bool entered = false;
  1640. Bool outside = false;
  1641. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1642. {
  1643. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1644. if (ai) {
  1645. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1646. {
  1647. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1648. continue;
  1649. }
  1650. }
  1651. } else {
  1652. // things without ai should consider themselves ground units
  1653. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1654. continue;
  1655. }
  1656. }
  1657. if (iter.cur()->isEffectivelyDead())
  1658. continue;
  1659. if (iter.cur()->isKindOf(KINDOF_INERT))
  1660. continue;
  1661. if (iter.cur()->didEnter(pTrigger)) {
  1662. entered = true;
  1663. } else {
  1664. if (!iter.cur()->isInside(pTrigger)) {
  1665. outside = true;
  1666. }
  1667. }
  1668. // We need this in order to prevent this from returning a false positive
  1669. anyConsidered = true;
  1670. }
  1671. return entered && !outside;
  1672. }
  1673. // ------------------------------------------------------------------------
  1674. Bool Team::didPartialEnter(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1675. {
  1676. // If any units entered or exited, they set this flag.
  1677. if (!m_enteredOrExited) return false;
  1678. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1679. {
  1680. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1681. if (ai) {
  1682. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1683. {
  1684. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1685. continue;
  1686. }
  1687. }
  1688. } else {
  1689. // things without ai should consider themselves ground units
  1690. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1691. continue;
  1692. }
  1693. }
  1694. if (iter.cur()->isEffectivelyDead())
  1695. continue;
  1696. if (iter.cur()->isKindOf(KINDOF_INERT))
  1697. continue;
  1698. if (iter.cur()->didEnter(pTrigger)) {
  1699. return true;
  1700. }
  1701. }
  1702. return false;
  1703. }
  1704. // ------------------------------------------------------------------------
  1705. Bool Team::didPartialExit(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1706. {
  1707. // If any units entered or exited, they set this flag.
  1708. if (!m_enteredOrExited) return false;
  1709. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1710. {
  1711. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1712. if (ai) {
  1713. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1714. {
  1715. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1716. continue;
  1717. }
  1718. }
  1719. } else {
  1720. // things without ai should consider themselves ground units
  1721. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1722. continue;
  1723. }
  1724. }
  1725. if (iter.cur()->isEffectivelyDead())
  1726. continue;
  1727. if (iter.cur()->isKindOf(KINDOF_INERT))
  1728. continue;
  1729. if (iter.cur()->didExit(pTrigger)) {
  1730. return true;
  1731. }
  1732. }
  1733. return false;
  1734. }
  1735. // ------------------------------------------------------------------------
  1736. Bool Team::didAllExit(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1737. {
  1738. // If any units entered or exited, they set this flag.
  1739. if (!m_enteredOrExited)
  1740. return false;
  1741. Bool anyConsidered = false;
  1742. Bool exited = false;
  1743. Bool inside = false;
  1744. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1745. {
  1746. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1747. if (ai) {
  1748. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1749. {
  1750. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1751. continue;
  1752. }
  1753. }
  1754. } else {
  1755. // things without ai should consider themselves ground units
  1756. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1757. continue;
  1758. }
  1759. }
  1760. if (iter.cur()->isEffectivelyDead())
  1761. continue;
  1762. if (iter.cur()->isKindOf(KINDOF_INERT))
  1763. continue;
  1764. if (iter.cur()->didExit(pTrigger)) {
  1765. exited = true;
  1766. } else {
  1767. if (iter.cur()->isInside(pTrigger)) {
  1768. inside = true;
  1769. }
  1770. }
  1771. // We need this in order to prevent this from returning a false positive
  1772. anyConsidered = true;
  1773. }
  1774. return anyConsidered && exited && !inside;
  1775. }
  1776. // ------------------------------------------------------------------------
  1777. Bool Team::allInside(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1778. {
  1779. // empty teams are not inside.
  1780. if (!hasAnyObjects()) {
  1781. return false;
  1782. }
  1783. Bool anyConsidered = false;
  1784. Bool anyOutside = false;
  1785. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1786. {
  1787. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1788. if (ai) {
  1789. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1790. {
  1791. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1792. continue;
  1793. }
  1794. }
  1795. } else {
  1796. // things without ai should consider themselves ground units
  1797. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1798. continue;
  1799. }
  1800. }
  1801. if (iter.cur()->isEffectivelyDead()) {
  1802. continue;
  1803. }
  1804. if (iter.cur()->isKindOf(KINDOF_INERT))
  1805. continue;
  1806. if (!iter.cur()->isInside(pTrigger)) {
  1807. anyOutside = true;
  1808. }
  1809. // We need this in order to prevent this from returning a false positive
  1810. anyConsidered = true;
  1811. }
  1812. return anyConsidered && !anyOutside;
  1813. }
  1814. // ------------------------------------------------------------------------
  1815. Bool Team::noneInside(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1816. {
  1817. Bool anyConsidered = false;
  1818. Bool anyInside = false;
  1819. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1820. {
  1821. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1822. if (ai) {
  1823. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1824. {
  1825. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1826. continue;
  1827. }
  1828. }
  1829. } else {
  1830. // things without ai should consider themselves ground units
  1831. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1832. continue;
  1833. }
  1834. }
  1835. // don't consider dead things.
  1836. if (iter.cur()->isEffectivelyDead()) {
  1837. continue;
  1838. }
  1839. if (iter.cur()->isKindOf(KINDOF_INERT))
  1840. continue;
  1841. if (iter.cur()->isInside(pTrigger)) {
  1842. anyInside = true;
  1843. }
  1844. // We need this in order to prevent this from returning a false positive
  1845. anyConsidered = true;
  1846. }
  1847. return anyConsidered && !anyInside;
  1848. }
  1849. // ------------------------------------------------------------------------
  1850. Bool Team::someInsideSomeOutside(PolygonTrigger *pTrigger, UnsignedInt whichToConsider) const
  1851. {
  1852. Bool anyConsidered = false;
  1853. Bool anyInside = false;
  1854. Bool anyOutside = false;
  1855. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1856. {
  1857. AIUpdateInterface *ai = iter.cur()->getAIUpdateInterface();
  1858. if (ai) {
  1859. const LocomotorSet& locoSet = ai->getLocomotorSet();
  1860. {
  1861. if (!locoSetMatches(locoSet.getValidSurfaces(), whichToConsider)) {
  1862. continue;
  1863. }
  1864. }
  1865. } else {
  1866. // things without ai should consider themselves ground units
  1867. if (!locoSetMatches(LOCOMOTORSURFACE_GROUND, whichToConsider)) {
  1868. continue;
  1869. }
  1870. }
  1871. // don't consider dead things.
  1872. if (iter.cur()->isEffectivelyDead()) {
  1873. continue;
  1874. }
  1875. if (iter.cur()->isKindOf(KINDOF_INERT))
  1876. continue;
  1877. if (iter.cur()->isInside(pTrigger)) {
  1878. anyInside = true;
  1879. } else {
  1880. anyOutside = true;
  1881. }
  1882. // In this particular case, this is unnecessary. However, unless it is a performance hit, please
  1883. // leave it.
  1884. anyConsidered = true;
  1885. }
  1886. return anyConsidered && anyInside && anyOutside;
  1887. }
  1888. const Coord3D* Team::getEstimateTeamPosition(void) const
  1889. {
  1890. // this doesn't actually calculate the team position, but rather estimates it by
  1891. // returning the position of the first member of the team
  1892. DLINK_ITERATOR<Object> iter = iterate_TeamMemberList();
  1893. Object *obj = iter.cur();
  1894. if (!obj)
  1895. return NULL;
  1896. const Coord3D *pos = iter.cur()->getPosition();
  1897. if (!pos)
  1898. return NULL;
  1899. return pos;
  1900. }
  1901. // ------------------------------------------------------------------------
  1902. void Team::deleteTeam(Bool ignoreDead)
  1903. {
  1904. // First off, if this Team is the Player's default team, we need to Evacuate everyone or else
  1905. // Garrisoned buildings will fall victim to this deletion as well, since they were added to the
  1906. // Default when captured. Design intends with this script to kill the people out from inside.
  1907. // If the thing is a transport, everything will still work, as the issue at hand is the container's
  1908. // wanting to change sides when emptied. The bug is that the people in the Garrisoned building
  1909. // are deleted, and that changes the Team of the building, and then the DLink walks down the new team
  1910. // and deletes the wrong stuff. Like every tree and civialian building on the map.
  1911. // Of course, to prevent the exact same DLINK jumping bug, I must first record what guys I am going to
  1912. // Evacuate, or else after the first occupied building is emptied, he will move his Next into the
  1913. // same damn wrong team.
  1914. if( this == getControllingPlayer()->getDefaultTeam() )
  1915. {
  1916. std::list<Object *> guysToMakeEvacuate;
  1917. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1918. {
  1919. Object *obj = iter.cur();
  1920. if (!obj)
  1921. continue;
  1922. if( obj->getContain() && (obj->getContain()->getContainCount() > 0) )
  1923. {
  1924. // Write them all down, so the DLINK track jumping doesn't screw me up here as well.
  1925. guysToMakeEvacuate.push_back( obj );
  1926. }
  1927. }
  1928. for( std::list<Object *>::iterator it = guysToMakeEvacuate.begin(); it != guysToMakeEvacuate.end(); /*nothing*/ )
  1929. {
  1930. Object *obj = *it;
  1931. it++;
  1932. if( obj->getContain() )
  1933. {
  1934. obj->getContain()->removeAllContained();
  1935. }
  1936. }
  1937. }
  1938. // this doesn't actually delete the team, it deletes the members of the team.
  1939. // the team itself will be deleted in updateState.
  1940. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  1941. {
  1942. Object *obj = iter.cur();
  1943. if (!obj) {
  1944. continue;
  1945. }
  1946. // The reason the comment says the team will be deleted is because it will see that it is empty.
  1947. // So yes, the Team will survive for a while, but it was going to anyway. This is a script flag, so if
  1948. // they use it on a team with things that can't die, then yeah, the Team will last forever. But then it is
  1949. // user error.
  1950. if( ignoreDead && obj->isEffectivelyDead() )
  1951. continue;
  1952. TheGameLogic->destroyObject(obj);
  1953. }
  1954. }
  1955. // ------------------------------------------------------------------------
  1956. /* Transfer our units to new team. */
  1957. void Team::transferUnitsTo(Team *newTeam)
  1958. {
  1959. if (this == newTeam) return;
  1960. if (newTeam == NULL) return;
  1961. Object *obj;
  1962. while ((obj = getFirstItemIn_TeamMemberList()) != 0)
  1963. {
  1964. obj->setTeam(newTeam);
  1965. }
  1966. }
  1967. // ------------------------------------------------------------------------
  1968. static Bool isInBuildVariations(const ThingTemplate* ttWithVariations, const ThingTemplate* b)
  1969. {
  1970. const std::vector<AsciiString>& bv = ttWithVariations->getBuildVariations();
  1971. if (bv.empty())
  1972. return false;
  1973. for (std::vector<AsciiString>::const_iterator it = bv.begin(); it != bv.end(); ++it)
  1974. {
  1975. if (b->getName() == *it)
  1976. return true;
  1977. }
  1978. return false;
  1979. }
  1980. // ------------------------------------------------------------------------
  1981. /* Try to recruit a unit from other teams of this player. */
  1982. Object *Team::tryToRecruit(const ThingTemplate *tTemplate, const Coord3D *teamHome, Real maxDist)
  1983. {
  1984. Player *myPlayer = getControllingPlayer();
  1985. Object *obj=NULL;
  1986. Real distSqr = maxDist*maxDist;
  1987. Object *recruit = NULL;
  1988. for( obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject() )
  1989. {
  1990. if (!obj->getTemplate()->isEquivalentTo(tTemplate))
  1991. {
  1992. // it might be ok, if tTemplate is really just a "build-variations" template...
  1993. if (!isInBuildVariations(tTemplate, obj->getTemplate()))
  1994. continue;
  1995. }
  1996. if (obj->getControllingPlayer() != myPlayer)
  1997. continue;
  1998. Team *team = obj->getTeam();
  1999. Bool isDefaultTeam = false;
  2000. if (team == myPlayer->getDefaultTeam()) {
  2001. isDefaultTeam = true;
  2002. }
  2003. if (!team->isActive()) {
  2004. continue; // Team is building, so don't steal it's members yet.
  2005. }
  2006. if (team->getPrototype()->getTemplateInfo()->m_productionPriority>=getPrototype()->getTemplateInfo()->m_productionPriority) {
  2007. continue;
  2008. }
  2009. Bool teamIsRecruitable = isDefaultTeam; // Default team always recruitable.
  2010. if (team->getPrototype()->getTemplateInfo()->m_isAIRecruitable) {
  2011. teamIsRecruitable = true;
  2012. }
  2013. // Check & see if individual team has been marked for recruitability.
  2014. if (team->m_isRecruitablitySet) {
  2015. teamIsRecruitable = team->m_isRecruitable;
  2016. }
  2017. if (!teamIsRecruitable) {
  2018. continue;
  2019. }
  2020. if (obj->getAIUpdateInterface() && !obj->getAIUpdateInterface()->isRecruitable()) {
  2021. continue; // can't recruit this unit.
  2022. }
  2023. if( obj->isDisabledByType( DISABLED_HELD ) )
  2024. {
  2025. continue; // Don't recruit held units.
  2026. }
  2027. Real dx, dy;
  2028. dx = teamHome->x - obj->getPosition()->x;
  2029. dy = teamHome->y - obj->getPosition()->y;
  2030. if (isDefaultTeam && recruit == NULL) {
  2031. recruit = obj;
  2032. distSqr = dx*dx+dy*dy;
  2033. }
  2034. if (dx*dx+dy*dy > distSqr) {
  2035. continue;
  2036. }
  2037. distSqr = dx*dx+dy*dy;
  2038. recruit = obj;
  2039. }
  2040. if (recruit!=NULL) {
  2041. return recruit;
  2042. }
  2043. return NULL;
  2044. }
  2045. // ------------------------------------------------------------------------
  2046. void Team::evacuateTeam(void)
  2047. {
  2048. std::list<Object *> objectsToProcess;
  2049. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  2050. Object *obj = iter.cur();
  2051. if (!obj || obj->isDestroyed() || obj->isEffectivelyDead()) {
  2052. continue;
  2053. }
  2054. ContainModuleInterface *cmi = obj->getContain();
  2055. UnsignedInt numContained = 0;
  2056. if (cmi != NULL) {
  2057. numContained = cmi->getContainCount();
  2058. }
  2059. if (numContained > 0) {
  2060. objectsToProcess.push_back(obj);
  2061. }
  2062. }
  2063. // evacuate any containers
  2064. std::list<Object *>::iterator objIt;
  2065. for (objIt = objectsToProcess.begin(); objIt != objectsToProcess.end(); ++objIt)
  2066. {
  2067. Object *obj = *objIt;
  2068. ContainModuleInterface *cmi = obj->getContain();
  2069. if (cmi)
  2070. {
  2071. cmi->removeAllContained();
  2072. }
  2073. }
  2074. objectsToProcess.clear();
  2075. }
  2076. // ------------------------------------------------------------------------
  2077. void Team::killTeam(void)
  2078. {
  2079. std::list<Object *> objectsToProcess;
  2080. evacuateTeam();
  2081. // beacons are effectively dead, so we need to destroy via a non-kill() method
  2082. const ThingTemplate *beaconTemplate = TheThingFactory->findTemplate( getControllingPlayer()->getPlayerTemplate()->getBeaconTemplate() );
  2083. // now find objects to kill
  2084. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance()) {
  2085. Object *obj = iter.cur();
  2086. if (!obj || obj->isDestroyed() || (obj->isEffectivelyDead() && !obj->getTemplate()->isEquivalentTo(beaconTemplate)))
  2087. {
  2088. continue;
  2089. }
  2090. Team *objTeam = obj->getTeam();
  2091. // the object's team could change after having all the passengers get out.
  2092. if (objTeam == this) {
  2093. objectsToProcess.push_back(obj);
  2094. }
  2095. }
  2096. // and finally, kill things
  2097. std::list<Object *>::iterator objIt;
  2098. for (objIt = objectsToProcess.begin(); objIt != objectsToProcess.end(); ++objIt)
  2099. {
  2100. Object *obj = *objIt;
  2101. if (obj->isKindOf(KINDOF_TECH_BUILDING))
  2102. obj->setTeam(ThePlayerList->getNeutralPlayer()->getDefaultTeam());
  2103. else
  2104. obj->kill();
  2105. }
  2106. objectsToProcess.clear();
  2107. }
  2108. // ------------------------------------------------------------------------
  2109. Bool Team::damageTeamMembers(Real amount)
  2110. {
  2111. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  2112. {
  2113. if (iter.cur()->isEffectivelyDead())
  2114. continue;
  2115. if (iter.cur()->isDestroyed())
  2116. continue;
  2117. // do max amount of damage to object
  2118. if (amount < 0.0) {
  2119. iter.cur()->kill();
  2120. } else {
  2121. DamageInfo damageInfo;
  2122. damageInfo.in.m_damageType = DAMAGE_UNRESISTABLE;
  2123. damageInfo.in.m_deathType = DEATH_NORMAL;
  2124. damageInfo.in.m_sourceID = INVALID_ID;
  2125. damageInfo.in.m_amount = amount;
  2126. iter.cur()->attemptDamage( &damageInfo );
  2127. }
  2128. }
  2129. return false;
  2130. }
  2131. // ------------------------------------------------------------------------
  2132. /// @todo This should give a "team move" command, not individual move orders (MSB)
  2133. void Team::moveTeamTo(Coord3D destination)
  2134. {
  2135. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  2136. {
  2137. if (iter.cur()->isEffectivelyDead())
  2138. continue;
  2139. if (iter.cur()->isDestroyed())
  2140. continue;
  2141. }
  2142. }
  2143. // ------------------------------------------------------------------------
  2144. Bool Team::hasAnyBuildFacility() const
  2145. {
  2146. for (DLINK_ITERATOR<Object> iter = iterate_TeamMemberList(); !iter.done(); iter.advance())
  2147. {
  2148. const ThingTemplate *objtmpl = iter.cur()->getTemplate();
  2149. if (objtmpl->isBuildFacility())
  2150. return true;
  2151. }
  2152. return false;
  2153. }
  2154. // ------------------------------------------------------------------------
  2155. //DECLARE_PERF_TIMER(updateGenericScripts)
  2156. void Team::updateGenericScripts(void)
  2157. {
  2158. //USE_PERF_TIMER(updateGenericScripts)
  2159. for (Int i = 0; i < MAX_GENERIC_SCRIPTS; ++i) {
  2160. if (m_shouldAttemptGenericScript[i]) {
  2161. // Does the condition succeed? If so, run it. If it is a run once script, also mark that we
  2162. // shouldn't run it again.
  2163. Script *script = m_proto->getGenericScript(i);
  2164. if (script) {
  2165. if (TheScriptEngine->evaluateConditions(script, this)) {
  2166. // It was successful.
  2167. if (script->isOneShot()) {
  2168. m_shouldAttemptGenericScript[i] = false;
  2169. }
  2170. TheScriptEngine->friend_executeAction(script->getAction(), this);
  2171. AsciiString msg = "Generic script '";
  2172. msg.concat(script->getName());
  2173. msg.concat("' run on team ");
  2174. msg.concat(getName());
  2175. TheScriptEngine->AppendDebugMessage(msg, false);
  2176. }
  2177. } else {
  2178. m_shouldAttemptGenericScript[i] = false;
  2179. }
  2180. }
  2181. }
  2182. }
  2183. // ------------------------------------------------------------------------------------------------
  2184. /** CRC */
  2185. // ------------------------------------------------------------------------------------------------
  2186. void Team::crc( Xfer *xfer )
  2187. {
  2188. } // end crc
  2189. // ------------------------------------------------------------------------------------------------
  2190. /** Xfer Method
  2191. * Version Info:
  2192. * 1: Initial version */
  2193. // ------------------------------------------------------------------------------------------------
  2194. void Team::xfer( Xfer *xfer )
  2195. {
  2196. // version
  2197. XferVersion currentVersion = 1;
  2198. XferVersion version = currentVersion;
  2199. xfer->xferVersion( &version, currentVersion );
  2200. // xfer id, this is a sanity check as team id m_id should always be valid at this point
  2201. TeamID teamID = m_id;
  2202. xfer->xferUser( &teamID, sizeof( TeamID ) );
  2203. if( teamID != m_id )
  2204. {
  2205. DEBUG_CRASH(( "Team::xfer - TeamID mismatch. Xfered '%d' but should be '%d'\n",
  2206. teamID, m_id ));
  2207. throw SC_INVALID_DATA;
  2208. } // end if
  2209. // member list count and data
  2210. ObjectID memberID;
  2211. UnsignedShort memberCount = 0;
  2212. for( DLINK_ITERATOR< Object > objIt = iterate_TeamMemberList();
  2213. objIt.done() == FALSE;
  2214. objIt.advance() )
  2215. memberCount++;
  2216. xfer->xferUnsignedShort( &memberCount );
  2217. if( xfer->getXferMode() == XFER_SAVE )
  2218. {
  2219. Object *obj;
  2220. // save all member info
  2221. for( DLINK_ITERATOR< Object > objIt = iterate_TeamMemberList();
  2222. objIt.done() == FALSE;
  2223. objIt.advance() )
  2224. {
  2225. // get object
  2226. obj = objIt.cur();
  2227. // save id
  2228. memberID = obj->getID();
  2229. xfer->xferObjectID( &memberID );
  2230. } // end for
  2231. } // end if, save
  2232. else
  2233. {
  2234. // load all members
  2235. for( UnsignedShort i = 0; i < memberCount; ++i )
  2236. {
  2237. // read ID
  2238. xfer->xferObjectID( &memberID );
  2239. // put on pending list for later processing
  2240. m_xferMemberIDList.push_back( memberID );
  2241. } // end for, i
  2242. } // end else, load
  2243. // state
  2244. xfer->xferAsciiString( &m_state );
  2245. // entered or exited
  2246. xfer->xferBool( &m_enteredOrExited );
  2247. // active status
  2248. xfer->xferBool( &m_active );
  2249. // created flag
  2250. xfer->xferBool( &m_created );
  2251. // check enemy sighted
  2252. xfer->xferBool( &m_checkEnemySighted );
  2253. // see enemy
  2254. xfer->xferBool( &m_seeEnemy );
  2255. // previous see enemy
  2256. xfer->xferBool( &m_prevSeeEnemy );
  2257. // was idle
  2258. xfer->xferBool( &m_wasIdle );
  2259. // destroy threshold
  2260. xfer->xferInt( &m_destroyThreshold );
  2261. // current units
  2262. xfer->xferInt( &m_curUnits );
  2263. // waypoint
  2264. UnsignedInt currentWaypointID = m_currentWaypoint ? m_currentWaypoint->getID() : 0;
  2265. xfer->xferUnsignedInt( &currentWaypointID );
  2266. if( xfer->getXferMode() == XFER_LOAD )
  2267. m_currentWaypoint = TheTerrainLogic->getWaypointByID( currentWaypointID );
  2268. UnsignedShort shouldAttemptGenericScriptCount = MAX_GENERIC_SCRIPTS;
  2269. xfer->xferUnsignedShort( &shouldAttemptGenericScriptCount );
  2270. if ( shouldAttemptGenericScriptCount != MAX_GENERIC_SCRIPTS )
  2271. {
  2272. DEBUG_CRASH(("Team::xfer - The number of allowable Generic scripts has changed, and this chunk needs to be versioned."));
  2273. throw SC_INVALID_DATA;
  2274. }
  2275. for (Int i = 0; i < shouldAttemptGenericScriptCount; ++i)
  2276. xfer->xferBool(&m_shouldAttemptGenericScript[i]);
  2277. // recruitability set
  2278. xfer->xferBool( &m_isRecruitablitySet );
  2279. // is recruitable
  2280. xfer->xferBool( &m_isRecruitable );
  2281. // Common attack target.
  2282. xfer->xferObjectID( &m_commonAttackTarget );
  2283. // team relations
  2284. xfer->xferSnapshot( m_teamRelations );
  2285. // player relations
  2286. xfer->xferSnapshot( m_playerRelations );
  2287. } // ene xfer
  2288. // ------------------------------------------------------------------------------------------------
  2289. /** Load post process */
  2290. // ------------------------------------------------------------------------------------------------
  2291. void Team::loadPostProcess( void )
  2292. {
  2293. //
  2294. // now that all objects have actually been loaded, populate the member list with
  2295. // real object pointers
  2296. //
  2297. Object *obj;
  2298. std::list< ObjectID >::const_iterator it;
  2299. for( it = m_xferMemberIDList.begin(); it != m_xferMemberIDList.end(); ++it )
  2300. {
  2301. // find object
  2302. obj = TheGameLogic->findObjectByID( *it );
  2303. if( obj == NULL )
  2304. {
  2305. DEBUG_CRASH(( "Team::loadPostProcess - Unable to post process object to member list, object ID = '%d'\n", *it ));
  2306. throw SC_INVALID_DATA;
  2307. } // end if
  2308. //
  2309. // we are now disabling this code since the objects set their team during their
  2310. // own xfer function which will actually put it on the team ... however, we will sanity
  2311. // check everything here to make sure that all the objects that should be on the team,
  2312. // are in fact on the team
  2313. //
  2314. if( isInList_TeamMemberList( obj ) == FALSE )
  2315. {
  2316. DEBUG_CRASH(( "Team::loadPostProcess - Object '%s'(%d) should be in team list but is not\n",
  2317. obj->getTemplate()->getName().str(), obj->getID() ));
  2318. throw SC_INVALID_DATA;
  2319. } // end if
  2320. } // end for
  2321. // since we prepended the object member pointers, reverse that list so it's just like before
  2322. // reverse_TeamMemberList();
  2323. // we're done with the xfer list now
  2324. m_xferMemberIDList.clear();
  2325. } // end loadPostProcess
  2326. // ------------------------------------------------------------------------
  2327. // ------------------------------------------------------------------------
  2328. // ------------------------------------------------------------------------