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.
 
 
 

269 lines
5.6 KiB

  1. const events = require('../../misc/events');
  2. const profanities = require('../../misc/profanities');
  3. const canChat = require('./canChat');
  4. const sendRegularMessage = async ({ obj }, msg) => {
  5. const charname = obj.auth.charname;
  6. const msgEvent = {
  7. username: obj.account,
  8. tagPrefix: null,
  9. tagSuffix: null,
  10. tags: [],
  11. emojiTag: null,
  12. namePrefix: '',
  13. nameSuffix: '',
  14. msgStyle: null,
  15. obj
  16. };
  17. await events.emit('onBeforeGetChatStyles', msgEvent);
  18. const { emojiTag } = msgEvent;
  19. let usePrefix = '';
  20. if (emojiTag) {
  21. const imgX = (-emojiTag.sprite[0] * emojiTag.spriteSize);
  22. const imgY = (-emojiTag.sprite[1] * emojiTag.spriteSize);
  23. const backgroundPosition = `${imgX}px ${imgY}px`;
  24. usePrefix = `<div class='emojiTag' style='background: url("${emojiTag.spritesheet}") no-repeat scroll ${backgroundPosition} / auto;'></div>`;
  25. } else if (msgEvent.tags.length > 0)
  26. usePrefix = `${msgEvent.tagPrefix}${msgEvent.tags.join(' ')}${msgEvent.tagSuffix} `;
  27. let useCharName = charname;
  28. if (msgEvent.namePrefix)
  29. useCharName = `${msgEvent.namePrefix}${useCharName}`;
  30. if (msgEvent.nameSuffix)
  31. useCharName = `${useCharName}${msgEvent.nameSuffix}`;
  32. const finalMessage = `${usePrefix}${useCharName}: ${msg.data.message}`;
  33. const item = msg.data.item ? JSON.parse(JSON.stringify(msg.data.item).replace(/(<([^>]+)>)/ig, '')) : undefined;
  34. const eventMsg = {
  35. event: 'onGetMessages',
  36. data: {
  37. messages: [{
  38. class: msgEvent.msgStyle ?? 'color-grayB',
  39. message: finalMessage,
  40. item,
  41. type: 'chat',
  42. source: obj.name
  43. }]
  44. }
  45. };
  46. cons.emit('event', eventMsg);
  47. };
  48. const sendPartyMessage = ({ party, obj }, msg) => {
  49. if (!party) {
  50. obj.socket.emit('events', {
  51. onGetMessages: [{
  52. messages: [{
  53. class: 'color-redA',
  54. message: 'you are not in a party',
  55. type: 'info'
  56. }]
  57. }]
  58. });
  59. return;
  60. }
  61. let charname = obj.auth.charname;
  62. let message = msg.data.message;
  63. party.forEach(p => {
  64. let player = cons.players.find(c => c.id === p);
  65. player.socket.emit('events', {
  66. onGetMessages: [{
  67. messages: [{
  68. class: 'color-tealC',
  69. message: '(party: ' + charname + '): ' + message,
  70. type: 'chat',
  71. source: obj.name
  72. }]
  73. }]
  74. });
  75. });
  76. };
  77. const sendCustomChannelMessage = (cpnSocial, msg) => {
  78. const { obj } = cpnSocial;
  79. const { data: { message, subType: channel } } = msg;
  80. if (!channel)
  81. return;
  82. if (!cpnSocial.isInChannel(obj, channel)) {
  83. obj.socket.emit('events', {
  84. onGetMessages: [{
  85. messages: [{
  86. class: 'color-redA',
  87. message: 'You are not currently in that channel',
  88. type: 'info'
  89. }]
  90. }]
  91. });
  92. return;
  93. }
  94. const sendMessage = `[${channel}] ${obj.auth.charname}: ${message}`;
  95. const eventData = {
  96. onGetMessages: [{
  97. messages: [{
  98. class: 'color-grayB',
  99. message: sendMessage,
  100. type: 'chat',
  101. subType: 'custom',
  102. channel: channel.trim(),
  103. source: obj.name
  104. }]
  105. }]
  106. };
  107. cons.players.forEach(p => {
  108. if (!cpnSocial.isInChannel(p, channel))
  109. return;
  110. p.socket.emit('events', eventData);
  111. });
  112. };
  113. const sendPrivateMessage = ({ obj: { name: sourceName, socket } }, msg) => {
  114. const { data: { message, subType: targetName } } = msg;
  115. if (targetName === sourceName)
  116. return;
  117. let target = cons.players.find(p => p.name === targetName);
  118. if (!target)
  119. return;
  120. socket.emit('event', {
  121. event: 'onGetMessages',
  122. data: {
  123. messages: [{
  124. class: 'color-yellowB',
  125. message: '(you to ' + targetName + '): ' + message,
  126. type: 'chat',
  127. subType: 'privateOut',
  128. target: targetName
  129. }]
  130. }
  131. });
  132. target.socket.emit('event', {
  133. event: 'onGetMessages',
  134. data: {
  135. messages: [{
  136. class: 'color-yellowB',
  137. message: '(' + sourceName + ' to you): ' + message,
  138. type: 'chat',
  139. subType: 'privateIn',
  140. source: sourceName
  141. }]
  142. }
  143. });
  144. };
  145. const sendErrorMsg = (cpnSocial, msgString) => {
  146. cpnSocial.sendMessage(msgString, 'color-redA');
  147. };
  148. module.exports = async (cpnSocial, msg) => {
  149. const { data: msgData } = msg;
  150. if (!msgData.message)
  151. return;
  152. const { obj, maxChatLength, messageHistory } = cpnSocial;
  153. const sendError = sendErrorMsg.bind(null, cpnSocial);
  154. msgData.message = msgData.message
  155. .split('<')
  156. .join('&lt;')
  157. .split('>')
  158. .join('&gt;');
  159. if (!msgData.message)
  160. return;
  161. if (msgData.message.trim() === '')
  162. return;
  163. let messageString = msgData.message;
  164. if (messageString.length > maxChatLength)
  165. return;
  166. let time = +new Date();
  167. messageHistory.spliceWhere(h => ((time - h.time) > 5000));
  168. if (messageHistory.length) {
  169. if (messageHistory[messageHistory.length - 1].msg === messageString) {
  170. sendError('You have already sent that message');
  171. return;
  172. } else if (messageHistory.length >= 3) {
  173. sendError('You are sending too many messages');
  174. return;
  175. }
  176. }
  177. cpnSocial.onBeforeChat(msgData);
  178. if (msgData.ignore)
  179. return;
  180. if (!msgData.item && !profanities.isClean(messageString)) {
  181. sendError('Profanities detected in message. Blocked.');
  182. return;
  183. }
  184. if (!canChat(obj, time)) {
  185. sendError('Your character needs to be played for at least 3 minutes or be at least level 3 to be able to send messages in chat.');
  186. return;
  187. }
  188. let msgEvent = {
  189. source: obj.auth.charname,
  190. sourceObj: obj,
  191. msg: messageString,
  192. type: msgData.type,
  193. subType: msgData.subType,
  194. ignore: false,
  195. error: null
  196. };
  197. events.emit('onBeforeSendMessage', msgEvent);
  198. if (msgEvent.ignore) {
  199. if (msgEvent.error)
  200. sendError(msgEvent.error);
  201. return;
  202. }
  203. messageHistory.push({
  204. msg: msgEvent.msg,
  205. time: time
  206. });
  207. const messageHandler = {
  208. global: sendRegularMessage,
  209. custom: sendCustomChannelMessage,
  210. direct: sendPrivateMessage,
  211. party: sendPartyMessage
  212. }[msgData.type];
  213. if (!messageHandler)
  214. return;
  215. await messageHandler(cpnSocial, msg);
  216. };