pc_mood.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. class Mood{
  2. /* Mood */
  3. get OWNER(){return State.variables.pc}
  4. get mood(){
  5. const moodletsEffect = this.moodletsActiveEffect;
  6. return Math.clamp(50 + moodletsEffect,0,100);
  7. }
  8. set mood(v){
  9. console.warn('pc.mood(set) is deprecated, use moodletApplyById instead',State.variables.here);
  10. const desiredEffect = v - this.mood;
  11. const time = State.variables.time;
  12. const effectId = 'DEPR_'+(time.now.getTime() / 60000)+'-'+Object.keys(this._moodlets).length;
  13. this._moodlets[effectId] = {
  14. effect: desiredEffect,
  15. expiration: time.nowWithMinutesOffset(60),
  16. title: 'Misc Effect'
  17. };
  18. }
  19. _moodlets:{[key: string]: object} = {};
  20. private moodlet(moodletId:string):ActiveMoodlet{
  21. return ActiveMoodlet.create(moodletId,this._moodlets[moodletId] ?? {});
  22. }
  23. /**
  24. * All moodlets that are currently stored as active. Use moodletsActive() to get only the ones which haven't expired yet.
  25. * @private
  26. * @readonly
  27. * @type {{[key: string]: ActiveMoodlet}}
  28. */
  29. private get moodlets():{[key: string]: ActiveMoodlet} {
  30. let result = {};
  31. for (const [moodletId, moodletDynamicData] of Object.entries(this._moodlets)) {
  32. result[moodletId] = ActiveMoodlet.create(moodletId,moodletDynamicData);
  33. }
  34. return result;
  35. }
  36. /**
  37. * The moodlets that are currently active.
  38. * @readonly
  39. * @type {{[key: string]: ActiveMoodlet}}
  40. */
  41. get moodletsActive():{[key: string]: ActiveMoodlet}{
  42. let defaultMoodlets= Object.fromEntries(
  43. Object.entries(this.moodlets).
  44. filter(
  45. ([moodletId,moodlet])=>moodlet.isActive
  46. )
  47. );
  48. let specialMoodlets = this.OWNER.moodletsSpecial;
  49. return Object.assign({},specialMoodlets,defaultMoodlets);
  50. }
  51. get moodletsActiveByGroup(){
  52. let result = {};
  53. for (const [moodletId,moodletData] of Object.entries(this.moodletsActive)) {
  54. const moodletGroup = moodletData.groupId ?? 'none';
  55. result[moodletGroup] ??= {};
  56. result[moodletGroup][moodletId] = moodletData;
  57. }
  58. return result;
  59. }
  60. /**
  61. * Returns the combined effect of all moodlets that are in effect.
  62. * @readonly
  63. * @type {number}
  64. */
  65. get moodletsActiveEffect():number{
  66. return Object.values(this.moodletsActiveByGroupAccumulationApplied).reduce(
  67. (accumulator, currentValue) => accumulator + Object.values(currentValue).reduce(
  68. (innerAccumulator,innerCurrentValue) => innerAccumulator + innerCurrentValue.effect
  69. ,0)
  70. ,0) as number;
  71. }
  72. get moodletsActiveByGroupAccumulationApplied(){
  73. let activeEffectsByGroup = this.moodletsActiveByGroup;
  74. for (const [moodletGroupId,moodletGroup] of Object.entries(activeEffectsByGroup)) {
  75. if(!Object.keys(moodletGroup).length) continue;
  76. const groupData = MoodletGroup.get(moodletGroupId);
  77. let moodletsSortedByEffect = Object.entries(moodletGroup).map(([moodletId,moodletData])=>([moodletId,moodletData.effect ?? 0])).sort((a,b)=>b[1]-a[1]);
  78. switch(groupData.accumulationMode){
  79. case moodletAccumulationMode.ADD:
  80. break;
  81. case moodletAccumulationMode.HIGHEST:
  82. for(let moodletIndex = 0;moodletIndex < moodletsSortedByEffect.length; moodletIndex++){
  83. if(moodletIndex)
  84. activeEffectsByGroup[moodletGroupId][moodletsSortedByEffect[moodletIndex][0]].effect = 0;
  85. }
  86. break;
  87. case moodletAccumulationMode.LOWEST:
  88. moodletsSortedByEffect.reverse();
  89. for(let moodletIndex = 0;moodletIndex < moodletsSortedByEffect.length; moodletIndex++){
  90. if(moodletIndex)
  91. activeEffectsByGroup[moodletGroupId][moodletsSortedByEffect[moodletIndex][0]].effect = 0;
  92. }
  93. break;
  94. case moodletAccumulationMode.DIMINISHING_REVERSE:
  95. moodletsSortedByEffect.reverse();
  96. case moodletAccumulationMode.DIMINISHING:
  97. const diminishFactor = groupData.diminishFactor ?? 0.5;
  98. for(let moodletIndex = 0;moodletIndex < moodletsSortedByEffect.length; moodletIndex++){
  99. activeEffectsByGroup[moodletGroupId][moodletsSortedByEffect[moodletIndex][0]].effect *= Math.pow(diminishFactor,moodletIndex);
  100. }
  101. break;
  102. }
  103. }
  104. return activeEffectsByGroup;
  105. }
  106. /**
  107. * Removes inactive moodlets from _moodlets
  108. * @date 11/19/2023 - 11:54:52 AM
  109. */
  110. _moodletsClean(){
  111. this._moodlets = Object.fromEntries(
  112. Object.entries(this._moodlets).
  113. filter(
  114. ([moodletId,moodletData])=>ActiveMoodlet.create(moodletId,moodletData).isActive
  115. )
  116. );
  117. }
  118. moodletApplyById(moodletId:string,minutes:number=0){
  119. const moodletData = Moodlet.get(moodletId);
  120. const time = State.variables.time;
  121. switch(moodletData.timeMode){
  122. case moodletTimeMode.Continuous:
  123. this.moodletIncTime(moodletId,minutes);
  124. break;
  125. case moodletTimeMode.Lasting:
  126. this.moodletIncTime(moodletId,525600000);
  127. break;
  128. case moodletTimeMode.Resetting:
  129. let expirationTimeResetting = time.nowWithMinutesOffset(moodletData.duration);
  130. this.moodletUpdate(moodletId,{expiration: expirationTimeResetting});
  131. break;
  132. }
  133. }
  134. moodletDeactivateById(moodletId){
  135. delete this._moodlets[moodletId];
  136. }
  137. moodletIncTime(moodletId,minutes,skipIncludedMoodlets=false){
  138. const moodletData = this.moodlet(moodletId);
  139. const time = State.variables.time;
  140. let expiration;
  141. if(moodletData.timeConversion)
  142. minutes *= moodletData.timeConversion;
  143. if(!moodletData.expiration || !time.isFuture(moodletData.expiration)){
  144. expiration = time.nowWithMinutesOffset(minutes);
  145. }else{
  146. expiration = new Date(moodletData.expiration.getTime());
  147. expiration.setUTCMinutes(expiration.getUTCMinutes() + minutes);
  148. }
  149. if(moodletData.maxDuration){
  150. let maxExpiration = time.nowWithMinutesOffset(moodletData.maxDuration);
  151. expiration = new Date(Math.min(expiration.getTime(),maxExpiration.getTime()));
  152. }
  153. this.moodletUpdate(moodletId,{expiration: expiration});
  154. if(!skipIncludedMoodlets && moodletData.includes){
  155. for(const includeId of moodletData.includes)
  156. this.moodletIncTime(includeId,minutes,true);
  157. }
  158. }
  159. moodletUpdate(moodletId,updateObject){
  160. this._moodlets[moodletId] = Object.assign({},this._moodlets[moodletId],updateObject);
  161. }
  162. constructor(moodlets={}){this._moodlets=moodlets;}
  163. _init(data){
  164. Object.keys(data).forEach(function (pn) {
  165. this[pn] = clone(data[pn]);
  166. }, this);
  167. return this;
  168. }
  169. clone = function () {
  170. return (new Mood())._init(this);
  171. };
  172. toJSON = function () {
  173. var ownData = {};
  174. Object.keys(this).forEach(function (data) {
  175. if(typeof this[data] !== "function")
  176. ownData[data] = clone(this[data]);
  177. }, this);
  178. return JSON.reviveWrapper('(new setup.Mood())._init($ReviveData$)', ownData);
  179. };
  180. }
  181. setup.Mood = Mood;