softskillsmanager.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. class SoftSkillsManager
  2. {
  3. protected PlayerBase m_Player;
  4. protected float m_SpecialtyLevel;
  5. protected float m_RoughLevel;
  6. protected float m_PreciseLevel;
  7. protected bool m_IsLinear;
  8. protected bool m_IsActive;
  9. protected bool m_IsCoolDown;
  10. protected int m_UserActionsCounter;
  11. static protected const int DEFAULT_EFFICIENCY = 0;
  12. static protected const float PRECISE_WEIGHT_LIMIT = -1;
  13. static protected const float ROUGH_WEIGHT_LIMIT = 1;
  14. static protected const float COOLDOWN_TIMER = 5; //default 5,
  15. protected ref Timer m_CoolDownTimer = new Timer();
  16. protected bool m_IsDebugMode;
  17. protected float m_CoolDownValue;
  18. protected float m_LastUAValue;
  19. protected float m_ComponentBonusBefore;
  20. protected float m_ComponentBonusAfter;
  21. protected float m_GeneralBonusBefore;
  22. protected float m_GeneralBonusAfter;
  23. protected ref SoftSkillManagerDebug m_DebugWindow;
  24. protected ref Timer m_SynchTimer;
  25. void SoftSkillsManager( PlayerBase player )
  26. {
  27. m_Player = player;
  28. m_IsCoolDown = false;
  29. m_IsLinear = false;
  30. m_IsActive = true;
  31. m_IsDebugMode = false;
  32. }
  33. void InitSpecialty( float specialty_level )
  34. {
  35. SetSpecialtyLevel( specialty_level );
  36. SynchSpecialtyLevel();
  37. }
  38. void ~SoftSkillsManager()
  39. {
  40. delete m_CoolDownTimer;
  41. }
  42. // ----------------------------------------------------------------------------------------
  43. float AddLinearPrecise( float specialty_weight )
  44. {
  45. m_SpecialtyLevel += specialty_weight;
  46. SetLastUAValue( specialty_weight );
  47. m_SpecialtyLevel = Math.Clamp( m_SpecialtyLevel, PRECISE_WEIGHT_LIMIT, ROUGH_WEIGHT_LIMIT );
  48. return m_SpecialtyLevel;
  49. }
  50. // ----------------------------------------------------------------------------------------
  51. float AddLinearRough( float specialty_weight )
  52. {
  53. m_SpecialtyLevel += specialty_weight;
  54. SetLastUAValue( specialty_weight );
  55. m_SpecialtyLevel = Math.Clamp( m_SpecialtyLevel, PRECISE_WEIGHT_LIMIT, ROUGH_WEIGHT_LIMIT );
  56. return m_SpecialtyLevel;
  57. }
  58. // ----------------------------------------------------------------------------------------
  59. float AddExponentialPrecise( float specialty_weight )
  60. {
  61. m_UserActionsCounter -= 1;
  62. if( m_UserActionsCounter == 0)
  63. {
  64. m_UserActionsCounter = -1;
  65. m_SpecialtyLevel = 0;
  66. }
  67. float adjusted_weight = specialty_weight / Math.Sqrt( Math.AbsInt( m_UserActionsCounter ) );
  68. SetLastUAValue( adjusted_weight );
  69. m_SpecialtyLevel += adjusted_weight;
  70. m_SpecialtyLevel = Math.Clamp( m_SpecialtyLevel, PRECISE_WEIGHT_LIMIT, ROUGH_WEIGHT_LIMIT );
  71. return m_SpecialtyLevel;
  72. }
  73. // ----------------------------------------------------------------------------------------
  74. float AddExponentialRough( float specialty_weight )
  75. {
  76. m_UserActionsCounter += 1;
  77. if( m_UserActionsCounter == 0)
  78. {
  79. m_UserActionsCounter = 1;
  80. m_SpecialtyLevel = 0;
  81. }
  82. float adjusted_weight = specialty_weight / Math.Sqrt( Math.AbsInt( m_UserActionsCounter ) );
  83. SetLastUAValue( adjusted_weight );
  84. m_SpecialtyLevel += adjusted_weight;
  85. m_SpecialtyLevel = Math.Clamp( m_SpecialtyLevel, PRECISE_WEIGHT_LIMIT, ROUGH_WEIGHT_LIMIT );
  86. return m_SpecialtyLevel;
  87. }
  88. // ----------------------------------------------------------------------------------------
  89. void AddSpecialty( float specialty_weight )
  90. {
  91. if( GetSoftSkillsState() )
  92. {
  93. if( !IsCoolDown() )
  94. {
  95. if( specialty_weight < 0 )
  96. {
  97. if( IsLinear() )
  98. {
  99. SetSpecialtyLevel( AddLinearPrecise( specialty_weight ) );
  100. }
  101. else
  102. {
  103. SetSpecialtyLevel( AddExponentialPrecise( specialty_weight ) );
  104. }
  105. m_Player.GetStatSpecialty().Set( m_SpecialtyLevel );
  106. StartCoolDownTimer( Math.AbsFloat( ( specialty_weight * 100 ) ) * COOLDOWN_TIMER );
  107. SynchSpecialtyLevel();
  108. }
  109. else if( specialty_weight > 0 )
  110. {
  111. if( IsLinear() )
  112. {
  113. SetSpecialtyLevel( AddLinearRough( specialty_weight ) );
  114. }
  115. else
  116. {
  117. SetSpecialtyLevel( AddExponentialRough( specialty_weight ) );
  118. }
  119. m_Player.GetStatSpecialty().Set( m_SpecialtyLevel );
  120. StartCoolDownTimer( Math.AbsFloat( ( specialty_weight * 100 ) ) * COOLDOWN_TIMER );
  121. SynchSpecialtyLevel();
  122. }
  123. else
  124. {
  125. //if the specialty weight for a recipe or UA is set to 0, it will increase neither specialty, nor UA counter
  126. return;
  127. }
  128. }
  129. else
  130. {
  131. StartCoolDownTimer( Math.AbsFloat( ( specialty_weight * 100 ) ) * COOLDOWN_TIMER );
  132. }
  133. }
  134. }
  135. // ----------------------------------------------------------------------------------------
  136. // Use AddSpecialtyBonus if you want to increase a value, based on the specialty level of the player. e.g. more harvested material
  137. // limit_efficiency sets the max amount of bonus, the soft skill can provide: limit_efficiency = 2 is 50% bonus, limit_efficiency = 3 is 33% bonus etc
  138. float AddSpecialtyBonus( float base_value, float specialty_weight, bool is_cacomponent = false, float limit_efficiency = 2 )
  139. {
  140. if ( specialty_weight == 0 )
  141. {
  142. return base_value;
  143. }
  144. SetBonusBefore( is_cacomponent, base_value);
  145. float adjusted_value;
  146. GetPreciseRoughLevels();
  147. if ( limit_efficiency != 0 )
  148. {
  149. if ( specialty_weight < 0 )
  150. {
  151. adjusted_value = base_value + ( ( base_value * m_PreciseLevel ) / limit_efficiency );
  152. }
  153. else
  154. {
  155. adjusted_value = base_value + ( ( base_value * m_RoughLevel ) / limit_efficiency );
  156. }
  157. }
  158. else
  159. {
  160. if ( specialty_weight < 0 )
  161. {
  162. adjusted_value = base_value + ( ( base_value * m_PreciseLevel ) );
  163. }
  164. else
  165. {
  166. adjusted_value = base_value + ( ( base_value * m_RoughLevel ) );
  167. }
  168. }
  169. SetBonusAfter( is_cacomponent, adjusted_value );
  170. return adjusted_value;
  171. }
  172. // ----------------------------------------------------------------------------------------
  173. // Use SubtractSpecialtyBonus if you want to decrease a value, based on the specialty level of the player. e.g. faster harvesting time
  174. // limit_efficiency sets the max amount of bonus, the soft skill can provide: limit_efficiency = 2 is 50% bonus, limit_efficiency = 3 is 33% bonus etc
  175. float SubtractSpecialtyBonus( float base_value, float specialty_weight, bool is_cacomponent = false, float limit_efficiency = 2 )
  176. {
  177. if ( specialty_weight == 0 )
  178. {
  179. return base_value;
  180. }
  181. SetBonusBefore( is_cacomponent, base_value);
  182. float adjusted_value;
  183. GetPreciseRoughLevels();
  184. if ( limit_efficiency != 0 )
  185. {
  186. if ( specialty_weight < 0 )
  187. {
  188. adjusted_value = base_value - ( ( base_value * m_PreciseLevel ) / limit_efficiency );
  189. }
  190. else
  191. {
  192. adjusted_value = base_value - ( ( base_value * m_RoughLevel ) / limit_efficiency );
  193. }
  194. }
  195. else
  196. {
  197. if ( specialty_weight < 0 )
  198. {
  199. adjusted_value = base_value - ( ( base_value * m_PreciseLevel ) );
  200. }
  201. else
  202. {
  203. adjusted_value = base_value - ( ( base_value * m_RoughLevel ) );
  204. }
  205. }
  206. SetBonusAfter( is_cacomponent, adjusted_value );
  207. return adjusted_value;
  208. }
  209. // ----------------------------------------------------------------------------------------
  210. // Use AdjustCraftingTime if you want to decrease time for recipe crafting
  211. // limit_efficiency sets the max amount of bonus, the soft skill can provide: limit_efficiency = 2 is 50% bonus, limit_efficiency = 3 is 33% bonus etc
  212. float AdjustCraftingTime( float base_time, float specialty_weight, float limit_efficiency = 2 )
  213. {
  214. if ( specialty_weight == 0 )
  215. {
  216. return base_time;
  217. }
  218. SetBonusBefore( false, base_time);
  219. float adjusted_time;
  220. GetPreciseRoughLevels();
  221. if ( specialty_weight < 0 )
  222. {
  223. adjusted_time = base_time - ( ( base_time * m_PreciseLevel ) / limit_efficiency );
  224. }
  225. else
  226. {
  227. adjusted_time = base_time - ( ( base_time * m_RoughLevel ) / limit_efficiency );
  228. }
  229. SetBonusAfter( false, adjusted_time );
  230. return adjusted_time;
  231. }
  232. // ----------------------------------------------------------------------------------------
  233. PlayerBase GetSoftSkillsPlayer()
  234. {
  235. return m_Player;
  236. }
  237. // ----------------------------------------------------------------------------------------
  238. void SetSpecialtyLevel( float specialty_level )
  239. {
  240. m_SpecialtyLevel = specialty_level;
  241. }
  242. // ----------------------------------------------------------------------------------------
  243. float GetSpecialtyLevel()
  244. {
  245. return m_SpecialtyLevel;
  246. }
  247. // ----------------------------------------------------------------------------------------
  248. void SynchSpecialtyLevel()
  249. {
  250. #ifdef SERVER
  251. Param1<float> specialty_level = new Param1<float>( m_SpecialtyLevel );
  252. GetGame().RPCSingleParam( m_Player, ERPCs.RPC_SOFT_SKILLS_SPECIALTY_SYNC, specialty_level, true, m_Player.GetIdentity() );
  253. #endif
  254. }
  255. // ----------------------------------------------------------------------------------------
  256. void SetSoftSkillsState( bool state )
  257. {
  258. m_IsActive = state;
  259. }
  260. // ----------------------------------------------------------------------------------------
  261. bool GetSoftSkillsState()
  262. {
  263. return m_IsActive;
  264. }
  265. // ----------------------------------------------------------------------------------------
  266. void SetLinearState( bool model )
  267. {
  268. m_IsLinear = model;
  269. }
  270. // ----------------------------------------------------------------------------------------
  271. bool IsLinear()
  272. {
  273. return m_IsLinear;
  274. }
  275. // ----------------------------------------------------------------------------------------
  276. void GetPreciseRoughLevels()
  277. {
  278. if ( m_SpecialtyLevel > 0)
  279. {
  280. m_RoughLevel = m_SpecialtyLevel;
  281. m_PreciseLevel = DEFAULT_EFFICIENCY;
  282. }
  283. else if ( m_SpecialtyLevel < 0)
  284. {
  285. m_RoughLevel = DEFAULT_EFFICIENCY;
  286. m_PreciseLevel = Math.AbsFloat( m_SpecialtyLevel );
  287. }
  288. else
  289. {
  290. m_RoughLevel = DEFAULT_EFFICIENCY;
  291. m_PreciseLevel = DEFAULT_EFFICIENCY;
  292. }
  293. }
  294. // ----------------------------------------------------------------------------------------
  295. void StartCoolDownTimer( float cooldown_value )
  296. {
  297. SetCoolDown( true );
  298. SetCoolDownValue( cooldown_value );
  299. m_CoolDownTimer.Run( cooldown_value, this, "SetCoolDown", new Param1<bool>( false ) );
  300. }
  301. // ----------------------------------------------------------------------------------------
  302. bool IsCoolDown()
  303. {
  304. return m_IsCoolDown;
  305. }
  306. // ----------------------------------------------------------------------------------------
  307. void SetCoolDown( bool cool_down )
  308. {
  309. m_IsCoolDown = cool_down;
  310. }
  311. // ----------------------------------------------------------------------------------------
  312. // SoftSkillManagerDebug support
  313. // ----------------------------------------------------------------------------------------
  314. void CreateDebugWindow( bool create )
  315. {
  316. if ( create )
  317. {
  318. m_DebugWindow = new SoftSkillManagerDebug( this );
  319. SetIsDebug( create );
  320. }
  321. else
  322. {
  323. ResetDebugWindow();
  324. SetIsDebug( create );
  325. delete m_DebugWindow;
  326. }
  327. }
  328. // ----------------------------------------------------------------------------------------
  329. void SynchDebugStats()
  330. {
  331. if ( GetGame().IsServer() && GetGame().IsMultiplayer() )
  332. {
  333. Param5<float, float, float, float, bool> debug_stats = new Param5<float, float, float, float, bool>( m_GeneralBonusBefore, m_GeneralBonusAfter, m_LastUAValue, m_CoolDownValue, m_IsCoolDown );
  334. GetGame().RPCSingleParam( m_Player, ERPCs.RPC_SOFT_SKILLS_STATS_SYNC, debug_stats, true, m_Player.GetIdentity() );
  335. }
  336. }
  337. // ----------------------------------------------------------------------------------------
  338. void SetIsDebug( bool is_debug )
  339. {
  340. m_IsDebugMode = is_debug;
  341. }
  342. // ----------------------------------------------------------------------------------------
  343. bool IsDebug()
  344. {
  345. return m_IsDebugMode;
  346. }
  347. // ----------------------------------------------------------------------------------------
  348. void SetCoolDownValue( float cooldown_value )
  349. {
  350. m_CoolDownValue = cooldown_value;
  351. }
  352. // ----------------------------------------------------------------------------------------
  353. float GetCoolDownValue()
  354. {
  355. return m_CoolDownValue;
  356. }
  357. // ----------------------------------------------------------------------------------------
  358. float GetLastUAValue()
  359. {
  360. return m_LastUAValue;
  361. }
  362. // ----------------------------------------------------------------------------------------
  363. void SetLastUAValue( float last_ua_value )
  364. {
  365. m_LastUAValue = last_ua_value;
  366. }
  367. // ----------------------------------------------------------------------------------------
  368. void SetBonusBefore( bool is_cacomponent, float base_value)
  369. {
  370. if ( IsDebug() )
  371. {
  372. if ( is_cacomponent )
  373. {
  374. SetComponentBonusBefore(base_value);
  375. }
  376. else
  377. {
  378. SetGeneralBonusBefore(base_value);
  379. }
  380. }
  381. }
  382. // ----------------------------------------------------------------------------------------
  383. void SetBonusAfter( bool is_cacomponent, float adjusted_value )
  384. {
  385. if ( IsDebug() )
  386. {
  387. if ( is_cacomponent )
  388. {
  389. SetComponentBonusAfter(adjusted_value);
  390. }
  391. else
  392. {
  393. SetGeneralBonusAfter(adjusted_value);
  394. }
  395. }
  396. }
  397. // ----------------------------------------------------------------------------------------
  398. float GetComponentBonusBefore()
  399. {
  400. return m_ComponentBonusBefore;
  401. }
  402. // ----------------------------------------------------------------------------------------
  403. void SetComponentBonusBefore( float component_bonus_before )
  404. {
  405. m_ComponentBonusBefore = component_bonus_before;
  406. }
  407. // ----------------------------------------------------------------------------------------
  408. float GetComponentBonusAfter()
  409. {
  410. return m_ComponentBonusAfter;
  411. }
  412. // ----------------------------------------------------------------------------------------
  413. void SetComponentBonusAfter( float component_bonus_after )
  414. {
  415. m_ComponentBonusAfter = component_bonus_after;
  416. }
  417. // ----------------------------------------------------------------------------------------
  418. float GetGeneralBonusBefore()
  419. {
  420. return m_GeneralBonusBefore;
  421. }
  422. // ----------------------------------------------------------------------------------------
  423. void SetGeneralBonusBefore( float general_bonus_before )
  424. {
  425. m_GeneralBonusBefore = general_bonus_before;
  426. }
  427. // ----------------------------------------------------------------------------------------
  428. float GetGeneralBonusAfter()
  429. {
  430. return m_GeneralBonusAfter;
  431. }
  432. // ----------------------------------------------------------------------------------------
  433. void SetGeneralBonusAfter( float general_bonus_after )
  434. {
  435. m_GeneralBonusAfter = general_bonus_after;
  436. }
  437. // ----------------------------------------------------------------------------------------
  438. void StartSynchTimer()
  439. {
  440. SetIsDebug( true );
  441. m_SynchTimer = new Timer;
  442. m_SynchTimer.Run( 2, this, "SynchDebugStats", NULL, true );
  443. }
  444. // ----------------------------------------------------------------------------------------
  445. void StopSynchTimer()
  446. {
  447. SetIsDebug( false );
  448. if ( m_SynchTimer )
  449. {
  450. m_SynchTimer.Stop();
  451. delete m_SynchTimer;
  452. }
  453. }
  454. // ----------------------------------------------------------------------------------------
  455. void ResetDebugWindow()
  456. {
  457. SetSpecialtyLevel( 0 );
  458. SetLastUAValue( 0 );
  459. SetComponentBonusBefore( 0 );
  460. SetComponentBonusAfter( 0 );
  461. SetGeneralBonusBefore( 0 );
  462. SetGeneralBonusAfter( 0 );
  463. SetCoolDownValue( 0 );
  464. SynchSpecialtyLevel();
  465. }
  466. }
  467. // ----------------------------------------------------------------------------------------
  468. // SoftSkillManagerDebug
  469. // ----------------------------------------------------------------------------------------
  470. class SoftSkillManagerDebug
  471. {
  472. SoftSkillsManager m_SoftSkillManager;
  473. ref Widget m_PanelSoftSkills;
  474. TextWidget SpecialtyTotal;
  475. TextWidget SpecialtyChange;
  476. TextWidget ComponentBonusBefore;
  477. TextWidget ComponentBonusAfter;
  478. TextWidget GeneralBonusBefore;
  479. TextWidget GeneralBonusAfter;
  480. TextWidget CoolDown;
  481. TextWidget IsCoolDown;
  482. void SoftSkillManagerDebug( SoftSkillsManager softskill_manager )
  483. {
  484. m_SoftSkillManager = softskill_manager;
  485. m_PanelSoftSkills = GetGame().GetWorkspace().CreateWidgets("gui/layouts/debug/day_z_hud_debug_softskills.layout");
  486. GetGame().GetUpdateQueue(CALL_CATEGORY_SYSTEM).Insert(this.OnUpdate);
  487. Class.CastTo(SpecialtyTotal, m_PanelSoftSkills.FindWidget("SpecialtyTotal"));
  488. Class.CastTo(SpecialtyChange, m_PanelSoftSkills.FindWidget("SpecialtyChange"));
  489. Class.CastTo(ComponentBonusBefore, m_PanelSoftSkills.FindWidget("ComponentBonusBefore"));
  490. Class.CastTo(ComponentBonusAfter, m_PanelSoftSkills.FindWidget("ComponentBonusAfter"));
  491. Class.CastTo(GeneralBonusBefore, m_PanelSoftSkills.FindWidget("GeneralBonusBefore"));
  492. Class.CastTo(GeneralBonusAfter, m_PanelSoftSkills.FindWidget("GeneralBonusAfter"));
  493. Class.CastTo(CoolDown, m_PanelSoftSkills.FindWidget("CoolDown"));
  494. Class.CastTo(IsCoolDown, m_PanelSoftSkills.FindWidget("IsCoolDown"));
  495. m_PanelSoftSkills.Show( true );
  496. SpecialtyTotal.Show( true );
  497. SpecialtyChange.Show( true );
  498. ComponentBonusBefore.Show( true );
  499. ComponentBonusAfter.Show( true );
  500. GeneralBonusBefore.Show( true );
  501. GeneralBonusAfter.Show( true );
  502. CoolDown.Show( true );
  503. IsCoolDown.Show( true );
  504. }
  505. void ~SoftSkillManagerDebug()
  506. {
  507. if ( GetGame() )
  508. {
  509. GetGame().GetUpdateQueue(CALL_CATEGORY_SYSTEM).Remove(this.OnUpdate);
  510. }
  511. delete m_PanelSoftSkills;
  512. }
  513. SoftSkillsManager GetActiveSoftSkillManager()
  514. {
  515. return m_SoftSkillManager;
  516. }
  517. void OnUpdate()
  518. {
  519. if ( GetActiveSoftSkillManager().GetSoftSkillsPlayer().IsAlive() )
  520. {
  521. float speciality = GetActiveSoftSkillManager().GetSpecialtyLevel();
  522. speciality = speciality * 100;
  523. speciality = Math.Round( speciality );
  524. speciality = speciality * 0.01;
  525. SpecialtyTotal.SetText( "Specialty level: " + speciality.ToString() );
  526. SpecialtyChange.SetText( "Specialty change: " + GetActiveSoftSkillManager().GetLastUAValue() );
  527. ComponentBonusBefore.SetText( "Component/craft default: " + GetActiveSoftSkillManager().GetComponentBonusBefore() );
  528. ComponentBonusAfter.SetText( "Component/craft with bonus: " + GetActiveSoftSkillManager().GetComponentBonusAfter() );
  529. GeneralBonusBefore.SetText( "General default: " + GetActiveSoftSkillManager().GetGeneralBonusBefore() );
  530. GeneralBonusAfter.SetText( "General with bonus: " + GetActiveSoftSkillManager().GetGeneralBonusAfter() );
  531. CoolDown.SetText( "CoolDown value: " + GetActiveSoftSkillManager().GetCoolDownValue() );
  532. IsCoolDown.SetText( "Cooldown active: " + GetActiveSoftSkillManager().IsCoolDown() );
  533. }
  534. else
  535. {
  536. delete this;
  537. }
  538. }
  539. }