You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

204 lines
4.5 KiB

  1. module.exports = {
  2. type: 'dialogue',
  3. states: {},
  4. sourceStates: {},
  5. trigger: null,
  6. init: function (blueprint) {
  7. this.states = blueprint.config;
  8. },
  9. destroy: function () {
  10. if (this.trigger)
  11. this.trigger.destroyed = true;
  12. },
  13. talk: async function (msg) {
  14. if (!msg)
  15. return false;
  16. let target = msg.target;
  17. if (!target && !msg.targetName)
  18. return false;
  19. if (target && !target.id) {
  20. target = this.obj.instance.objects.objects.find(o => o.id === target);
  21. if (!target)
  22. return false;
  23. } else if (msg.targetName) {
  24. target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() === msg.targetName.toLowerCase())));
  25. if (!target)
  26. return false;
  27. }
  28. if (!target.dialogue)
  29. return false;
  30. //Auto-discover faction
  31. if ((target.trade) && (target.trade.faction))
  32. this.obj.reputation.discoverFaction(target.trade.faction.id);
  33. let state = await target.dialogue.getState(this.obj, msg.state);
  34. if (!state) {
  35. this.obj.syncer.set(true, 'dialogue', 'state', null);
  36. return false;
  37. }
  38. this.obj.syncer.set(true, 'dialogue', 'state', state);
  39. },
  40. stopTalk: function () {
  41. this.obj.syncer.set(true, 'dialogue', 'state', null);
  42. },
  43. /* eslint-disable-next-line max-lines-per-function */
  44. getState: async function (sourceObj, state = 1) {
  45. let result = null;
  46. if ((state + '').indexOf('.') > -1) {
  47. let config = this.states[(state + '').split('.')[0]];
  48. if (!config)
  49. return false;
  50. let goto = (config.options[state] || {}).goto;
  51. if (goto instanceof Array) {
  52. let gotos = [];
  53. goto.forEach(function (g) {
  54. let rolls = (g.chance * 100) || 100;
  55. for (let i = 0; i < rolls; i++)
  56. gotos.push(g.number);
  57. });
  58. state = gotos[~~(Math.random() * gotos.length)];
  59. } else
  60. state = goto;
  61. }
  62. this.sourceStates[sourceObj.id] = state;
  63. if (!this.states)
  64. return null;
  65. let stateConfig = this.states[state];
  66. if (!stateConfig)
  67. return null;
  68. let useMsg = stateConfig.msg;
  69. if (stateConfig.cpn) {
  70. let cpn = sourceObj[stateConfig.cpn];
  71. let newArgs = extend([], stateConfig.args);
  72. newArgs.push(this.obj);
  73. result = cpn[stateConfig.method].apply(cpn, newArgs);
  74. if (stateConfig.goto) {
  75. if (result)
  76. return await this.getState(sourceObj, stateConfig.goto.success);
  77. return await this.getState(sourceObj, stateConfig.goto.failure);
  78. }
  79. if (result) {
  80. useMsg = extend([], useMsg);
  81. useMsg[0].msg = result;
  82. } else
  83. return null;
  84. } else if (stateConfig.method) {
  85. let methodResult = await stateConfig.method.call(this.obj, sourceObj);
  86. if (methodResult) {
  87. useMsg = extend([], useMsg);
  88. useMsg[0].msg = methodResult;
  89. }
  90. if (!useMsg)
  91. return;
  92. }
  93. result = {
  94. id: this.obj.id,
  95. msg: null,
  96. from: this.obj.name,
  97. options: []
  98. };
  99. if (useMsg instanceof Array) {
  100. let msgs = [];
  101. useMsg.forEach(function (m, i) {
  102. let rolls = (m.chance * 100) || 100;
  103. for (let j = 0; j < rolls; j++) {
  104. msgs.push({
  105. msg: m,
  106. index: i
  107. });
  108. }
  109. });
  110. let pick = msgs[~~(Math.random() * msgs.length)];
  111. result.msg = pick.msg.msg;
  112. result.options = useMsg[pick.index].options;
  113. } else {
  114. result.msg = useMsg;
  115. result.options = stateConfig.options;
  116. }
  117. if (!(result.options instanceof Array)) {
  118. if (result.options[0] === '$')
  119. result.options = this.states[result.options.replace('$', '')].options;
  120. result.options = Object.keys(result.options);
  121. }
  122. result.options = result.options
  123. .map(function (o) {
  124. let gotoState = this.states[(o + '').split('.')[0]];
  125. let picked = gotoState.options[o];
  126. if (!picked)
  127. return null;
  128. else if (picked.prereq) {
  129. let doesConform = picked.prereq(sourceObj);
  130. if (!doesConform)
  131. return null;
  132. }
  133. return {
  134. id: o,
  135. msg: picked.msg
  136. };
  137. }, this)
  138. .filter(o => !!o);
  139. result.options.push({
  140. msg: 'Goodbye',
  141. id: 999
  142. });
  143. return result;
  144. },
  145. simplify: function (self) {
  146. return {
  147. type: 'dialogue'
  148. };
  149. },
  150. //These don't belong here, but I can't figure out where to put them right now
  151. //They are actions that can be performed while chatting with someone
  152. teleport: function (msg) {
  153. this.obj.syncer.set(true, 'dialogue', 'state', null);
  154. let portal = extend({}, require('./portal'), msg);
  155. portal.collisionEnter(this.obj);
  156. },
  157. getItem: function (msg, source) {
  158. let inventory = this.obj.inventory;
  159. let exists = inventory.items.find(i => (i.name === msg.item.name));
  160. if (!exists) {
  161. inventory.getItem(msg.item);
  162. return msg.successMsg || false;
  163. } return msg.existsMsg || false;
  164. }
  165. };