sectormap.cpp 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519
  1. #include "pch.h"
  2. #include "trekmdl.h"
  3. #include "trekctrls.h"
  4. const int c_iClusterHasNoRipcord = 0;
  5. const int c_iClusterHasStationRipcord = 1;
  6. const int c_iClusterHasShipRipcord = 2;
  7. const Color c_rgColorNeutral(0.5f, 0.5f, 0.5f);
  8. static void GetClusterOwners(IclusterIGC* pcluster, SideID& sideOwner, SideID& sideSecondaryOwner)
  9. {
  10. assert (c_cSidesMax == 6);
  11. int nStations[c_cSidesMax] = {0, 0, 0, 0, 0, 0};
  12. // count the stations by side
  13. for (StationLinkIGC* psl = pcluster->GetStations()->first();
  14. (psl != NULL);
  15. psl = psl->next())
  16. {
  17. if (!psl->data()->GetStationType()->HasCapability(c_sabmPedestal))
  18. nStations[psl->data()->GetSide()->GetObjectID()]++;
  19. }
  20. // the owner is the one with the most stations
  21. int nStationsOwner = 0;
  22. int nStationsSecondaryOwner = 0;
  23. sideOwner = NA;
  24. sideSecondaryOwner = NA;
  25. SideID sideID;
  26. for (sideID = 0; sideID < c_cSidesMax; sideID++)
  27. {
  28. if (nStations[sideID] > nStationsOwner)
  29. {
  30. // demote the current top owner
  31. sideSecondaryOwner = sideOwner;
  32. nStationsSecondaryOwner = nStationsOwner;
  33. // track the new top owner
  34. sideOwner = sideID;
  35. nStationsOwner = nStations[sideID];
  36. }
  37. else if (nStations[sideID] > nStationsSecondaryOwner)
  38. {
  39. sideSecondaryOwner = sideID;
  40. nStationsSecondaryOwner = nStations[sideID];
  41. }
  42. }
  43. }
  44. static int GetClusterPopulation(IclusterIGC* pcluster, IsideIGC* pside)
  45. {
  46. int n = 0;
  47. SectorID sectorID = pcluster->GetObjectID();
  48. for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
  49. {
  50. IshipIGC* pship = psl->data();
  51. if (pship->GetSide() == pside)
  52. {
  53. PlayerInfo* ppi = (PlayerInfo*)(pship->GetPrivateData());
  54. if (trekClient.m_fm.IsConnected())
  55. {
  56. if (ppi && (ppi->LastSeenSector() == sectorID) && (ppi->StatusIsCurrent()))
  57. {
  58. if (ppi->LastSeenState() != c_ssObserver && ppi->LastSeenState() != c_ssTurret)
  59. {
  60. IhullTypeIGC* pht = trekClient.GetCore()->GetHullType(ppi->LastSeenShipType());
  61. if (pht != NULL && !(pht->GetCapabilities() & c_habmLifepod))
  62. n++;
  63. }
  64. }
  65. }
  66. else
  67. {
  68. if (pship->GetCluster() == pcluster)
  69. n++;
  70. }
  71. }
  72. }
  73. return n;
  74. }
  75. //////////////////////////////////////////////////////////////////////////////
  76. //
  77. // SectorInfoPane
  78. //
  79. //////////////////////////////////////////////////////////////////////////////
  80. struct StoredIcon
  81. {
  82. Surface* psurfaceIcon;
  83. IsideIGC* pside;
  84. int count;
  85. int sortOrder;
  86. StoredIcon(void)
  87. :
  88. count(1)
  89. {
  90. }
  91. };
  92. typedef Slist_utl<StoredIcon> IconList;
  93. typedef Slink_utl<StoredIcon> IconLink;
  94. static void AddIcon(IObject* psurfaceIcon,
  95. IsideIGC* pside,
  96. int sortOrder,
  97. int sideID,
  98. IconList* picons)
  99. {
  100. for (IconLink* pil = picons->first(); (pil != NULL); pil = pil->next())
  101. {
  102. if ((pil->data().psurfaceIcon == (Surface*)psurfaceIcon) &&
  103. (pil->data().pside == pside))
  104. {
  105. pil->data().count++;
  106. return;
  107. }
  108. }
  109. IconLink* p = new IconLink;
  110. p->data().psurfaceIcon = (Surface*)psurfaceIcon;
  111. p->data().pside = pside;
  112. //Hash in the side ID
  113. p->data().sortOrder = sortOrder += ((int)sideID) * 0x10000;
  114. {
  115. //Walk the list till we find the proper spot
  116. for (IconLink* pil = picons->first(); (pil != NULL); pil = pil->next())
  117. {
  118. if (sortOrder < pil->data().sortOrder)
  119. {
  120. pil->txen(p);
  121. return;
  122. }
  123. }
  124. }
  125. picons->last(p);
  126. }
  127. class SectorInfoPane : public Image
  128. {
  129. private:
  130. TRef<Image> m_pimageBkgnd;
  131. TRef<Image> m_pimageSmallBkgnd;
  132. TRef<Image> m_pimageLargeBkgnd;
  133. TRef<Image> m_pimageExpand;
  134. TRef<IclusterIGC> m_pClusterSel;
  135. TRef<IclusterIGC> m_pClusterMouseOver;
  136. public:
  137. SectorInfoPane()
  138. {
  139. m_pimageSmallBkgnd = GetModeler()->LoadImage("consectorinfobmp", true);
  140. m_pimageLargeBkgnd = GetModeler()->LoadImage("conesectorinfobmp", true);
  141. m_pimageExpand = GetModeler()->LoadImage("consectorexpandbmp", true);
  142. m_pimageBkgnd = m_pimageSmallBkgnd;
  143. }
  144. void CalcBounds()
  145. {
  146. m_bounds = m_pimageBkgnd->GetBounds();
  147. }
  148. void ClearCluster(void)
  149. {
  150. m_pClusterSel = NULL;
  151. m_pClusterMouseOver = NULL;
  152. }
  153. void SelectCluster(IclusterIGC* pClusterSel)
  154. {
  155. m_pClusterSel = pClusterSel;
  156. Changed();
  157. }
  158. void SelectMouseOverCluster(IclusterIGC* pClusterMouseOver)
  159. {
  160. m_pClusterMouseOver = pClusterMouseOver;
  161. Changed();
  162. }
  163. MouseResult HitTest(IInputProvider* pprovider, const Point& point, bool bCaptured)
  164. {
  165. Surface* psurfaceBackground = m_pimageBkgnd->GetSurface();
  166. Surface* psurfaceExpand = m_pimageExpand->GetSurface();
  167. WinPoint pntButton = psurfaceBackground->GetSize() - psurfaceExpand->GetSize();
  168. pntButton = pntButton - WinPoint(16, 4);
  169. if (point.X() > pntButton.X() && point.Y() > pntButton.Y()
  170. && point.X() < psurfaceBackground->GetSize().X()
  171. && point.Y() < psurfaceBackground->GetSize().Y())
  172. {
  173. return MouseResultHit();
  174. }
  175. return m_pimageBkgnd->HitTest(pprovider, point, bCaptured);
  176. }
  177. WinPoint GetButtonOffset()
  178. {
  179. Surface* psurfaceBackground = m_pimageBkgnd->GetSurface();
  180. Surface* psurfaceExpand = m_pimageExpand->GetSurface();
  181. WinPoint pntButton = psurfaceBackground->GetSize() - psurfaceExpand->GetSize();
  182. return pntButton - WinPoint(16, 4);
  183. }
  184. MouseResult Button(IInputProvider* pprovider, const Point& point, int button, bool bCaptured, bool bInside, bool bDown)
  185. {
  186. if (button == 0 && !bDown)
  187. {
  188. WinPoint pntButton = GetButtonOffset();
  189. if (point.X() > pntButton.X() && point.Y() > pntButton.Y())
  190. {
  191. if (m_pimageBkgnd == m_pimageSmallBkgnd)
  192. {
  193. m_pimageBkgnd = m_pimageLargeBkgnd;
  194. }
  195. else
  196. {
  197. m_pimageBkgnd = m_pimageSmallBkgnd;
  198. }
  199. Changed();
  200. }
  201. }
  202. return MouseResult();
  203. }
  204. /*
  205. void DrawStationIconsOfClass(Context* pcontext, IclusterIGC* pcluster,
  206. Point& ptNext, StationClassID classID)
  207. {
  208. const StationListIGC* stationList = pcluster->GetStations();
  209. for (StationLinkIGC* stationLink = (stationList ? stationList->first() : NULL);
  210. stationLink; stationLink=stationLink->next())
  211. {
  212. IstationIGC* pstation = stationLink->data();
  213. // if this station is in the correct class of station
  214. if (pstation->GetBaseStationType()->GetClassID() == classID)
  215. {
  216. // draw this station icon
  217. Surface* psurfaceIcon = (Surface*)(pstation->GetIcon());
  218. if (ptNext.X() < GetButtonOffset().X())
  219. {
  220. pcontext->DrawImage3D(psurfaceIcon, pstation->GetSide()->GetColor(), false, ptNext);
  221. ptNext += Point(psurfaceIcon->GetSize().X(), 0);
  222. }
  223. }
  224. }
  225. }
  226. void DrawStationIcons(Context* pcontext, IclusterIGC* pcluster,
  227. const Point& ptStations)
  228. {
  229. Point ptNext = ptStations;
  230. // draw the station icons in order of importance
  231. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scStarbase);
  232. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scGarrison);
  233. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scShipyard);
  234. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scRipcord);
  235. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scResearch);
  236. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scOrdinance);
  237. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scElectronics);
  238. DrawStationIconsOfClass(pcontext, pcluster, ptNext, c_scMining);
  239. }
  240. */
  241. void DrawAsteroidIcons(Context* pcontext, IEngineFont* pfont, IclusterIGC* pcluster,
  242. const Point& ptAsteroids)
  243. {
  244. Point ptNext = ptAsteroids;
  245. // Count the asteroids
  246. TMap<AsteroidAbilityBitMask, int> mapSpecialAsteroids;
  247. TMap<AsteroidAbilityBitMask, Surface*> mapSpecialAsteroidIcons;
  248. for (AsteroidLinkIGC* asteroidLink = pcluster->GetAsteroids()->first();
  249. asteroidLink != NULL; asteroidLink = asteroidLink->next())
  250. {
  251. AsteroidAbilityBitMask aabm = asteroidLink->data()->GetCapabilities();
  252. // if this asteroid has any special capabilities besides being buildable
  253. if ((aabm & ~c_aabmBuildable) != 0)
  254. {
  255. // let it stand up and be counted.
  256. int nCount = 0;
  257. mapSpecialAsteroids.Find(aabm, nCount);
  258. mapSpecialAsteroids.Set(aabm, nCount+1);
  259. mapSpecialAsteroidIcons.Set(aabm, (Surface*)asteroidLink->data()->GetIcon());
  260. }
  261. }
  262. // draw the asteroids
  263. TMap<AsteroidAbilityBitMask, int>::Iterator iterCount(mapSpecialAsteroids);
  264. TMap<AsteroidAbilityBitMask, Surface*>::Iterator iterIcon(mapSpecialAsteroidIcons);
  265. while (!iterCount.End())
  266. {
  267. pcontext->DrawImage3D(iterIcon.Value(), Color::White(), false, ptNext);
  268. pcontext->DrawString(
  269. pfont,
  270. Color::White(),
  271. ptNext + Point(iterIcon.Value()->GetSize().X() + 4, 0),
  272. ZString(iterCount.Value())
  273. );
  274. ptNext = ptNext - Point(0, iterIcon.Value()->GetSize().Y());
  275. iterCount.Next();
  276. iterIcon.Next();
  277. }
  278. }
  279. float GetHeliumInCluster(IclusterIGC* pcluster)
  280. {
  281. float fOre = 0;
  282. for (AsteroidLinkIGC* asteriodLink = pcluster->GetAsteroids()->first();
  283. asteriodLink != NULL; asteriodLink = asteriodLink->next())
  284. {
  285. AsteroidAbilityBitMask aabm = asteriodLink->data()->GetCapabilities();
  286. // if we can mine helium at this asteroid
  287. if ((aabm & c_aabmMineHe3) != 0)
  288. {
  289. // count it.
  290. fOre += asteriodLink->data()->GetOre();
  291. }
  292. }
  293. return fOre;
  294. }
  295. void Render(Context* pcontext)
  296. {
  297. // draw the background
  298. Surface* psurfaceBackground = m_pimageBkgnd->GetSurface();
  299. pcontext->DrawImage(psurfaceBackground);
  300. // set font
  301. TRef<IEngineFont> pfont = TrekResources::SmallFont();
  302. // draw the resize button
  303. Surface* psurfaceExpand = m_pimageExpand->GetSurface();
  304. pcontext->DrawImage(psurfaceExpand, false,
  305. Point::Cast(psurfaceBackground->GetSize() - psurfaceExpand->GetSize() - WinPoint(16, 4)));
  306. if (m_pClusterSel)
  307. {
  308. const int xBorder = 4;
  309. float yTop = m_pimageBkgnd->GetBounds().GetRect().YSize();
  310. Point ptSectorName(xBorder + 20, yTop - 13);
  311. Point ptStations(xBorder, yTop - 26);
  312. // draw sectorname
  313. pcontext->DrawString(
  314. pfont,
  315. Color::White(),
  316. ptSectorName,
  317. ZString(m_pClusterSel->GetName()) + " Sector"
  318. );
  319. // draw station icons c_cSidesMax
  320. {
  321. IconList icons;
  322. IsideIGC* psideMe = trekClient.GetSide();
  323. {
  324. for (StationLinkIGC* psl = m_pClusterSel->GetStations()->first(); (psl != NULL); psl = psl->next())
  325. {
  326. if (!psl->data()->GetStationType()->HasCapability(c_sabmPedestal))
  327. {
  328. IsideIGC* pside = psl->data()->GetSide();
  329. AddIcon(psl->data()->GetIcon(), pside, NA,
  330. (pside == psideMe) ? (c_cSidesMax * 2) : (c_cSidesMax + pside->GetObjectID()), &icons);
  331. }
  332. }
  333. }
  334. {
  335. SectorID sid = m_pClusterSel->GetObjectID();
  336. for (ShipLinkIGC* psl = trekClient.m_pCoreIGC->GetShips()->first(); (psl != NULL); psl = psl->next())
  337. {
  338. PlayerInfo* ppi = (PlayerInfo*)(psl->data()->GetPrivateData());
  339. if (ppi &&
  340. ppi->StatusIsCurrent() &&
  341. (ppi->LastSeenState() == c_ssFlying) &&
  342. (ppi->LastSeenSector() == sid))
  343. {
  344. HullID hid = ppi->LastSeenShipType();
  345. IhullTypeIGC* pht = trekClient.m_pCoreIGC->GetHullType(hid);
  346. if (pht)
  347. {
  348. IsideIGC* pside = psl->data()->GetSide();
  349. AddIcon(pht->GetIcon(), pside, hid,
  350. (pside == psideMe) ? c_cSidesMax : pside->GetObjectID(), &icons);
  351. }
  352. }
  353. }
  354. }
  355. {
  356. Point ptNext = ptStations;
  357. for (IconLink* pil = icons.first(); (pil != NULL); pil = pil->next())
  358. {
  359. if (ptNext.X() < GetButtonOffset().X())
  360. {
  361. const Color& color = pil->data().pside->GetColor();
  362. pcontext->DrawImage3D(pil->data().psurfaceIcon,
  363. color,
  364. false, ptNext);
  365. ptNext += Point(pil->data().psurfaceIcon->GetSize().X(), 0);
  366. if (pil->data().count > 1)
  367. {
  368. TRef<IEngineFont> pfont = TrekResources::SmallFont();
  369. ZString strCount = pil->data().count;
  370. WinPoint pt = pfont->GetTextExtent(strCount);
  371. pcontext->DrawString(pfont, Color::White(),
  372. ptNext + Point(0, (pil->data().psurfaceIcon->GetSize().Y() - pt.Y())/2),
  373. strCount);
  374. ptNext += Point(pt.X() + 2, 0);
  375. }
  376. }
  377. }
  378. }
  379. }
  380. //DrawStationIcons(pcontext, m_pClusterSel, ptStations);
  381. if (m_pimageBkgnd == m_pimageLargeBkgnd)
  382. {
  383. const int xSecondColumn = m_pimageSmallBkgnd->GetBounds().GetRect().XSize() + xBorder - 15;
  384. Point ptHelium(xSecondColumn, yTop - 30);
  385. Point ptAsteroids(xSecondColumn, yTop - 45);
  386. // draw the helium count
  387. pcontext->DrawString(
  388. pfont,
  389. Color::White(),
  390. ptHelium,
  391. "He3: " + ZString(int(GetHeliumInCluster(m_pClusterSel)))
  392. );
  393. // draw asteroids
  394. DrawAsteroidIcons(pcontext, pfont, m_pClusterSel, ptAsteroids);
  395. }
  396. if (m_pClusterMouseOver)
  397. {
  398. assert(m_pClusterMouseOver == m_pClusterSel);
  399. // draw the cluster warning
  400. AssetMask am = m_pClusterMouseOver->GetClusterSite()->GetClusterAssetMask();
  401. ClusterWarning cw = GetClusterWarning(am,
  402. trekClient.MyMission()->GetMissionParams().bInvulnerableStations);
  403. if (cw > c_cwNoThreat)
  404. {
  405. pcontext->DrawString(
  406. pfont,
  407. Color::White(),
  408. Point(0,0),
  409. GetClusterWarningText(cw)
  410. );
  411. }
  412. }
  413. }
  414. }
  415. };
  416. TRef<IObject> SectorInfoPaneFactory::Apply(ObjectStack& stack)
  417. {
  418. TRef<SectorInfoPane> psectorinfo = new SectorInfoPane();
  419. return (Value*)psectorinfo;
  420. }
  421. //////////////////////////////////////////////////////////////////////////////
  422. //
  423. // SectorMapPane
  424. //
  425. //////////////////////////////////////////////////////////////////////////////
  426. class SectorMapPane : public Image, public IEventSink, public TrekClientEventSink
  427. {
  428. private:
  429. TRef<Image> m_pimageSectorEmpty;
  430. TRef<Image> m_pimageOwnerHighlight;
  431. TRef<Image> m_pimageSecondaryOwnerHighlight;
  432. TRef<Image> m_pimageBkgnd;
  433. TRef<Image> m_pimageSectorHighlight;
  434. TRef<Image> m_pimageSectorTargetHighlight;
  435. TRef<Image> m_pimageSectorSel;
  436. TRef<Image> m_pimageSectorPickable;
  437. TRef<Image> m_pimageSectorPickTarget;
  438. TRef<Image> m_pimageSectorPickableStation;
  439. TRef<Image> m_pimageSectorPickStationTarget;
  440. TRef<Image> m_pimageSectorQueued;
  441. TRef<Image> m_pimageCapitalWarning;
  442. TRef<Image> m_pimageSectorEnemy;
  443. TRef<Image> m_pimageSectorMiner;
  444. TRef<Image> m_pimageSectorWarning;
  445. TRef<Image> m_pimageBomberWarning;
  446. TRef<Image> m_pimageSectorCombat;
  447. TRef<IclusterIGC> m_pClusterSel;
  448. TRef<IEventSink> m_peventSinkTimer;
  449. TRef<SectorInfoPane> m_pSectorInfoPane;
  450. float m_xMin;
  451. float m_xMax;
  452. float m_yMin;
  453. float m_yMax;
  454. float m_xClusterMin;
  455. float m_xClusterMax;
  456. float m_yClusterMin;
  457. float m_yClusterMax;
  458. bool m_bVisible;
  459. int m_nMaskModeActive;
  460. float m_xDrag;
  461. float m_yDrag;
  462. bool m_bDragging;
  463. bool m_bHovering;
  464. bool m_bCanDrag;
  465. Point m_pointLastDrag;
  466. WinRect m_rectMap;
  467. bool m_bFlashFrame;
  468. public:
  469. enum { c_nXBorder = 4, c_nYBorder = 4 };
  470. SectorMapPane(SectorInfoPane* pSectorInfoPane, Number* pvalueMode, int nMaskModeActive) :
  471. Image(pvalueMode),
  472. m_nMaskModeActive(nMaskModeActive),
  473. m_pSectorInfoPane(pSectorInfoPane),
  474. m_bVisible(false),
  475. m_xDrag(0),
  476. m_yDrag(0),
  477. m_bDragging(false),
  478. m_bHovering(false),
  479. m_bCanDrag(false),
  480. m_bFlashFrame(true)
  481. {
  482. pvalueMode->Update();
  483. Modeler* pmodeler = GetModeler();
  484. m_pimageBkgnd = pmodeler->LoadImage("sectormapbkgndbmp", false);
  485. m_pimageSectorHighlight = pmodeler->LoadImage("sectorhighlightbmp", true);
  486. m_pimageSectorTargetHighlight = pmodeler->LoadImage("sectortargetbmp", true);
  487. m_pimageSectorSel = pmodeler->LoadImage("sectorselbmp", true);
  488. m_peventSinkTimer = IEventSink::CreateDelegate(this);
  489. //GetWindow()->GetTimer()->AddSink(m_peventSinkTimer, 1.0f);
  490. m_rectMap = WinRect::Cast(m_pimageBkgnd->GetBounds().GetRect());
  491. m_pimageSectorEmpty = pmodeler->LoadImage("sectoremptybmp", true);
  492. m_pimageOwnerHighlight = pmodeler->LoadImage("sectorownerbmp", true);
  493. m_pimageSecondaryOwnerHighlight = pmodeler->LoadImage("sectorinvaderbmp", true);
  494. m_pimageSectorPickable = pmodeler->LoadImage("sectorripcordbmp", true);
  495. m_pimageSectorPickTarget = pmodeler->LoadImage("sectorripcordtargetbmp", true);
  496. m_pimageSectorPickableStation = pmodeler->LoadImage("sectorripcordstationbmp", true);
  497. m_pimageSectorPickStationTarget = pmodeler->LoadImage("sectorripcordstationtargetbmp", true);
  498. m_pimageSectorQueued = pmodeler->LoadImage("sectorqueuedbmp", true);
  499. m_pimageCapitalWarning = pmodeler->LoadImage("sectorcapitalbmp", true);
  500. m_pimageSectorCombat = pmodeler->LoadImage("sectorcombatbmp", true);
  501. m_pimageSectorWarning = pmodeler->LoadImage("sectorwarningbmp", true);
  502. m_pimageBomberWarning = pmodeler->LoadImage("sectorbomberbmp", true);
  503. m_pimageSectorMiner = pmodeler->LoadImage("sectorminerbmp", true);
  504. m_pimageSectorEnemy = pmodeler->LoadImage("sectorenemybmp", true);
  505. }
  506. ~SectorMapPane()
  507. {
  508. SetVisible(false);
  509. }
  510. void CalcBounds()
  511. {
  512. m_bounds = m_pimageBkgnd->GetBounds();
  513. }
  514. MouseResult HitTest(IInputProvider* pprovider, const Point& point, bool bCaptured)
  515. {
  516. return m_pimageBkgnd->HitTest(pprovider, point, bCaptured);
  517. }
  518. void OnSessionLost(char * szReason, LPDPMSG_SESSIONLOST lpSessionLost, Time lastUpdate, Time now)
  519. {
  520. SetVisible(false);
  521. //Clear the selected cluster without sending the advise
  522. m_pClusterSel = NULL;
  523. m_pSectorInfoPane->ClearCluster();
  524. }
  525. void OnDelPlayer(MissionInfo* pMissionInfo, SideID sideID, PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam)
  526. {
  527. if (pPlayerInfo == trekClient.GetPlayerInfo())
  528. {
  529. SetVisible(false);
  530. //Clear the selected cluster without sending the advise
  531. m_pClusterSel = NULL;
  532. m_pSectorInfoPane->ClearCluster();
  533. }
  534. }
  535. void SelectCluster(IclusterIGC* pClusterSel)
  536. {
  537. if (pClusterSel == NULL)
  538. {
  539. IstationIGC* pstation = trekClient.GetShip()->GetStation();
  540. if (pstation)
  541. pClusterSel = pstation->GetCluster();
  542. }
  543. if (pClusterSel != m_pClusterSel)
  544. {
  545. m_pClusterSel = pClusterSel;
  546. ZAssert(m_pSectorInfoPane);
  547. m_pSectorInfoPane->SelectCluster(pClusterSel);
  548. Changed();
  549. }
  550. }
  551. void SetVisible(bool bVisible)
  552. {
  553. if (m_bVisible != bVisible)
  554. {
  555. m_bVisible = bVisible;
  556. if (bVisible)
  557. {
  558. GetWindow()->GetTimer()->AddSink(m_peventSinkTimer, 0.2f);
  559. SelectCluster(trekClient.GetChatCluster());
  560. m_pSectorInfoPane->SelectMouseOverCluster(NULL);
  561. }
  562. else
  563. {
  564. m_pClusterSel = NULL;
  565. ZAssert(m_pSectorInfoPane);
  566. m_pSectorInfoPane->SelectCluster(NULL);
  567. m_pSectorInfoPane->SelectMouseOverCluster(NULL);
  568. GetWindow()->GetTimer()->RemoveSink(m_peventSinkTimer);
  569. }
  570. }
  571. }
  572. bool OnEvent(IEventSource* pevent)
  573. {
  574. Changed();
  575. const int cDivisor = 2;
  576. static int nTick = 0;
  577. ++nTick;
  578. if (nTick == cDivisor)
  579. {
  580. m_bFlashFrame = !m_bFlashFrame;
  581. nTick = 0;
  582. }
  583. return true;
  584. }
  585. void CalculateScreenMinAndMax()
  586. {
  587. // map the sector data
  588. bool bFirstCluster = true;
  589. const ClusterListIGC* clusters = trekClient.m_pCoreIGC->GetClusters();
  590. for (ClusterLinkIGC* cLink = clusters->first(); cLink != NULL; cLink = cLink->next())
  591. {
  592. IclusterIGC* pCluster = cLink->data();
  593. if (pCluster->GetModels()->n() != 0)
  594. {
  595. float x = pCluster->GetScreenX();
  596. float y = pCluster->GetScreenY();
  597. if (bFirstCluster)
  598. {
  599. bFirstCluster = false;
  600. m_xClusterMin = m_xClusterMax = x;
  601. m_yClusterMin = m_yClusterMax = y;
  602. }
  603. else
  604. {
  605. if (x < m_xClusterMin)
  606. m_xClusterMin = x;
  607. else if (x > m_xClusterMax)
  608. m_xClusterMax = x;
  609. if (y < m_yClusterMin)
  610. m_yClusterMin = y;
  611. else if (y > m_yClusterMax)
  612. m_yClusterMax = y;
  613. }
  614. }
  615. }
  616. const float c_bfr = 0.1f *
  617. max(0.0001, max(m_xClusterMax - m_xClusterMin,
  618. m_yClusterMax - m_yClusterMin));
  619. m_xClusterMin -= c_bfr;
  620. m_xClusterMax += c_bfr;
  621. m_yClusterMin -= c_bfr;
  622. m_yClusterMax += c_bfr;
  623. // figure out the minimum and maximum screen coordinates
  624. m_xMin = m_xClusterMin;
  625. m_xMax = m_xClusterMax;
  626. m_yMin = m_yClusterMin;
  627. m_yMax = m_yClusterMax;
  628. float fDesiredAspectRatio = float(m_rectMap.XSize() - 2*c_nXBorder)/(m_rectMap.YSize() - 2*c_nYBorder);
  629. // scale it so that a map with height 2 will fit exactly
  630. const float fMapmakerHeight = 2.2f; // 10% fudge factor
  631. const float fMaxHeight = fMapmakerHeight;
  632. const float fMaxWidth = fMaxHeight * fDesiredAspectRatio;
  633. // if the map is bigger than we want to display, clip the view to the max size
  634. if (m_xMax - m_xMin > fMaxWidth || m_yMax - m_yMin > fMaxHeight)
  635. {
  636. m_bCanDrag = true;
  637. m_xMax = m_xMin + min(m_xMax - m_xMin, fMaxWidth);
  638. m_yMax = m_yMin + min(m_yMax - m_yMin, fMaxHeight);
  639. }
  640. else
  641. {
  642. m_bCanDrag = false;
  643. }
  644. //Preserve the aspect ratio
  645. float fAspectRatio = (m_xMax - m_xMin) / (m_yMax - m_yMin);
  646. if (fAspectRatio < fDesiredAspectRatio)
  647. {
  648. // grow the X size to correct the aspect ratio
  649. float fXGrowth = (fDesiredAspectRatio / fAspectRatio - 1) * (m_xMax - m_xMin);
  650. m_xMax += fXGrowth / 2;
  651. m_xMin -= fXGrowth / 2;
  652. }
  653. else if (fAspectRatio > fDesiredAspectRatio)
  654. {
  655. // grow the Y size to correct the aspect ratio
  656. float fYGrowth = (fAspectRatio / fDesiredAspectRatio - 1) * (m_yMax - m_yMin);
  657. m_yMax += fYGrowth / 2;
  658. m_yMin -= fYGrowth / 2;
  659. }
  660. // translate by the current drag offset
  661. m_xMin += m_xDrag;
  662. m_xMax += m_xDrag;
  663. m_yMin += m_yDrag;
  664. m_yMax += m_yDrag;
  665. }
  666. int ClusterHasFriendlyRipcord(IclusterIGC* pcluster, IsideIGC* pside, const ClusterListIGC& clustersRipcord)
  667. {
  668. const StationListIGC* stationList = pcluster->GetStations();
  669. for (StationLinkIGC* stationLink = stationList->first();
  670. stationLink; stationLink=stationLink->next())
  671. {
  672. IstationIGC* pstation = stationLink->data();
  673. if (pstation->GetStationType()->HasCapability(c_sabmRipcord) &&
  674. (pstation->GetSide() == pside))
  675. {
  676. return c_iClusterHasStationRipcord;
  677. }
  678. }
  679. float ripcordSpeed;
  680. {
  681. IshipIGC* pss = trekClient.GetShip()->GetSourceShip();
  682. if (pss->GetBaseHullType())
  683. ripcordSpeed = pss->GetHullType()->GetRipcordSpeed();
  684. else
  685. ripcordSpeed = -1.0f;
  686. }
  687. for (ProbeLinkIGC* ppl = pcluster->GetProbes()->first(); (ppl != NULL); ppl = ppl->next())
  688. {
  689. IprobeIGC* pprobe = ppl->data();
  690. if ((pprobe->GetSide() == pside) && pprobe->GetCanRipcord(ripcordSpeed))
  691. return c_iClusterHasStationRipcord;
  692. }
  693. return clustersRipcord.find(pcluster) != NULL ? c_iClusterHasShipRipcord : c_iClusterHasNoRipcord;
  694. }
  695. IstationIGC* FindFriendlyStation(IclusterIGC* pcluster, IsideIGC* pside)
  696. {
  697. const StationListIGC* stationList = pcluster->GetStations();
  698. for (StationLinkIGC* stationLink = stationList->first();
  699. stationLink; stationLink=stationLink->next())
  700. {
  701. IstationIGC* pstation = stationLink->data();
  702. if (pstation->GetStationType()->HasCapability(c_sabmRestart) &&
  703. (pstation->GetSide() == pside))
  704. {
  705. return pstation;
  706. }
  707. }
  708. return NULL;
  709. }
  710. bool HasBuildableAsteroid(IclusterIGC* pcluster,
  711. AsteroidAbilityBitMask aabm1,
  712. AsteroidAbilityBitMask aabm2)
  713. {
  714. AsteroidAbilityBitMask aabm = (aabm1 != 0) ? aabm1 : aabm2;
  715. if ((aabm & ~c_aabmBuildable) != 0)
  716. {
  717. aabm &= ~c_aabmBuildable;
  718. for (AsteroidLinkIGC* pal = pcluster->GetAsteroids()->first(); (pal != NULL); pal = pal->next())
  719. {
  720. if (pal->data()->HasCapability(aabm))
  721. return true;
  722. }
  723. }
  724. else if (aabm == c_aabmBuildable)
  725. {
  726. for (AsteroidLinkIGC* pal = pcluster->GetAsteroids()->first(); (pal != NULL); pal = pal->next())
  727. {
  728. if (pal->data()->HasCapability(aabm))
  729. return true;
  730. }
  731. }
  732. return false;
  733. }
  734. bool HasCommandTarget(IclusterIGC* pCluster, Command cmd)
  735. {
  736. ImodelIGC* ptarget = trekClient.GetShip()->GetCommandTarget(cmd);
  737. if (ptarget)
  738. {
  739. if (ptarget->GetCluster() == pCluster)
  740. return true;
  741. else if (ptarget->GetObjectType() == OT_ship)
  742. {
  743. IshipIGC* pship = (IshipIGC*)ptarget;
  744. PlayerInfo* ppi = (PlayerInfo*)(pship->GetPrivateData());
  745. if (ppi->LastSeenSector() == pCluster->GetObjectID())
  746. return true;
  747. }
  748. }
  749. return false;
  750. }
  751. void Render(Context* pcontext)
  752. {
  753. pcontext->SetShadeMode(ShadeModeFlat);
  754. Rect rectClip = m_bounds.GetRect();
  755. rectClip.Expand(-1);
  756. pcontext->Clip(rectClip);
  757. CalculateScreenMinAndMax();
  758. // draw the background
  759. pcontext->DrawImage(m_pimageBkgnd->GetSurface());
  760. // draw all the connecting lines for warps
  761. {
  762. const WarpListIGC* warps = trekClient.m_pCoreIGC->GetWarps();
  763. TVector<VertexL> vertices(warps->n(), 0);
  764. TVector<WORD> indices(warps->n(), 0);
  765. for (WarpLinkIGC* warpLink = warps->first(); warpLink != NULL; warpLink = warpLink->next())
  766. {
  767. IwarpIGC* pWarp = warpLink->data();
  768. IwarpIGC* pwarpDestination = pWarp->GetDestination();
  769. assert (pwarpDestination != NULL);
  770. if (pWarp->GetObjectID() > pwarpDestination->GetObjectID())
  771. {
  772. Color colorWarp = 0.5f * Color::White();
  773. WinPoint point1 = GetClusterPoint(pWarp->GetCluster());
  774. WinPoint point2 = GetClusterPoint(pwarpDestination->GetCluster());
  775. indices.PushEnd(vertices.GetCount());
  776. vertices.PushEnd(VertexL(Vector(point1.x, point1.y, 0), colorWarp));
  777. indices.PushEnd(vertices.GetCount());
  778. vertices.PushEnd(VertexL(Vector(point2.x, point2.y, 0), colorWarp));
  779. }
  780. }
  781. if (vertices.GetCount() != 0)
  782. {
  783. pcontext->SetLineWidth(1.0f);
  784. pcontext->DrawLines(vertices, indices);
  785. }
  786. }
  787. ImodelIGC* pmodelRipcord = trekClient.GetShip()->GetRipcordModel();
  788. IclusterIGC* pclusterRipcord;
  789. IsideIGC* pside = trekClient.GetSide();
  790. ClusterListIGC clustersRipcord;
  791. if (pmodelRipcord)
  792. {
  793. {
  794. IshipIGC* pshipSource = trekClient.GetShip()->GetSourceShip();
  795. IhullTypeIGC* phtSource = pshipSource->GetBaseHullType();
  796. HullAbilityBitMask habm = (phtSource && phtSource->HasCapability(c_habmCanLtRipcord))
  797. ? (c_habmIsRipcordTarget | c_habmIsLtRipcordTarget)
  798. : c_habmIsRipcordTarget;
  799. for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
  800. {
  801. IshipIGC* pship = psl->data();
  802. if (pship != pshipSource)
  803. {
  804. IclusterIGC* pc = trekClient.GetRipcordCluster(pship, habm);
  805. if (pc)
  806. clustersRipcord.last(pc);
  807. }
  808. }
  809. }
  810. pclusterRipcord = pmodelRipcord->GetCluster();
  811. if ((pclusterRipcord == NULL) && (pmodelRipcord->GetObjectType() == OT_ship))
  812. {
  813. PlayerInfo* ppi = (PlayerInfo*)(((IshipIGC*)pmodelRipcord)->GetPrivateData());
  814. if (ppi->StatusIsCurrent())
  815. pclusterRipcord = trekClient.m_pCoreIGC->GetCluster(ppi->LastSeenSector());
  816. }
  817. }
  818. // draw the data for each sector
  819. const ClusterListIGC* clusters = trekClient.m_pCoreIGC->GetClusters();
  820. for (ClusterLinkIGC* cLink = clusters->first(); cLink != NULL; cLink = cLink->next())
  821. {
  822. IclusterIGC* pCluster = cLink->data();
  823. if (pCluster->GetModels()->n() != 0)
  824. {
  825. Point xy = Point::Cast(GetClusterPoint(pCluster));
  826. // draw the sector outline
  827. pcontext->DrawImage3D(m_pimageSectorEmpty->GetSurface(), Color::White(), true, xy);
  828. // color it by the owner(s), if any
  829. SideID sideOwner;
  830. SideID sideSecondaryOwner;
  831. GetClusterOwners(pCluster, sideOwner, sideSecondaryOwner);
  832. // draw the conflict state
  833. AssetMask am = pCluster->GetClusterSite()->GetClusterAssetMask();
  834. ClusterWarning warn = GetClusterWarning(am,
  835. trekClient.MyMission()->GetMissionParams().bInvulnerableStations);
  836. if (warn >= c_cwStationThreatened)
  837. {
  838. if (m_bFlashFrame)
  839. pcontext->DrawImage3D(m_pimageSectorWarning->GetSurface(), Color::White(), true, xy);
  840. }
  841. else if (warn >= c_cwCapitalInCluster)
  842. {
  843. if (m_bFlashFrame)
  844. pcontext->DrawImage3D(m_pimageCapitalWarning->GetSurface(), Color::White(), true, xy);
  845. }
  846. else if (warn >= c_cwBomberInCluster)
  847. {
  848. if (m_bFlashFrame)
  849. pcontext->DrawImage3D(m_pimageBomberWarning->GetSurface(), Color::White(), true, xy);
  850. }
  851. else if (warn >= c_cwMinerThreatened)
  852. {
  853. if (m_bFlashFrame)
  854. pcontext->DrawImage3D(m_pimageSectorMiner->GetSurface(), Color::White(), true, xy);
  855. }
  856. else if (warn >= c_cwCombatInCluster)
  857. {
  858. if (m_bFlashFrame)
  859. pcontext->DrawImage3D(m_pimageSectorCombat->GetSurface(), Color::White(), true, xy);
  860. }
  861. /*
  862. else if (warn >= c_cwEnemyMinerInCluster)
  863. {
  864. pcontext->DrawImage3D(m_pimageSectorMiner->GetSurface(), Color::White(), true, xy);
  865. }
  866. else if (warn > c_cwNoThreat)
  867. {
  868. pcontext->DrawImage3D(m_pimageSectorEnemy->GetSurface(), Color::White(), true, xy);
  869. }
  870. */
  871. // highlight it if it is ours
  872. if (trekClient.GetChatCluster() == pCluster)
  873. pcontext->DrawImage3D(m_pimageSectorHighlight->GetSurface(), Color::White(), true, xy);
  874. else if (m_pClusterSel == pCluster)
  875. pcontext->DrawImage3D(m_pimageSectorSel->GetSurface(), Color::White(), true, xy);
  876. // highlight it if it contains our current or queued command target
  877. bool bHasCurrentCommand = HasCommandTarget(pCluster, c_cmdAccepted);
  878. bool bHasQueuedCommand = HasCommandTarget(pCluster, c_cmdQueued);
  879. if (bHasCurrentCommand)
  880. pcontext->DrawImage3D(m_pimageSectorTargetHighlight->GetSurface(), Color::White(), true, xy);
  881. else if (bHasQueuedCommand)
  882. pcontext->DrawImage3D(m_pimageSectorQueued->GetSurface(), Color::White(), true, xy);
  883. // overlay the ripcord info if we are ripcording
  884. if (pmodelRipcord)
  885. {
  886. if (pmodelRipcord->GetObjectType() == OT_ship)
  887. {
  888. if (pCluster == pclusterRipcord)
  889. {
  890. if (m_bFlashFrame)
  891. pcontext->DrawImage3D(m_pimageSectorPickTarget->GetSurface(), Color::White(), true, xy);
  892. else
  893. pcontext->DrawImage3D(m_pimageSectorPickable->GetSurface(), Color::White(), true, xy);
  894. }
  895. else
  896. {
  897. int cfr = ClusterHasFriendlyRipcord(pCluster, pside, clustersRipcord);
  898. if (cfr != c_iClusterHasNoRipcord)
  899. {
  900. pcontext->DrawImage3D(cfr == c_iClusterHasStationRipcord
  901. ? m_pimageSectorPickableStation->GetSurface()
  902. : m_pimageSectorPickable->GetSurface(),
  903. Color::White(), true, xy);
  904. }
  905. }
  906. }
  907. else
  908. {
  909. if (pCluster == pclusterRipcord)
  910. {
  911. if (m_bFlashFrame)
  912. pcontext->DrawImage3D(m_pimageSectorPickStationTarget->GetSurface(), Color::White(), true, xy);
  913. else
  914. pcontext->DrawImage3D(m_pimageSectorPickableStation->GetSurface(), Color::White(), true, xy);
  915. }
  916. else
  917. {
  918. int cfr = ClusterHasFriendlyRipcord(pCluster, pside, clustersRipcord);
  919. if (cfr != c_iClusterHasNoRipcord)
  920. {
  921. pcontext->DrawImage3D(cfr == c_iClusterHasStationRipcord
  922. ? m_pimageSectorPickableStation->GetSurface()
  923. : m_pimageSectorPickable->GetSurface(),
  924. Color::White(), true, xy);
  925. }
  926. }
  927. }
  928. }
  929. else if (GetWindow()->GetOverlayFlags() & ofTeleportPane)
  930. {
  931. IstationIGC* pstation = trekClient.GetShip()->GetStation();
  932. if (pstation && (pstation->GetCluster() != pCluster) &&
  933. (FindFriendlyStation(pCluster, pside) != NULL))
  934. {
  935. pcontext->DrawImage3D(m_pimageSectorPickable->GetSurface(), Color::White(), true, xy);
  936. }
  937. }
  938. else if (HasBuildableAsteroid(pCluster,
  939. GetWindow()->GetCommandAsteroid(),
  940. GetWindow()->GetInvestAsteroid()))
  941. {
  942. pcontext->DrawImage3D(m_pimageSectorPickable->GetSurface(), Color::White(), true, xy);
  943. }
  944. if (sideOwner != NA)
  945. {
  946. pcontext->DrawImage3D(
  947. m_pimageOwnerHighlight->GetSurface(),
  948. trekClient.GetCore()->GetSide(sideOwner)->GetColor(),
  949. true,
  950. xy
  951. );
  952. }
  953. if (sideSecondaryOwner != NA)
  954. {
  955. pcontext->DrawImage3D(
  956. m_pimageSecondaryOwnerHighlight->GetSurface(),
  957. trekClient.GetCore()->GetSide(sideSecondaryOwner)->GetColor(),
  958. true,
  959. xy
  960. );
  961. }
  962. // draw the dots for the ships
  963. {
  964. int vnSidePopCount[c_cSidesMax];
  965. int nSidesPresent = 0;
  966. // count the population and sides in the sector
  967. {
  968. for (SideLinkIGC* psl = trekClient.m_pCoreIGC->GetSides()->first();
  969. (psl != NULL);
  970. psl = psl->next())
  971. {
  972. SideID sideID = psl->data()->GetObjectID();
  973. vnSidePopCount[sideID] = GetClusterPopulation(pCluster, psl->data());
  974. if (vnSidePopCount[sideID] != 0)
  975. ++nSidesPresent;
  976. }
  977. }
  978. // draw the rows of dots
  979. if (nSidesPresent > 0)
  980. {
  981. const int nDotHeight = 2;
  982. const int nDotWidth = 2;
  983. const int nShipWidth = 1;
  984. const int nDotPitch = 1;
  985. const int nRowPitch = 1;
  986. const int nMaxPop = 7;
  987. int nY = xy.Y() - (nSidesPresent * (nDotHeight + nDotPitch) - nRowPitch)/2;
  988. for (SideLinkIGC* psl = trekClient.m_pCoreIGC->GetSides()->first();
  989. (psl != NULL);
  990. psl = psl->next())
  991. {
  992. int nPopulation = min(nMaxPop, vnSidePopCount[psl->data()->GetObjectID()]);
  993. int nX = xy.X() + 6;
  994. if (nPopulation > 0)
  995. {
  996. while (nPopulation > 0)
  997. {
  998. int nDotPopulation = min(nPopulation, nDotWidth/nShipWidth);
  999. pcontext->FillRect(
  1000. WinRect(
  1001. nX,
  1002. nY,
  1003. nX + nDotPopulation * nShipWidth,
  1004. nY + nDotHeight
  1005. ),
  1006. psl->data()->GetColor()
  1007. );
  1008. nX += nDotWidth + nDotPitch;
  1009. nPopulation -= nDotPopulation;
  1010. }
  1011. nY += nDotHeight + nRowPitch;
  1012. }
  1013. }
  1014. }
  1015. }
  1016. /*
  1017. // draw the bars for the ships
  1018. {
  1019. int nX = xy.X() + 6;
  1020. int nMaxPlayers = 32;
  1021. const int nMaxBarHeight = 8;
  1022. const int nBarWidth = (trekClient.m_pCoreIGC->GetSides()->n() > 2) ? 1 : 2;
  1023. for (SideLinkIGC* psl = trekClient.m_pCoreIGC->GetSides()->first();
  1024. (psl != NULL);
  1025. psl = psl->next())
  1026. {
  1027. IsideIGC* pside = psl->data();
  1028. SideID sideID = pside->GetObjectID();
  1029. int nPopulation = GetClusterPopulation(pCluster, pside);
  1030. if (nPopulation > 0)
  1031. {
  1032. // draw bars for ships
  1033. int nBarHeight = min(min(nPopulation, nMaxBarHeight), max(1,
  1034. (int)((nMaxBarHeight - 1) * log((float)nPopulation)/log((float)nMaxPlayers))+ 1));
  1035. pcontext->FillRect(
  1036. WinRect(
  1037. nX,
  1038. xy.Y() - nMaxBarHeight/2,
  1039. nX + nBarWidth,
  1040. xy.Y() - nMaxBarHeight/2 + nBarHeight
  1041. ),
  1042. pside->GetColor()
  1043. );
  1044. nX += nBarWidth + 1;
  1045. }
  1046. }
  1047. }
  1048. */
  1049. }
  1050. }
  1051. }
  1052. private:
  1053. WinPoint GetClusterPoint(IclusterIGC* pcluster)
  1054. {
  1055. WinPoint pt = WinPoint(
  1056. (int)(m_rectMap.XMin() + ((pcluster->GetScreenX() - m_xMin)/(m_xMax - m_xMin))*(m_rectMap.XSize() - 2*c_nXBorder) + c_nXBorder),
  1057. (int)(m_rectMap.YMin() + ((pcluster->GetScreenY() - m_yMin)/(m_yMax - m_yMin))*(m_rectMap.YSize() - 2*c_nYBorder) + c_nYBorder)
  1058. );
  1059. return pt;
  1060. }
  1061. IclusterIGC* GetClusterAtPoint(const Point& point)
  1062. {
  1063. const ClusterListIGC* clusters = trekClient.m_pCoreIGC->GetClusters();
  1064. IclusterIGC* pClusterFound = NULL;
  1065. int nMinDistance = 15;
  1066. for (ClusterLinkIGC* cLink = clusters->first(); cLink != NULL; cLink = cLink->next())
  1067. {
  1068. IclusterIGC* pCluster = cLink->data();
  1069. // if we know about this cluster...
  1070. if (pCluster->GetModels()->n() != 0)
  1071. {
  1072. WinPoint xy = GetClusterPoint(pCluster);
  1073. Point pointSector((float)xy.X(), (float)xy.Y());
  1074. Point offset = point - pointSector;
  1075. int nDistance = sqrt(offset.LengthSquared());
  1076. if (nDistance < nMinDistance)
  1077. {
  1078. pClusterFound = pCluster;
  1079. nMinDistance = nDistance;
  1080. }
  1081. }
  1082. }
  1083. return pClusterFound;
  1084. }
  1085. void AttemptTeleportTo(IclusterIGC* pcluster)
  1086. {
  1087. // try teleporting to that station
  1088. IstationIGC* pstation = FindFriendlyStation(pcluster, trekClient.GetSide());
  1089. if (NULL == trekClient.GetShip()->GetStation())
  1090. {
  1091. // race condition?
  1092. }
  1093. else if (trekClient.GetShip()->GetStation()->GetCluster() == pcluster)
  1094. {
  1095. trekClient.PostText(false, "You are already in this cluster.");
  1096. trekClient.PlaySoundEffect(errorSound);
  1097. }
  1098. else if (pstation == NULL)
  1099. {
  1100. trekClient.PostText(false, "You do not have an appropriate station in this cluster.");
  1101. trekClient.PlaySoundEffect(errorSound);
  1102. }
  1103. else if (trekClient.GetShip()->GetParentShip() != NULL)
  1104. {
  1105. trekClient.DisembarkAndTeleport(pstation);
  1106. GetWindow()->TurnOffOverlayFlags(ofTeleportPane);
  1107. }
  1108. else
  1109. {
  1110. trekClient.SetMessageType(BaseClient::c_mtGuaranteed);
  1111. BEGIN_PFM_CREATE(trekClient.m_fm, pfmDocked, C, DOCKED)
  1112. END_PFM_CREATE
  1113. pfmDocked->stationID = pstation->GetObjectID();
  1114. trekClient.StartLockDown(
  1115. "Teleporting to " + ZString(pstation->GetName()) + "....",
  1116. BaseClient::lockdownTeleporting);
  1117. GetWindow()->TurnOffOverlayFlags(ofTeleportPane);
  1118. }
  1119. }
  1120. void ChildChanged(Value* pvalue, Value* pvalueNew)
  1121. {
  1122. ZAssert(NULL == pvalueNew);
  1123. ZAssert(GetChild(0) == pvalue);
  1124. pvalue->Update();
  1125. if (trekClient.GetShip()->GetCluster() || trekClient.GetShip()->GetStation())
  1126. SetVisible((((int)Number::Cast(pvalue)->GetValue()) & m_nMaskModeActive) != 0);
  1127. }
  1128. const char* GetClusterCursor()
  1129. {
  1130. if (trekClient.GetShip()->fRipcordActive()
  1131. || (GetWindow()->GetOverlayFlags() & ofTeleportPane))
  1132. return AWF_CURSOR_DEFAULT;
  1133. else if (GetWindow()->GetConsoleImage()->GetConsoleData()->IsComposingCommand()
  1134. || trekClient.GetShip()->GetCluster() != NULL)
  1135. return "goto";
  1136. else
  1137. return AWF_CURSOR_DEFAULT;
  1138. }
  1139. void MouseMove(IInputProvider* pprovider, const Point& point, bool bCaptured, bool bInside)
  1140. {
  1141. if (bCaptured)
  1142. {
  1143. ZAssert(m_bDragging && m_bCanDrag);
  1144. float fScale = (m_xMax - m_xMin)/m_rectMap.XSize();
  1145. float fDeltaX = fScale * (m_pointLastDrag.X() - point.X());
  1146. float fDeltaY = fScale * (m_pointLastDrag.Y() - point.Y());
  1147. // make sure we don't drag the map off of the screen
  1148. m_xDrag = max(min((m_xClusterMax - m_xClusterMin) - (m_xMax - m_xMin), m_xDrag + fDeltaX), 0);
  1149. m_yDrag = max(min((m_yClusterMax - m_yClusterMin) - (m_yMax - m_yMin), m_yDrag + fDeltaY), 0);
  1150. m_pointLastDrag = point;
  1151. GetWindow()->SetCursor(AWF_CURSOR_DRAG);
  1152. Changed();
  1153. }
  1154. else
  1155. {
  1156. IclusterIGC* pClusterFound = GetClusterAtPoint(point);
  1157. m_pSectorInfoPane->SelectMouseOverCluster(pClusterFound);
  1158. if (pClusterFound)
  1159. {
  1160. m_bHovering = true;
  1161. if (m_pClusterSel != pClusterFound)
  1162. trekClient.PlaySoundEffect(mouseoverSound);
  1163. SelectCluster(pClusterFound);
  1164. GetWindow()->SetCursor(GetClusterCursor());
  1165. /*
  1166. AssetMask am = pClusterFound->GetClusterSite()->GetClusterAssetMask();
  1167. ClusterWarning cw = GetClusterWarning(am,
  1168. trekClient.MyMission()->GetMissionParams().bInvulnerableStations);
  1169. trekClient.PostText(false, GetClusterWarningText(cw));
  1170. */
  1171. }
  1172. else
  1173. {
  1174. m_bHovering = false;
  1175. SelectCluster(trekClient.GetChatCluster());
  1176. if (m_bCanDrag)
  1177. {
  1178. GetWindow()->SetCursor(AWF_CURSOR_DRAG);
  1179. }
  1180. else
  1181. {
  1182. GetWindow()->SetCursor(AWF_CURSOR_DEFAULT);
  1183. }
  1184. }
  1185. }
  1186. Changed();
  1187. }
  1188. virtual void MouseLeave(IInputProvider* pprovider)
  1189. {
  1190. m_bHovering = false;
  1191. SelectCluster(trekClient.GetChatCluster());
  1192. m_pSectorInfoPane->SelectMouseOverCluster(NULL);
  1193. if (!m_bDragging)
  1194. GetWindow()->SetCursor(AWF_CURSOR_DEFAULT);
  1195. Changed();
  1196. }
  1197. MouseResult Button(IInputProvider* pprovider, const Point& point, int button, bool bCaptured, bool bInside, bool bDown)
  1198. {
  1199. IclusterIGC* pClusterFound = GetClusterAtPoint(point);
  1200. if (bDown)
  1201. {
  1202. if (0 == button)
  1203. {
  1204. if (pClusterFound)
  1205. {
  1206. trekClient.PlaySoundEffect(mouseclickSound);
  1207. SelectCluster(pClusterFound);
  1208. // if we are ripcording, set the target ripcord cluster
  1209. if (trekClient.GetShip()->fRipcordActive() && !trekClient.GetShip()->GetAutopilot())
  1210. {
  1211. trekClient.RequestRipcord(trekClient.GetShip(), pClusterFound);
  1212. }
  1213. // if we are teleporting, try to teleport to a station in
  1214. // the selected station.
  1215. else if (GetWindow()->GetOverlayFlags() & ofTeleportPane)
  1216. {
  1217. AttemptTeleportTo(pClusterFound);
  1218. }
  1219. else
  1220. {
  1221. // if we are in a station, change the view cluster
  1222. if (trekClient.GetShip()->GetCluster() == NULL)
  1223. {
  1224. ZAssert(trekClient.GetShip()->GetStation() != NULL);
  1225. trekClient.RequestViewCluster(pClusterFound);
  1226. GetWindow()->SetViewMode(TrekWindow::vmCommand);
  1227. }
  1228. else if (pClusterFound == trekClient.GetShip()->GetCluster())
  1229. {
  1230. // do nothing - users find anything else confusing.
  1231. }
  1232. else if (true)//!TrekWindow::CommandCamera(GetWindow()->GetCameraMode()))
  1233. {
  1234. // give the player a command to goto that sector
  1235. DataBuoyIGC db;
  1236. db.position = Vector(0, 0, 0);
  1237. db.clusterID = pClusterFound->GetObjectID();
  1238. db.type = c_buoyCluster;
  1239. IbuoyIGC* b = (IbuoyIGC*)(trekClient.m_pCoreIGC->CreateObject(trekClient.m_now, OT_buoy, &db, sizeof(db)));
  1240. assert (b);
  1241. b->AddConsumer();
  1242. trekClient.SendChat(trekClient.GetShip(),
  1243. CHAT_INDIVIDUAL, trekClient.GetShipID(),
  1244. NA, NULL,
  1245. c_cidGoto, OT_buoy, b->GetObjectID(), b);
  1246. b->ReleaseConsumer();
  1247. b->Release();
  1248. }
  1249. }
  1250. }
  1251. else if (m_bCanDrag)
  1252. {
  1253. // start a drag
  1254. m_bDragging = true;
  1255. m_pointLastDrag = point;
  1256. GetWindow()->SetCursor(AWF_CURSOR_DRAG);
  1257. Changed();
  1258. return MouseResultCapture();
  1259. }
  1260. }
  1261. else if (1 == button && pClusterFound)
  1262. {
  1263. // let the console handle this
  1264. trekClient.PlaySoundEffect(mouseclickSound);
  1265. TrekWindow* pWindow = GetWindow ();
  1266. pWindow->GetConsoleImage()->GetConsoleData()->PickCluster(pClusterFound, button);
  1267. pWindow->GetInput ()->SetFocus (false);
  1268. }
  1269. }
  1270. else
  1271. {
  1272. if (m_bDragging && 0 == button)
  1273. {
  1274. m_bDragging = false;
  1275. if (pClusterFound)
  1276. {
  1277. GetWindow()->SetCursor(GetClusterCursor());
  1278. }
  1279. else if (!bInside)
  1280. {
  1281. GetWindow()->SetCursor(AWF_CURSOR_DEFAULT);
  1282. }
  1283. else
  1284. {
  1285. GetWindow()->SetCursor(AWF_CURSOR_DRAG);
  1286. }
  1287. Changed();
  1288. return MouseResultRelease();
  1289. }
  1290. }
  1291. Changed();
  1292. return MouseResult();
  1293. }
  1294. void OnClusterChanged(IclusterIGC* pcluster)
  1295. {
  1296. if (!m_bHovering)
  1297. {
  1298. SelectCluster(pcluster);
  1299. }
  1300. }
  1301. };
  1302. TRef<IObject> SectorMapPaneFactory::Apply(ObjectStack& stack)
  1303. {
  1304. TRef<SectorInfoPane> pinfoPane; CastTo(pinfoPane, (Pane*)(IObject*)stack.Pop());
  1305. TRef<Number> pnumberMode; CastTo(pnumberMode, (IObject*)stack.Pop());
  1306. TRef<Number> pnumberMaskModeActive; CastTo(pnumberMaskModeActive, (IObject*)stack.Pop());
  1307. TRef<Image> psectormap = new SectorMapPane(pinfoPane, pnumberMode, (int)pnumberMaskModeActive->GetValue());
  1308. return (Value*)psectormap;
  1309. }