multihud.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/multihud.cpp $*
  25. * *
  26. * $Author:: Byon_g $*
  27. * *
  28. * $Modtime:: 2/11/02 6:06p $*
  29. * *
  30. * $Revision:: 139 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "multihud.h"
  36. #include <stdio.h>
  37. #include "soldier.h"
  38. #include "assets.h"
  39. #include "wwprofile.h"
  40. #include "playermanager.h"
  41. #include "teammanager.h"
  42. #include "cnetwork.h"
  43. #include "timemgr.h"
  44. #include "miscutil.h"
  45. #include "gamedata.h"
  46. #include "combat.h"
  47. #include "ccamera.h"
  48. #include "gameobjmanager.h"
  49. #include "smartgameobj.h"
  50. #include "vehicle.h"
  51. #include "physcoltest.h"
  52. #include "pscene.h"
  53. #include "phys.h"
  54. #include "damage.h"
  55. #include "movephys.h"
  56. #include "humanphys.h"
  57. #include "weapons.h"
  58. #include "useroptions.h"
  59. #include "devoptions.h"
  60. #include "wwdebug.h"
  61. #include "overlay.h"
  62. #include "spawn.h"
  63. #include "string_ids.h"
  64. #include "translatedb.h"
  65. #include "texture.h"
  66. #include "render2d.h"
  67. #include "render2dsentence.h"
  68. #include "networkobjectmgr.h"
  69. #include "networkobject.h"
  70. #include "building.h"
  71. #include "powerup.h"
  72. #include "staticnetworkobject.h"
  73. #include "widestring.h"
  74. #include "font3d.h"
  75. #include "apppackettypes.h"
  76. #include "bandwidthgraph.h"
  77. #include "priority.h"
  78. #include "consolemode.h"
  79. #include "stylemgr.h"
  80. #include "demosupport.h"
  81. //
  82. // MultiHUDClass statics
  83. //
  84. const float MultiHUDClass::MAX_OVERLAY_DISTANCE_M = 50;
  85. const float MultiHUDClass::Y_INCREMENT_FACTOR = 1.2f;
  86. #ifdef WWDEBUG
  87. Render2DTextClass * MultiHUDClass::PTextRenderer = NULL;
  88. Font3DInstanceClass * MultiHUDClass::PFont = NULL;
  89. #endif
  90. Render2DSentenceClass* MultiHUDClass::NameRenderer = NULL;
  91. float MultiHUDClass::BottomTextYPos = 0;
  92. //bool MultiHUDClass::VerboseLists = false;
  93. PlayerlistFormatEnum MultiHUDClass::PlayerlistFormat = PLAYERLIST_FORMAT_TINY;
  94. bool MultiHUDClass::IsOn = false;
  95. //-----------------------------------------------------------------------------
  96. void MultiHUDClass::Init(void)
  97. {
  98. WWDEBUG_SAY(("MultiHUDClass::Init\n"));
  99. if (!ConsoleBox.Is_Exclusive()) {
  100. #ifdef WWDEBUG
  101. WWASSERT(WW3DAssetManager::Get_Instance() != NULL);
  102. PFont = WW3DAssetManager::Get_Instance()->Get_Font3DInstance("FONT6x8.TGA");
  103. WWASSERT(PFont != NULL);
  104. PFont->Set_Mono_Spaced();
  105. SET_REF_OWNER(PFont);
  106. PTextRenderer = new Render2DTextClass(PFont);
  107. PTextRenderer->Set_Coordinate_Range(Render2DClass::Get_Screen_Resolution());
  108. #endif
  109. NameRenderer = new Render2DSentenceClass;
  110. StyleMgrClass::Assign_Font(NameRenderer, StyleMgrClass::FONT_INGAME_TXT);
  111. NameRenderer->Set_Mono_Spaced(true);
  112. IsOn = true;
  113. }
  114. }
  115. //-----------------------------------------------------------------------------
  116. void MultiHUDClass::Shutdown(void)
  117. {
  118. WWDEBUG_SAY(("MultiHUDClass::Shutdown\n"));
  119. if (NameRenderer) {
  120. delete NameRenderer;
  121. NameRenderer = NULL;
  122. }
  123. #ifdef WWDEBUG
  124. if (PTextRenderer != NULL) {
  125. delete PTextRenderer;
  126. PTextRenderer = NULL;
  127. }
  128. if (PFont != NULL) {
  129. PFont->Release_Ref();
  130. PFont = NULL;
  131. }
  132. #endif
  133. IsOn = false;
  134. }
  135. //-----------------------------------------------------------------------------
  136. void MultiHUDClass::Render_Text(WideStringClass & text, float x, float y, ULONG color)
  137. {
  138. if (NameRenderer) {
  139. //
  140. // Text comes out blurry with the new text system if the text position
  141. // is non-integral.
  142. //
  143. x = cMathUtil::Round(x);
  144. y = cMathUtil::Round(y);
  145. NameRenderer->Set_Location(Vector2(x, y));
  146. NameRenderer->Build_Sentence(text);
  147. NameRenderer->Draw_Sentence(color);
  148. }
  149. }
  150. //-----------------------------------------------------------------------------
  151. void MultiHUDClass::Toggle(void)
  152. {
  153. if (IsOn) {
  154. Shutdown();
  155. } else {
  156. Init();
  157. }
  158. }
  159. //-----------------------------------------------------------------------------
  160. bool MultiHUDClass::Is_On(void)
  161. {
  162. return IsOn;
  163. }
  164. //-----------------------------------------------------------------------------
  165. void MultiHUDClass::Render(void)
  166. {
  167. #ifdef WWDEBUG
  168. if (PTextRenderer != NULL) {
  169. WWPROFILE("MultiHud Debug Render");
  170. PTextRenderer->Render();
  171. }
  172. #endif
  173. if (NameRenderer != NULL) {
  174. WWPROFILE("MultiHud Render");
  175. NameRenderer->Render();
  176. }
  177. }
  178. //-----------------------------------------------------------------------------
  179. //
  180. // Simple but presumably hugely inefficient code follows
  181. //
  182. void MultiHUDClass::Show_Player_Names(void)
  183. {
  184. if (NameRenderer == NULL) {
  185. return;
  186. }
  187. WWPROFILE("Show_Player_Name");
  188. if (GameModeManager::Find("Menu")->Is_Active() ||
  189. COMBAT_CAMERA == NULL ||
  190. !cNetwork::I_Am_Client() ||
  191. cUserOptions::ShowNamesOnSoldier.Is_False()) {
  192. return;
  193. }
  194. //
  195. // Project name of each player onto his commando
  196. //
  197. for (
  198. SLNode<SmartGameObj> * smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head();
  199. smart_objnode;
  200. smart_objnode = smart_objnode->Next()) {
  201. SmartGameObj * p_smart_obj = smart_objnode->Data();
  202. WWASSERT(p_smart_obj != NULL);
  203. //
  204. // We will eliminate candidates with sequential tests. Want to
  205. // avoid deep conditional nesting here
  206. //
  207. if (p_smart_obj->Is_Delete_Pending()) {
  208. continue;
  209. }
  210. //
  211. // We are only interested in soldiers
  212. //
  213. if (p_smart_obj->As_SoldierGameObj() == NULL) {
  214. continue;
  215. }
  216. //
  217. // ... living soldiers
  218. //
  219. WWASSERT(p_smart_obj->Get_Defense_Object() != NULL);
  220. float health = p_smart_obj->Get_Defense_Object()->Get_Health();
  221. if (health < WWMATH_EPSILON) {
  222. continue;
  223. }
  224. //
  225. // ... with player objects
  226. //
  227. cPlayer * p_player = NULL;
  228. if (p_smart_obj->Has_Player()) {
  229. p_player = cPlayerManager::Find_Player(p_smart_obj->Get_Control_Owner());
  230. }
  231. if (p_player == NULL) {
  232. continue;
  233. }
  234. //
  235. // Is this guy inside our frustrum?
  236. //
  237. Vector3 text_position_3d;
  238. p_smart_obj->Get_Position(&text_position_3d);
  239. text_position_3d.Z += 1.3f;
  240. Vector3 text_position_2d;
  241. if (COMBAT_CAMERA->Project(text_position_2d, text_position_3d) != CameraClass::INSIDE_FRUSTUM) {
  242. continue;
  243. }
  244. //
  245. // Take stealthing into account.
  246. //
  247. bool is_stealthed = false;
  248. SoldierGameObj * p_soldier = p_smart_obj->As_SoldierGameObj();
  249. WWASSERT(p_soldier != NULL);
  250. VehicleGameObj * p_vehicle = NULL;
  251. if (p_soldier->Is_Stealthed()) {
  252. is_stealthed = true;
  253. } else {
  254. p_vehicle = p_soldier->Get_Vehicle();
  255. if (p_vehicle != NULL && p_vehicle->Is_Stealthed()) {
  256. is_stealthed = true;
  257. }
  258. }
  259. if (COMBAT_STAR != NULL && p_soldier->Is_Teammate(COMBAT_STAR)) {
  260. //
  261. // Don't skip for teammates...
  262. //
  263. } else if (is_stealthed) {
  264. continue;
  265. }
  266. //
  267. // adjust x,y from range -1 to 1
  268. //
  269. text_position_2d.X = (text_position_2d.X + 1) * Render2DClass::Get_Screen_Resolution().Width() / 2;
  270. text_position_2d.Y = (1 - text_position_2d.Y) * Render2DClass::Get_Screen_Resolution().Height() / 2;
  271. //
  272. // Is this guy nearby?
  273. //
  274. Vector3 ray_start = COMBAT_CAMERA->Get_Transform().Get_Translation();
  275. Vector3 delta = text_position_3d - ray_start;
  276. float apparent_distance = delta.Length();
  277. if (COMBAT_CAMERA->Is_Star_Sniping()) {
  278. //
  279. // adjust the apparent distance
  280. //
  281. float zoom = COMBAT_CAMERA->Get_Profile_Zoom();
  282. WWASSERT(zoom > 0);
  283. apparent_distance /= zoom;
  284. }
  285. if (apparent_distance > MAX_OVERLAY_DISTANCE_M) {
  286. continue;
  287. }
  288. if (CombatManager::Is_First_Person() && COMBAT_STAR != NULL) {
  289. //
  290. // Ignore collision between ray and own commando
  291. //
  292. COMBAT_STAR->Peek_Physical_Object()->Inc_Ignore_Counter();
  293. }
  294. //
  295. // Ok! This guy deserves a ray-cast for visibility...
  296. //
  297. Vector3 ray_end = ray_start + delta * 1.1f;
  298. LineSegClass ray(ray_start, ray_end);
  299. CastResultStruct res;
  300. PhysRayCollisionTestClass raytest(ray, &res,
  301. BULLET_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL);
  302. {
  303. WWPROFILE("Cast Ray");
  304. COMBAT_SCENE->Cast_Ray(raytest);
  305. }
  306. if (CombatManager::Is_First_Person() && COMBAT_STAR != NULL) {
  307. COMBAT_STAR->Peek_Physical_Object()->Dec_Ignore_Counter();
  308. }
  309. if (raytest.CollidedPhysObj == NULL) {
  310. //
  311. // I think this means that the ray collided with the terrain.
  312. //
  313. continue;
  314. }
  315. if (raytest.CollidedPhysObj->Get_Observer() == NULL) {
  316. continue;
  317. } else {
  318. PhysicalGameObj * p_blocker = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_PhysicalGameObj();
  319. //if (p_blocker != p_smart_obj) {
  320. if ((p_blocker == NULL) ||
  321. ((p_blocker != p_smart_obj) && (p_blocker != p_vehicle))) {
  322. //
  323. // The ray failed to collide with the soldier in question
  324. //
  325. continue;
  326. }
  327. }
  328. //
  329. // OK, we should go ahead and draw the name
  330. //
  331. //
  332. // Show name text
  333. //
  334. if (cUserOptions::ShowNamesOnSoldier.Is_True()) {
  335. WideStringClass text(0,true);
  336. text += p_player->Get_Name();
  337. #ifdef WWDEBUG
  338. if (p_player->Invulnerable.Is_True()) {
  339. text += L"\n";
  340. text += TRANSLATE (IDS_MENU_GOD);
  341. }
  342. if (p_player->Get_Damage_Scale_Factor() < 100) {
  343. text += L"\n";
  344. text += TRANSLATE (IDS_MENU_VIP);
  345. }
  346. #endif // WWDEBUG
  347. //
  348. // MVP carries over into next game
  349. //
  350. WWASSERT(The_Game() != NULL);
  351. WideStringClass mvp_name = The_Game()->Get_Mvp_Name();
  352. if (!p_player->Get_Name().Compare_No_Case(mvp_name.Peek_Buffer())) {
  353. text += L"\n";
  354. text += TRANSLATE(IDS_MP_MVP);
  355. if (The_Game()->Get_Mvp_Count() > 1) {
  356. WideStringClass consecutives_text;
  357. consecutives_text.Format(L" * %d", The_Game()->Get_Mvp_Count());
  358. text += consecutives_text;
  359. }
  360. }
  361. //
  362. // WOL game newbies get a "recruit" tag
  363. //
  364. if (GameModeManager::Find("WOL")->Is_Active() &&
  365. COMBAT_STAR != NULL &&
  366. p_soldier->Is_Teammate(COMBAT_STAR) &&
  367. p_player->Get_Num_Wol_Games() <= cPlayer::NUM_NEWBIE_GAMES) {
  368. text += L"\n";
  369. text += TRANSLATE(IDS_MP_RECRUIT);
  370. }
  371. Vector2 textExtent = NameRenderer->Get_Text_Extents(text);
  372. float x = text_position_2d.X - textExtent.X / 2.0f;
  373. float y = text_position_2d.Y;
  374. float scale = (MAX_OVERLAY_DISTANCE_M - apparent_distance) / MAX_OVERLAY_DISTANCE_M;
  375. int color = (((int)(scale * 255) & 0xFF) << 24) |
  376. (VRGB_TO_INT32(p_player->Get_Color()) & 0x00FFFFFF);
  377. Render_Text(text, x, y, color);
  378. }
  379. }
  380. }
  381. #ifdef WWDEBUG
  382. //-----------------------------------------------------------------------------
  383. void MultiHUDClass::Render_Debug_Text(LPCSTR text, float x, float y, ULONG color)
  384. {
  385. //
  386. // Text comes out blurry with the new text system if the text position
  387. // is non-integral.
  388. //
  389. WWASSERT(text != NULL);
  390. x = cMathUtil::Round(x);
  391. y = cMathUtil::Round(y);
  392. if (PTextRenderer != NULL) {
  393. WWASSERT(PTextRenderer != NULL);
  394. PTextRenderer->Set_Location(Vector2(x, y));
  395. PTextRenderer->Draw_Text(text, color);
  396. }
  397. }
  398. //-----------------------------------------------------------------------------
  399. void MultiHUDClass::Show_Import_State_Counts(NetworkObjectClass *object)
  400. {
  401. WWASSERT(object != NULL);
  402. if (PTextRenderer == NULL) {
  403. return;
  404. }
  405. bool show = false;
  406. if (cDevOptions::ShowImportStates.Is_True())
  407. {
  408. show = true;
  409. }
  410. float z_offset = 0;
  411. if (cDevOptions::ShowImportStatesSV.Is_True() &&
  412. (object->Get_App_Packet_Type() == APPPACKETTYPE_SOLDIER ||
  413. object->Get_App_Packet_Type() == APPPACKETTYPE_VEHICLE))
  414. {
  415. z_offset = 1.5f;
  416. show = true;
  417. }
  418. Vector3 text_position_3d;
  419. if ( show &&
  420. COMBAT_CAMERA != NULL &&
  421. object->Get_World_Position (text_position_3d))
  422. {
  423. text_position_3d.Z += z_offset;
  424. Vector3 text_position_2d;
  425. if (COMBAT_CAMERA->Project(text_position_2d, text_position_3d) == CameraClass::INSIDE_FRUSTUM) {
  426. text_position_2d.X = (text_position_2d.X + 1) * Render2DClass::Get_Screen_Resolution().Width() / 2;
  427. text_position_2d.Y = (1 - text_position_2d.Y) * Render2DClass::Get_Screen_Resolution().Height() / 2;
  428. StringClass text;
  429. StringClass sub_string;
  430. if (cNetwork::I_Am_Only_Client()) {
  431. sub_string.Format("ISC %d\n", object->Get_Import_State_Count());
  432. text += sub_string;
  433. }
  434. /*
  435. if (cNetwork::I_Am_Server()) {
  436. sub_string.Format(" PRI %7.4f\n", object->Get_Cached_Priority ());
  437. text += sub_string;
  438. }
  439. */
  440. float x = text_position_2d.X - PTextRenderer->Peek_Font()->String_Width("XXXX XXXXX") / 2.0f;
  441. float y = text_position_2d.Y;
  442. int color = 0xFFFFFFFF; // white
  443. if (object->Get_Import_State_Count() % 2 != 0) {
  444. color = 0xFF00FF00; // green
  445. }
  446. Render_Debug_Text(text, x, y, color);
  447. }
  448. }
  449. }
  450. void MultiHUDClass::Show_Distance_And_Priority(NetworkObjectClass *object)
  451. {
  452. WWASSERT(object != NULL);
  453. if (PTextRenderer == NULL) {
  454. return;
  455. }
  456. bool show = false;
  457. if (cDevOptions::ShowPriorities.Is_True()) {
  458. show = true;
  459. }
  460. Vector3 text_position_3d;
  461. if (show && COMBAT_CAMERA != NULL && object->Get_World_Position (text_position_3d))
  462. {
  463. SmartGameObj * player_ptr = GameObjManager::Find_Soldier_Of_Client_ID(cNetwork::Get_My_Id());
  464. if (player_ptr) {
  465. Vector3 position;
  466. player_ptr->Get_Position(&position);
  467. float priority = cPriority::Compute_Object_Priority(cNetwork::Get_My_Id(), position, object, true);
  468. float distance = cPriority::Get_Object_Distance(position, object);
  469. Vector3 text_position_2d;
  470. if (COMBAT_CAMERA->Project(text_position_2d, text_position_3d) == CameraClass::INSIDE_FRUSTUM) {
  471. text_position_2d.X = (text_position_2d.X + 1) * Render2DClass::Get_Screen_Resolution().Width() / 2;
  472. text_position_2d.Y = (1 - text_position_2d.Y) * Render2DClass::Get_Screen_Resolution().Height() / 2;
  473. StringClass text;
  474. StringClass sub_string;
  475. if (cNetwork::I_Am_Only_Client()) {
  476. sub_string.Format("DIS %.1f\n", distance);
  477. text += sub_string;
  478. }
  479. StringClass text2;
  480. StringClass sub_string2;
  481. if (cNetwork::I_Am_Only_Client()) {
  482. sub_string2.Format("PRI %.2f\n", priority);
  483. text2 += sub_string2;
  484. }
  485. /*
  486. if (cNetwork::I_Am_Server()) {
  487. sub_string.Format(" PRI %7.4f\n", object->Get_Cached_Priority ());
  488. text += sub_string;
  489. }
  490. */
  491. float x = text_position_2d.X - PTextRenderer->Peek_Font()->String_Width("XXXX XXXXX") / 2.0f;
  492. float y = text_position_2d.Y;
  493. int color = 0xFFFFFFFF; // white
  494. if (distance < 300.0f) {
  495. color = 0xFF00FF00; // green
  496. }
  497. // Render down a bit so we don't overlap with ISC info.
  498. Render_Debug_Text(text, x, y+10, color);
  499. Render_Debug_Text(text2, x, y+20, color);
  500. }
  501. }
  502. }
  503. }
  504. //-----------------------------------------------------------------------------
  505. void MultiHUDClass::Show_Player_Rhost_Data(SmartGameObj * smart_obj)
  506. {
  507. WWASSERT(smart_obj != NULL);
  508. if (PTextRenderer == NULL) {
  509. return;
  510. }
  511. if (cDevOptions::ShowServerRhostData.Is_True() &&
  512. cNetwork::I_Am_Server() &&
  513. COMBAT_CAMERA != NULL &&
  514. smart_obj->Is_Human_Controlled() &&
  515. !smart_obj->Is_Delete_Pending()) {
  516. int controlling_client = smart_obj->Get_Control_Owner();
  517. cPlayer * p_player = cPlayerManager::Find_Player(controlling_client);
  518. WWASSERT(p_player != NULL);
  519. if (!The_Game() || The_Game()->IsDedicated.Is_False()) {
  520. Vector3 text_position_3d;
  521. smart_obj->Get_Position(&text_position_3d);
  522. text_position_3d.Z += 1.5f;
  523. Vector3 text_position_2d;
  524. if (COMBAT_CAMERA->Project(text_position_2d, text_position_3d) == CameraClass::INSIDE_FRUSTUM) {
  525. text_position_2d.X = (text_position_2d.X + 1) * Render2DClass::Get_Screen_Resolution().Width() / 2;
  526. text_position_2d.Y = (1 - text_position_2d.Y) * Render2DClass::Get_Screen_Resolution().Height() / 2;
  527. SoldierGameObj * p_soldier = smart_obj->As_SoldierGameObj();
  528. if (p_soldier != NULL) {
  529. cRemoteHost * p_rhost = cNetwork::Get_Server_Rhost(controlling_client);
  530. WWASSERT(p_rhost != NULL);
  531. StringClass text;
  532. StringClass sub_string;
  533. sub_string.Format( "Id: %d\n", controlling_client);
  534. text += sub_string;
  535. sub_string.Format( "TP: %-7.4f\n", p_rhost->Get_Threshold_Priority());
  536. text += sub_string;
  537. sub_string.Format( "TBps: %d\n", p_rhost->Get_Target_Bps());
  538. text += sub_string;
  539. sub_string.Format( "RTMs: %d\n", p_rhost->Get_Resend_Timeout_Ms());
  540. text += sub_string;
  541. float x = text_position_2d.X - PTextRenderer->Peek_Font()->String_Width("AAAA: AAAA") / 2.0f;
  542. float y = text_position_2d.Y;
  543. Render_Debug_Text(text, x, y);
  544. }
  545. }
  546. } else {
  547. cRemoteHost * p_rhost = cNetwork::Get_Server_Rhost(controlling_client);
  548. float x = 20;
  549. float y = 60 + controlling_client * 10;
  550. WideStringClass name(p_player->Get_Name(), true);
  551. StringClass short_name;
  552. name.Convert_To(short_name);
  553. int len = name.Get_Length();
  554. char temp_name[256];
  555. strcpy(temp_name, short_name.Peek_Buffer());
  556. strncat(temp_name, " ", 13-len);
  557. StringClass text(temp_name, true);
  558. StringClass sub_string;
  559. sub_string.Format( "Id: %03d ", controlling_client);
  560. text += sub_string;
  561. sub_string.Format( "AP:%1.2f ", p_rhost->Get_Average_Priority());
  562. text += sub_string;
  563. sub_string.Format( "BM:%05.2f ", p_rhost->Get_Bandwidth_Multiplier());
  564. text += sub_string;
  565. sub_string.Format( "TBps:%08d ", p_rhost->Get_Target_Bps());
  566. text += sub_string;
  567. sub_string.Format( "RTMs:%05d ", p_rhost->Get_Resend_Timeout_Ms());
  568. text += sub_string;
  569. sub_string.Format( "%05d/%05d/%05d ", p_rhost->Get_Min_Internal_Pingtime_Ms(), p_rhost->Get_Max_Internal_Pingtime_Ms(), p_rhost->Get_Average_Internal_Pingtime_Ms());
  570. text += sub_string;
  571. sub_string.Format( "Rs:%05d ", p_rhost->Get_Total_Resends());
  572. text += sub_string;
  573. unsigned long time = TIMEGETTIME() - p_rhost->Get_Creation_Time();
  574. time = time / 1000;
  575. sub_string.Format( " Con: %03d.%02d.%02d", time / (60*60), (time / 60) % 60, time % 60);
  576. text += sub_string;
  577. Render_Debug_Text(text, x, y);
  578. if (controlling_client == 1) {
  579. y = 50;
  580. StringClass text("Name ", true);
  581. StringClass sub_string;
  582. sub_string.Format( "RHost ID ");
  583. text += sub_string;
  584. sub_string.Format( "Ave Pri ");
  585. text += sub_string;
  586. sub_string.Format( "Band Mult ");
  587. text += sub_string;
  588. sub_string.Format( "Target BPS ");
  589. text += sub_string;
  590. sub_string.Format( "Resend dly ");
  591. text += sub_string;
  592. sub_string.Format( "Min/Max/Ave ping ");
  593. text += sub_string;
  594. sub_string.Format( "Tot rsnds ");
  595. text += sub_string;
  596. sub_string.Format( "Duration");
  597. text += sub_string;
  598. Render_Debug_Text(text, x, y);
  599. }
  600. }
  601. }
  602. }
  603. //-----------------------------------------------------------------------------
  604. void MultiHUDClass::Show_Client_Rhost_Data(void)
  605. {
  606. if (PTextRenderer == NULL) {
  607. return;
  608. }
  609. if (cDevOptions::ShowClientRhostData.Is_True() &&
  610. cNetwork::I_Am_Client() &&
  611. COMBAT_CAMERA != NULL) {
  612. cRemoteHost * p_rhost = cNetwork::Get_Client_Rhost();
  613. if (p_rhost != NULL) {
  614. StringClass text;
  615. StringClass sub_string;
  616. sub_string.Format("Id: %d\n", 0);
  617. text += sub_string;
  618. sub_string.Format("TP: %-7.4f\n", p_rhost->Get_Threshold_Priority());
  619. text += sub_string;
  620. sub_string.Format("TBps: %d\n", p_rhost->Get_Target_Bps());
  621. text += sub_string;
  622. sub_string.Format("RTMs: %d\n", p_rhost->Get_Resend_Timeout_Ms());
  623. text += sub_string;
  624. float x = 20;
  625. float y = 20;
  626. Render_Debug_Text(text, x, y);
  627. }
  628. }
  629. }
  630. //-----------------------------------------------------------------------------
  631. void MultiHUDClass::Show_Description(NetworkObjectClass * p_object, float height_offset, float max_distance)
  632. {
  633. WWASSERT(p_object != NULL);
  634. WWASSERT(max_distance > 0);
  635. if (PTextRenderer == NULL) {
  636. return;
  637. }
  638. if (COMBAT_CAMERA != NULL &&
  639. !p_object->Is_Delete_Pending()) {
  640. Vector3 text_position_3d;
  641. if (p_object->Get_World_Position(text_position_3d)) {
  642. text_position_3d.Z += height_offset;
  643. Vector3 ray_start = COMBAT_CAMERA->Get_Transform().Get_Translation();
  644. Vector3 delta = text_position_3d - ray_start;
  645. Vector3 text_position_2d;
  646. if (delta.Length() < max_distance &&
  647. COMBAT_CAMERA->Project(text_position_2d, text_position_3d) == CameraClass::INSIDE_FRUSTUM) {
  648. text_position_2d.X = (text_position_2d.X + 1) * Render2DClass::Get_Screen_Resolution().Width() / 2;
  649. text_position_2d.Y = (1 - text_position_2d.Y) * Render2DClass::Get_Screen_Resolution().Height() / 2;
  650. float x = text_position_2d.X;
  651. float y = text_position_2d.Y;
  652. StringClass description;
  653. p_object->Get_Description(description);
  654. if (!description.Is_Empty()) {
  655. float scale = (max_distance - delta.Length()) / max_distance;
  656. int color = (((int)(scale * 255) & 0xFF) << 24) | 0x00FFFFFF;
  657. Render_Debug_Text(description, x, y, color);
  658. }
  659. }
  660. }
  661. }
  662. }
  663. //-----------------------------------------------------------------------------
  664. void MultiHUDClass::Show_Spawner_Data(void)
  665. {
  666. if (PTextRenderer == NULL) {
  667. return;
  668. }
  669. if (COMBAT_CAMERA != NULL && cDevOptions::ShowSpawnerData.Is_True()) {
  670. DynamicVectorClass<SpawnerClass*> spawner_list = SpawnManager::Get_Spawner_List();
  671. for (int i = 0; i < spawner_list.Count(); i++) {
  672. WWASSERT(spawner_list[i] != NULL);
  673. Vector3 text_position_3d;
  674. spawner_list[i]->Get_TM().Get_Translation(&text_position_3d);
  675. text_position_3d.Z += 1.0f;
  676. Vector3 text_position_2d;
  677. if (COMBAT_CAMERA->Project(text_position_2d, text_position_3d) == CameraClass::INSIDE_FRUSTUM) {
  678. char text[300];
  679. ::strcpy(text, spawner_list[i]->Get_Definition().Get_Name());
  680. text_position_2d.X = (text_position_2d.X + 1) * Render2DClass::Get_Screen_Resolution().Width() / 2;
  681. text_position_2d.Y = (1 - text_position_2d.Y) * Render2DClass::Get_Screen_Resolution().Height() / 2;
  682. float x = text_position_2d.X - PTextRenderer->Peek_Font()->String_Width(text) / 2.0f;
  683. float y = text_position_2d.Y;
  684. Render_Debug_Text(text, x, y);
  685. }
  686. }
  687. }
  688. }
  689. #endif // WWDEBUG
  690. //-----------------------------------------------------------------------------
  691. void MultiHUDClass::Think(void)
  692. {
  693. #ifdef WWDEBUG
  694. if (PTextRenderer == NULL) {
  695. return;
  696. }
  697. #endif
  698. if (NameRenderer == NULL) {
  699. return;
  700. }
  701. WWPROFILE("MultiHud Think");
  702. #ifdef WWDEBUG
  703. PTextRenderer->Reset();
  704. #endif
  705. NameRenderer->Reset();
  706. DEMO_SECURITY_CHECK;
  707. if (!GameModeManager::Find("Combat")->Is_Active() ||
  708. GameModeManager::Find("Menu")->Is_Active()) {
  709. return;
  710. }
  711. Show_Player_Names();
  712. // BottomTextYPos = Render2DClass::Get_Screen_Resolution().Bottom - 15;
  713. //
  714. // From here down its all diagnostics
  715. //
  716. #ifdef WWDEBUG
  717. //
  718. // Loop over each network object
  719. //
  720. int count = NetworkObjectMgrClass::Get_Object_Count ();
  721. for (int index = 0; index < count; index ++) {
  722. NetworkObjectClass *object = NetworkObjectMgrClass::Get_Object (index);
  723. //
  724. // Display the import state count and priority for each object
  725. //
  726. Show_Import_State_Counts (object);
  727. Show_Distance_And_Priority(object);
  728. }
  729. {
  730. int count = StaticNetworkObjectClass::Get_Static_Network_Object_Count ();
  731. for (int index = 0; index < count; index ++) {
  732. StaticNetworkObjectClass * p_object = (StaticNetworkObjectClass * ) StaticNetworkObjectClass::Get_Static_Network_Object (index);
  733. WWASSERT(p_object != NULL);
  734. if (
  735. (p_object->As_Door_Network_Object_Class() != NULL && cDevOptions::ShowDoorData.Is_True()) ||
  736. (p_object->As_Elevator_Network_Object_Class() != NULL && cDevOptions::ShowElevatorData.Is_True()) ||
  737. (p_object->As_DSAPO_Network_Object_Class() != NULL && cDevOptions::ShowDSAPOData.Is_True())) {
  738. Show_Description(p_object, 0, 20);
  739. }
  740. }
  741. }
  742. //
  743. // Traverse objects and show pertinent diagnostics
  744. //
  745. SLNode<BaseGameObj> * objnode;
  746. for (objnode = GameObjManager::Get_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) {
  747. WWASSERT(objnode->Data() != NULL);
  748. PhysicalGameObj * p_phys_obj = objnode->Data()->As_PhysicalGameObj();
  749. if (p_phys_obj != NULL) {
  750. SmartGameObj * p_smart_obj = p_phys_obj->As_SmartGameObj();
  751. if (p_smart_obj != NULL) {
  752. Show_Player_Rhost_Data(p_smart_obj);
  753. if (cDevOptions::ShowSoldierData.Is_True()) {
  754. SoldierGameObj * p_soldier = p_smart_obj->As_SoldierGameObj();
  755. if (p_soldier != NULL) {
  756. Show_Description(p_soldier, 1.5f, 20);
  757. }
  758. }
  759. if (cDevOptions::ShowVehicleData.Is_True()) {
  760. VehicleGameObj * p_vehicle = p_smart_obj->As_VehicleGameObj();
  761. if (p_vehicle != NULL) {
  762. Show_Description(p_vehicle, 1.5f, 20);
  763. }
  764. }
  765. }
  766. if (cDevOptions::ShowPowerupData.Is_True()) {
  767. if (p_phys_obj->As_SimpleGameObj() != NULL) {
  768. PowerUpGameObj * p_powerup = p_phys_obj->As_SimpleGameObj()->As_PowerUpGameObj();
  769. if (p_powerup != NULL) {
  770. Show_Description(p_powerup, 0, 20);
  771. }
  772. }
  773. }
  774. }
  775. if (cDevOptions::ShowBuildingData.Is_True()) {
  776. if (objnode->Data()->As_ScriptableGameObj() != NULL) {
  777. BuildingGameObj * p_building = objnode->Data()->As_ScriptableGameObj()->As_BuildingGameObj();
  778. if (p_building != NULL) {
  779. Show_Description(p_building, 0, 100);
  780. }
  781. }
  782. }
  783. }
  784. Show_Spawner_Data();
  785. Show_Client_Rhost_Data();
  786. //#endif // WWDEBUG
  787. //BottomTextYPos = Render2DClass::Get_Screen_Resolution().Bottom - 15;
  788. //#ifdef WWDEBUG
  789. cNetwork::Set_Graphing_Y(64);
  790. //cNetwork::Watch_Bandwidth(PTextRenderer);
  791. cNetwork::Watch_Latency(PTextRenderer);
  792. cNetwork::Watch_Last_Contact(PTextRenderer);
  793. cNetwork::Watch_Packets(PTextRenderer);
  794. cNetwork::Watch_Size_Lists(PTextRenderer);
  795. cNetwork::Watch_Time_Lists(PTextRenderer);
  796. cNetwork::Watch_Packet_Size_Lists(PTextRenderer);
  797. cNetwork::Simulation_Warnings(PTextRenderer);
  798. cBandwidthGraph::Think();
  799. #endif
  800. }
  801. //-----------------------------------------------------------------------------
  802. void MultiHUDClass::Next_Playerlist_Format(void)
  803. {
  804. switch (PlayerlistFormat) {
  805. case PLAYERLIST_FORMAT_TINY:
  806. PlayerlistFormat = PLAYERLIST_FORMAT_MEDIUM;
  807. break;
  808. case PLAYERLIST_FORMAT_MEDIUM:
  809. PlayerlistFormat = PLAYERLIST_FORMAT_FULL;
  810. break;
  811. case PLAYERLIST_FORMAT_FULL:
  812. PlayerlistFormat = PLAYERLIST_FORMAT_TINY;
  813. break;
  814. default:
  815. DIE;
  816. break;
  817. }
  818. }