playermanager.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519
  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/playermanager.cpp $*
  25. * *
  26. * $Author:: Denzil_l $*
  27. * *
  28. * $Modtime:: 2/27/02 6:08p $*
  29. * *
  30. * $Revision:: 128 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "playermanager.h"
  36. #include <win.h>
  37. #include <stdio.h>
  38. #include <float.h>
  39. #include "teammanager.h"
  40. #include "miscutil.h"
  41. #include "_globals.h"
  42. #include "assets.h"
  43. #include "cnetwork.h"
  44. #include "multihud.h"
  45. #include "textdisplay.h"
  46. #include "font3d.h"
  47. #include "gamedata.h"
  48. #include "wwdebug.h"
  49. #include "chunkio.h"
  50. #include "useroptions.h"
  51. #include "smartgameobj.h"
  52. #include "playertype.h"
  53. #include "devoptions.h"
  54. #include "render2d.h"
  55. #include "wwprofile.h"
  56. #include "gametype.h"
  57. #include "translatedb.h"
  58. #include "string_ids.h"
  59. #include "systeminfolog.h"
  60. #include "consolemode.h"
  61. #include "gamespyadmin.h"
  62. #include "demosupport.h"
  63. //
  64. // Class statics
  65. //
  66. SList<cPlayer> cPlayerManager::PlayerList;
  67. cPlayer * cPlayerManager::Player_Array[];
  68. Render2DTextClass * cPlayerManager::PTextRenderer = NULL;
  69. Font3DInstanceClass * cPlayerManager::PFont = NULL;
  70. const float cPlayerManager::Y_INCREMENT_FACTOR = 1.2f;
  71. int cPlayerManager::XPos = 0;
  72. int cPlayerManager::YPos = 0;
  73. Notifier<PlayerMgrEvent> cPlayerManager::mNotifier;
  74. //------------------------------------------------------------------------------------
  75. void cPlayerManager::Onetime_Init(void)
  76. {
  77. WWDEBUG_SAY(("cPlayerManager::Onetime_Init\n"));
  78. if (!ConsoleBox.Is_Exclusive()) {
  79. WWASSERT(PFont == NULL);
  80. WWASSERT(WW3DAssetManager::Get_Instance() != NULL);
  81. PFont = WW3DAssetManager::Get_Instance()->Get_Font3DInstance("FONT6x8.TGA");
  82. WWASSERT(PFont != NULL);
  83. PFont->Set_Mono_Spaced();
  84. SET_REF_OWNER(PFont);
  85. WWASSERT(PTextRenderer == NULL);
  86. PTextRenderer = new Render2DTextClass(PFont);
  87. WWASSERT(PTextRenderer != NULL);
  88. PTextRenderer->Set_Coordinate_Range(Render2DClass::Get_Screen_Resolution());
  89. }
  90. ZeroMemory(Player_Array, sizeof(Player_Array));
  91. }
  92. //------------------------------------------------------------------------------------
  93. void cPlayerManager::Onetime_Shutdown(void)
  94. {
  95. WWDEBUG_SAY(("cPlayerManager::Onetime_Shutdown\n"));
  96. if (!ConsoleBox.Is_Exclusive()) {
  97. WWASSERT(PTextRenderer != NULL);
  98. delete PTextRenderer;
  99. PTextRenderer = NULL;
  100. WWASSERT(PFont != NULL);
  101. PFont->Release_Ref();
  102. PFont = NULL;
  103. }
  104. }
  105. //------------------------------------------------------------------------------------
  106. void cPlayerManager::Think(void)
  107. {
  108. WWPROFILE("cPlayerManager::Think");
  109. if (MultiHUDClass::Is_On()) {
  110. WWASSERT(PTextRenderer != NULL);
  111. Render_Player_List();
  112. }
  113. else {
  114. if (PTextRenderer) PTextRenderer->Reset();
  115. }
  116. }
  117. //-----------------------------------------------------------------------------------
  118. void cPlayerManager::Render(void)
  119. {
  120. WWPROFILE("cPlayerManager::Render");
  121. if (PTextRenderer != NULL) {
  122. WWASSERT(PTextRenderer != NULL);
  123. PTextRenderer->Render();
  124. }
  125. }
  126. //------------------------------------------------------------------------------------
  127. cPlayer * cPlayerManager::Find_Player(int id)
  128. {
  129. SLNode<cPlayer> * objnode;
  130. for (objnode = PlayerList.Head(); objnode; objnode = objnode->Next()) {
  131. cPlayer * p_player = objnode->Data();
  132. WWASSERT(p_player != NULL);
  133. if (p_player->Get_Is_Active().Is_True() &&
  134. p_player->Get_Id() == id) {
  135. return p_player; // found it
  136. }
  137. }
  138. return NULL; // Not found
  139. }
  140. //------------------------------------------------------------------------------------
  141. cPlayer * cPlayerManager::Find_Player(const WideStringClass & name)
  142. {
  143. SLNode<cPlayer> * objnode;
  144. for (objnode = PlayerList.Head(); objnode; objnode = objnode->Next()) {
  145. cPlayer *p_player = objnode->Data();
  146. WWASSERT(p_player != NULL);
  147. if (p_player->Get_Is_Active().Is_True() &&
  148. !name.Compare_No_Case(p_player->Get_Name())) {
  149. return p_player; // found it
  150. }
  151. }
  152. return NULL; // Not found
  153. }
  154. //------------------------------------------------------------------------------------
  155. cPlayer * cPlayerManager::Find_Inactive_Player(const WideStringClass & name)
  156. {
  157. cPlayer * p_result = NULL;
  158. for (
  159. SLNode<cPlayer> * objnode = PlayerList.Head();
  160. objnode != NULL;
  161. objnode = objnode->Next())
  162. {
  163. cPlayer * p_player = objnode->Data();
  164. WWASSERT(p_player != NULL);
  165. if (p_player->Get_Is_Active().Is_False() &&
  166. !p_player->Get_Name().Compare_No_Case(name)) {
  167. p_result = p_player;
  168. break;
  169. }
  170. }
  171. return p_result;
  172. }
  173. //------------------------------------------------------------------------------------
  174. cPlayer * cPlayerManager::Find_Team_Player(int team_number)
  175. {
  176. //WWASSERT(The_Game()->Is_Team_Game());
  177. WWASSERT(team_number >= 0 && team_number < MAX_TEAMS);
  178. SLNode<cPlayer> * objnode;
  179. for (objnode = PlayerList.Head(); objnode; objnode = objnode->Next()) {
  180. cPlayer * p_player = objnode->Data();
  181. WWASSERT(p_player != NULL);
  182. if (p_player->Get_Is_Active().Is_True() &&
  183. p_player->Get_Player_Type() == team_number) {
  184. return p_player; // found it
  185. }
  186. }
  187. return NULL; // Not found
  188. }
  189. //------------------------------------------------------------------------------------
  190. cPlayer * cPlayerManager::Find_Random_Team_Player(int team_number)
  191. {
  192. //WWASSERT(The_Game()->Is_Team_Game());
  193. WWASSERT(team_number >= 0 && team_number < MAX_TEAMS);
  194. int chosen_player = rand() % Tally_Team_Size(team_number);
  195. int count = 0;
  196. SLNode<cPlayer> * objnode;
  197. for (objnode = PlayerList.Head(); objnode; objnode = objnode->Next()) {
  198. cPlayer * p_player = objnode->Data();
  199. WWASSERT(p_player != NULL);
  200. if (p_player->Get_Is_Active().Is_True() &&
  201. p_player->Get_Player_Type() == team_number &&
  202. count++ == chosen_player) {
  203. return p_player; // found it
  204. }
  205. }
  206. return NULL; // Not found
  207. }
  208. //------------------------------------------------------------------------------------
  209. cPlayer * cPlayerManager::Find_Team_Mate(cPlayer * p_player1)
  210. {
  211. WWASSERT(p_player1 != NULL);
  212. WWASSERT(p_player1->Get_Is_Active().Is_True());
  213. //WWASSERT(The_Game()->Is_Team_Game());
  214. int team_number = p_player1->Get_Player_Type();
  215. WWASSERT(team_number >= 0 && team_number < MAX_TEAMS);
  216. SLNode<cPlayer> * objnode;
  217. for (objnode = PlayerList.Head(); objnode; objnode = objnode->Next()) {
  218. cPlayer * p_player2 = objnode->Data();
  219. WWASSERT(p_player2 != NULL);
  220. if (p_player2->Get_Is_Active().Is_True() &&
  221. p_player2->Get_Id() != p_player1->Get_Id() &&
  222. p_player2->Get_Player_Type() == team_number) {
  223. return p_player2; // found it
  224. }
  225. }
  226. return NULL; // Not found
  227. }
  228. cPlayer* cPlayerManager::Find_Clan_Mate(cPlayer* player)
  229. {
  230. if (player != NULL) {
  231. unsigned long clan = player->Get_WOL_ClanID();
  232. int playerID = player->Get_Id();
  233. SLNode<cPlayer>* node = PlayerList.Head();
  234. while (node) {
  235. cPlayer* mate = node->Data();
  236. WWASSERT(mate != NULL);
  237. if (playerID != mate->Get_Id()) {
  238. if (clan == mate->Get_WOL_ClanID()) {
  239. return mate;
  240. }
  241. }
  242. node = node->Next();
  243. }
  244. }
  245. return NULL;
  246. }
  247. //------------------------------------------------------------------------------------
  248. bool cPlayerManager::Is_Player_Present(int id)
  249. {
  250. return (Find_Player(id) != NULL);
  251. }
  252. //------------------------------------------------------------------------------------
  253. bool cPlayerManager::Is_Player_Present(WideStringClass & name)
  254. {
  255. return (Find_Player(name) != NULL);
  256. }
  257. //------------------------------------------------------------------------------------
  258. const WideStringClass & cPlayerManager::Get_Player_Name(int id)
  259. {
  260. cPlayer * p_player = Find_Player(id);
  261. WWASSERT(p_player != NULL);
  262. WWASSERT(p_player->Get_Is_Active().Is_True());
  263. return p_player->Get_Name();
  264. }
  265. //------------------------------------------------------------------------------------
  266. void cPlayerManager::Add(cPlayer * p_player)
  267. {
  268. WWASSERT(p_player != NULL);
  269. PlayerList.Add_Tail(p_player);
  270. PlayerMgrEvent event(PLAYER_ADDED, p_player);
  271. mNotifier.NotifyObservers(event);
  272. }
  273. //------------------------------------------------------------------------------------
  274. void cPlayerManager::Remove(cPlayer * p_player)
  275. {
  276. WWASSERT(p_player != NULL);
  277. PlayerList.Remove(p_player);
  278. PlayerMgrEvent event(PLAYER_REMOVED, p_player);
  279. mNotifier.NotifyObservers(event);
  280. }
  281. void cPlayerManager::Deactivated(cPlayer* p_player)
  282. {
  283. PlayerMgrEvent event(PLAYER_DEACTIVATED, p_player);
  284. mNotifier.NotifyObservers(event);
  285. }
  286. void cPlayerManager::Activated(cPlayer* p_player)
  287. {
  288. PlayerMgrEvent event(PLAYER_ACTIVATED, p_player);
  289. mNotifier.NotifyObservers(event);
  290. }
  291. //------------------------------------------------------------------------------------
  292. int cPlayerManager::Get_Average_Ladder_Points(void)
  293. {
  294. int numPlayers = 0;
  295. int totalPoints = 0;
  296. SList<cPlayer>* playerList = Get_Player_Object_List();
  297. SLNode<cPlayer>* playerNode = playerList->Head();
  298. while (playerNode) {
  299. cPlayer* player = playerNode->Data();
  300. if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  301. ++numPlayers;
  302. totalPoints += player->Get_Ladder_Points();
  303. }
  304. playerNode = playerNode->Next();
  305. }
  306. if (numPlayers) {
  307. return totalPoints / numPlayers;
  308. }
  309. return 0;
  310. }
  311. //------------------------------------------------------------------------------------
  312. unsigned short cPlayerManager::Get_Average_WOL_Points(void)
  313. {
  314. unsigned long numPlayers = 0;
  315. unsigned long totalPoints = 0;
  316. SList<cPlayer>* playerList = Get_Player_Object_List();
  317. SLNode<cPlayer>* playerNode = playerList->Head();
  318. while (playerNode) {
  319. cPlayer* player = playerNode->Data();
  320. if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  321. ++numPlayers;
  322. totalPoints += player->Get_WOL_Points();
  323. }
  324. playerNode = playerNode->Next();
  325. }
  326. if (numPlayers) {
  327. return (unsigned short)(totalPoints / numPlayers);
  328. }
  329. return 0;
  330. }
  331. //------------------------------------------------------------------------------------
  332. int cPlayerManager::Get_Average_Games_Played(void)
  333. {
  334. int numPlayers = 0;
  335. int totalPlayed = 0;
  336. SList<cPlayer>* playerList = Get_Player_Object_List();
  337. SLNode<cPlayer>* playerNode = playerList->Head();
  338. while (playerNode) {
  339. cPlayer* player = playerNode->Data();
  340. if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  341. ++numPlayers;
  342. totalPlayed += player->Get_Num_Wol_Games();
  343. }
  344. playerNode = playerNode->Next();
  345. }
  346. if (numPlayers) {
  347. return (totalPlayed / numPlayers);
  348. }
  349. return 0;
  350. }
  351. //------------------------------------------------------------------------------------
  352. int cPlayerManager::Get_Average_Ping(void)
  353. {
  354. int numPlayers = 0;
  355. int totalPing = 0;
  356. SList<cPlayer>* playerList = Get_Player_Object_List();
  357. SLNode<cPlayer>* playerNode = playerList->Head();
  358. while (playerNode) {
  359. cPlayer* player = playerNode->Data();
  360. //if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  361. if (player && player->Get_Is_Active().Is_True() && player->Is_Human() && player->Get_Ping() >= 0) {
  362. ++numPlayers;
  363. //totalPing += player->Get_Avg_Ping();
  364. totalPing += player->Get_Ping();
  365. }
  366. playerNode = playerNode->Next();
  367. }
  368. if (numPlayers) {
  369. return totalPing / numPlayers;
  370. }
  371. return 0;
  372. }
  373. //------------------------------------------------------------------------------------
  374. int cPlayerManager::Get_Average_FPS(void)
  375. {
  376. int numPlayers = 0;
  377. int totalFPS = 0;
  378. SList<cPlayer>* playerList = Get_Player_Object_List();
  379. SLNode<cPlayer>* playerNode = playerList->Head();
  380. while (playerNode) {
  381. cPlayer* player = playerNode->Data();
  382. if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  383. ++numPlayers;
  384. totalFPS += player->Get_Fps();
  385. }
  386. playerNode = playerNode->Next();
  387. }
  388. if (numPlayers) {
  389. return totalFPS / numPlayers;
  390. }
  391. return 0;
  392. }
  393. //------------------------------------------------------------------------------------
  394. static int Sum_Positions(int position)
  395. {
  396. WWASSERT(position >= 1);
  397. int retval = 0;
  398. for (int i = 0; i < position; i++) {
  399. retval += i;
  400. }
  401. return retval;
  402. }
  403. //------------------------------------------------------------------------------------
  404. void cPlayerManager::Compute_Ladder_Points(int winning_team)
  405. {
  406. WWASSERT(cNetwork::I_Am_Server());
  407. WWASSERT(PTheGameData != NULL);
  408. if (The_Game()->IsLaddered.Is_False()) {
  409. return;
  410. }
  411. cPlayerManager::Sort_Players(false);
  412. DWORD min_qualifying_time_ms = The_Game()->Get_Min_Qualifying_Time_Minutes() * 60 * 1000;
  413. int i = 0;
  414. //
  415. // Count qualifying winners and losers
  416. //
  417. int num_winners = 0;
  418. int num_losers = 0;
  419. for (i = 0; i < MAX_PLAYERS; i++) {
  420. if (Player_Array[i] == NULL ||
  421. Player_Array[i]->Get_Total_Time() < min_qualifying_time_ms) {
  422. continue;
  423. }
  424. if (Player_Array[i]->Get_Player_Type() == winning_team) {
  425. num_winners++;
  426. } else {
  427. num_losers++;
  428. }
  429. }
  430. int win_pos = num_winners;
  431. int lose_pos = 1;
  432. for (i = 0; i < MAX_PLAYERS; i++) {
  433. if (Player_Array[i] == NULL ||
  434. Player_Array[i]->Get_Total_Time() < min_qualifying_time_ms) {
  435. continue;
  436. }
  437. if (Player_Array[i]->Get_Player_Type() == winning_team) {
  438. Player_Array[i]->Set_Ladder_Points(Sum_Positions(win_pos));
  439. win_pos--;
  440. WWASSERT(win_pos >= 0);
  441. } else {
  442. Player_Array[i]->Set_Ladder_Points(-Sum_Positions(lose_pos));
  443. lose_pos++;
  444. }
  445. }
  446. //
  447. // TSS121501
  448. // Additional step. Let's now post-multiply ladder points by the fraction of
  449. // gametime that each player was present.
  450. //
  451. float game_duration_s = The_Game()->Get_Game_Duration_S();
  452. //WWASSERT(game_duration_s > 0);
  453. if (game_duration_s == 0)
  454. {
  455. game_duration_s = 1;
  456. }
  457. for (i = 0; i < MAX_PLAYERS; i++) {
  458. if (Player_Array[i] == NULL ||
  459. Player_Array[i]->Get_Total_Time() < min_qualifying_time_ms) {
  460. continue;
  461. }
  462. float player_duration_s = Player_Array[i]->Get_Total_Time() / 1000.0;
  463. float ratio_present = player_duration_s / game_duration_s;
  464. float ladder_points = ratio_present * Player_Array[i]->Get_Ladder_Points();
  465. /*
  466. WWDEBUG_SAY(("%5.2f * %-4d = %5.2f (%d)\n",
  467. ratio_present,
  468. Player_Array[i]->Get_Ladder_Points(),
  469. ladder_points,
  470. cMathUtil::Round(ladder_points)
  471. ));
  472. */
  473. Player_Array[i]->Set_Ladder_Points(cMathUtil::Round(ladder_points));
  474. }
  475. //
  476. // Do another sort so that the list is sorted on these newly calculated ladder points
  477. //
  478. cPlayerManager::Sort_Players(false);
  479. }
  480. //------------------------------------------------------------------------------------
  481. void cPlayerManager::Increment_Player_Times(void)
  482. {
  483. WWASSERT(cNetwork::I_Am_Server());
  484. //
  485. // Increment the participation time of all active players
  486. //
  487. for (int i = 0; i < MAX_PLAYERS; i++) {
  488. if (Player_Array[i] != NULL &&
  489. Player_Array[i]->Is_Active()) {
  490. Player_Array[i]->Increment_Total_Time();
  491. }
  492. }
  493. }
  494. //------------------------------------------------------------------------------------
  495. WideStringClass cPlayerManager::Determine_Mvp_Name(void)
  496. {
  497. WWASSERT(cNetwork::I_Am_Server());
  498. WideStringClass mvp_name;
  499. WWASSERT(The_Game() != NULL);
  500. DWORD min_qualifying_time_ms = The_Game()->Get_Min_Qualifying_Time_Minutes() * 60 * 1000;
  501. //
  502. // Find the top active, time-qualifying player.
  503. // Player_Array has already been sorted on score.
  504. //
  505. for (int i = 0; i < MAX_PLAYERS; i++) {
  506. if (Player_Array[i] != NULL) {
  507. //Player_Array[i]->Increment_Total_Time();
  508. if (Player_Array[i]->Is_Active() &&
  509. Player_Array[i]->Get_Total_Time() > min_qualifying_time_ms) {
  510. mvp_name = Player_Array[i]->Get_Name();
  511. break;
  512. }
  513. }
  514. }
  515. return mvp_name;
  516. }
  517. //------------------------------------------------------------------------------------
  518. int cPlayerManager::Compute_Full_Player_List_Height(void)
  519. {
  520. bool show_inactive = false;
  521. #ifdef WWDEBUG
  522. if (cDevOptions::ShowInactivePlayers.Is_True()) {
  523. show_inactive = true;
  524. }
  525. #endif // WWDEBUG
  526. int count = 0;
  527. if (show_inactive) {
  528. count = PlayerList.Get_Count();
  529. } else {
  530. count = Count();
  531. }
  532. WWASSERT(PFont != NULL);
  533. int height = (int)((count + 1) * PFont->Char_Height() * Y_INCREMENT_FACTOR);
  534. return height;
  535. }
  536. //------------------------------------------------------------------------------------
  537. void cPlayerManager::Remove_Inactive(void)
  538. {
  539. for (
  540. SLNode<cPlayer> * objnode = PlayerList.Head();
  541. objnode != NULL;)
  542. {
  543. cPlayer * p_player = objnode->Data();
  544. WWASSERT(p_player != NULL);
  545. objnode = objnode->Next();
  546. if (p_player->Get_Is_Active().Is_False())
  547. {
  548. PlayerList.Remove(p_player);
  549. delete p_player;
  550. }
  551. }
  552. }
  553. //------------------------------------------------------------------------------------
  554. void cPlayerManager::Remove_All(void)
  555. {
  556. WWDEBUG_SAY(("cPlayerManager::Remove_All\n"));
  557. for (SLNode<cPlayer> * objnode = PlayerList.Head(); objnode != NULL;) {
  558. cPlayer * p_player = objnode->Data();
  559. WWASSERT(p_player != NULL);
  560. objnode = objnode->Next();
  561. PlayerList.Remove(p_player);
  562. delete p_player;
  563. }
  564. WWASSERT(PlayerList.Get_Count() == 0);
  565. //Remove_Inactive();
  566. }
  567. //-----------------------------------------------------------------------------
  568. int cPlayerManager::Count(void)
  569. {
  570. int count = 0;
  571. for (
  572. SLNode<cPlayer> * objnode = PlayerList.Head();
  573. objnode != NULL;
  574. objnode = objnode->Next()) {
  575. cPlayer * p_player = objnode->Data();
  576. WWASSERT(p_player != NULL);
  577. if (p_player->Get_Is_Active().Is_True())
  578. {
  579. count++;
  580. }
  581. }
  582. return count;
  583. }
  584. //-----------------------------------------------------------------------------
  585. void cPlayerManager::Reset_Players(void)
  586. {
  587. //
  588. // Call reset on active players.
  589. // Remove all inactive players.
  590. //
  591. Remove_Inactive();
  592. for (
  593. SLNode<cPlayer> * objnode = PlayerList.Head();
  594. objnode != NULL;
  595. objnode = objnode->Next()) {
  596. cPlayer * p_player = objnode->Data();
  597. WWASSERT(p_player != NULL);
  598. p_player->Reset_Player();
  599. }
  600. }
  601. //-----------------------------------------------------------------------------
  602. int cPlayerManager::Tally_Team_Size(int type)
  603. {
  604. WWROOTPROFILE("Tally_Team_Size");
  605. //WWASSERT(team >= 0 && team < MAX_TEAMS);
  606. //WWASSERT(The_Game()->Is_Team_Game());
  607. int tally = 0;
  608. SLNode<cPlayer> * objnode;
  609. cPlayer * p_player = NULL;
  610. for (objnode = PlayerList.Head(); objnode != NULL; objnode = objnode->Next()) {
  611. p_player = objnode->Data();
  612. WWASSERT(p_player != NULL);
  613. if (p_player->Get_Is_Active().Is_True() &&
  614. p_player->Get_Player_Type() == type) {
  615. tally++;
  616. }
  617. }
  618. PlayerInfoLog::Report_Tally_Size(type,tally);
  619. return tally;
  620. }
  621. //-----------------------------------------------------------------------------
  622. bool cPlayerManager::Is_Kill_Treasonous(cPlayer * p_killer, cPlayer * p_victim)
  623. {
  624. return (
  625. //The_Game()->Is_Team_Game() &&
  626. //The_Game()->Is_Team_Game() &&
  627. p_killer != NULL &&
  628. p_victim != NULL &&
  629. p_killer != p_victim &&
  630. p_killer->Get_Player_Type() == p_victim->Get_Player_Type());
  631. }
  632. //-----------------------------------------------------------------------------
  633. void cPlayerManager::Sort_Players(bool fast_sort)
  634. {
  635. WWPROFILE("cPlayerManager::Sort_Players");
  636. ZeroMemory(Player_Array, sizeof(Player_Array));
  637. //
  638. // Copy non-spectators from SList into array usable by qsort
  639. //
  640. int num_players = 0;
  641. //int active_players = 0;
  642. cPlayer * p_player;
  643. SLNode<cPlayer> * objnode;
  644. for (objnode = Get_Player_Object_List()->Head(); objnode; objnode = objnode->Next()) {
  645. p_player = objnode->Data();
  646. WWASSERT(p_player != NULL);
  647. //if (p_player->Is_Living()) {
  648. //active_players++;
  649. //}
  650. WWASSERT(num_players < MAX_PLAYERS);
  651. Player_Array[num_players] = p_player;
  652. num_players++;
  653. }
  654. if (fast_sort) {
  655. //
  656. // If we're sorting the list in-game, use the fast sort
  657. //
  658. for (int i=0; i<num_players; i++) {
  659. Player_Array[i]->Set_Fast_Sort_Key(Compute_Fast_Sort_Key(Player_Array[i]));
  660. }
  661. qsort(&Player_Array[0], num_players, sizeof(cPlayer *), &Fast_Player_Compare);
  662. } else {
  663. //
  664. // Otherwise use the full-blown Player_Compare sort
  665. //
  666. qsort(&Player_Array[0], num_players, sizeof(cPlayer *), &Player_Compare);
  667. }
  668. //
  669. // Set rungs. Only increment for active players.
  670. //
  671. /*
  672. for (int index = 0; index < num_players; index ++) {
  673. Player_Array[index]->Set_Rung (index + 1);
  674. }
  675. */
  676. int rung = 1;
  677. for (int index = 0; index < num_players; index ++) {
  678. Player_Array[index]->Set_Rung(rung);
  679. if (Player_Array[index]->IsActive.Is_True()) {
  680. rung++;
  681. }
  682. }
  683. }
  684. //-----------------------------------------------------------------------------
  685. int cPlayerManager::Player_Compare(const void * elem1, const void * elem2)
  686. {
  687. //
  688. // Used by qsort
  689. // (gth) Note, this function is very expensive due to the number of
  690. // data-safe variables being accessed.
  691. //
  692. WWASSERT(elem1 != NULL);
  693. WWASSERT(elem2 != NULL);
  694. cPlayer * p_player1 = *((cPlayer **)elem1);
  695. cPlayer * p_player2 = *((cPlayer **)elem2);
  696. WWASSERT(p_player1 != NULL);
  697. WWASSERT(p_player2 != NULL);
  698. int result;
  699. int p1_type = p_player1->Get_Player_Type();
  700. if (p1_type > PLAYERTYPE_NOD) {
  701. p1_type = PLAYERTYPE_NOD;
  702. }
  703. int p2_type = p_player2->Get_Player_Type();
  704. if (p2_type > PLAYERTYPE_NOD) {
  705. p2_type = PLAYERTYPE_NOD;
  706. }
  707. //
  708. // Sort on Ladder Points
  709. //
  710. if (p_player1->Get_Ladder_Points() > p_player2->Get_Ladder_Points()) {
  711. result = -1;
  712. } else if (p_player1->Get_Ladder_Points() == p_player2->Get_Ladder_Points()) {
  713. //
  714. // Sort on Score
  715. //
  716. if (p_player1->Get_Score() > p_player2->Get_Score()) {
  717. result = -1;
  718. } else if (p_player1->Get_Score() == p_player2->Get_Score()) {
  719. //
  720. // Sort on KTD ratio
  721. //
  722. //if (p_player1->Get_Kill_To_Death_Ratio() > p_player2->Get_Kill_To_Death_Ratio()) {
  723. // result = -1;
  724. //} else if (p_player1->Get_Kill_To_Death_Ratio() == p_player2->Get_Kill_To_Death_Ratio()) {
  725. //
  726. // Sort on Kills
  727. //
  728. if (p_player1->Get_Kills() > p_player2->Get_Kills()) {
  729. result = -1;
  730. } else if (p_player1->Get_Kills() == p_player2->Get_Kills()) {
  731. //
  732. // Sort on Deaths (less is better)
  733. //
  734. if (p_player1->Get_Deaths() < p_player2->Get_Deaths()) {
  735. result = -1;
  736. } else if (p_player1->Get_Deaths() == p_player2->Get_Deaths()) {
  737. //
  738. // Sort on team number. For non-teammembers this is a
  739. // redundant but harmless comparison
  740. //
  741. if (p_player1->Get_Player_Type() < p_player2->Get_Player_Type()) {
  742. result = -1;
  743. } else if (p_player1->Get_Player_Type() == p_player2->Get_Player_Type()) {
  744. //
  745. // Sort lexicographically on name
  746. //
  747. //if (stricmp(p_player1->Get_Name(), p_player2->Get_Name()) < 0) {
  748. if (p_player1->Get_Name() < p_player2->Get_Name()) {
  749. result = -1;
  750. //} else if (stricmp(p_player1->Get_Name(), p_player2->Get_Name()) == 0) {
  751. } else if (p_player1->Get_Name() == p_player2->Get_Name()) {
  752. //
  753. // Enough!
  754. //
  755. result = 0;
  756. } else {
  757. result = 1;
  758. }
  759. } else {
  760. result = 1;
  761. }
  762. } else {
  763. result = 1;
  764. }
  765. } else {
  766. result = 1;
  767. }
  768. //} else {
  769. // result = 1;
  770. //}
  771. } else {
  772. result = 1;
  773. }
  774. } else {
  775. result = 1;
  776. }
  777. return result;
  778. }
  779. //-----------------------------------------------------------------------------
  780. int cPlayerManager::Fast_Player_Compare(const void * elem1, const void * elem2)
  781. {
  782. //
  783. // Used by qsort
  784. //
  785. WWASSERT(elem1 != NULL);
  786. WWASSERT(elem2 != NULL);
  787. cPlayer * p_player1 = *((cPlayer **)elem1);
  788. cPlayer * p_player2 = *((cPlayer **)elem2);
  789. WWASSERT(p_player1 != NULL);
  790. WWASSERT(p_player2 != NULL);
  791. if (p_player1->Get_Fast_Sort_Key() > p_player2->Get_Fast_Sort_Key()) {
  792. return -1;
  793. } else {
  794. return 1;
  795. }
  796. }
  797. //-----------------------------------------------------------------------------
  798. int cPlayerManager::Compute_Fast_Sort_Key(cPlayer * player)
  799. {
  800. int key = 0;
  801. key = player->Get_Score();
  802. return key;
  803. }
  804. //-----------------------------------------------------------------------------
  805. void cPlayerManager::Construct_Heading(WideStringClass & string, bool force_verbose)
  806. {
  807. string.Format(L"");
  808. WWASSERT(PTheGameData != NULL);
  809. //bool is_verbose = force_verbose || The_Game()->IsIntermission.Get() || MultiHUDClass::Get_Verbose_Lists();
  810. bool is_verbose = force_verbose ||
  811. The_Game()->IsIntermission.Is_True() ||
  812. //MultiHUDClass::Get_Verbose_Lists();
  813. (MultiHUDClass::Get_Playerlist_Format() == PLAYERLIST_FORMAT_FULL);
  814. WideStringClass substring(0,true);
  815. //
  816. // Standing
  817. //
  818. substring.Format(L"%-5s", L"");
  819. string += substring;
  820. //
  821. // Name
  822. //
  823. //GAMESPY
  824. //substring.Format(L"%-11s", TRANSLATION(IDS_MP_PLAYER));
  825. if (cGameSpyAdmin::Is_Gamespy_Game()) {
  826. substring.Format(L"%-36s", TRANSLATION(IDS_MP_PLAYER));
  827. } else {
  828. substring.Format(L"%-11s", TRANSLATION(IDS_MP_PLAYER));
  829. }
  830. string += substring;
  831. //
  832. // Kills
  833. //
  834. if (is_verbose) {
  835. substring.Format(L"%-8s", TRANSLATION(IDS_MP_KILLS));
  836. string += substring;
  837. }
  838. //
  839. // Deaths
  840. //
  841. if (is_verbose) {
  842. substring.Format(L"%-8s", TRANSLATION(IDS_MP_DEATHS));
  843. string += substring;
  844. }
  845. //
  846. // Kill to Death ratio
  847. //
  848. if (is_verbose) {
  849. substring.Format(L"%-8s", TRANSLATION(IDS_MP_KILL_TO_DEATH_RATIO));
  850. string += substring;
  851. }
  852. //
  853. // Money
  854. //
  855. if ((The_Game()->Is_Cnc() || The_Game()->Is_Skirmish()) && is_verbose) {
  856. substring.Format(L"%-8s", TRANSLATION(IDS_MP_MONEY));
  857. string += substring;
  858. }
  859. //
  860. // Score
  861. //
  862. substring.Format(L"%-8s", TRANSLATION(IDS_MP_SCORE));
  863. string += substring;
  864. //
  865. // Ladder Points
  866. //
  867. if (force_verbose && The_Game()->IsLaddered.Is_True()) {
  868. substring.Format(L"%-8s", TRANSLATION(IDS_MP_LADDER));
  869. string += substring;
  870. }
  871. //
  872. // WOL rank
  873. //
  874. if (GameModeManager::Find("WOL")->Is_Active() && is_verbose) {
  875. substring.Format(L"%-8s", TRANSLATION(IDS_MP_RANK));
  876. string += substring;
  877. }
  878. #ifdef WWDEBUG
  879. //
  880. // Ping
  881. //
  882. if (cDevOptions::ShowPing.Is_True()) {
  883. substring.Format(L"%-8s", L"Ping");
  884. string += substring;
  885. }
  886. //
  887. // Player Id
  888. //
  889. if (cDevOptions::ShowId.Is_True()) {
  890. substring.Format(L"%-8s", L"Id");
  891. string += substring;
  892. }
  893. //
  894. // Fps
  895. //
  896. if (cNetwork::I_Am_Server() && cDevOptions::ShowClientFps.Is_True()) {
  897. substring.Format(L"%-8s", L"Fps");
  898. string += substring;
  899. }
  900. //
  901. // GameSpy auth. state
  902. //
  903. if (cNetwork::I_Am_Server() && cGameSpyAdmin::Is_Gamespy_Game() &&
  904. cDevOptions::ShowGameSpyAuthState.Is_True()) {
  905. substring.Format(L"%-12s", L"GS_AUTH");
  906. string += substring;
  907. }
  908. //
  909. // IP Address
  910. //
  911. if (cNetwork::I_Am_Server() && cDevOptions::ShowIpAddresses.Is_True()) {
  912. substring.Format(L"%-30s", L"IP Address");
  913. string += substring;
  914. }
  915. #endif // WWDEBUG
  916. }
  917. //-----------------------------------------------------------------------------
  918. void cPlayerManager::List_Print(WideStringClass & text, Vector3 color)
  919. {
  920. //WWASSERT(text != NULL);
  921. //WWASSERT(::strlen(text) > 0);
  922. if (PTextRenderer == NULL) {
  923. return;
  924. }
  925. WWASSERT(PTextRenderer != NULL);
  926. PTextRenderer->Set_Location(Vector2(cMathUtil::Round(XPos), cMathUtil::Round(YPos)));
  927. int c = ((int)(color[0]*255)&0xFF) << 16 | ((int)(color[1]*255)&0xFF) << 8 | ((int)(color[2]*255)&0xFF) << 0 | 0xFF000000;
  928. PTextRenderer->Draw_Text(text, c);
  929. WWASSERT(PFont != NULL);
  930. YPos += PFont->Char_Height() * Y_INCREMENT_FACTOR;
  931. }
  932. //-----------------------------------------------------------------------------
  933. void cPlayerManager::Line(float x, float length, int line_color)
  934. {
  935. WWASSERT(length > 0);
  936. if (PTextRenderer == NULL) {
  937. return;
  938. }
  939. WWASSERT(PTextRenderer != NULL);
  940. float y = YPos + PTextRenderer->Peek_Font()->Char_Height() / 2.0f;
  941. PTextRenderer->Draw_Block(RectClass(x, y, x + length, y + 1), line_color);
  942. }
  943. //-----------------------------------------------------------------------------
  944. void cPlayerManager::Render_Player_List(void)
  945. {
  946. //
  947. // Format:
  948. // AAAAAAAAAxxNNNNxxNNNxNNNxNNN.NxxNNNxxNNNNN, e.g:
  949. // Charlie 220 25 13 5.3 3 12
  950. //
  951. // Fields are name, ping, kills, death, kills-to-deaths, num-lives, score
  952. //
  953. if (PTextRenderer == NULL) {
  954. return;
  955. }
  956. WWASSERT(PTheGameData != NULL);
  957. if (GameModeManager::Find("Combat") == NULL ||
  958. !GameModeManager::Find("Combat")->Is_Active() ||
  959. The_Game()->IsIntermission.Is_True()) {
  960. PTextRenderer->Reset();
  961. return;
  962. }
  963. //bool is_verbose = The_Game()->IsIntermission.Get() || MultiHUDClass::Get_Verbose_Lists();
  964. bool is_verbose = The_Game()->IsIntermission.Get() || (MultiHUDClass::Get_Playerlist_Format() == PLAYERLIST_FORMAT_FULL);
  965. bool changed=false;
  966. static WideStringClass renderer_player_heading;
  967. static WideStringClass renderer_player_strings[MAX_PLAYERS];
  968. static Vector3 renderer_player_colors[MAX_PLAYERS];
  969. static int renderer_player_count;
  970. static int renderer_displayed_player_count;
  971. static int renderer_star_index = -1;
  972. static float renderer_star_x;
  973. static float renderer_star_y;
  974. static bool renderer_is_intermission_true;
  975. static int LastSortedSecond = 0;
  976. //
  977. // Sort the list of players once a second
  978. //
  979. bool sort=is_verbose;
  980. //bool sort = false;//XXX
  981. int seconds = cMathUtil::Round(TimeManager::Get_Seconds());
  982. if (!sort) {
  983. if (seconds != LastSortedSecond) {
  984. LastSortedSecond = seconds;
  985. sort=true;
  986. }
  987. }
  988. sort=true;//XXX
  989. if (sort) {
  990. WWPROFILE("Team & Player sorts");
  991. cTeamManager::Sort_Teams();
  992. cPlayerManager::Sort_Players(true);
  993. }
  994. //
  995. // Build heading
  996. //
  997. WideStringClass heading(0,true);
  998. Construct_Heading(heading);
  999. if (heading!=renderer_player_heading) {
  1000. renderer_player_heading=heading;
  1001. changed=true;
  1002. }
  1003. if (The_Game()->IsIntermission.Is_True()!=renderer_is_intermission_true) {
  1004. changed=true;
  1005. renderer_is_intermission_true=The_Game()->IsIntermission.Is_True();
  1006. }
  1007. // Build player list
  1008. //int current_count = Count();
  1009. int current_count = PlayerList.Get_Count();
  1010. if (renderer_player_count!= current_count) {
  1011. renderer_player_count = current_count;
  1012. changed=true;
  1013. }
  1014. LPCSTR star_text = "*";
  1015. int displayed_player_count=0;
  1016. int count = current_count;
  1017. bool show_inactive = false;
  1018. #ifdef WWDEBUG
  1019. if (cDevOptions::ShowInactivePlayers.Is_True()) {
  1020. show_inactive = true;
  1021. }
  1022. #endif // WWDEBUG
  1023. for (int j = 0; j < count; j++) {
  1024. WWASSERT(j < MAX_PLAYERS);
  1025. cPlayer * p_player = Player_Array[j];
  1026. if (!p_player) continue;
  1027. //
  1028. // In the abbreviated form we only show the score leader and ourself.
  1029. // 09/26/01 And the guy at the bottom of the list !
  1030. // 10/29/01 Now we just show me.
  1031. //
  1032. bool is_me = cNetwork::I_Am_Client() && (p_player->Get_Id() == cNetwork::Get_My_Id());
  1033. //if (!is_verbose && (j != 0) && (j != count - 1) && !is_me) continue;
  1034. //if (!is_verbose && !is_me) {
  1035. if ((MultiHUDClass::Get_Playerlist_Format() == PLAYERLIST_FORMAT_TINY) && !is_me) {
  1036. continue;
  1037. }
  1038. if (p_player->Get_Is_Active().Is_False() && !show_inactive) {
  1039. continue;
  1040. }
  1041. if (changed) {
  1042. p_player->Get_Player_String(j + 1, renderer_player_strings[displayed_player_count]);
  1043. renderer_player_colors[displayed_player_count]=p_player->Get_Color();
  1044. }
  1045. else {
  1046. WideStringClass player_string(0,true);
  1047. p_player->Get_Player_String(j + 1, player_string);
  1048. if (player_string!=renderer_player_strings[displayed_player_count]) {
  1049. renderer_player_strings[displayed_player_count]=player_string;
  1050. changed=true;
  1051. }
  1052. // If list hasn't changed so far, check if the player color is the same
  1053. if (renderer_player_colors[displayed_player_count]!=p_player->Get_Color()) {
  1054. renderer_player_colors[displayed_player_count]=p_player->Get_Color();
  1055. changed=true;
  1056. }
  1057. }
  1058. if (cNetwork::I_Am_Client() && p_player->Get_Id() == cNetwork::Get_My_Id()) {
  1059. //
  1060. // Put a symbol next to my name so that it stands out
  1061. //
  1062. if (renderer_star_index!=displayed_player_count) {
  1063. renderer_star_index=displayed_player_count;
  1064. changed=true;
  1065. }
  1066. }
  1067. displayed_player_count++;
  1068. }
  1069. if (renderer_displayed_player_count!=displayed_player_count) {
  1070. renderer_displayed_player_count=displayed_player_count;
  1071. changed=true;
  1072. }
  1073. if (!changed) return;
  1074. PTextRenderer->Reset();
  1075. WWASSERT(PFont != NULL);
  1076. WWASSERT(PTextRenderer != NULL);
  1077. DEMO_SECURITY_CHECK;
  1078. //
  1079. // Determine left edge placement
  1080. //
  1081. XPos = 0;
  1082. float text_len = PFont->String_Width(heading);
  1083. if (The_Game()->IsIntermission.Is_True()) {
  1084. XPos = Render2DClass::Get_Screen_Resolution().Center().X - text_len / 2.0f;
  1085. } else {
  1086. XPos = Render2DClass::Get_Screen_Resolution().Right - 20 - text_len;
  1087. }
  1088. //
  1089. // Top placement
  1090. //
  1091. if (The_Game()->IsIntermission.Is_True()) {
  1092. //YPos = 70;
  1093. int combined_height =
  1094. cTeamManager::Compute_Team_List_Height() +
  1095. cPlayerManager::Compute_Full_Player_List_Height() +
  1096. 2 * PFont->Char_Height() * Y_INCREMENT_FACTOR;
  1097. YPos = (int)(Render2DClass::Get_Screen_Resolution().Height() / 2.0 - combined_height / 2.0);
  1098. if (YPos < 10) {
  1099. YPos = 10;
  1100. }
  1101. /*
  1102. if (The_Game()->Is_Team_Game()) {
  1103. YPos += 2 * PFont->Char_Height() * Y_INCREMENT_FACTOR;
  1104. YPos += cTeamManager::Compute_Team_List_Height();
  1105. } else {
  1106. //
  1107. // Show the win text
  1108. //
  1109. WideStringClass text(cGameData::Get_Win_Text(),true);
  1110. float x = Render2DClass::Get_Screen_Resolution().Center().X -
  1111. PFont->String_Width(text) / 2.0f;
  1112. float y = YPos;
  1113. PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y)));
  1114. PTextRenderer->Draw_Text(text);
  1115. YPos += 2 * PFont->Char_Height() * Y_INCREMENT_FACTOR;
  1116. }
  1117. */
  1118. YPos += 2 * PFont->Char_Height() * Y_INCREMENT_FACTOR;
  1119. YPos += cTeamManager::Compute_Team_List_Height();
  1120. } else {
  1121. //YPos = 50;
  1122. /*
  1123. YPos = 10;
  1124. if (The_Game()->Is_Team_Game()) {
  1125. //YPos += 4 * PFont->Char_Height() * Y_INCREMENT_FACTOR;
  1126. YPos += cTeamManager::Compute_Team_List_Height();
  1127. }
  1128. */
  1129. YPos = 10 + cTeamManager::Compute_Team_List_Height();
  1130. }
  1131. //
  1132. // Draw the heading
  1133. //
  1134. /*
  1135. if (The_Game()->Is_Team_Game()) {
  1136. List_Print(heading, Vector3(1, 1, 1));
  1137. } else {
  1138. List_Print(heading, Vector3(1, 1, 0));
  1139. }
  1140. */
  1141. List_Print(heading, Vector3(1, 1, 1));
  1142. for (j = 0; j < renderer_displayed_player_count; j++) {
  1143. //
  1144. // Put a symbol next to my name so that it stands out
  1145. //
  1146. //if (is_verbose && renderer_star_index==j) {
  1147. if ((MultiHUDClass::Get_Playerlist_Format() != PLAYERLIST_FORMAT_TINY) &&
  1148. (renderer_star_index == j)) {
  1149. float x = XPos - 2 * PFont->String_Width(star_text);
  1150. float y = YPos;
  1151. PTextRenderer->Set_Location(Vector2(cMathUtil::Round(x), cMathUtil::Round(y)));
  1152. PTextRenderer->Draw_Text(star_text);
  1153. }
  1154. List_Print(renderer_player_strings[j], renderer_player_colors[j]);
  1155. }
  1156. }
  1157. //-----------------------------------------------------------------------------
  1158. void cPlayerManager::Log_Player_List(void)
  1159. {
  1160. WWDEBUG_SAY(("cPlayerManager::Log_Player_List\n"));
  1161. StringClass results_filename;
  1162. results_filename.Format("results%d.txt", cUserOptions::ResultsLogNumber.Get());
  1163. FILE * file = ::fopen(results_filename, "at");
  1164. if (file != NULL) {
  1165. char line[2000] = "";
  1166. WideStringClass wide_text(0, true);
  1167. Construct_Heading(wide_text, true);
  1168. StringClass text;
  1169. wide_text.Convert_To(text);
  1170. ::sprintf(line, "%s\n", text.Peek_Buffer());
  1171. ::fwrite(line, 1, ::strlen(line), file);
  1172. for (int j = 0; j < MAX_PLAYERS; j++) {
  1173. cPlayer * p_player = Player_Array[j];
  1174. if (p_player != NULL) {
  1175. p_player->Get_Player_String(j + 1, wide_text, true);
  1176. wide_text.Convert_To(text);
  1177. ::sprintf(line, "%s\n", text.Peek_Buffer());
  1178. ::fwrite(line, 1, ::strlen(line), file);
  1179. }
  1180. }
  1181. ::sprintf(line, "\n");
  1182. ::fwrite(line, 1, ::strlen(line), file);
  1183. ::fclose(file);
  1184. }
  1185. }
  1186. //-----------------------------------------------------------------------------
  1187. enum {
  1188. CHUNKID_PLAYERLIST = 1232345,
  1189. CHUNKID_PLAYER,
  1190. };
  1191. //-----------------------------------------------------------------------------
  1192. bool cPlayerManager::Save(ChunkSaveClass & csave)
  1193. {
  1194. csave.Begin_Chunk(CHUNKID_PLAYERLIST);
  1195. SLNode<cPlayer> * objnode;
  1196. for (objnode = PlayerList.Head(); objnode; objnode = objnode->Next()) {
  1197. cPlayer * p_player = objnode->Data();
  1198. WWASSERT(p_player != NULL);
  1199. csave.Begin_Chunk(CHUNKID_PLAYER);
  1200. p_player->Save(csave);
  1201. csave.End_Chunk();
  1202. }
  1203. csave.End_Chunk();
  1204. return true;
  1205. }
  1206. //-----------------------------------------------------------------------------
  1207. bool cPlayerManager::Load(ChunkLoadClass &cload)
  1208. {
  1209. while (cload.Open_Chunk()) {
  1210. switch(cload.Cur_Chunk_ID()) {
  1211. case CHUNKID_PLAYERLIST:
  1212. //Remove_All(); // TSS091401
  1213. //TSS110101. WWASSERT(PlayerList.Get_Count() == 0);
  1214. while (cload.Open_Chunk()) {
  1215. switch(cload.Cur_Chunk_ID()) {
  1216. case CHUNKID_PLAYER:
  1217. cPlayer * p_player;
  1218. p_player = new cPlayer();
  1219. p_player->Load(cload);
  1220. /*
  1221. if (!The_Game()->Is_Valid_Player_Type(p_player->Get_Player_Type())) {
  1222. Debug_Say(("* Removing loaded player due to invalid playertype for this game.\n"));
  1223. Remove(p_player);
  1224. }
  1225. */
  1226. //
  1227. // TSS110101.
  1228. // Do not perturb the save/load code, but nullify it's effect.
  1229. //
  1230. if ( !IS_MISSION ) {
  1231. Remove(p_player);
  1232. }
  1233. break;
  1234. default:
  1235. Debug_Say(( "Unrecognized cPlayerManager chunkID\n" ));
  1236. break;
  1237. }
  1238. cload.Close_Chunk();
  1239. }
  1240. break;
  1241. default:
  1242. Debug_Say(( "Unrecognized cPlayerManager chunkID\n" ));
  1243. break;
  1244. }
  1245. cload.Close_Chunk();
  1246. }
  1247. return true;
  1248. }
  1249. //-----------------------------------------------------------------------------