選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

dialogue.js 4.5 KiB

5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
7年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
5年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. };