pluginlifespan.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. //-----------------------------
  2. // LIFESPAN plugin
  3. //-----------------------------
  4. /*
  5. Lifespan plugin handles player facial hair, bloody hands, blood type in HUD
  6. */
  7. enum eBloodyHandsTypes
  8. {
  9. CLEAN = 0,//clean needs to be 0
  10. SALMONELA,
  11. JUST_BLOOD,
  12. //--- ONLY LAST_INDEX BELLOW !!!
  13. LAST_INDEX,
  14. }
  15. enum LifeSpanState
  16. {
  17. BEARD_NONE = 0,
  18. BEARD_MEDIUM = 1,
  19. BEARD_LARGE = 2,
  20. BEARD_EXTRA = 3,
  21. COUNT = 4,
  22. }
  23. class PluginLifespan extends PluginBase
  24. {
  25. protected static const int LIFESPAN_MIN = 0;
  26. protected static const int LIFESPAN_MAX = 240; // value in minutes when player achieved maximum age in order to have full beard
  27. protected int m_FakePlaytime;
  28. protected ref map<PlayerBase, ref LifespanLevel> m_PlayerCurrentLevel;
  29. protected ref map<string, ref array< ref LifespanLevel>> m_LifespanLevels;
  30. protected ref map<string, ref BloodyHands> m_BloodyHands;
  31. protected ref map<PlayerBase, int> m_BloodType;
  32. //========================================
  33. // GetInstance
  34. //========================================
  35. static PluginLifespan GetInstance()
  36. {
  37. return PluginLifespan.Cast( GetPlugin(PluginLifespan) );
  38. }
  39. void PluginLifespan()
  40. {
  41. LoadFromCfg();
  42. m_PlayerCurrentLevel = new map<PlayerBase, ref LifespanLevel>;
  43. m_BloodType = new map<PlayerBase, int>;
  44. m_FakePlaytime = 0;
  45. }
  46. //-----------------------------
  47. // Player load from config
  48. //-----------------------------
  49. void LoadFromCfg()
  50. {
  51. m_LifespanLevels = new map<string, ref array< ref LifespanLevel>>;
  52. m_BloodyHands = new map<string, ref BloodyHands>;
  53. const int LIFESPAN_LENGTH = LIFESPAN_MAX - LIFESPAN_MIN;
  54. //cfg_name = 'CfgVehicles'
  55. // config_name = 'CfgVehicles'
  56. //cfg_class_count = 2348
  57. // config_count = 2348
  58. //cfg_class_name = 'SurvivorMale_Base'
  59. // survivor_name = 'SurvivorMale_Base'
  60. //cfg_class_fullname = 'CfgVehicles SurvivorMale_Base'
  61. // survivor_path = 'CfgVehicles SurvivorMale_Base'
  62. //cfg_class_member_count = 10
  63. // survivor_lifespan_count = 10
  64. //cfg_class_member_name = 'Lifespan'
  65. // survivor_lifespan_name = 'Lifespan'
  66. //cfg_class_member_fullname = 'CfgVehicles SurvivorMale_Base Lifespan';
  67. // survivor_lifespan_path = 'CfgVehicles SurvivorMale_Base Lifespan';
  68. //cfg_class_member_member_count = 1
  69. // survivor_lifespan_beard_count = 1
  70. //cfg_class_member_member_name = 'Beard'
  71. // survivor_lifespan_beard_name = 'Beard'
  72. //cfg_class_member_member_fullname = 'CfgVehicles SurvivorMale_Base Lifespan Beard'
  73. // survivor_lifespan_beard_path = 'CfgVehicles SurvivorMale_Base Lifespan Beard'
  74. //cfg_class_member_member_variable_name = 'mat'
  75. // survivor_lifespan_beard_material_name = 'mat'
  76. //cfg_class_member_member_variable_fullname = 'CfgVehicles SurvivorMale_Base Lifespan Beard mat'
  77. // survivor_lifespan_beard_material_path = 'CfgVehicles SurvivorMale_Base Lifespan Beard mat'
  78. string config_name = "CfgVehicles";
  79. int config_count = GetGame().ConfigGetChildrenCount( config_name );
  80. int i, j, k, l, m;
  81. //Print( "config_count: " + config_count );
  82. for ( i = 0; i < config_count; i++ )
  83. {
  84. string survivor_name = "";
  85. GetGame().ConfigGetChildName( config_name, i, survivor_name );
  86. if ( survivor_name != "" && survivor_name != "access" )
  87. {
  88. if ( GetGame().IsKindOf(survivor_name, "SurvivorMale_Base") || GetGame().IsKindOf(survivor_name, "SurvivorFemale_Base") )
  89. {
  90. string survivor_path = config_name + " " + survivor_name;
  91. int survivor_lifespan_count = GetGame().ConfigGetChildrenCount( survivor_path );
  92. //Print( "survivor_path: " + survivor_path );
  93. for ( j = 0; j < survivor_lifespan_count; j++ )
  94. {
  95. string survivor_lifespan_name = "";
  96. GetGame().ConfigGetChildName( survivor_path, j, survivor_lifespan_name );
  97. string survivor_lifespan_path = survivor_path + " " + survivor_lifespan_name;
  98. if ( survivor_lifespan_name == "Lifespan" )
  99. {
  100. int survivor_lifespan_beard_count = GetGame().ConfigGetChildrenCount( survivor_lifespan_path );
  101. for ( k = 0; k < survivor_lifespan_beard_count; k++ )
  102. {
  103. string survivor_lifespan_beard_name = "";
  104. GetGame().ConfigGetChildName( survivor_lifespan_path, k, survivor_lifespan_beard_name );
  105. string survivor_lifespan_beard_path = survivor_lifespan_path + " " + survivor_lifespan_beard_name;
  106. if ( survivor_lifespan_beard_name == "Beard" )
  107. {
  108. TStringArray materials = new TStringArray;
  109. int cfg_class_member_member_variable_count = GetGame().ConfigGetChildrenCount( survivor_lifespan_beard_path );
  110. for ( l = 0; l < cfg_class_member_member_variable_count; l++ )
  111. {
  112. string survivor_lifespan_beard_material_name = "";
  113. GetGame().ConfigGetChildName( survivor_lifespan_beard_path, l, survivor_lifespan_beard_material_name );
  114. string survivor_lifespan_beard_material_path = survivor_lifespan_beard_path + " " + survivor_lifespan_beard_material_name;
  115. if ( survivor_lifespan_beard_material_name == "mat" )
  116. {
  117. GetGame().ConfigGetTextArray( survivor_lifespan_beard_material_path, materials );
  118. array<ref LifespanLevel> lifespan_levels = new array< ref LifespanLevel>;
  119. int level_count = materials.Count() / 2;
  120. for ( m = 0; m < level_count; m++ )
  121. {
  122. int tex = m*2;
  123. int mat = ((m*2)+1);
  124. if ( mat < materials.Count() )
  125. {
  126. float threshold = (((float)m / (float)(level_count - 1)) * (float)LIFESPAN_LENGTH) + (float)LIFESPAN_MIN;
  127. lifespan_levels.Insert( new LifespanLevel(m, threshold, materials.Get(tex), materials.Get(mat)) );
  128. //Print("material a textura a threshold: " + materials.Get(tex) + " " + materials.Get(mat) + " " + threshold );
  129. }
  130. }
  131. if ( lifespan_levels.Count() > 0 )
  132. {
  133. m_LifespanLevels.Set( survivor_name, lifespan_levels );
  134. }
  135. }
  136. }
  137. }
  138. }
  139. }
  140. else if ( survivor_lifespan_name == "BloodyHands" )
  141. {
  142. string bloody_material, normal_material;
  143. string path_normal = survivor_lifespan_path + " mat_normal";
  144. string path_bloody = survivor_lifespan_path + " mat_blood";
  145. GetGame().ConfigGetText(path_normal, normal_material);
  146. GetGame().ConfigGetText(path_bloody, bloody_material);
  147. m_BloodyHands.Set( survivor_name, new BloodyHands(normal_material, bloody_material) );
  148. }
  149. }
  150. }
  151. }
  152. }
  153. /*for ( int cl = 0; cl < m_LifespanLevels.Count(); cl++ )
  154. {
  155. string class_name = m_LifespanLevels.GetKey( cl );
  156. array<ref LifespanLevel> levels = m_LifespanLevels.GetElement( cl );
  157. Print( class_name );
  158. for ( int ll = 0; ll < levels.Count(); ll++)
  159. {
  160. Print( "lvl: " + levels.Get( ll ).GetLevel() );
  161. Print( "treshold: " + levels.Get( ll ).GetThreshold() );
  162. Print( "texture: " + levels.Get( ll ).GetTextureName() );
  163. Print( "material: " + levels.Get( ll ).GetMaterialName() );
  164. }
  165. }*/
  166. }
  167. //-----------------------------
  168. // Support functions
  169. //-----------------------------
  170. void SynchLifespanVisual( PlayerBase player, int beard_state_visible, bool bloody_hands_visible, bool blood_type_visible, int blood_type )
  171. {
  172. SynchBeardVisual( player, beard_state_visible );
  173. SynchBloodyHandsVisual( player, bloody_hands_visible );
  174. SynchShowBloodTypeVisual( player, blood_type_visible );
  175. SynchShowBloodType( player, blood_type );
  176. }
  177. void ChangeFakePlaytime( PlayerBase player, int change )
  178. {
  179. if ( !GetGame().IsMultiplayer() )
  180. {
  181. m_FakePlaytime = change;
  182. UpdateLifespan( player, true );
  183. }
  184. }
  185. //-----------------------------
  186. // Facial hair
  187. //-----------------------------
  188. void UpdateLifespan(PlayerBase player, bool force_update = false)
  189. {
  190. if (player != null)
  191. {
  192. float playerPlaytime = m_FakePlaytime;
  193. if (GetGame().IsMultiplayer() && GetGame().IsServer())
  194. playerPlaytime = player.StatGet(AnalyticsManagerServer.STAT_PLAYTIME);
  195. float playerBeard = playerPlaytime - player.GetLastShavedSeconds();
  196. playerBeard = playerBeard / 60.0;
  197. UpdateLifespanLevel(player, playerBeard, force_update);
  198. }
  199. }
  200. protected void UpdateLifespanLevel( PlayerBase player, float player_beard, bool force_update = false )
  201. {
  202. if ( !player.IsAlive() )
  203. return;
  204. if ( m_PlayerCurrentLevel.Contains(player) )
  205. {
  206. LifespanLevel current_level = m_PlayerCurrentLevel.Get( player );
  207. if ( player_beard > current_level.GetThreshold() || force_update )
  208. {
  209. LifespanLevel next_level = GetLifespanLevel( player.GetPlayerClass(), player_beard );
  210. if ( next_level != NULL )
  211. {
  212. SetPlayerLifespanLevel( player, next_level );
  213. m_PlayerCurrentLevel.Set( player, next_level );
  214. }
  215. }
  216. }
  217. else
  218. {
  219. if ( m_LifespanLevels.Contains( player.GetPlayerClass() ) )
  220. {
  221. LifespanLevel level = GetLifespanLevel( player.GetPlayerClass(), player_beard );
  222. if ( level != NULL )
  223. {
  224. SetPlayerLifespanLevel( player, level );
  225. m_PlayerCurrentLevel.Set( player, level );
  226. }
  227. }
  228. }
  229. }
  230. protected LifespanLevel GetLifespanLevel( string player_class, float age = 0 )
  231. {
  232. array<ref LifespanLevel> lifespan_levels = m_LifespanLevels.Get( player_class );
  233. if ( lifespan_levels != NULL )
  234. {
  235. for ( int i = lifespan_levels.Count() - 1; i >= 0; i-- )
  236. {
  237. LifespanLevel level = lifespan_levels.Get( i );
  238. if ( age >= level.GetThreshold() )
  239. {
  240. return level;
  241. }
  242. }
  243. }
  244. return NULL;
  245. }
  246. protected void SetPlayerLifespanLevel( PlayerBase player, LifespanLevel level )
  247. {
  248. if (player.m_CorpseState != 0)
  249. return;
  250. int slot_id = InventorySlots.GetSlotIdFromString("Head");
  251. EntityAI players_head = player.GetInventory().FindPlaceholderForSlot( slot_id );
  252. if ( players_head )
  253. {
  254. switch (level.GetLevel())
  255. {
  256. case LifeSpanState.BEARD_NONE:
  257. {
  258. players_head.SetObjectTexture( 0, "");
  259. players_head.SetObjectMaterial( 0, "");
  260. player.SetFaceTexture( level.GetTextureName() );
  261. player.SetFaceMaterial( level.GetMaterialName() );
  262. player.SetLifeSpanStateVisible(LifeSpanState.BEARD_NONE);
  263. //Print("LifeSpanState.BEARD_NONE");
  264. break;
  265. }
  266. case LifeSpanState.BEARD_MEDIUM:
  267. {
  268. players_head.SetObjectTexture( 0, "");
  269. players_head.SetObjectMaterial( 0, "");
  270. player.SetFaceTexture( level.GetTextureName() );
  271. player.SetFaceMaterial( level.GetMaterialName() );
  272. player.SetLifeSpanStateVisible(LifeSpanState.BEARD_MEDIUM);
  273. //Print("LifeSpanState.BEARD_MEDIUM");
  274. break;
  275. }
  276. case LifeSpanState.BEARD_LARGE:
  277. {
  278. players_head.SetObjectTexture( 0, "");
  279. players_head.SetObjectMaterial( 0, "");
  280. player.SetFaceTexture( level.GetTextureName() );
  281. player.SetFaceMaterial( level.GetMaterialName() );
  282. player.SetLifeSpanStateVisible(LifeSpanState.BEARD_LARGE);
  283. //Print("LifeSpanState.BEARD_LARGE");
  284. break;
  285. }
  286. case LifeSpanState.BEARD_EXTRA:
  287. {
  288. players_head.SetObjectTexture( 0, level.GetTextureName() );
  289. players_head.SetObjectMaterial( 0, level.GetMaterialName() );
  290. array< ref LifespanLevel> lifespan_levels = m_LifespanLevels.Get( player.GetPlayerClass() );
  291. LifespanLevel prev_level = lifespan_levels.Get(LifeSpanState.BEARD_LARGE);
  292. player.SetFaceTexture( prev_level.GetTextureName() );
  293. player.SetFaceMaterial( prev_level.GetMaterialName() );
  294. player.SetLifeSpanStateVisible(LifeSpanState.BEARD_EXTRA);
  295. //Print("LifeSpanState.BEARD_EXTRA");
  296. break;
  297. }
  298. default:
  299. {
  300. Print("Lifespan state missing");
  301. break;
  302. }
  303. }
  304. }
  305. }
  306. void SynchBeardVisual( PlayerBase player, int state )
  307. {
  308. float player_beard;
  309. switch (state)
  310. {
  311. case LifeSpanState.BEARD_NONE:
  312. {
  313. // first out of 4 states
  314. player_beard = LIFESPAN_MIN;
  315. break;
  316. }
  317. case LifeSpanState.BEARD_MEDIUM:
  318. {
  319. // second out of 4 states
  320. player_beard = LIFESPAN_MAX/3;
  321. break;
  322. }
  323. case LifeSpanState.BEARD_LARGE:
  324. {
  325. // third out of 4 states
  326. player_beard = LIFESPAN_MAX/1.5;
  327. break;
  328. }
  329. case LifeSpanState.BEARD_EXTRA:
  330. {
  331. // fourth out of 4 states
  332. player_beard = LIFESPAN_MAX;
  333. break;
  334. }
  335. default:
  336. {
  337. Print("Lifespan state missing");
  338. break;
  339. }
  340. }
  341. UpdateLifespanLevel( player, player_beard, true );
  342. }
  343. //-----------------------------
  344. // Bloody hands
  345. //-----------------------------
  346. void UpdateBloodyHandsVisibilityEx( PlayerBase player, eBloodyHandsTypes type )
  347. {
  348. if ( CanMakeHandsBloody( player ) )
  349. {
  350. SetBloodyHandsEx( player, type );
  351. }
  352. }
  353. void UpdateBloodyHandsVisibility( PlayerBase player, bool show )
  354. {
  355. if ( CanMakeHandsBloody( player ) )
  356. {
  357. SetBloodyHands( player, show );
  358. }
  359. }
  360. void SynchBloodyHandsVisual( PlayerBase player, bool has_bloody_hands )
  361. {
  362. UpdateBloodyHandsVisibility( player, has_bloody_hands );
  363. }
  364. void SetBloodyHandsEx( PlayerBase player, eBloodyHandsTypes type )
  365. {
  366. player.SetBloodyHandsEx( type );
  367. if ( type )
  368. {
  369. SetHandsMaterial( player, BloodyHands.MATERIAL_TYPE_BLOODY );
  370. }
  371. else
  372. {
  373. SetHandsMaterial( player, BloodyHands.MATERIAL_TYPE_NORMAL );
  374. }
  375. }
  376. void SetBloodyHands( PlayerBase player, bool show )
  377. {
  378. player.SetBloodyHands( show );
  379. if ( show )
  380. {
  381. SetHandsMaterial( player, BloodyHands.MATERIAL_TYPE_BLOODY );
  382. }
  383. else
  384. {
  385. SetHandsMaterial( player, BloodyHands.MATERIAL_TYPE_NORMAL );
  386. }
  387. }
  388. protected void SetHandsMaterial( PlayerBase player, int material_type )
  389. {
  390. string player_class = player.GetPlayerClass();
  391. int slot_id;
  392. EntityAI eai;
  393. if ( m_BloodyHands.Contains(player_class))
  394. {
  395. slot_id = InventorySlots.GetSlotIdFromString("Gloves");
  396. eai = player.GetInventory().FindPlaceholderForSlot( slot_id );
  397. if (eai)
  398. {
  399. eai.SetObjectMaterial( 0, m_BloodyHands.Get(player_class).GetMaterial(material_type) );
  400. }
  401. }
  402. else
  403. {
  404. //Print("Error! Player class <" + player_class + "> does not contain valid configuration for bloody hands!");
  405. }
  406. }
  407. bool CanMakeHandsBloody( PlayerBase player )
  408. {
  409. return !player.FindAttachmentBySlotName( "Gloves" ) );
  410. }
  411. //-----------------------------
  412. // Blood type in HUD
  413. //-----------------------------
  414. void UpdateBloodTypeVisibility( PlayerBase player, bool show )
  415. {
  416. player.SetBloodTypeVisible( show );
  417. if ( player.m_Hud )
  418. {
  419. player.m_Hud.UpdateBloodName();
  420. }
  421. }
  422. void UpdateBloodType( PlayerBase player, int blood_type )
  423. {
  424. player.SetBloodType( blood_type );
  425. }
  426. void SynchShowBloodTypeVisual( PlayerBase player, bool show )
  427. {
  428. UpdateBloodTypeVisibility( player, show );
  429. }
  430. void SynchShowBloodType( PlayerBase player, int blood_type )
  431. {
  432. UpdateBloodType( player, blood_type );
  433. }
  434. //-----------------------------
  435. // Getters for other systems
  436. //-----------------------------
  437. string GetCurrentHeadTexture(PlayerBase player)
  438. {
  439. if ( m_PlayerCurrentLevel.Contains(player) )
  440. {
  441. LifespanLevel current_level = m_PlayerCurrentLevel.Get( player );
  442. return current_level.GetTextureName();
  443. }
  444. return "";
  445. }
  446. string GetCurrentHeadMaterial(PlayerBase player)
  447. {
  448. if ( m_PlayerCurrentLevel.Contains(player) )
  449. {
  450. LifespanLevel current_level = m_PlayerCurrentLevel.Get( player );
  451. return current_level.GetMaterialName();
  452. }
  453. return "";
  454. }
  455. }