TW Friends

Friend Management for The West Events

目前为 2015-06-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name TW Friends
  3. // @name:el TW Friends
  4. // @name:es TW Friends
  5. // @name:fr TW Friends
  6. // @name:pt-PT TW Friends
  7. // @version 0.23
  8. // @description Friend Management for The West Events
  9. // @description:el Διαχείριση Φίλων για τις Εκδηλώσεις του The West
  10. // @description:es Gestión de Amigos para Eventos de The West
  11. // @description:fr Gestion des Amis pour les Evénements de The West
  12. // @description:pt-PT Gestão de amigos para eventos no The West
  13. // @author hiroaki
  14. // @translation pepe100 (es_ES)
  15. // @translation jccwest (pt_PT)
  16. // @include http://*.the-west.*/game.php*
  17. // @include https://*.the-west.*/game.php*
  18. // @include http://*.tw.innogames.*/game.php*
  19. // @include https://*.tw.innogames.*/game.php*
  20. // @grant none
  21. // @namespace https://greasyfork.org/users/3197
  22. // ==/UserScript==
  23.  
  24. function hiroFriendsScript(fn) {
  25. var script = document.createElement('script');
  26. script.setAttribute("type", "application/javascript");
  27. script.textContent = '(' + fn + ')();';
  28. document.body.appendChild(script);
  29. document.body.removeChild(script);
  30. }
  31. hiroFriendsScript(function() {
  32. var VERSION = 0.23;
  33. var installURL = "https://greasyfork.org/scripts/2992-tw-friends";
  34. var codeURL = "https://greasyfork.org/scripts/2992-tw-friends/code/TW%20Friends.user.js";
  35. var versionURL = "https://gist.githubusercontent.com/TWFriends/974718d615afe3d2c2a2/raw/version?"+Date.now();
  36. var scriptName = "TW Friends";
  37. var scriptAuthor = "hiroaki";
  38. var refreshMs = 2 * 60 * 1e3; // 2 minutes
  39. var enableLog = true;
  40. HiroFriends = {
  41. api: TheWestApi.register('HiroFriends', scriptName, '2.04', Game.version.toString(), scriptAuthor, installURL),
  42. version: VERSION,
  43. latestVersion: undefined,
  44. storageItem: "HiroFriends.version",
  45. cdnBase: '',
  46. eventName : '',
  47. eventInfo : {},
  48. eventEndStamp : 0,
  49. friends : {},
  50. interval: false,
  51. locale: 'en_US',
  52. pendingInvitations: 0,
  53. messages: {
  54. el_GR: {
  55. description: '<h1>Διαχείριση Φίλων για τις Εκδηλώσεις του The West</h1><p style="margin: 8pt;">Μην κλικάρετε πολύ γρήγορα, για να αποφύγετε ένα σερί κακής τύχης :)</p><p style="margin: 8pt;">Υποστηριζόμενες Εκδηλώσεις:</p><ul style="list-style: disc outside; margin-left: 16pt; padding-left: 16pt;"><li>Άγιος Βαλεντίνος</li><li>Πάσχα</li><li>Ημέρα Ανεξαρτησίας</li><li>Ημέρα των Νεκρών</li></ul><p style="margin: 8pt;"><a target="_blank" href="http://forum.the-west.gr/showthread.php?t=8029">Συζήτηση στο Φόρουμ</a> | <a target="_blank" href="https://greasyfork.org/scripts/2992-tw-friends/feedback">Feedback</a>: Αναφορά Bugs, Ιδέες, Μεταφράσεις.</p><p style="margin: 8pt;"><b>Ευχαριστίες</b>: jccwest, noolas, pepe100, Pnevma</p>',
  56. version: 'έκδοση',
  57. upgrade: 'Μια νέα έκδοση είναι διαθέσιμη. Θες να την εγκαταστήσεις;',
  58. refresh: 'Ανανέωση',
  59. timeLeft: 'Χρόνος που υπολείπεται μέχρι το τέλος της εκδήλωσης',
  60. serverTime: 'ώρα διακομιστή',
  61. availFriends: 'Αριθμός Φιλων στους οποίους μπορείς να στείλεις τώρα',
  62. totalFriends: 'Αριθμός Φίλων',
  63. pendingInvitation: 'Μία εκκρεμής πρόσκληση',
  64. pendingInvitations: 'εκκρεμείς πρoσκλήσεις',
  65. noFriends: 'Δεν έχεις φίλους',
  66. name: 'Όνομα',
  67. received: 'Έλαβες',
  68. frequency: 'Συχνότητα',
  69. removeFriend: 'Αφαίρεση φίλου',
  70. removeConfirm: 'Θέλεις πραγματικά να διαγράψεις αυτόν τον παίχτη από τη λίστα;',
  71. removeSuccess: 'Ο φίλος αφαιρέθηκε από τη λίστα.',
  72. removeFailed: 'Ο φίλος δεν μπόρεσε να αφαιρεθεί',
  73. exporter: 'Εξαγωγή',
  74. everything: 'Όλα',
  75. stats: 'Στατιστικά',
  76. since: 'από',
  77. collected: 'Έχεις συλλέξει',
  78. friends: 'Φίλοι',
  79. jobs: 'Εργασίες',
  80. fortBattles: 'Μάχες Οχυρών',
  81. adventures: 'Περιπέτειες',
  82. duels: 'Μονομαχίες',
  83. npcDuels: 'Μονομαχίες με NPC',
  84. construction: 'Χτίσιμο',
  85. itemUse: 'Χρήση Αντικειμένων',
  86. other: 'Άλλα',
  87. used: 'Έχεις χρησιμοποιήσει',
  88. timerReset: 'Μηδενισμός χρονομέτρου',
  89. bribe: 'Δωροδοκίες',
  90. nextYear: 'Του χρόνου',
  91. theEnd: 'Τετέλεσται',
  92. },
  93. en_US: {
  94. description: '<h1>Friend Management for The West Events</h1><p style="margin: 8pt;">Don&#039;t click too fast, to avoid a streak of bad luck upon you :)</p><p style="margin: 8pt;">Supported Events:</p><ul style="list-style: disc outside; margin-left: 16pt; padding-left: 16pt;"><li>Valentine&#039;s Day</li><li>Easter</li><li>Independence Day</li><li>Day of the Dead</li></ul><p style="margin: 8pt;"><a target="_blank" href="https://greasyfork.org/scripts/2992-tw-friends/feedback">Feedback</a>: Bug Reports, Ideas, Translations (in English).</p><p style="margin: 8pt;"><b>Credits</b>: jccwest, noolas, pepe100, Pnevma</p>',
  95. version: 'version',
  96. upgrade: 'A new version is available. Do you want to upgrade now?',
  97. refresh: 'Refresh',
  98. timeLeft: 'Time Left until the event ends',
  99. serverTime: 'server time',
  100. availFriends: 'Number of Friends you can send now',
  101. totalFriends: 'Number of Friends',
  102. pendingInvitation: 'One pending invitation',
  103. pendingInvitations: 'pending invitations',
  104. noFriends: 'No Friends',
  105. name: 'Name',
  106. received: 'Received',
  107. frequency: 'Frequency',
  108. removeFriend: 'Remove friend',
  109. removeConfirm: 'Do you really want to delete this player from the list?',
  110. removeSuccess: 'Friend removed from your list.',
  111. removeFailed: 'Friend could not be removed',
  112. exporter: 'Export',
  113. everything: 'Everything',
  114. stats: 'Stats',
  115. since: 'since',
  116. collected: 'Collected',
  117. friends: 'Friends',
  118. jobs: 'Jobs',
  119. fortBattles: 'Fort Battles',
  120. adventures: 'Adventures',
  121. duels: 'Duels',
  122. npcDuels: 'NPC Duels',
  123. construction: 'Construction',
  124. itemUse: 'Item Use',
  125. other: 'Other',
  126. used: 'Used',
  127. timerReset: 'Reset Timers',
  128. bribe: 'Bribe',
  129. gameAction: 'Event game action',
  130. nextYear: 'Next Year',
  131. theEnd: 'The End',
  132. },
  133. es_ES: {
  134. description: '<h1>Gestión de Amigos para Eventos de The West</h1><p style="margin: 8pt;">No haga clic demasiado rápido, para evitar una racha de mala suerte :)</p><p style="margin: 8pt;">Eventos soportados:</p><ul style="list-style: disc outside; margin-left: 16pt; padding-left: 16pt;"><li>Día de San Valentín</li><li>Pascua</li><li>Día de la Independencia</li><li>Día de los Muertos</li></ul><p style="margin: 8pt;"><a target="_blank" href="https://greasyfork.org/scripts/2992-tw-friends/feedback">Comentarios</a>: Bug Reports, Ideas, Translations (in English).</p><p style="margin: 8pt;"><b>Créditos</b>: jccwest, noolas, pepe100, Pnevma</p>',
  135. version: 'versión',
  136. upgrade: 'Una nueva versión está disponible. ¿Quieres instalarla ahora?',
  137. refresh: 'Actualizar',
  138. timeLeft: 'Tiempo que queda hasta el final del evento',
  139. serverTime: 'hora del servidor',
  140. availFriends: 'Número de Amigos que se puede enviar ahora',
  141. totalFriends: 'Número de Amigos',
  142. pendingInvitation: 'Una invitación pendiente',
  143. pendingInvitations: 'invitaciones pendientes',
  144. noFriends: 'Sin Amigos',
  145. name: 'Nombre',
  146. received: 'Recibidos',
  147. frequency: 'Frecuencia',
  148. removeFriend: 'Remover amigo',
  149. removeConfirm: '¿Estas seguro que quieres eliminar a este jugador de tu lista?',
  150. removeSuccess: 'Amigo removido de tu lista',
  151. removeFailed: 'El amigo no ha podido ser eliminado',
  152. exporter: 'Exportar',
  153. everything: 'Todo',
  154. stats: 'Estadísticas',
  155. since: 'desde',
  156. collected: 'Conseguidos',
  157. friends: 'Amigos',
  158. jobs: 'Trabajos',
  159. fortBattles: 'Batallas de fuertes',
  160. adventures: 'Aventuras',
  161. duels: 'Duelos',
  162. npcDuels: 'Duelos NPC',
  163. construction: 'Ampliación',
  164. itemUse: 'Objetos usados',
  165. other: 'Otros',
  166. used: 'Usados',
  167. timerReset: 'Reiniciar temporizadores',
  168. bribe: 'Soborno',
  169. nextYear: 'El próximo año',
  170. theEnd: 'Final',
  171. },
  172. fr_FR: {
  173. description: '<h1>Gestion des Amis pour les Evénements de The West</h1><p style="margin: 8pt;">Ne cliquez pas trop vite, pour éviter une série de malchance sur vous :)</p><p style="margin: 8pt;">Evénements:</p><ul style="list-style: disc outside; margin-left: 16pt; padding-left: 16pt;"><li>Saint Valentin</li><li>Pâques</li><li>Jour De L&#039;Indépendance</li><li>Jour des Morts</li></ul><p style="margin: 8pt;"><a target="_blank" href="https://greasyfork.org/scripts/2992-tw-friends/feedback">Commentaires</a>: Bug Reports, Ideas, Translations (in English).</p><p style="margin: 8pt;"><b>Credits</b>: jccwest, noolas, pepe100, Pnevma</p>',
  174. version: 'version',
  175. upgrade: 'Une nouvelle version est disponible. Installer maintenant?',
  176. refresh: 'Rafraîchir',
  177. timeLeft: "Temps restant jusqu'à la fin de l'événement",
  178. serverTime: 'horaire du serveur',
  179. availFriends: 'Nombre des amis que tu peux envoyer maintenant',
  180. totalFriends: 'Nombre des Amis',
  181. pendingInvitation: 'Une invitation en attente',
  182. pendingInvitations: 'invitations en attentes',
  183. noFriends: "Pas d'Amis",
  184. name: 'Nom',
  185. received: 'Tu as reçu',
  186. frequency: 'Fréquence',
  187. removeFriend: "Supprimer l'ami(e)",
  188. removeConfirm: 'Veux-tu vraiment supprimer ce joueur de la liste?',
  189. removeSuccess: 'Ami supprimé de la liste',
  190. removeFailed: "L'ami n'a pas pu être supprimé",
  191. exporter: 'Exportation',
  192. everything: 'Tout',
  193. stats: 'Statistiques',
  194. since: 'à partir de',
  195. collected: 'Collectés',
  196. friends: 'Amis',
  197. jobs: 'Travaux',
  198. fortBattles: 'Batailles',
  199. adventures: 'Aventures',
  200. duels: 'Duels',
  201. npcDuels: 'Duels PNJ',
  202. construction: 'Agrandissement',
  203. itemUse: 'Objets utilisés',
  204. other: 'Autres',
  205. used: 'Utilisés',
  206. timerReset: 'Se battre en duel',
  207. bribe: 'Soudoyer',
  208. nextYear: "L'année prochaine",
  209. theEnd: 'La Fin',
  210. },
  211. pt_PT: {
  212. description: '<h1>Gestão de amigos para eventos no The West</h1><p style="margin: 8pt;">não clique rápido demais, para evitar uma maré de azar :)</p><p style="margin: 8pt;">Eventos suportados:</p><ul style="list-style: disc outside; margin-left: 16pt; padding-left: 16pt;"><li>Dia dos namorados</li><li>Páscoa</li><li>Dia da independência</li><li>Dia de los Muertos</li></ul><p style="margin: 8pt;"><a target="_blank" href="https://greasyfork.org/scripts/2992-tw-friends/feedback">Comentários</a>: Bug Reports, Ideas, Translations (in English).</p><p style="margin: 8pt;"><b>Créditos</b>: jccwest, noolas, pepe100, Pnevma</p>',
  213. version: 'versão',
  214. upgrade: 'A nova versão está disponível. Atualize agora?',
  215. refresh: 'Actualizar',
  216. timeLeft: 'Tempo restante até ao final do evento',
  217. serverTime: 'hora do servidor',
  218. availFriends: 'Número de amigos a quem pode enviar agora',
  219. totalFriends: 'Número de Amigos',
  220. pendingInvitation: 'Um convite pendente',
  221. pendingInvitations: 'convites pendentes',
  222. noFriends: 'Sem Amigos',
  223. name: 'Nome',
  224. received: 'Recebidos',
  225. frequency: 'Freqüência',
  226. removeFriend: 'Remover amigo',
  227. removeConfirm: 'Queres mesmo remover amigo da lista ?',
  228. removeSuccess: 'Amigo removido da lista',
  229. removeFailed: 'Amigo não pode ser removido',
  230. exporter: 'Exportar',
  231. everything: 'Tudo',
  232. stats: 'Estatísticas',
  233. since: 'desde',
  234. collected: 'Recolhidos',
  235. friends: 'Amigos',
  236. jobs: 'Trabalhos',
  237. fortBattles: 'Batalhas de Forte',
  238. adventures: 'Aventuras',
  239. duels: 'Duelos',
  240. npcDuels: 'Duelos NPC',
  241. construction: 'Construção',
  242. itemUse: 'Itens usados',
  243. other: 'Outros',
  244. used: 'Usados',
  245. timerReset: 'Reiniciar temporizadores',
  246. bribe: 'Suborno',
  247. nextYear: 'Próximo Ano',
  248. theEnd: 'Final',
  249. },
  250. },
  251. timeLeft : 0,
  252. total : 0,
  253. avail: 0,
  254. log: { firstLog: Date.now()/1e3, lastLog: 0, friendLog: {}, entries: [], count_friends: 0, count_job: 0, count_duel: 0, count_npc: 0, count_fort: 0, count_mpi: 0, count_build: 0, count_item: 0, count_other: 0, count_reset: 0, count_bribe: 0, count_action: 0, times_reset: 0, times_bribe: 0, received: 0, used: 0 },
  255. spanCounter: $("<span />", { id: "hiro_friends_counter", style: "position: absolute; right: 5px; color: #f8c57c; font-size: 13pt; height: 25px; line-height: 25px; bottom: 0px" }),
  256. spanInvitations: null,
  257. spanTimeLeft: null,
  258. display: function(sort) {
  259. var friend_time, server_time = Game.getServerTime();
  260. var maindiv = $('<div class="hiro_friends_maindiv" />');
  261. var friends = [];
  262. for(var key in this.friends) if(this.friends.hasOwnProperty(key)) friends.push({ id: key, name: this.friends[key].name, activation_time: this.friends[key].activation_time, recv: this.friends[key].recv });
  263. if(!friends.length) $('<h1 style="text-align: center; color: #990000; margin-bottom: 80px;">'+this.localeMsg('noFriends')+'</h1>').appendTo(maindiv);
  264. else {
  265. var hiroTable;
  266. switch(sort) {
  267. case "name" : friends.sort(this.sortByName); break;
  268. case "name_desc": friends.sort(this.sortByName).reverse(); break;
  269. case "recv" : friends.sort(this.sortByRecv); break;
  270. case "recv_asc" : friends.sort(this.sortByRecv).reverse(); break;
  271. case "time_asc" : friends.sort(this.sortByTime).reverse(); break;
  272. case "time" :
  273. default : sort = "time"; friends.sort(this.sortByTime);
  274. }
  275. var thName = $('<a style="cursor: pointer;"><img src="'+this.cdnBase+'/images/icons/user.png" alt="" />&nbsp;'+this.localeMsg('name')+'</a>').click(function(){ HiroFriends.display(sort == 'name' ? 'name_desc' : 'name'); return false; });
  276. var thAction = $('<a style="cursor: pointer;"><img src="'+this.cdnBase+'/images/icons/clock.png" alt="" />&nbsp;'+this.eventInfo.label+'</a>').click(function(){ HiroFriends.display(sort == 'time' ? 'time_asc' : 'time'); return false; });
  277. var thRecv = enableLog ? $('<a style="cursor: pointer;" title="'+this.localeMsg('since')+' '+new Date(this.log.firstLog*1e3).toDateTimeString()+'"><img src="'+this.cdnBase+'/images/icons/watch.png" alt="" />&nbsp;'+this.localeMsg('received')+'</a>').click(function(){ HiroFriends.display(sort == 'recv' ? 'recv_asc' : 'recv'); return false; }) : '';
  278. hiroTable = new west.gui.Table().appendTo(maindiv).addColumn("hf_idx").addColumn("hf_player").addColumn("hf_action").addColumn("hf_log").addColumn("hf_delete").appendToCell("head", "hf_idx", '&nbsp;').appendToCell("head", "hf_player", thName).appendToCell("head", "hf_action", thAction).appendToCell("head","hf_log",thRecv).appendToCell("head", "hf_delete", '&nbsp;');
  279. var idx = 1;
  280. var now = Date.now()/1e3;
  281. $.each(friends, function(key, val) {
  282. var actionCell, recvCell;
  283. friend_time = val.activation_time + HiroFriends.eventInfo.cooldown - server_time;
  284. if(friend_time > HiroFriends.timeLeft) actionCell = '('+HiroFriends.localeMsg('nextYear')+')';
  285. else if(friend_time > 0) actionCell = '('+friend_time.formatDurationBuffWay()+')';
  286. else {
  287. actionCell = $('<a style="cursor: pointer;">'+HiroFriends.eventInfo.label+'</a>').click({ id: val.id, ev: HiroFriends.eventName }, function(e) {
  288. $(this).parent().parent().remove();
  289. Ajax.remoteCall("friendsbar", "event", { player_id: val.id, event: HiroFriends.eventName }, function(response) {
  290. if(response.error) return MessageError(response.msg).show();
  291. MessageSuccess(response.msg).show();
  292. HiroFriends.friends[val.id].activation_time = Date.now()/1e3;
  293. if(HiroFriends.avail) -- HiroFriends.avail;
  294. HiroFriends.updateCounter();
  295. if(WestUi.FriendsBar.friendsBarUi !== null)
  296. WestUi.FriendsBar.friendsBarUi.friendsBar.eventActivations[val.id][HiroFriends.eventName] = response.activationTime;
  297. });
  298. return false;
  299. });
  300. }
  301. recvCell = '';
  302. if(enableLog) {
  303. if(val.recv) {
  304. var recv_list = '';
  305. HiroFriends.log.friendLog[val.id].dates.sort(function(a, b){ return new Date(a)-new Date(b); });
  306. if(HiroFriends.log.friendLog[val.id].total && HiroFriends.log.friendLog[val.id].dates.length > 1) {
  307. recv_list += '<p style=&quot;text-align: center; margin-bottom: 8px;&quot;>'+HiroFriends.localeMsg('frequency')+': <b>'+((now - HiroFriends.log.friendLog[val.id].dates[0]) / (HiroFriends.log.friendLog[val.id].dates.length-1)).formatDuration()+'</b></p>';
  308. }
  309. recv_list += '<ol style=&quot;list-style-type: decimal; padding: 0 0 0 20px;&quot;>';
  310. $.each(HiroFriends.log.friendLog[val.id].dates, function(dkey, dval) {
  311. recv_list += '<li style=&quot;display: list-item; white-space: nowrap;&quot;>' + new Date(dval * 1e3).toDateTimeStringNice() + '</li>';
  312. });
  313. recv_list += '<ol>';
  314. recvCell = '<span title="'+recv_list+'" style="cursor: help;">'+val.recv+'</span>';
  315. }
  316. else recvCell = val.recv;
  317. }
  318. hiroTable.appendRow(null, 'hiroFriendRow_'+val.id)
  319. .appendToCell(-1, "hf_idx", idx)
  320. .appendToCell(-1, "hf_player", '<a href="javascript:void(PlayerProfileWindow.open('+val.id+'));">' + val.name + '</a>')
  321. .appendToCell(-1, "hf_action", actionCell)
  322. .appendToCell(-1, "hf_log", recvCell)
  323. .appendToCell(-1, "hf_delete", '<a href="javascript:void(HiroFriends.removeFriend('+val.id+'));"><img style="width:16px; height: 16px;" title="'+HiroFriends.localeMsg('removeFriend')+'" src="'+HiroFriends.cdnBase+'/images/icons/delete.png" alt="delete" /></a>');
  324. ++ idx;
  325. });
  326. hiroTable.appendToCell('foot', 'hf_idx', '<a target="_blank" href="'+installURL+'"><img src="'+this.cdnBase+'/images/icons/link.png" alt=""></a>');
  327. hiroTable.appendToCell('foot', 'hf_player', '<a target="_blank" href="'+installURL+'">TW Friends</a> '+this.localeMsg('version')+' ' + this.version.toFixed(2));
  328. if('http://gr1.the-west.gr' == Game.gameURL || 'http://gr4.the-west.gr' == Game.gameURL || 'http://gr5.the-west.gr' == Game.gameURL) hiroTable.appendToCell('foot', 'hf_action', 'by <a href="javascript:void(PlayerProfileWindow.open(92184));">'+scriptAuthor+'</a>');
  329. else if('https://zz1.beta.the-west.net' == Game.gameURL) hiroTable.appendToCell('foot', 'hf_action', 'by <a href="javascript:void(PlayerProfileWindow.open(16866));">'+scriptAuthor+'</a>');
  330. if (this.pendingInvitations) hiroTable.appendToCell('foot', 'hf_delete', '<a href="javascript:void(FriendslistWindow.open(\'openrequests\'));"><img style="width:16px; height: 16px;" title="'+this.pendingInvitationsMsg()+'" src="'+this.cdnBase+'/images/icons/friends.png" alt="add" /></a>');
  331. if(enableLog) hiroTable.appendToCell('foot', 'hf_log', $('<a style="cursor: pointer;">'+HiroFriends.localeMsg('exporter')+'</a>').click(function() {
  332. HiroFriends.log.entries.sort(function(a,b) { return a.date - b.date; });
  333. var tsv_friends = "id\t"+HiroFriends.localeMsg('name')+"\t"+HiroFriends.localeMsg('received')+"\r\n";
  334. $.each(HiroFriends.log.friendLog, function(key,val) { tsv_friends += key+"\t"+val.name+"\t"+val.total+"\r\n"; });
  335. new west.gui.Dialog(HiroFriends.localeMsg('exporter'),'<b>'+HiroFriends.localeMsg('friends')+'</b> (<a download="TW Friends - '+HiroFriends.eventName+' - '+ Game.worldName+' - '+Character.name+' - '+HiroFriends.localeMsg('friends')+' - '+Date.now()+'.tsv" href="data:text/tab-separated-values,'+encodeURI(tsv_friends)+'">TSV</a>):<br /><textarea cols="60" rows="8" style="width: 100%; height: 100px;">' + JSON.stringify(HiroFriends.log.friendLog) + '</textarea><br /><b>'+HiroFriends.localeMsg('everything')+'</b>:<br /><textarea cols="60" rows="8" style="width: 100%; height: 100px;">' + JSON.stringify(HiroFriends.log.entries) + '</textarea>').setModal(true,true,{bg:HiroFriends.cdnBase+'/images/curtain_bg.png',opacity:0.7}).addButton("ok").show();
  336. return false;
  337. }) );
  338. }
  339. if(enableLog) {
  340. var statsTable = $('<table style="margin: auto; width: 96%;"><tr><th colspan="3" style="border-bottom: 1px dotted;">'+this.localeMsg('stats')+' ('+this.localeMsg('since')+' '+new Date(this.log.firstLog*1e3).toDateTimeString()+')</th></tr><tr style="vertical-align: top;"><td style="white-space: nowrap;">'+this.localeMsg('collected')+':</td><td style="color: #006600; font-weight: bold; text-align: right; padding-right: 8pt;">'+this.log.received+'</td><td> <span style="white-space: nowrap;">'+this.localeMsg('friends')+': <b>'+this.log.count_friends+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('jobs')+': <b>'+this.log.count_job+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('fortBattles')+': <b>'+this.log.count_fort+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('adventures')+': <b>'+this.log.count_mpi+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('duels')+': <b>'+this.log.count_duel+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('npcDuels')+': <b>'+this.log.count_npc+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('construction')+': <b>'+this.log.count_build+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('itemUse')+': <b>'+this.log.count_item+'</b>,</span> <span style="white-space: nowrap;">'+this.localeMsg('other')+': <b>'+this.log.count_other+'</b></span></td></tr>'+(this.log.used?'<tr style="vertical-align: top;"><td style="white-space: nowrap;">'+this.localeMsg('used')+':</td><td style="color: #660000; font-weight: bold; text-align: right; padding-right: 8pt;">'+this.log.used+'</td><td>'+(this.log.count_reset?'<span style="white-space: nowrap;">'+this.localeMsg('timerReset')+': <b>'+this.log.count_reset+'</b> (#'+this.log.times_reset+'),</span> ' : '')+(this.log.count_action?'<span style="white-space: nowrap;">'+this.localeMsg('gameAction')+': <b>'+this.log.count_action+'</b>,</span> ' : '')+(this.log.count_bribe?'<span style="white-space: nowrap;">'+this.localeMsg('bribe')+': <b>'+this.log.count_bribe+'</b> (#'+this.log.times_bribe+')</span>' : '')+'</td></tr>' : '') + '</table>').appendTo(maindiv);
  341. }
  342. var hiroPane = new west.gui.Scrollpane();
  343. hiroPane.appendContent(maindiv);
  344. var hiroWindow = wman.open("HiroFriends_"+this.eventName, null, "noreload").setMiniTitle(this.eventInfo.label).setTitle(this.eventInfo.label).appendToContentPane(hiroPane.getMainDiv());
  345. },
  346. eventManager: function(eventName) {
  347. if(undefined === Game.sesData[eventName] || undefined === Game.sesData[eventName].friendsbar) return false;
  348. this.eventName = eventName;
  349. this.eventInfo = Game.sesData[eventName].friendsbar;
  350. if(undefined === Game.sesData[this.eventName].meta.end) return false;
  351. this.eventEndStamp = (buildTimestamp(Game.sesData[this.eventName].meta.end) - Game.serverTimeDifference) / 1e3;
  352. this.timeLeft = this.eventEndStamp - Game.getServerTime();
  353. if(this.timeLeft < 0) return false;
  354. this.cdnBase = (undefined === Game.cdnURL) ? "https://westzzs.innogamescdn.com" : Game.cdnURL;
  355. if(enableLog) this.getLog();
  356. this.spanTimeLeft = $("<span />", { id: "hiro_event_timeleft", style: "position: absolute; left: 5px; color: #d3d3d3; font-size: 11px; height: 25px; line-height: 25px; cursor: pointer", title: this.localeMsg('timeLeft')+'<br />('+new Date(buildTimestamp(Game.sesData[this.eventName].meta.end)).toDateTimeStringNice()+' '+this.localeMsg('serverTime')+')' });
  357. var eventImage = this.cdnBase + "/images/interface/friendsbar/events/" + this.eventName + ".png"; // event based
  358. var divContainer = $("<div />", { id: "hiro_friends_container", style: "position: absolute; top: 32px; right: 50%; margin-right: 120px; z-index: 16; width: 180px; height: 36px; text-align: left; text-shadow: 1px 1px 1px #000; background: url('"+this.cdnBase+"/images/interface/custom_unit_counter_sprite.png?2') no-repeat scroll 50% 0px transparent;" })
  359. var divCounter = $("<div />", { id: "hiro_friends", style: "background: url('"+this.cdnBase+"/images/interface/custom_unit_counter_sprite.png?2') no-repeat scroll 0 -36px rgba(0, 0, 0, 0); height: 25px; left: 32px; line-height: 25px; padding: 0 5px; position: absolute; top: 3px; width: 105px; z-index: 1; text-shadow: 1px 1px 1px #000;" });
  360. var divRefresh = $("<div />", { style: "width: 24px; height: 24px; position: absolute; left: 8px; top: 3px; z-index: 3; padding: 4px 0px 0px 4px;" });
  361. var spanRefresh = $('<span />', { title: this.localeMsg('refresh'), style: "display: inline-block; width: 20px; height: 20px; cursor: pointer; background: url('"+this.cdnBase+"/images/tw2gui/window/window2_buttons.png?5') repeat scroll 0px -20px transparent;" });
  362. var spanSend = $("<span />", { style: "width: 26px; height: 26px; left: auto; position: absolute; right: 7px; top: 2px; z-index: 3;" });
  363. var imageSend = $("<img />", { src: eventImage, title: this.eventInfo.label, style: "width: 26px; height: 26px; cursor: pointer" });
  364. if(this.pendingInvitations) {
  365. this.spanCounter.css("right", "20px");
  366. this.spanInvitations = $("<span />", { id: "hiro_friends_invitations", title: HiroFriends.pendingInvitationsMsg(), style: "position: absolute; right: 0px; width: 19px; height: 25px; background-image: url('"+this.cdnBase+"/images/interface/more.jpg'); background-repeat: no-repeat;" });
  367. this.spanInvitations.hover(function() { $(this).css("background-position", "0px -25px"); }, function() { $(this).css("background-position", ""); });
  368. this.spanInvitations.click(function() { $(this).hide(); HiroFriends.spanCounter.css("right", "5px"); FriendslistWindow.open('openrequests'); return false; });
  369. divCounter.append(this.spanInvitations);
  370. }
  371. divContainer.append(divRefresh.append(spanRefresh), spanSend.append(imageSend), divCounter.append(this.spanTimeLeft, this.spanCounter)).appendTo("#user-interface");
  372. spanRefresh.hover(function() { $(this).css("background-position", ""); }, function() { $(this).css("background-position", "0px -20px"); });
  373. spanRefresh.click(function() { HiroFriends.spanCounter.slideUp(500, function() { HiroFriends.fetch(); }).slideDown(1500); return false; });
  374. imageSend.click(function() { HiroFriends.open(); return false; });
  375. this.updateTimer();
  376. if(typeof(Storage) !== "undefined") {
  377. var previousVersion = (localStorage.getItem(this.storageItem) === null) ? 0 : parseFloat(localStorage.getItem(this.storageItem));
  378. localStorage.setItem(this.storageItem, this.version);
  379. // if(previousVersion && this.version > previousVersion) var msg=new west.gui.Dialog("TW Friends", "Script upgraded to version "+this.version, west.gui.Dialog.SYS_WARNING).addButton("OK").show();
  380. }
  381. $("<style>.hf_idx { width: 32px; text-align: right; padding-right: 8px; } .hf_player { width: 250px; } .hf_action { width: 200px; } .hf_log { width: 100px; text-align: right; padding-right: 8px; } .hf_delete { width: 40px; text-align: center; } div.tbody .hf_idx, div.tbody .hf_delete { background-image: url('"+this.cdnBase+"/images/tw2gui/table/cell_shadow_y.png'); }</style>").appendTo("head");
  382. return true;
  383. },
  384. fetch: function() {
  385. if(this.interval !== false) clearInterval(this.interval);
  386. var event_times = {};
  387. var friends = {}, total = 0, avail = 0, recv = 0;
  388. var server_time = Game.getServerTime(), activation_time, friend_time;
  389. if(this.timeLeft < 0) {
  390. $("#hiro_friends_container").slideUp(5000);
  391. throw "Event is over";
  392. }
  393. return $.post("/game.php?window=friendsbar&mode=search", { search_type: "friends" } , function(data) {
  394. $.each(data.eventActivations, function(key, val) {
  395. if(val.event_name == HiroFriends.eventName) event_times[val.friend_id] = val.activation_time;
  396. });
  397. $.each(data.players, function(key, val) {
  398. if(val.name !== Character.name) {
  399. activation_time = (event_times[val.player_id] !== undefined) ? event_times[val.player_id]: 0;
  400. if(undefined === HiroFriends.log.friendLog[val.player_id]) {
  401. recv = 0;
  402. HiroFriends.log.friendLog[val.player_id] = { name: val.name, total: 0, dates: [] };
  403. }
  404. else recv = HiroFriends.log.friendLog[val.player_id].total;
  405. friends[val.player_id] = { name: val.name, activation_time: activation_time, recv: recv };
  406. ++ total;
  407. if(activation_time + HiroFriends.eventInfo.cooldown - server_time <= 0) ++ avail;
  408. }
  409. });
  410. HiroFriends.friends = friends;
  411. HiroFriends.avail = avail;
  412. HiroFriends.total = total;
  413. HiroFriends.interval = setInterval(function() { HiroFriends.fetch(); }, refreshMs);
  414. HiroFriends.updateCounter();
  415. });
  416. },
  417. getLog: function() {
  418. var hasNext = true;
  419. var limit = 100;
  420. var page = 1;
  421. var count = 0;
  422. var details;
  423. var maxDate = HiroFriends.log.lastLog;
  424. while(hasNext) {
  425. $.ajax({ type: "POST", url: "/game.php?window=ses&mode=log", data: { ses_id: HiroFriends.eventName, page: page, limit: limit }, async: false, success: function(data) {
  426. hasNext = data.hasNext;
  427. limit = data.limit;
  428. page = data.page + 1;
  429. $.each(data.entries, function(key, val) {
  430. count = parseInt(val.value);
  431. if(val.date < HiroFriends.log.firstLog) HiroFriends.log.firstLog = val.date;
  432. if(val.date <= HiroFriends.log.lastLog) {
  433. hasNext = false;
  434. return false;
  435. }
  436. HiroFriends.log.entries.push(val);
  437. if(val.date > maxDate) maxDate = val.date;
  438. switch(val.type) {
  439. case "friendDrop":
  440. if (null !== val.details) {
  441. details = JSON.parse(val.details);
  442. if(undefined !== HiroFriends.friends[details.player_id]) HiroFriends.friends[details.player_id].recv += count;
  443. if(undefined === HiroFriends.log.friendLog[details.player_id]) HiroFriends.log.friendLog[details.player_id] = { name: details.name, total: count, dates: [] };
  444. else HiroFriends.log.friendLog[details.player_id].total += count;
  445. HiroFriends.log.friendLog[details.player_id].dates.push(val.date);
  446. }
  447. HiroFriends.log.count_friends += count;
  448. HiroFriends.log.received += count;
  449. break;
  450. case "jobDrop": HiroFriends.log.count_job += count; HiroFriends.log.received += count; break;
  451. case "buildDrop": HiroFriends.log.count_build += count; HiroFriends.log.received += count; break;
  452. case "duelDrop": HiroFriends.log.count_duel += count; HiroFriends.log.received += count; break;
  453. case "duelNPCDrop": HiroFriends.log.count_npc += count; HiroFriends.log.received += count; break;
  454. case "battleDrop": HiroFriends.log.count_fort += count; HiroFriends.log.received += count; break;
  455. case "adventureDrop": HiroFriends.log.count_mpi += count; HiroFriends.log.received += count; break;
  456. case "itemUse": HiroFriends.log.count_item += count; HiroFriends.log.received += count; break;
  457. case "wofPay":
  458. HiroFriends.log.used += count;
  459. if (null !== val.details) {
  460. if(val.details == "timerreset") {
  461. HiroFriends.log.count_reset += count;
  462. ++ HiroFriends.log.times_reset;
  463. }
  464. else if(val.details == "sneakyshot") {
  465. HiroFriends.log.count_bribe += count;
  466. ++ HiroFriends.log.times_bribe;
  467. }
  468. }
  469. break;
  470. default:
  471. HiroFriends.log.count_other += count;
  472. HiroFriends.log.received += count;
  473. }
  474. });
  475. } });
  476. }
  477. this.log.lastLog = maxDate;
  478. Chat.Request.Nop();
  479. },
  480. getPendingInvitations: function() {
  481. return $.post("/game.php?window=character&mode=get_open_requests", function(data) {
  482. var openReq = 0;
  483. $.each(data.open_friends, function(key, val) { if(val.inviter_id != Character.playerId) ++ openReq; });
  484. HiroFriends.pendingInvitations = openReq;
  485. });
  486. },
  487. localeMsg: function(msg) {
  488. if(undefined !== this.messages[this.locale][msg]) return this.messages[this.locale][msg];
  489. if(undefined !== this.messages['en_US'][msg]) return this.messages['en_US'][msg];
  490. return '';
  491. },
  492. open: function() {
  493. if(!WestUi.FriendsBar.hidden) WestUi.FriendsBar.toggle();
  494. if(enableLog) this.getLog();
  495. return this.fetch().done(function() { HiroFriends.getPendingInvitations().done(function() { HiroFriends.display('time'); }) });
  496. },
  497. pendingInvitationsMsg: function() { return this.pendingInvitations == 1 ? this.localeMsg('pendingInvitation') : this.pendingInvitations+' '+this.localeMsg('pendingInvitations'); },
  498. removeFriend: function(charId) {
  499. new west.gui.Dialog(HiroFriends.localeMsg('removeFriend'), HiroFriends.localeMsg('removeConfirm')).setIcon(west.gui.Dialog.SYS_QUESTION).addButton("yes", function() {
  500. Ajax.remoteCall('character', 'cancel_friendship', { friend_id: charId }, function(json) {
  501. if(json["result"]) {
  502. new UserMessage(HiroFriends.localeMsg('removeSuccess'), UserMessage.TYPE_SUCCESS).show();
  503. $("div.hiroFriendRow_" + charId).remove();
  504. $("div.friendData_" + charId, FriendslistWindow.DOM).remove();
  505. delete(HiroFriends.friends[charId]);
  506. if(HiroFriends.avail) -- HiroFriends.avail;
  507. if(HiroFriends.total) -- HiroFriends.total;
  508. HiroFriends.updateCounter();
  509. Chat.Friendslist.removeFriend(charId);
  510. }
  511. else new UserMessage(HiroFriends.localeMsg('removeFailed'), UserMessage.TYPE_ERROR).show();
  512. })
  513. }).addButton("no").show();
  514. },
  515. sortByName: function(a, b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); },
  516. sortByRecv: function(a, b) { return b.recv - a.recv; },
  517. sortByTime: function(a, b) { return a.activation_time - b.activation_time; },
  518. updateCounter: function() {
  519. this.spanCounter.html('<span title="'+this.localeMsg('availFriends')+'">'+this.avail+'</span> <span style="color: #d3d3d3; font-size: 11px;" title="'+this.localeMsg('totalFriends')+'">/ '+this.total+'</span>');
  520. },
  521. updateTimer: function() {
  522. this.timeLeft = this.eventEndStamp - Game.getServerTime();
  523. if(this.timeLeft <= 0) {
  524. this.spanTimeLeft.html(this.localeMsg('theEnd'));
  525. this.fetch();
  526. return;
  527. }
  528. this.spanTimeLeft.html(this.timeLeft.formatDurationBuffWay());
  529. var seconds = 0;
  530. if(this.timeLeft < 70) seconds = 1;
  531. else if(this.timeLeft < 3660) seconds = 10;
  532. else if(this.timeLeft < 86520) seconds = 60;
  533. else seconds = 120;
  534. setTimeout(function() { HiroFriends.updateTimer(); }, seconds * 1e3);
  535. },
  536. scriptInit: function(tries, maxTries) {
  537. var ev, eventName;
  538. if(tries >= maxTries) return false;
  539. if(Game && Game.loaded && Character.playerId) {
  540. this.locale = (undefined === Game.locale || undefined == this.messages[Game.locale]) ? "en_US" : Game.locale;
  541. this.api.setGui(this.localeMsg('description'));
  542. try {
  543. $.getScript(versionURL).done(function() {
  544. if(HiroFriends.latestVersion && HiroFriends.latestVersion > VERSION) {
  545. var upgradeDialog = new west.gui.Dialog(scriptName, HiroFriends.localeMsg('upgrade'), west.gui.Dialog.SYS_WARNING).addButton('ok', function() {
  546. try { upgradeDialog.hide(); location.href = codeURL; } catch(e) {}
  547. }).addButton('cancel').show();
  548. }
  549. });
  550. }
  551. catch(e) { }
  552. for(eventName in Game.sesData) {
  553. if(!Game.sesData.hasOwnProperty(eventName)) continue;
  554. var ev = Game.sesData[eventName];
  555. if(!ev.friendsbar) continue;
  556. if('Hearts' == eventName || 'Easter' == eventName || 'Independence' == eventName || 'DayOfDead' == eventName) {
  557. this.getPendingInvitations().done(function() {
  558. if(HiroFriends.eventManager(eventName)) HiroFriends.fetch();
  559. });
  560. return false;
  561. }
  562. }
  563. return true;
  564. }
  565. ++ tries;
  566. setTimeout(function() { HiroFriends.scriptInit(tries, maxTries); }, tries * 1e3);
  567. },
  568. }
  569. try { HiroFriends.scriptInit(0, 100); } catch(e) { }
  570. });