team.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. //******************************************************************************************
  2. //
  3. // team.cpp - This file contains the Team Class code
  4. //
  5. // MechCommander 2
  6. //
  7. //---------------------------------------------------------------------------//
  8. // Copyright (C) Microsoft Corporation. All rights reserved. //
  9. //===========================================================================//*
  10. #ifndef MCLIB_H
  11. #include "mclib.h"
  12. #endif
  13. #ifndef OBJMGR_H
  14. #include "objmgr.h"
  15. #endif
  16. #ifndef MOVER_H
  17. #include "mover.h"
  18. #endif
  19. #ifdef USE_MECHS
  20. #ifndef MECH_H
  21. #include <mech.h>
  22. #endif
  23. #endif
  24. #ifndef GVEHICL_H
  25. #include "gvehicl.h"
  26. #endif
  27. #ifdef USE_ARTILLERY
  28. #ifndef ARTLRY_H
  29. #include <artlry.h>
  30. #endif
  31. #endif
  32. #ifndef UNITDESG_H
  33. #include "unitdesg.h"
  34. #endif
  35. #ifndef TEAM_H
  36. #include "team.h"
  37. #endif
  38. #ifdef USE_MOVERCONTROL
  39. #ifndef AICTRL_H
  40. #include <aictrl.h>
  41. #endif
  42. #endif
  43. #ifndef MULTPLYR_H
  44. #include "multplyr.h"
  45. #endif
  46. #ifndef CONTACT_H
  47. #include "contact.h"
  48. #endif
  49. #ifndef MISSION_H
  50. #include "mission.h"
  51. #endif
  52. #ifndef MISSIONGUI_H
  53. #include "missionGui.h"
  54. #endif
  55. #ifndef WARRIOR_H
  56. #include "warrior.h"
  57. #endif
  58. char Team::relations[MAX_TEAMS][MAX_TEAMS] = {
  59. {0, 2, RELATION_NEUTRAL, 2, 2, 2, 2, 2},
  60. {2, 0, 2, 2, 2, 2, 2, 2},
  61. {RELATION_NEUTRAL, 2, 0, 2, 2, 2, 2, 2},
  62. {2, 2, 2, 0, 2, 2, 2, 2},
  63. {2, 2, 2, 2, 0, 2, 2, 2},
  64. {2, 2, 2, 2, 2, 0, 2, 2},
  65. {2, 2, 2, 2, 2, 2, 0, 2},
  66. {2, 2, 2, 2, 2, 2, 2, 0}
  67. };
  68. bool Team::noPain[MAX_TEAMS] = {false, false, false, false, false, false, false, false};
  69. long Team::numTeams = 0;
  70. TeamPtr Team::home = NULL;
  71. TeamPtr Team::teams[MAX_TEAMS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  72. SortListPtr Team::sortList = NULL;
  73. bool useRealLOS = true;
  74. #ifdef LAB_ONLY
  75. extern bool drawTerrainGrid;
  76. extern long currentLineElement;
  77. extern LineElement *debugLines[];
  78. #endif
  79. extern float maxVisualRange;
  80. extern long visualRangeTable[];
  81. extern unsigned long MaxTreeLOSCellBlock;
  82. //***************************************************************************
  83. // TEAM class
  84. //***************************************************************************
  85. void Team::init (void) {
  86. id = 0;
  87. rosterSize = 0;
  88. objectives.Clear();
  89. numPrimaryObjectives = 0;
  90. //numMechs = 0;
  91. //numVehicles = 0;
  92. //numElementals = 0;
  93. //mechHandle = -1;
  94. //vehicleHandle = -1;
  95. //elementalHandle = -1;
  96. /* nextContactId = 1;
  97. numContactUpdatesPerPass = NUM_CONTACT_UPDATES_PER_PASS;
  98. curContactUpdate = 0;
  99. numEnemyContacts = 0;
  100. numLOSContacts = 0;
  101. numSensorContacts = 0;
  102. */
  103. /* maxSensors = 0;
  104. numSensors = 0;
  105. jammers = NULL;
  106. ecms = NULL;
  107. */
  108. numTeams++;
  109. }
  110. //---------------------------------------------------------------------------
  111. long Team::init (long _id, FitIniFile *pMissionFile) {
  112. id = _id;
  113. objectives.Alignment(id);
  114. if (pMissionFile) {
  115. objectives.Read(pMissionFile);
  116. numPrimaryObjectives = 0;
  117. CObjectives::EIterator it = objectives.Begin();
  118. while (!it.IsDone()) {
  119. if (1 == (*it)->Priority())
  120. numPrimaryObjectives++;
  121. it++;
  122. }
  123. ReadNavMarkers(pMissionFile, objectives);
  124. }
  125. return(NO_ERR);
  126. }
  127. //---------------------------------------------------------------------------
  128. long Team::loadObjectives (FitIniFile *pMissionFile) {
  129. objectives.Alignment(id);
  130. if (pMissionFile) {
  131. objectives.Read(pMissionFile);
  132. numPrimaryObjectives = 0;
  133. CObjectives::EIterator it = objectives.Begin();
  134. while (!it.IsDone()) {
  135. if (1 == (*it)->Priority())
  136. numPrimaryObjectives++;
  137. it++;
  138. }
  139. ReadNavMarkers(pMissionFile, objectives);
  140. }
  141. return(NO_ERR);
  142. }
  143. //---------------------------------------------------------------------------
  144. void Team::buildRoster (void) {
  145. //---------------------------------------------------------------------
  146. // This function builds a roster for the team from the movers currently
  147. // registered in the object manager. It assumes the teamId is already
  148. // set for each mover, and compares this team's id to that of the
  149. // objects to determine which objects belong on this team...
  150. rosterSize = 0;
  151. for (long i = 0; i < ObjectManager->getNumMovers(); i++) {
  152. MoverPtr mover = ObjectManager->getMover(i);
  153. if (mover->getTeamId() == id)
  154. roster[rosterSize++] = mover->getWatchID();
  155. }
  156. // numMechs = objClassTally[0];
  157. // numVehicles = objClassTally[1];
  158. // numElementals = objClassTally[2];
  159. }
  160. //---------------------------------------------------------------------------
  161. MoverPtr Team::getMover (long index) {
  162. if (roster[index] > 0)
  163. return((MoverPtr)ObjectManager->getByWatchID(roster[index]));
  164. return(NULL);
  165. }
  166. //----------------------------------------------------------------------------
  167. void Team::addToRoster (MoverPtr mover) {
  168. if (mover)
  169. roster[rosterSize++] = mover->getWatchID();
  170. }
  171. //---------------------------------------------------------------------------
  172. void Team::removeFromRoster (MoverPtr mover) {
  173. for (long i = 0; i < rosterSize; i++)
  174. if (roster[i] == mover->getWatchID()) {
  175. roster[i] = roster[--rosterSize];
  176. break;
  177. }
  178. }
  179. //---------------------------------------------------------------------------
  180. bool Team::isContact (GameObjectPtr looker, MoverPtr mover, long contactCriteria) {
  181. return(SensorManager->getTeamSensor(id)->meetsCriteria(looker, mover, contactCriteria));
  182. }
  183. //---------------------------------------------------------------------------
  184. long Team::getContacts (GameObjectPtr looker, long* contactList, long contactCriteria, long sortType) {
  185. return(SensorManager->getTeamSensor(id)->getContacts(looker, contactList, contactCriteria, sortType));
  186. }
  187. //---------------------------------------------------------------------------
  188. bool Team::hasSensorContact (long teamID) {
  189. return(SensorManager->getTeamSensor(id)->hasSensorContact(teamID));
  190. }
  191. //---------------------------------------------------------------------------
  192. long Team::getRoster (GameObjectPtr* objList, bool existsOnly) {
  193. long count = 0;
  194. if (existsOnly) {
  195. for (long i = 0; i < rosterSize; i++) {
  196. GameObjectPtr object = ObjectManager->getByWatchID(roster[i]);
  197. if (object && object->getExists())
  198. objList[count++] = object;
  199. }
  200. }
  201. else {
  202. for (long i = 0; i < rosterSize; i++) {
  203. GameObjectPtr object = ObjectManager->getByWatchID(roster[i]);
  204. if (object)
  205. objList[count++] = object;
  206. }
  207. }
  208. return(count);
  209. }
  210. ///////////////////////////////////
  211. //---------------------------------------------------------------------------
  212. void Team::disableTargets (void) {
  213. for (long i = 0; i < rosterSize; i++) {
  214. GameObjectPtr object = ObjectManager->getByWatchID(roster[i]);
  215. if (object) {
  216. GameObjectPtr target = NULL;
  217. if (object->isMover())
  218. target = ((MoverPtr)object)->getPilot()->getCurrentTarget();
  219. if (target && target->isMover())
  220. ((MoverPtr)target)->disable(66);
  221. }
  222. }
  223. }
  224. //---------------------------------------------------------------------------
  225. void Team::eject (void) {
  226. for (long i = 0; i < rosterSize; i++) {
  227. MoverPtr mover = (MoverPtr)ObjectManager->getByWatchID(roster[i]);
  228. if (mover) {
  229. if (mover->getObjectClass() == BATTLEMECH)
  230. mover->getPilot()->orderEject(false, true, ORDER_ORIGIN_COMMANDER);
  231. else {
  232. WeaponShotInfo shot;
  233. shot.init(NULL, -3, 254.0, 0, 0);
  234. mover->handleWeaponHit(&shot, (MPlayer != NULL));
  235. }
  236. }
  237. }
  238. }
  239. //---------------------------------------------------------------------------
  240. void Team::destroyTargets (void) {
  241. for (long i = 0; i < rosterSize; i++) {
  242. GameObjectPtr object = ObjectManager->getByWatchID(roster[i]);
  243. if (object) {
  244. GameObjectPtr target = NULL;
  245. if (object->isMover())
  246. target = ((MoverPtr)object)->getPilot()->getCurrentTarget();
  247. if (target && target->isMover())
  248. {
  249. //-----------------------------------------
  250. //-- Need to pound these guys to death.
  251. WeaponShotInfo shot;
  252. shot.init(NULL, -3, 5, 0, 0);
  253. for (long i=0;i<100;i++)
  254. {
  255. if (RollDice(30))
  256. shot.hitLocation = target->calcHitLocation(NULL,-1,ATTACKSOURCE_DFA,0);
  257. else
  258. shot.hitLocation = target->calcHitLocation(NULL,-1,ATTACKSOURCE_ARTILLERY,0);
  259. if (MPlayer) {
  260. target->handleWeaponHit(&shot, true);
  261. }
  262. else
  263. target->handleWeaponHit(&shot);
  264. }
  265. }
  266. }
  267. }
  268. }
  269. //---------------------------------------------------------------------------
  270. bool Team::isTargeting (GameObjectWatchID targetWID, GameObjectWatchID exceptWID) {
  271. if (exceptWID)
  272. for (long i = 0; i < rosterSize; i++) {
  273. if (roster[i] == exceptWID)
  274. continue;
  275. MoverPtr mover = dynamic_cast<MoverPtr>(ObjectManager->getByWatchID(roster[i]));
  276. Assert(mover != NULL, roster[i], " Team.isTargeting: NULL mover ");
  277. MechWarriorPtr pilot = mover->getPilot();
  278. if (pilot) {
  279. GameObjectPtr target = pilot->getCurrentTarget();
  280. if (target && (target->getWatchID() == targetWID))
  281. return(true);
  282. }
  283. }
  284. else
  285. for (long i = 0; i < rosterSize; i++) {
  286. MoverPtr mover = dynamic_cast<MoverPtr>(ObjectManager->getByWatchID(roster[i]));
  287. Assert(mover != NULL, roster[i], " Team.isTargeting: NULL mover ");
  288. MechWarriorPtr pilot = mover->getPilot();
  289. if (pilot) {
  290. GameObjectPtr target = pilot->getCurrentTarget();
  291. if (target && (target->getWatchID() == targetWID))
  292. return(true);
  293. }
  294. }
  295. return(false);
  296. }
  297. //---------------------------------------------------------------------------
  298. bool Team::isCapturing (GameObjectWatchID targetWID, GameObjectWatchID exceptWID) {
  299. if (exceptWID)
  300. for (long i = 0; i < rosterSize; i++) {
  301. if (roster[i] == exceptWID)
  302. continue;
  303. MoverPtr mover = dynamic_cast<MoverPtr>(ObjectManager->getByWatchID(roster[i]));
  304. Assert(mover != NULL, roster[i], " Team.isTargeting: NULL mover ");
  305. MechWarriorPtr pilot = mover->getPilot();
  306. if (pilot && (pilot->getCurTacOrder()->code == TACTICAL_ORDER_CAPTURE)) {
  307. GameObjectPtr target = pilot->getCurTacOrder()->getTarget();
  308. if (target && (target->getWatchID() == targetWID))
  309. return(true);
  310. }
  311. }
  312. else
  313. for (long i = 0; i < rosterSize; i++) {
  314. MoverPtr mover = dynamic_cast<MoverPtr>(ObjectManager->getByWatchID(roster[i]));
  315. Assert(mover != NULL, roster[i], " Team.isTargeting: NULL mover ");
  316. MechWarriorPtr pilot = mover->getPilot();
  317. if (pilot && (pilot->getCurTacOrder()->code == TACTICAL_ORDER_CAPTURE)) {
  318. GameObjectPtr target = pilot->getCurTacOrder()->getTarget();
  319. if (target && (target->getWatchID() == targetWID))
  320. return(true);
  321. }
  322. }
  323. return(false);
  324. }
  325. //---------------------------------------------------------------------------
  326. void Team::markRadiusSeen (Stuff::Vector3D& location, float radius) {
  327. //---------------------------------------------------------------
  328. // Once we get visibits in for all 8 teams, we should change this
  329. // appropriately...
  330. land->markRadiusSeen(location, radius, id);
  331. }
  332. //---------------------------------------------------------------------------
  333. void Team::markRadiusSeenToTeams (Stuff::Vector3D& location, float radius, bool shrinkForNight) {
  334. if (radius < 0.0)
  335. radius = fireVisualRange;
  336. if (shrinkForNight)
  337. radius -= (radius * 0.25f);
  338. bool didTeam[MAX_TEAMS] = {false, false, false, false, false, false, false, false};
  339. for (long i = 0; i < ObjectManager->getNumMovers(); i++) {
  340. MoverPtr mover = ObjectManager->getMover(i);
  341. if (mover->getTeam() && !didTeam[mover->getTeamId()] && !isFriendly(mover->getTeam())) {
  342. Stuff::Vector3D result;
  343. result.x = location.x - mover->getPosition().x;
  344. result.y = location.y - mover->getPosition().y;
  345. result.z = 0.0;
  346. float dist = result.GetLength() * metersPerWorldUnit;
  347. if (dist < maxVisualRange) {
  348. markRadiusSeen(location, radius);
  349. didTeam[mover->getTeamId()] = true;
  350. }
  351. }
  352. }
  353. }
  354. //---------------------------------------------------------------------------
  355. void Team::markSeen (Stuff::Vector3D& location, float specialUnitExpand) {
  356. //---------------------------------------------------------------
  357. // Once we get visibits in for all 8 teams, we should change this
  358. // appropriately...
  359. land->markSeen(location, id, specialUnitExpand);
  360. }
  361. //---------------------------------------------------------------------------
  362. #if 0
  363. SystemTrackerPtr Team::addJammer (GameObjectPtr owner, long masterId) {
  364. SystemTrackerPtr newJammer = (SystemTrackerPtr)systemHeap->Malloc(sizeof(SystemTracker));
  365. if (!newJammer)
  366. Fatal(0, " Cannot allocate SystemTracker ");
  367. newJammer->owner = owner;
  368. newJammer->masterId = masterId;
  369. newJammer->effect = MasterComponent::masterList[masterId].getJammerEffect();
  370. newJammer->prev = NULL;
  371. newJammer->next = NULL;
  372. //----------------------
  373. // Find where it goes...
  374. SystemTrackerPtr prevJammer = NULL;
  375. SystemTrackerPtr curJammer = jammers;
  376. while (curJammer) {
  377. if (newJammer->effect >= curJammer->effect)
  378. break;
  379. prevJammer = curJammer;
  380. curJammer = curJammer->next;
  381. }
  382. //------------------------------------------------------------
  383. // Add it, sorted in descending order, into the jammer list...
  384. if (!curJammer)
  385. //----------------------------------------------
  386. // List is empty, or we add newJammer to the end...
  387. if (!prevJammer)
  388. jammers = newJammer;
  389. else {
  390. prevJammer->next = newJammer;
  391. newJammer->prev = prevJammer;
  392. }
  393. else {
  394. //----------------------------------------------------------------------
  395. // List not empty and add not at end of list, so insert the newJammer...
  396. if (prevJammer)
  397. prevJammer->next = newJammer;
  398. else
  399. jammers = newJammer;
  400. newJammer->next = curJammer;
  401. newJammer->prev = curJammer->prev;
  402. curJammer->prev = newJammer;
  403. }
  404. return(newJammer);
  405. }
  406. //---------------------------------------------------------------------------
  407. void Team::removeJammer (SystemTrackerPtr jammerTracker) {
  408. if (!jammerTracker)
  409. return;
  410. if (jammerTracker->next)
  411. jammerTracker->next->prev = jammerTracker->prev;
  412. if (jammerTracker->prev)
  413. jammerTracker->prev->next = jammerTracker->next;
  414. else
  415. jammers = jammerTracker->next;
  416. jammerTracker->owner = NULL;
  417. systemHeap->Free(jammerTracker);
  418. }
  419. //---------------------------------------------------------------------------
  420. float Team::getJammerEffect (void) {
  421. float effect = 1.0;
  422. //---------------------------------------------------------
  423. // Get our strongest jammer (with an owner still alive:)...
  424. SystemTrackerPtr curJammer = jammers;
  425. while (curJammer) {
  426. if (curJammer->owner)
  427. break;
  428. curJammer = curJammer->next;
  429. }
  430. if (curJammer)
  431. effect = curJammer->effect;
  432. return(effect);
  433. }
  434. //---------------------------------------------------------------------------
  435. SystemTrackerPtr Team::addECM (GameObjectPtr owner, long masterId) {
  436. SystemTrackerPtr newECM = (SystemTrackerPtr)systemHeap->Malloc(sizeof(SystemTracker));
  437. if (!newECM)
  438. Fatal(0, " Cannot allocate SystemTracker ");
  439. newECM->owner = owner;
  440. newECM->masterId = masterId;
  441. newECM->effect = MasterComponent::masterList[masterId].getEcmEffect();
  442. newECM->prev = NULL;
  443. newECM->next = NULL;
  444. //----------------------
  445. // Find where it goes...
  446. SystemTrackerPtr prevECM = NULL;
  447. SystemTrackerPtr curECM = ecms;
  448. while (curECM) {
  449. if (newECM->effect >= curECM->effect)
  450. break;
  451. prevECM = curECM;
  452. curECM = curECM->next;
  453. }
  454. //---------------------------------------------------------
  455. // Add it, sorted in descending order, into the ECM list...
  456. if (!curECM) {
  457. //----------------------------------------------
  458. // List is empty, or we add newECM to the end...
  459. if (!prevECM)
  460. ecms = newECM;
  461. else {
  462. prevECM->next = newECM;
  463. newECM->prev = prevECM;
  464. }
  465. }
  466. else {
  467. //-------------------------------------------------------------------
  468. // List not empty and add not at end of list, so insert the newECM...
  469. if (prevECM)
  470. prevECM->next = newECM;
  471. else
  472. ecms = newECM;
  473. newECM->next = curECM;
  474. newECM->prev = curECM->prev;
  475. curECM->prev = newECM;
  476. }
  477. return(newECM);
  478. }
  479. //---------------------------------------------------------------------------
  480. void Team::removeECM (SystemTrackerPtr ecm) {
  481. if (!ecm)
  482. return;
  483. if (ecm->next)
  484. ecm->next->prev = ecm->prev;
  485. if (ecm->prev)
  486. ecm->prev->next = ecm->next;
  487. else
  488. ecms = ecm->next;
  489. //--------------------
  490. // Free the watcher...
  491. ecm->owner = NULL;
  492. //---------------
  493. // Free up mem...
  494. systemHeap->Free(ecm);
  495. }
  496. //---------------------------------------------------------------------------
  497. float Team::getECMEffect (Stuff::Vector3D position) {
  498. //NOT how it works anymore. An ECM component stealths a mech. Period.
  499. //-----------------------------------------------------------
  500. // Since the ECMs are in descending order, the first in range
  501. // is the one we want...
  502. float effect = 1.0;
  503. /*
  504. SystemTrackerPtr curEcm = ecms;
  505. while (curEcm)
  506. {
  507. if (curEcm->masterId == 38 || curEcm->masterId == 42)
  508. {
  509. GameObjectPtr obj = curEcm->owner;
  510. if (obj)
  511. {
  512. float ecmRange = MasterComponent::masterList[curEcm->masterId].getEcmRange();
  513. float distance = obj->distanceFrom(position);
  514. if (distance <= ecmRange && obj->getExistsAndAwake() && (obj->getStatus() == OBJECT_STATUS_NORMAL))
  515. {
  516. //------------------------------------------------------
  517. // OPTIMIZE: could just return curEcm->ecmEffect, right?
  518. // Won't change at this late date, but should later...
  519. effect = MasterComponent::masterList[curEcm->masterId].getEcmEffect();
  520. break;
  521. }
  522. }
  523. }
  524. curEcm = curEcm->next;
  525. }
  526. */
  527. return(effect);
  528. }
  529. #endif
  530. //---------------------------------------------------------------------------
  531. Stuff::Vector3D Team::calcEscapeVector (MoverPtr mover, float threatRange) {
  532. static float distance[100];
  533. static Stuff::Vector3D delta[100];
  534. Stuff::Vector3D escapeVector;
  535. escapeVector.Zero();
  536. //------------------------------
  537. // Get the initial delta info...
  538. long shortest = 0;
  539. long longest = 0;
  540. for (long i = 0; i < rosterSize; i++) {
  541. GameObjectPtr obj = ObjectManager->getByWatchID(roster[i]);
  542. if (obj) {
  543. float distanceToObj = mover->distanceFrom(obj->getPosition());
  544. if (distanceToObj <= threatRange) {
  545. delta[i].Subtract(mover->getPosition(), obj->getPosition());
  546. distance[i] = distanceToObj;
  547. if (distance[i] > longest)
  548. longest = i;
  549. if (distance[i] < shortest)
  550. shortest = i;
  551. }
  552. else
  553. distance[i] = -999.0;
  554. }
  555. else
  556. distance[i] = -999.0;
  557. }
  558. //-----------------------------------------------------------------
  559. // Now, find the furthest enemy and scale the deltas accordingly...
  560. for (i = 0; i < rosterSize; i++)
  561. if (distance[i] >= 0.0) {
  562. float scale = distance[longest] / distance[i];
  563. delta[i] *= scale;
  564. escapeVector += delta[i];
  565. }
  566. //--------------------------------------------------------------------------------
  567. // We don't care about the length, just the direction (we assume you want to go as
  568. // FAR as necessary)...
  569. escapeVector.Normalize(escapeVector);
  570. return(escapeVector);
  571. }
  572. //---------------------------------------------------------------------------
  573. void Team::statusCount (long* statusTally) {
  574. //----------------------------------------------------------
  575. // statusTally counts the number of objects in the team with
  576. // each of the statuses...
  577. for (long i = 0; i < rosterSize; i++)
  578. {
  579. MoverPtr obj = (MoverPtr)ObjectManager->getByWatchID(roster[i]);
  580. Assert(obj != NULL, i, " Team.statusCount: NULL roster object ");
  581. MechWarriorPtr pilot = obj->getPilot();
  582. if (!obj->getExists())
  583. statusTally[8]++;
  584. else if (!obj->getAwake())
  585. statusTally[7]++;
  586. else if (pilot && (pilot->getStatus() == WARRIOR_STATUS_WITHDRAWN))
  587. statusTally[6]++;
  588. else
  589. {
  590. long status = obj->getStatus();
  591. if ((status < 0) || (status > 5))
  592. Fatal(status," Status out of bounds ");
  593. statusTally[obj->getStatus()]++;
  594. }
  595. }
  596. }
  597. //---------------------------------------------------------------------------
  598. void Team::destroy (void) {
  599. objectives.Clear();
  600. #if 0
  601. if (ecms) {
  602. SystemTrackerPtr curTracker = ecms;
  603. while (curTracker) {
  604. SystemTrackerPtr nextTracker = curTracker->next;
  605. systemHeap->Free(curTracker);
  606. curTracker = nextTracker;
  607. }
  608. ecms = NULL;
  609. }
  610. if (jammers) {
  611. SystemTrackerPtr curTracker = jammers;
  612. while (curTracker) {
  613. SystemTrackerPtr nextTracker = curTracker->next;
  614. systemHeap->Free(curTracker);
  615. curTracker = nextTracker;
  616. }
  617. jammers = NULL;
  618. }
  619. #endif
  620. }
  621. //---------------------------------------------------------------------------
  622. bool Team::teamLineOfSight (Stuff::Vector3D tPos, float extRad)
  623. {
  624. //-----------------------------------------------------------
  625. // For each member of the team, check LOS to point provided.
  626. for (long i = 0; i < rosterSize; i++)
  627. {
  628. MoverPtr obj = (MoverPtr)ObjectManager->getByWatchID(roster[i]);
  629. if (!obj->isDisabled() && !obj->isDestroyed() && (obj->getStatus() != OBJECT_STATUS_SHUTDOWN))
  630. {
  631. Stuff::Vector3D distance;
  632. distance.Subtract(tPos,obj->getPosition());
  633. float dist = distance.GetApproximateLength();
  634. //Figure out altitude above minimum terrain altitude and look up in table.
  635. float baseElevation = MapData::waterDepth;
  636. if (MapData::waterDepth < Terrain::userMin)
  637. baseElevation = Terrain::userMin;
  638. float altitude = obj->getPosition().z - baseElevation;
  639. float altitudeIntegerRange = (Terrain::userMax - baseElevation) * 0.00390625f;
  640. long altLevel = 0;
  641. if (altitudeIntegerRange > Stuff::SMALL)
  642. altLevel = altitude / altitudeIntegerRange;
  643. if (altLevel < 0)
  644. altLevel = 0;
  645. if (altLevel > 255)
  646. altLevel = 255;
  647. float radius = visualRangeTable[altLevel];
  648. //Scouting specialty skill.
  649. if (obj->isMover())
  650. {
  651. MoverPtr mover = (MoverPtr)obj;
  652. if (mover->pilot && mover->pilot->isScout())
  653. radius += (radius * 0.2f);
  654. radius *= mover->getLOSFactor();
  655. }
  656. if (dist <= (radius * 25.0f * worldUnitsPerMeter))
  657. {
  658. if (lineOfSight(obj->getLOSPosition(),tPos,id,extRad,0.0f,false))
  659. return true;
  660. }
  661. }
  662. }
  663. //-------------------------------------------------------------------------
  664. // Check the lookout towers now. You can find them in special Buildings!!
  665. for (long spBuilding = 0; spBuilding < ObjectManager->numSpecialBuildings; spBuilding++)
  666. {
  667. if (ObjectManager->specialBuildings[spBuilding] &&
  668. ObjectManager->specialBuildings[spBuilding]->getExists() &&
  669. ObjectManager->specialBuildings[spBuilding]->isLookoutTower() &&
  670. (ObjectManager->specialBuildings[spBuilding]->getTeamId() ==id))
  671. {
  672. GameObjectPtr obj = ObjectManager->specialBuildings[spBuilding];
  673. if (!obj->isDisabled() && !obj->isDestroyed() && (obj->getStatus() != OBJECT_STATUS_SHUTDOWN))
  674. {
  675. Stuff::Vector3D distance;
  676. distance.Subtract(tPos,obj->getPosition());
  677. float dist = distance.GetApproximateLength();
  678. //Figure out altitude above minimum terrain altitude and look up in table.
  679. float baseElevation = MapData::waterDepth;
  680. if (MapData::waterDepth < Terrain::userMin)
  681. baseElevation = Terrain::userMin;
  682. float altitude = obj->getPosition().z - baseElevation;
  683. float altitudeIntegerRange = (Terrain::userMax - baseElevation) * 0.00390625f;
  684. long altLevel = 0;
  685. if (altitudeIntegerRange > Stuff::SMALL)
  686. altLevel = altitude / altitudeIntegerRange;
  687. if (altLevel < 0)
  688. altLevel = 0;
  689. if (altLevel > 255)
  690. altLevel = 255;
  691. float radius = visualRangeTable[altLevel];
  692. //Scouting specialty skill.
  693. if (obj->isMover())
  694. {
  695. MoverPtr mover = (MoverPtr)obj;
  696. if (mover->pilot && mover->pilot->isScout())
  697. radius += (radius * 0.2f);
  698. radius *= mover->getLOSFactor();
  699. }
  700. if (dist <= (radius * 25.0f * worldUnitsPerMeter))
  701. {
  702. if (lineOfSight(obj->getLOSPosition(),tPos,id,0.0f,obj->getAppearRadius(),false))
  703. return true;
  704. }
  705. }
  706. }
  707. }
  708. return false;
  709. }
  710. #ifdef LAB_ONLY
  711. __int64 MCTimeLOSCalc = 0;
  712. #endif
  713. //#define USE_OLD_LOS
  714. #ifdef USE_OLD_LOS
  715. //---------------------------------------------------------------------------
  716. bool Team::lineOfSight (float startLocal, long mCellRow, long mCellCol, long tCellRow, long tCellCol, long teamId, float extRad, bool checkVisibleBits)
  717. {
  718. #ifdef LAB_ONLY
  719. __int64 x=GetCycles();
  720. #endif
  721. //-----------------------------------------------------
  722. // Once we allow teams to have alliances (for contacts,
  723. // etc.), simply set all nec. team bits in this mask...
  724. //TILE HACK...
  725. long tileRow = tCellRow / 3;
  726. long tileCol = tCellCol / 3;
  727. if ((teamId < 0) || (teamId >= MAX_TEAMS)) //Not on any team. It can see everything!
  728. return true;
  729. if (checkVisibleBits) {
  730. unsigned char teamMask = 0x01 << teamId;
  731. unsigned char visbBits[4];
  732. //----------------------------------------------------------------------------
  733. // First check is simple. Is anyone within the magical line of sight radius?
  734. // If not, return false and move on.
  735. // If they are, you MUST check LOS between this object and the other one.
  736. bool losResult = false;
  737. visbBits[0] = Terrain::VisibleBits->getFlag(tileRow, tileCol);
  738. if (visbBits[0] & teamMask)
  739. losResult = true;
  740. if (!losResult)
  741. {
  742. visbBits[1] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol);
  743. if (visbBits[1] & teamMask)
  744. losResult = true;
  745. }
  746. if (!losResult)
  747. {
  748. visbBits[2] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol + 1);
  749. if (visbBits[2] & teamMask)
  750. losResult = true;
  751. }
  752. if (!losResult)
  753. {
  754. visbBits[3] = Terrain::VisibleBits->getFlag(tileRow, tileCol + 1);
  755. if (visbBits[3] & teamMask)
  756. losResult = true;
  757. }
  758. if (!losResult)
  759. {
  760. #ifdef LAB_ONLY
  761. x=GetCycles()-x;
  762. MCTimeLOSCalc += x;
  763. #endif
  764. return losResult;
  765. }
  766. }
  767. if (useRealLOS)
  768. {
  769. //------------------------------------------------------------------------------------------
  770. // Within magic radius. Check REAL LOS now.
  771. // Check is really simple.
  772. // Find deltaCellRow and deltaCellCol and iterate over them from source to dest.
  773. // If the magic line ever goes BELOW the terrainElevation PLUS localElevation return false.
  774. Stuff::Vector3D startPos, endPos;
  775. startPos.Zero();
  776. endPos.Zero();
  777. land->getCellPos(tCellRow,tCellCol,endPos);
  778. land->getCellPos(mCellRow,mCellCol,startPos);
  779. startPos.z += startLocal;
  780. Stuff::Vector3D deltaCellVec;
  781. deltaCellVec.y = tCellRow - mCellRow;
  782. deltaCellVec.x = tCellCol - mCellCol;
  783. deltaCellVec.z = 0.0f;
  784. float startHeight = startPos.z;
  785. float length = deltaCellVec.GetApproximateLength();
  786. if (length > Stuff::SMALL)
  787. {
  788. float colLength = deltaCellVec.x / length;
  789. float rowLength = deltaCellVec.y / length;
  790. float heightLen = (endPos.z - startPos.z) / length;
  791. float lastCol = fabs(colLength * 2.0);
  792. float lastRow = fabs(rowLength * 2.0);
  793. float startCellRow = mCellRow;
  794. float startCellCol = mCellCol;
  795. float endCellRow = tCellRow;
  796. float endCellCol = tCellCol;
  797. Stuff::Vector3D currentPos = startPos;
  798. Stuff::Vector3D dist;
  799. dist.Subtract(endPos,currentPos);
  800. float remainingDist = dist.GetApproximateLength();
  801. bool colDone = false, rowDone = false;
  802. while (!colDone || !rowDone)
  803. {
  804. if (fabs(startCellRow - endCellRow) > lastRow) //DO NOT INCLUDE LAST CELL!!!!!
  805. {
  806. startCellRow += rowLength;
  807. }
  808. else
  809. {
  810. // startCellRow = (endCellRow - lastRow);
  811. rowDone = true;
  812. }
  813. if (fabs(startCellCol - endCellCol) > lastCol) //DO NOT INCLUDE LAST CELL!!!!!
  814. {
  815. startCellCol += colLength;
  816. }
  817. else
  818. {
  819. // startCellCol = (endCellCol - lastCol);
  820. colDone = true;
  821. }
  822. startHeight += heightLen;
  823. long startCellC = startCellCol;
  824. long startCellR = startCellRow;
  825. land->getCellPos(startCellR,startCellC,currentPos);
  826. float localElev = (worldUnitsPerMeter * 4.0f * (float)GameMap->getLocalHeight(startCellR,startCellC));
  827. currentPos.z += localElev;
  828. if (startHeight+startLocal < currentPos.z)
  829. {
  830. #ifdef LAB_ONLY
  831. x=GetCycles()-x;
  832. MCTimeLOSCalc += x;
  833. #endif
  834. #ifdef LAB_ONLY
  835. if (drawTerrainGrid)
  836. {
  837. Stuff::Vector3D realStart = startPos;
  838. Stuff::Vector4D lineStart, lineEnd;
  839. eye->projectZ(realStart,lineStart);
  840. eye->projectZ(endPos,lineEnd);
  841. debugLines[currentLineElement++] = new LineElement(lineStart,lineEnd,SD_RED,NULL,-1);
  842. }
  843. #endif
  844. return false;
  845. }
  846. if (extRad > Stuff::SMALL)
  847. {
  848. dist.Subtract(endPos,currentPos);
  849. remainingDist = dist.GetApproximateLength();
  850. if (remainingDist < extRad)
  851. break;
  852. }
  853. }
  854. }
  855. #ifdef LAB_ONLY
  856. if (drawTerrainGrid)
  857. {
  858. Stuff::Vector3D realStart = startPos;
  859. Stuff::Vector4D lineStart, lineEnd;
  860. eye->projectZ(realStart,lineStart);
  861. eye->projectZ(endPos,lineEnd);
  862. debugLines[currentLineElement++] = new LineElement(lineStart,lineEnd,SD_GREEN,NULL,-1);
  863. }
  864. #endif
  865. }
  866. #ifdef LAB_ONLY
  867. x=GetCycles()-x;
  868. MCTimeLOSCalc += x;
  869. #endif
  870. return true;
  871. }
  872. #else
  873. #define ACCURACY_ADJUST 1.5f
  874. const float HALF_CELL_DIST = (128.0f / 6.0f);
  875. //---------------------------------------------------------------------------
  876. bool Team::lineOfSight (float startLocal, long mCellRow, long mCellCol, float endLocal, long tCellRow, long tCellCol, long teamId, float extRad, float startExtRad, bool checkVisibleBits)
  877. {
  878. #ifdef LAB_ONLY
  879. __int64 x=GetCycles();
  880. #endif
  881. //-----------------------------------------------------
  882. // Once we allow teams to have alliances (for contacts,
  883. // etc.), simply set all nec. team bits in this mask...
  884. //TILE HACK...
  885. long tileRow = tCellRow / 3;
  886. long tileCol = tCellCol / 3;
  887. if ((teamId < 0) || (teamId >= MAX_TEAMS)) //Not on any team. It can see everything!
  888. return true;
  889. #if 0 //Don't need to check this anymore. We do a distance check outside of this function.
  890. if (checkVisibleBits) {
  891. unsigned char teamMask = 0x01 << teamId;
  892. unsigned char visbBits[4];
  893. //----------------------------------------------------------------------------
  894. // First check is simple. Is anyone within the magical line of sight radius?
  895. // If not, return false and move on.
  896. // If they are, you MUST check LOS between this object and the other one.
  897. bool losResult = false;
  898. visbBits[0] = Terrain::VisibleBits->getFlag(tileRow, tileCol);
  899. if (visbBits[0] & teamMask)
  900. losResult = true;
  901. if (!losResult)
  902. {
  903. visbBits[1] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol);
  904. if (visbBits[1] & teamMask)
  905. losResult = true;
  906. }
  907. if (!losResult)
  908. {
  909. visbBits[2] = Terrain::VisibleBits->getFlag(tileRow + 1, tileCol + 1);
  910. if (visbBits[2] & teamMask)
  911. losResult = true;
  912. }
  913. if (!losResult)
  914. {
  915. visbBits[3] = Terrain::VisibleBits->getFlag(tileRow, tileCol + 1);
  916. if (visbBits[3] & teamMask)
  917. losResult = true;
  918. }
  919. if (!losResult)
  920. {
  921. #ifdef LAB_ONLY
  922. x=GetCycles()-x;
  923. MCTimeLOSCalc += x;
  924. #endif
  925. return losResult;
  926. }
  927. }
  928. #endif
  929. if (useRealLOS)
  930. {
  931. //------------------------------------------------------------------------------------------
  932. // Within magic radius. Check REAL LOS now.
  933. // Check is really simple.
  934. // Find deltaCellRow and deltaCellCol and iterate over them from source to dest.
  935. // If the magic line ever goes BELOW the terrainElevation PLUS localElevation return false.
  936. Stuff::Vector3D startPos, endPos;
  937. startPos.Zero();
  938. endPos.Zero();
  939. land->getCellPos(tCellRow,tCellCol,endPos);
  940. land->getCellPos(mCellRow,mCellCol,startPos);
  941. startPos.z += startLocal;
  942. endPos.z += endLocal;
  943. Stuff::Vector3D deltaCellVec;
  944. deltaCellVec.y = tCellRow - mCellRow;
  945. deltaCellVec.x = tCellCol - mCellCol;
  946. deltaCellVec.z = 0.0f;
  947. float startHeight = startPos.z;
  948. float length = deltaCellVec.GetApproximateLength();
  949. length *= ACCURACY_ADJUST;
  950. if (length > Stuff::SMALL)
  951. {
  952. float colLength = (endPos.x - startPos.x) / length;
  953. float rowLength = (endPos.y - startPos.y) / length;
  954. float heightLen = (endPos.z - startPos.z) / (length + ACCURACY_ADJUST);
  955. Stuff::Vector3D currentPos = startPos;
  956. currentPos.z = land->getTerrainElevation(currentPos);
  957. long maxDistIter = (length - 0.5f);
  958. long maxTrees = 0;
  959. Stuff::Vector3D dist;
  960. dist.Subtract(endPos,currentPos);
  961. float remainingDist = dist.GetApproximateLength();
  962. bool checkExtent = (extRad > Stuff::SMALL);
  963. bool checkStart = (startExtRad > Stuff::SMALL);
  964. extRad += HALF_CELL_DIST;
  965. for (long distIter = 0;distIter < maxDistIter;distIter++)
  966. {
  967. bool outsideStartRadius = true;
  968. if (checkStart)
  969. {
  970. Stuff::Vector3D distance;
  971. distance.Subtract(currentPos,startPos);
  972. distance.z = 0.0f;
  973. float dist = distance.GetApproximateLength();
  974. if (dist <= startExtRad)
  975. outsideStartRadius = false;
  976. }
  977. startHeight += heightLen;
  978. long curCellRow, curCellCol;
  979. land->worldToCell(currentPos,curCellRow, curCellCol);
  980. float localElev = (worldUnitsPerMeter * 4.0f * (float)GameMap->getLocalHeight(curCellRow,curCellCol));
  981. float thisHeight = currentPos.z + localElev;
  982. //First, check if we are now inside the extent radius of the thing we are calcing LOS to.
  983. // If we are and we haven't returned false since we're here, we can see it!!!!
  984. if (checkExtent)
  985. {
  986. dist.Subtract(endPos,currentPos);
  987. remainingDist = dist.GetApproximateLength();
  988. if (remainingDist <= extRad)
  989. break;
  990. }
  991. if (outsideStartRadius && (startHeight < thisHeight))
  992. {
  993. bool isTree = false;
  994. if (GameMap->getForest(curCellRow,curCellCol))
  995. {
  996. maxTrees++;
  997. isTree = true;
  998. }
  999. if (!isTree || (maxTrees >= MaxTreeLOSCellBlock))
  1000. {
  1001. #ifdef LAB_ONLY
  1002. x=GetCycles()-x;
  1003. MCTimeLOSCalc += x;
  1004. #endif
  1005. #ifdef LAB_ONLY
  1006. if (drawTerrainGrid)
  1007. {
  1008. Stuff::Vector3D realStart = startPos;
  1009. Stuff::Vector4D lineStart, lineEnd;
  1010. eye->projectZ(realStart,lineStart);
  1011. eye->projectZ(endPos,lineEnd);
  1012. debugLines[currentLineElement++] = new LineElement(lineStart,lineEnd,SD_RED,NULL,-1);
  1013. }
  1014. #endif
  1015. return false;
  1016. }
  1017. }
  1018. currentPos.x += colLength;
  1019. currentPos.y += rowLength;
  1020. currentPos.z = land->getTerrainElevation(currentPos);
  1021. }
  1022. }
  1023. #ifdef LAB_ONLY
  1024. if (drawTerrainGrid)
  1025. {
  1026. Stuff::Vector3D realStart = startPos;
  1027. Stuff::Vector4D lineStart, lineEnd;
  1028. eye->projectZ(realStart,lineStart);
  1029. eye->projectZ(endPos,lineEnd);
  1030. debugLines[currentLineElement++] = new LineElement(lineStart,lineEnd,SD_GREEN,NULL,-1);
  1031. }
  1032. #endif
  1033. }
  1034. #ifdef LAB_ONLY
  1035. x=GetCycles()-x;
  1036. MCTimeLOSCalc += x;
  1037. #endif
  1038. return true;
  1039. }
  1040. #endif
  1041. //---------------------------------------------------------------------------
  1042. bool Team::lineOfSight (Stuff::Vector3D position, Stuff::Vector3D targetPosition, long teamId, float extRad, float startExtRad, bool checkVisibleBits)
  1043. {
  1044. long posCellR, posCellC;
  1045. long tarCellR, tarCellC;
  1046. land->worldToCell(position, posCellR, posCellC);
  1047. land->worldToCell(targetPosition, tarCellR, tarCellC);
  1048. float elev = land->getTerrainElevation(position);
  1049. float localStart = position.z - elev;
  1050. elev = land->getTerrainElevation(targetPosition);
  1051. float localEnd = targetPosition.z - elev;
  1052. return(lineOfSight(localStart,posCellR, posCellC, localEnd, tarCellR, tarCellC,teamId,extRad, startExtRad, checkVisibleBits));
  1053. }
  1054. //***************************************************************************
  1055. void disableHomeTeamTargets (void) {
  1056. Team::home->disableTargets();
  1057. }
  1058. //---------------------------------------------------------------------------
  1059. void killHomeTeamTargets (void) {
  1060. Team::home->destroyTargets();
  1061. }
  1062. //---------------------------------------------------------------------------
  1063. long Team::Save (PacketFilePtr file, long packetNum)
  1064. {
  1065. TeamStaticData staticData;
  1066. staticData.numTeams = numTeams;
  1067. staticData.homeTeamId = home->getId();
  1068. memcpy(staticData.relations,relations,sizeof(char) * MAX_TEAMS * MAX_TEAMS);
  1069. memcpy(staticData.noPain,noPain,sizeof(bool) * MAX_TEAMS);
  1070. file->writePacket(packetNum,(MemoryPtr)&staticData,sizeof(TeamStaticData),STORAGE_TYPE_RAW);
  1071. packetNum++;
  1072. for (long i=0;i<numTeams;i++)
  1073. {
  1074. TeamData data;
  1075. data.id = teams[i]->getId();
  1076. data.rosterSize = teams[i]->rosterSize;
  1077. memcpy(data.roster,teams[i]->roster,sizeof(GameObjectWatchID) * MAX_MOVERS_PER_TEAM);
  1078. file->writePacket(packetNum,(MemoryPtr)&data,sizeof(TeamData),STORAGE_TYPE_RAW);
  1079. packetNum++;
  1080. }
  1081. return packetNum;
  1082. }
  1083. //---------------------------------------------------------------------------
  1084. long Team::Load (PacketFilePtr file, long packetNum)
  1085. {
  1086. TeamStaticData staticData;
  1087. file->readPacket(packetNum,(MemoryPtr)&staticData);
  1088. packetNum++;
  1089. numTeams = staticData.numTeams;
  1090. memcpy(relations,staticData.relations,sizeof(char) * MAX_TEAMS * MAX_TEAMS);
  1091. memcpy(noPain,staticData.noPain,sizeof(bool) * MAX_TEAMS);
  1092. for (long i=0;i<numTeams;i++)
  1093. {
  1094. TeamData data;
  1095. file->readPacket(packetNum,(MemoryPtr)&data);
  1096. packetNum++;
  1097. teams[i] = new Team;
  1098. //Yet another Haxor.
  1099. // void Init increments numTeams. Decrement here.
  1100. numTeams--;
  1101. teams[i]->init(data.id);
  1102. teams[i]->rosterSize = data.rosterSize;
  1103. memcpy(teams[i]->roster,data.roster,sizeof(GameObjectWatchID) * MAX_MOVERS_PER_TEAM);
  1104. if (data.id == staticData.homeTeamId)
  1105. home = teams[i];
  1106. }
  1107. return packetNum;
  1108. }
  1109. //***************************************************************************