act.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. const enum EActionPosition{
  2. ACTIONBAR = -1,
  3. BOTH = 0,
  4. PASSAGE = 1
  5. }
  6. var actAdd = function(macroContext:TwineSugarCube.MacroContext,label:string,contents:string,position?:EActionPosition,flags?:ActFlags){
  7. const pc = State.variables.pc;
  8. label ??= flags.label;
  9. let _styleClass = 'action';
  10. let _tooltip = '';
  11. let _act_contents = flags.contents ?? contents;
  12. let _capture_vars = flags.capture ?? [];
  13. _capture_vars.push('_autoCapture')//<!-- The vars that always get captured by actions -->
  14. if('action' in flags){
  15. flags = Object.assign({},flags,setup.getGenericActionApplied(flags.action))
  16. _act_contents += `<<actionApply '${flags.action}'>>`;
  17. }
  18. if(flags.disabled){
  19. _tooltip = flags.disabled ?? '';
  20. _styleClass += ' disabled';
  21. _act_contents = ''
  22. }
  23. if(flags.hidden){
  24. return;
  25. }
  26. if('time' in flags){
  27. if(flags.time > 0)
  28. _act_contents = `<<addtime ${flags.time}>>${_act_contents}`;
  29. label += ` (${setup.durationToString(Math.abs(flags.time))})`;
  30. }
  31. if('moodlet' in flags){
  32. let _moodletData = Moodlet.get(flags.moodlet);
  33. _tooltip += 'This would likely lead to you getting the effect '+_moodletData.title+'.';
  34. }
  35. if('mood' in flags){
  36. if(pc.mood < flags.mood){
  37. _tooltip += 'Your mood is too low to do this.'
  38. _styleClass += ' mood disabled'
  39. _act_contents = ''
  40. }else{
  41. _tooltip += 'Your mood is high enough (>='+flags.mood+') to do this.'
  42. _styleClass += ' mood'
  43. }
  44. }
  45. if('arousal' in flags){
  46. if(pc.horny < flags.arousal){
  47. _tooltip += 'Your arousal is too low ('+pc.horny+'/'+flags.arousal+') to do this.'
  48. _styleClass += ' arousal disabled'
  49. _act_contents = ''
  50. }else{
  51. _tooltip += 'Your arousal is high enough (>='+flags.arousal+') to do this.'
  52. _styleClass += ' arousal'
  53. }
  54. }
  55. /*if('fetish' in flags){
  56. let _actFetishes = flags.fetish
  57. <<for _actFetish range _actFetishes>>
  58. if(pc.fetish(_actFetish) < 0){
  59. let _tooltip += _actFetish+ ': You can\'t do this because of your fetish-settings (you can change them in the character-menu).'
  60. let _styleClass += ' fetish disabled'
  61. let _act_contents = ''
  62. }
  63. <</for>>
  64. }*/
  65. //<!-- Skills -->
  66. if('skillRequirment' in flags){
  67. let _skillsMessage = ''
  68. let _skillsEnable = true
  69. for(const[_skillId, _skillMin] of Object.entries(flags.skillRequirment)){
  70. if(pc.skillLevel(_skillId) >= _skillMin){
  71. _skillsMessage += 'Your skill '+_skillId+' of '+_skillMin+'+ enables you to do this.'
  72. }else{
  73. _skillsMessage += 'Your skill '+_skillId+' needs to be '+_skillMin+'+ to do this.'
  74. _skillsEnable = false
  75. }
  76. }
  77. _tooltip += _skillsMessage
  78. if(_skillsEnable){
  79. _styleClass += ' skill'
  80. }else{
  81. _styleClass += ' skill disabled'
  82. _act_contents = ''
  83. }
  84. }
  85. //#region Personality
  86. if(flags.personality){
  87. if(flags.willpower){
  88. console.error('personality and willpower must not be declare at the same time in actAdd: (label, flags)',label,flags);
  89. }
  90. let personality_willpower = 0;
  91. for(const [personalityId, personalityRequirement] of Object.entries(flags.personality)){
  92. const expectedPersonalityEffect = pc.personalityScale(personalityId).effectOfAction(personalityRequirement);
  93. if(expectedPersonalityEffect.willpower > 0)
  94. personality_willpower += expectedPersonalityEffect.willpower;
  95. }
  96. if(personality_willpower){
  97. }
  98. }
  99. //#endregion
  100. //#region Willpower
  101. if(flags.willpower){
  102. let _willpower_cost = 0;
  103. if(typeof flags.willpower == "number"){
  104. _willpower_cost = flags.willpower
  105. }else{
  106. _willpower_cost = setup.func('willpower','cost',flags.willpower)
  107. }
  108. label += " ("+_willpower_cost+")"
  109. if(_willpower_cost > pc.willpower){
  110. _styleClass += ' willpower willpower_disabled disabled'
  111. _act_contents = ''
  112. _tooltip = "You don\'t have enough willpower to perform this action."
  113. }else{
  114. _styleClass += ' willpower'
  115. _act_contents = "<<gs 'willpower' 'pay' "+_willpower_cost+" `"+ JSON.stringify(flags.willpower)+"`" + _act_contents;
  116. }
  117. }
  118. //#endregion
  119. //<!-- Money Cost -->
  120. if('cost' in flags){
  121. if(flags.cost.cash){
  122. let _cashCost = flags.cost.cash;
  123. label += " (<b>"+Math.abs(_cashCost).toLocaleString()+" ₽</b> Cash)"
  124. if(Math.abs(_cashCost) > State.variables.finances.cash){
  125. _styleClass += ' cost cost_disabled disabled'
  126. _act_contents = ''
  127. _tooltip = "You don\'t have enough cash to perform this action."
  128. }else{
  129. _styleClass += ' cost'
  130. if(_cashCost > 0){
  131. _act_contents = "<<set $finances.cash -= "+_cashCost+">>" + _act_contents;
  132. }
  133. }
  134. }else if(flags.cost.bank){
  135. let _bankCost = flags.cost.bank;
  136. label += " (<b>"+Math.abs(_bankCost).toLocaleString()+" ₽</b> from Bank Account)"
  137. if(!State.variables.finances.hasBankAccount){
  138. _styleClass += ' cost cost_disabled disabled';
  139. _act_contents = '';
  140. _tooltip = "You don't have a bank account.";
  141. }else if(Math.abs(_bankCost) > State.variables.finances.bankAvailable){
  142. _styleClass += ' cost cost_disabled disabled'
  143. _act_contents = ''
  144. _tooltip = "You don\'t have enough money on your bank account to perform this action."
  145. }else{
  146. _styleClass += ' cost'
  147. if(_bankCost > 0){
  148. _act_contents = "<<set $finances.bank -= "+_bankCost+">>" + _act_contents;
  149. }
  150. }
  151. }else if(flags.cost.both){
  152. let flagsOfCashButton = clone(flags);
  153. flagsOfCashButton.cost = {cash: flags.cost.both};
  154. let _contentsOfCashButton = clone(this.payload[0].contents)
  155. let flagsOfBankButton = clone(flags)
  156. flagsOfBankButton.cost = {bank: flags.cost.both}
  157. let _contentsOfBankButton = clone(this.payload[0].contents)
  158. actAdd(macroContext,label,_contentsOfCashButton,position,flagsOfCashButton);
  159. actAdd(macroContext,label,_contentsOfBankButton,position,flagsOfBankButton);
  160. return;
  161. }
  162. }
  163. //<!-- Do Once Every n time-units -->
  164. if('repeatReset' in flags){
  165. let _uniqueActionId = State.temporary.thisMainPassage + '~' + this.args[0]//<!-- Use the raw label so it doesn't get fucked up by willlpower calculations -->
  166. let _repeatResetCooldownEnd = State.variables.actions[_uniqueActionId]?.cooldownEnd ?? 0
  167. if(_repeatResetCooldownEnd < State.variables.time.now.getTime()){
  168. if(flags.repeatReset.days){
  169. _act_contents = "<<set $actions['"+_uniqueActionId+"'] = {cooldownEnd:$time.dayWithOffset("+flags.repeatReset.days+")}>>" + _act_contents;
  170. }
  171. }else{
  172. return;
  173. }
  174. }
  175. //<!-- items -->
  176. if('items' in flags){
  177. let _missingItems = ''
  178. for(const[_itemKey, _itemAmount] of Object.entries(flags.items)){
  179. if(_itemAmount > State.variables.inventory.get(_itemKey))
  180. _missingItems += '<br/>'+State.variables.inventory.metadata(_itemKey).label+': '+_itemAmount
  181. else if(_itemAmount > 0)
  182. _act_contents = "<<run $inventory.dec('"+_itemKey+"',"+_itemAmount+")>>" + _act_contents
  183. }
  184. if(_missingItems){
  185. _styleClass += ' disabled'
  186. _act_contents = ''
  187. _tooltip = 'You are missing the following:'+_missingItems+"x"
  188. }
  189. }
  190. if(_act_contents){
  191. _act_contents = (flags.contents_header ?? '') + _act_contents + (flags.contents_footer ?? '');
  192. }
  193. if(position == EActionPosition.BOTH || position === EActionPosition.ACTIONBAR){
  194. let _ab_label = flags.ab_label ?? label;
  195. let _priority = flags.priority ?? 0;
  196. let _capture_vars_actionBar = {};
  197. for(const _capture_var of _capture_vars)
  198. _capture_vars_actionBar[_capture_var] = clone(State.getVar(_capture_var))
  199. State.temporary.actions ??= [];
  200. State.temporary.actions.push( new setup.Action(
  201. {
  202. passage: passage(),
  203. label: _ab_label,
  204. contents: _act_contents,
  205. priority: _priority,
  206. captured: _capture_vars_actionBar,
  207. styleClass: _styleClass,
  208. tooltip: _tooltip,
  209. image: flags.image
  210. })
  211. );
  212. }
  213. if(position == EActionPosition.BOTH || position === EActionPosition.PASSAGE){
  214. let _linkMarkup = `<<link '${label}'>>${_act_contents}<</link>>`;
  215. if(_capture_vars.length > 0){
  216. _linkMarkup = '<<capture '+_capture_vars.join(', ')+'>>'+_linkMarkup+'<</capture>>';
  217. }
  218. jQuery(macroContext.output).wiki(`<<tooltip 'span' '${_styleClass}' '${_tooltip}'>>${_linkMarkup}<</tooltip>>`);
  219. }
  220. }
  221. Macro.add('act', {
  222. skipArgs : false,
  223. tags:[],
  224. handler : function () {
  225. try {
  226. let label:string = this.args[0];
  227. const position:EActionPosition = this.args[1] ?? State.temporary.actionBarOverride ?? EActionPosition.ACTIONBAR;
  228. let flags:ActFlags = this.args[2] ?? {};
  229. actAdd(this,label,this.payload[0].contents,position,flags);
  230. }
  231. catch (ex) {
  232. return this.error('ERROR in act-widget: ' + ex.message);
  233. }
  234. }
  235. });
  236. Macro.add('actCLA', {
  237. skipArgs : false,
  238. tags:[],
  239. handler : function () {
  240. try {
  241. let label:string = this.args[0];
  242. const position:EActionPosition = this.args[1] ?? State.temporary.actionBarOverride ?? EActionPosition.ACTIONBAR;
  243. let flags:ActFlags = this.args[2] ?? {};
  244. flags.contents_header = '<<set _actions = []>><<replace ".passage">>';
  245. flags.contents_footer = '<</replace>><<actionsRefresh>><<sidebarUpdate>>';
  246. actAdd(this,label,this.payload[0].contents,position,flags);
  247. }
  248. catch (ex) {
  249. return this.error('ERROR in act-widget: ' + ex.message);
  250. }
  251. }
  252. });