TW Friends

Friend Management for The West Events

Stan na 18-04-2015. Zobacz najnowsza wersja.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name              TW Friends
// @name:el           TW Friends
// @name:es           TW Friends
// @name:fr           TW Friends
// @name:pt-PT        TW Friends
// @version           0.20
// @description       Friend Management for The West Events
// @description:el    Διαχείριση Φίλων για τις Εκδηλώσεις του The West
// @description:es    Gestión de Amigos para Eventos de The West
// @description:fr    Gestion des Amis pour les Evénements de The West
// @description:pt-PT Gestão de amigos para eventos no The West
// @author            hiroaki
// @translation       pepe100 (es_ES)
// @translation       jccwest (pt_PT)
// @include           http://*.the-west.*/game.php*
// @include           https://*.the-west.*/game.php*
// @grant             none
// @namespace         https://greasyfork.org/users/3197
// ==/UserScript==

function hiroFriendsScript(fn) {
	var script = document.createElement('script');
	script.setAttribute("type", "application/javascript");
	script.textContent = '(' + fn + ')();';
	document.body.appendChild(script);
	document.body.removeChild(script);
}
hiroFriendsScript(function() {
	var VERSION = 0.20;
	var installURL = "https://greasyfork.org/scripts/2992-tw-friends";
	var codeURL = "https://greasyfork.org/scripts/2992-tw-friends/code/TW%20Friends.user.js";
	var versionURL = "https://gist.githubusercontent.com/TWFriends/974718d615afe3d2c2a2/raw/version?"+Date.now();
	var scriptName = "TW Friends";
	var scriptAuthor = "hiroaki";
	var refreshMs = 2 * 60 * 1e3;	// 2 minutes
	HiroFriends = {
		api: TheWestApi.register('HiroFriends', scriptName, '2.04', Game.version.toString(), scriptAuthor, installURL),
		version: VERSION,
		latestVersion: undefined,
		storageItem: "HiroFriends.version",
		cdnBase: '',
		eventName : '',
		eventInfo : {},
		eventEndStamp : 0,
		friends : [],
		interval: false,
		locale: 'en_US',
		pendingInvitations: 0,
		messages: {
			el_GR: {
				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</p>',
				version: 'έκδοση',
				upgrade: 'Μια νέα έκδοση είναι διαθέσιμη. Θες να την εγκαταστήσεις;',
				refresh: 'Ανανέωση',
				timeLeft: 'Χρόνος που υπολείπεται μέχρι το τέλος της εκδήλωσης',
				serverTime: 'ώρα διακομιστή',
				availFriends: 'Αριθμός Φιλων στους οποίους μπορείς να στείλεις τώρα',
				totalFriends: 'Αριθμός Φίλων',
				pendingInvitation: 'Μία εκκρεμής πρόσκληση',
				pendingInvitations: 'εκκρεμείς πρoσκλήσεις',
				noFriends: 'Δεν έχεις φίλους',
				name: 'Όνομα',
				received: 'Έλαβες',
				removeFriend: 'Αφαίρεση φίλου',
				removeConfirm: 'Θέλεις πραγματικά να διαγράψεις αυτόν τον παίχτη από τη λίστα;',
				removeSuccess: 'Ο φίλος αφαιρέθηκε από τη λίστα.',
				removeFailed: 'Ο φίλος δεν μπόρεσε να αφαιρεθεί',
				exporter: 'Εξαγωγή',
				everything: 'Όλα',
				stats: 'Στατιστικά',
				since: 'από',
				collected: 'Έχεις συλλέξει',
				friends: 'Φίλοι',
				jobs: 'Εργασίες',
				fortBattles: 'Μάχες Οχυρών',
				adventures: 'Περιπέτειες',
				duels: 'Μονομαχίες',
				npcDuels: 'Μονομαχίες με NPC',
				construction: 'Χτίσιμο',
				itemUse: 'Χρήση Αντικειμένων',
				other: 'Άλλα',
				used: 'Έχεις χρησιμοποιήσει',
				timerReset: 'Μηδενισμός χρονομέτρου',
				bribe: 'Δωροδοκίες',
				nextYear: 'Του χρόνου',
				theEnd: 'Τετέλεσται',
			},
			en_US: {
				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</p>',
				version: 'version',
				upgrade: 'A new version is available. Do you want to upgrade now?',
				refresh: 'Refresh',
				timeLeft: 'Time Left until the event ends',
				serverTime: 'server time',
				availFriends: 'Number of Friends you can send now',
				totalFriends: 'Number of Friends',
				pendingInvitation: 'One pending invitation',
				pendingInvitations: 'pending invitations',
				noFriends: 'No Friends',
				name: 'Name',
				received: 'Received',
				removeFriend: 'Remove friend',
				removeConfirm: 'Do you really want to delete this player from the list?',
				removeSuccess: 'Friend removed from your list.',
				removeFailed: 'Friend could not be removed',
				exporter: 'Export',
				everything: 'Everything',
				stats: 'Stats',
				since: 'since',
				collected: 'Collected',
				friends: 'Friends',
				jobs: 'Jobs',
				fortBattles: 'Fort Battles',
				adventures: 'Adventures',
				duels: 'Duels',
				npcDuels: 'NPC Duels',
				construction: 'Construction',
				itemUse: 'Item Use',
				other: 'Other',
				used: 'Used',
				timerReset: 'Reset Timers',
				bribe: 'Bribe',
				nextYear: 'Next Year',
				theEnd: 'The End',
			},
			es_ES: {
				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</p>',
				version: 'versión',
				upgrade: 'Una nueva versión está disponible. ¿Quieres instalarla ahora?',
				refresh: 'Actualizar',
				timeLeft: 'Tiempo que queda hasta el final del evento',
				serverTime: 'hora del servidor',
				availFriends: 'Número de Amigos que se puede enviar ahora',
				totalFriends: 'Número de Amigos',
				pendingInvitation: 'Una invitación pendiente',
				pendingInvitations: 'invitaciones pendientes',
				noFriends: 'Sin Amigos',
				name: 'Nombre',
				received: 'Recibidos',
				removeFriend: 'Remover amigo',
				removeConfirm: '¿Estas seguro que quieres eliminar a este jugador de tu lista?',
				removeSuccess: 'Amigo removido de tu lista',
				removeFailed: 'El amigo no ha podido ser eliminado',
				exporter: 'Exportar',
				everything: 'Todo',
				stats: 'Estadísticas',
				since: 'desde',
				collected: 'Conseguidos',
				friends: 'Amigos',
				jobs: 'Trabajos',
				fortBattles: 'Batallas de fuertes',
				adventures: 'Aventuras',
				duels: 'Duelos',
				npcDuels: 'Duelos NPC',
				construction: 'Ampliación',
				itemUse: 'Objetos usados',
				other: 'Otros',
				used: 'Usados',
				timerReset: 'Reiniciar temporizadores',
				bribe: 'Soborno',
				nextYear: 'El próximo año',
				theEnd: 'Final',
			},
			fr_FR: {
				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</p>',
				version: 'version',
				upgrade: 'Une nouvelle version est disponible. Installer maintenant?',
				refresh: 'Rafraîchir',
				timeLeft: "Temps restant jusqu'à la fin de l'événement",
				serverTime: 'horaire du serveur',
				availFriends: 'Nombre des amis que tu peux envoyer maintenant',
				totalFriends: 'Nombre des Amis',
				pendingInvitation: 'Une invitation en attente',
				pendingInvitations: 'invitations en attentes',
				noFriends: "Pas d'Amis",
				name: 'Nom',
				received: 'Tu as reçu',
				removeFriend: "Supprimer l'ami(e)",
				removeConfirm: 'Veux-tu vraiment supprimer ce joueur de la liste?',
				removeSuccess: 'Ami supprimé de la liste',
				removeFailed: "L'ami n'a pas pu être supprimé",
				exporter: 'Exportation',
				everything: 'Tout',
				stats: 'Statistiques',
				since: 'à partir de',
				collected: 'Collectés',
				friends: 'Amis',
				jobs: 'Travaux',
				fortBattles: 'Batailles',
				adventures: 'Aventures',
				duels: 'Duels',
				npcDuels: 'Duels PNJ',
				construction: 'Agrandissement',
				itemUse: 'Objets utilisés',
				other: 'Autres',
				used: 'Utilisés',
				timerReset: 'Se battre en duel',
				bribe: 'Soudoyer',
				nextYear: "L'année prochaine",
				theEnd: 'La Fin',
			},
			pt_PT: {
				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</p>',
                                version: 'versão',
				upgrade: 'A nova versão está disponível. Atualize agora?',
                                refresh: 'Actualizar',
                                timeLeft: 'Tempo restante até ao final do evento',
                                serverTime: 'hora do servidor',
                                availFriends: 'Número de amigos a quem pode enviar agora',
                                totalFriends: 'Número de Amigos',
				pendingInvitation: 'Um convite pendente',
				pendingInvitations: 'convites pendentes',
                                noFriends: 'Sem Amigos',
                                name: 'Nome',
                                received: 'Recebidos',
                                removeFriend: 'Remover amigo',
                                removeConfirm: 'Queres mesmo remover amigo da lista ?',
                                removeSuccess: 'Amigo removido da lista',
                                removeFailed: 'Amigo não pode ser removido',
                                exporter: 'Exportar',
                                everything: 'Tudo',
				stats: 'Estatísticas',
				since: 'desde',
                                collected: 'Recolhidos',
                                friends: 'Amigos',
                                jobs: 'Trabalhos',
                                fortBattles: 'Batalhas de Forte',
                                adventures: 'Aventuras',
                                duels: 'Duelos',
                                npcDuels: 'Duelos NPC',
                                construction: 'Construção',
                                itemUse: 'Itens usados',
                                other: 'Outros',
                                used: 'Usados',
                                timerReset: 'Reiniciar temporizadores',
                                bribe: 'Suborno',
                                nextYear: 'Próximo Ano',
                                theEnd: 'Final',
			},
		},
		timeLeft : 0,
		total : 0,
		avail: 0,
		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, times_reset: 0, times_bribe: 0, received: 0, used: 0 },
		spanCounter: $("<span />", { id: "hiro_friends_counter", style: "position: absolute; right: 5px; color: #f8c57c; font-size: 13pt; height: 25px; line-height: 25px; bottom: 0px" }),
		spanInvitations: null,
		spanTimeLeft: null,
		eventManager: function(eventName) {
			if(undefined === Game.sesData[eventName] || undefined === Game.sesData[eventName].friendsbar) return false;
			this.eventName = eventName;
			this.eventInfo = Game.sesData[eventName].friendsbar;
			if(undefined === Game.sesData[this.eventName].meta.end) return false;
			this.eventEndStamp = (buildTimestamp(Game.sesData[this.eventName].meta.end) - Game.serverTimeDifference) / 1e3;
			this.timeLeft = this.eventEndStamp - Game.getServerTime();
			if(this.timeLeft < 0) return false;
			this.cdnBase = (undefined === Game.cdnURL) ? "https://westzzs.innogamescdn.com" : Game.cdnURL;
			this.getLog();
			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')+')' });
			var eventImage = this.cdnBase + "/images/interface/friendsbar/events/" + this.eventName + ".png";	// event based
			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;" })
			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;" });
			var divRefresh = $("<div />", { style: "width: 24px; height: 24px; position: absolute; left: 8px; top: 3px; z-index: 3; padding: 4px 0px 0px 4px;" });
			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;" });
			var spanSend = $("<span />", { style: "width: 26px; height: 26px; left: auto; position: absolute; right: 7px; top: 2px; z-index: 3;" });
			var imageSend = $("<img />", { src: eventImage, title: this.eventInfo.label, style: "width: 26px; height: 26px; cursor: pointer" });
			if(this.pendingInvitations) {
				this.spanCounter.css("right", "20px");
				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;" });
				this.spanInvitations.hover(function() { $(this).css("background-position", "0px -25px"); }, function() { $(this).css("background-position", ""); });
				this.spanInvitations.click(function() { $(this).hide(); HiroFriends.spanCounter.css("right", "5px"); FriendslistWindow.open('openrequests'); return false; });
				divCounter.append(this.spanInvitations);
			}
			divContainer.append(divRefresh.append(spanRefresh), spanSend.append(imageSend), divCounter.append(this.spanTimeLeft, this.spanCounter)).appendTo("#user-interface");
			spanRefresh.hover(function() { $(this).css("background-position", ""); }, function() { $(this).css("background-position", "0px -20px"); });
			spanRefresh.click(function() { HiroFriends.spanCounter.slideUp(500, function() { HiroFriends.fetch(); }).slideDown(1500); return false; });
			imageSend.click(function() { HiroFriends.open(); return false; });
			this.updateTimer();
			if(typeof(Storage) !== "undefined") {
				var previousVersion = (localStorage.getItem(this.storageItem) === null) ? 0 : parseFloat(localStorage.getItem(this.storageItem));
				localStorage.setItem(this.storageItem, this.version);
				// 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();
			}
			$("<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");
			return true;
		},
		localeMsg: function(msg) {
			if(undefined !== this.messages[this.locale][msg]) return this.messages[this.locale][msg];
			if(undefined !== this.messages['en_US'][msg]) return this.messages['en_US'][msg];
			return '';
		},
		fetch: function() {
			if(this.interval !== false) clearInterval(this.interval);
			var event_times = {};
			var friends = [], total = 0, avail = 0, recv = 0;
			var server_time = Game.getServerTime(), activation_time, friend_time;
			if(this.timeLeft < 0) {
				$("#hiro_friends_container").slideUp(5000);
				throw "Event is over";
			}
			return $.post("/game.php?window=friendsbar&mode=search", { search_type: "friends" } , function(data) {
				$.each(data.eventActivations, function(key, val) {
					if(val.event_name == HiroFriends.eventName) event_times[val.friend_id] = val.activation_time;
				});
				$.each(data.players, function(key, val) {
					if(val.name !== Character.name) {
						activation_time = (event_times[val.player_id] !== undefined) ? event_times[val.player_id]: 0;
						recv = (undefined === HiroFriends.log.friendLog[val.player_id]) ? 0 : HiroFriends.log.friendLog[val.player_id].total;
						friends.push({ id: val.player_id, name: val.name, activation_time: activation_time, recv: recv });
						++ total;
						if(activation_time + HiroFriends.eventInfo.cooldown - server_time <= 0) ++ avail;
					}
				});
				HiroFriends.friends = friends;
				HiroFriends.avail = avail;
				HiroFriends.total = total;
				HiroFriends.interval = setInterval(function() { HiroFriends.fetch(); }, refreshMs);
				HiroFriends.update();
			});
		},
		getPendingInvitations: function() {
			return $.post("/game.php?window=character&mode=get_open_requests", function(data) {
				var openReq = 0;
				$.each(data.open_friends, function(key, val) { if(val.inviter_id != Character.playerId) ++ openReq; });
				HiroFriends.pendingInvitations = openReq;
			});
		},
		pendingInvitationsMsg: function() { return this.pendingInvitations == 1 ? this.localeMsg('pendingInvitation') : this.pendingInvitations+' '+this.localeMsg('pendingInvitations'); },
		getLog: function() {
			var hasNext = true;
			var limit = 100;
			var page = 1;
			var count = 0;
			var details;
			var maxDate = HiroFriends.log.lastLog;
			while(hasNext) {
				$.ajax({ type: "POST", url: "/game.php?window=ses&mode=log", data: { ses_id: HiroFriends.eventName, page: page, limit: limit }, async: false, success: function(data) {
					hasNext = data.hasNext;
					limit = data.limit;
					page = data.page + 1;
					$.each(data.entries, function(key, val) {
						count = parseInt(val.value);
						if(val.date < HiroFriends.log.firstLog) HiroFriends.log.firstLog = val.date;
						if(val.date <= HiroFriends.log.lastLog) {
							hasNext = false;
							return false;
						}
						HiroFriends.log.entries.push(val);
						if(val.date > maxDate) maxDate = val.date;
						switch(val.type) {
							case "friendDrop":
								details = JSON.parse(val.details);
								if(undefined !== HiroFriends.friends[details.player_id]) HiroFriends.friends[details.player_id].recv += count;
								if(undefined === HiroFriends.log.friendLog[details.player_id]) HiroFriends.log.friendLog[details.player_id] = { name: details.name, total: count, dates: [] };
								else HiroFriends.log.friendLog[details.player_id].total += count;
								HiroFriends.log.friendLog[details.player_id].dates.push(val.date);
								HiroFriends.log.count_friends += count;
								HiroFriends.log.received += count;
								break;
							case "jobDrop":		HiroFriends.log.count_job += count; HiroFriends.log.received += count; break;
							case "buildDrop":	HiroFriends.log.count_build += count; HiroFriends.log.received += count; break;
							case "duelDrop":	HiroFriends.log.count_duel += count; HiroFriends.log.received += count; break;
							case "duelNPCDrop":	HiroFriends.log.count_npc += count; HiroFriends.log.received += count; break;
							case "battleDrop":	HiroFriends.log.count_fort += count; HiroFriends.log.received += count; break;
							case "adventureDrop":	HiroFriends.log.count_mpi += count; HiroFriends.log.received += count; break;
							case "itemUse":		HiroFriends.log.count_item += count; HiroFriends.log.received += count; break;
							case "wofPay":
								HiroFriends.log.used += count;
								if(val.details == "timerreset") {
									HiroFriends.log.count_reset += count;
									++ HiroFriends.log.times_reset;
								}
								else if(val.details == "sneakyshot") {
									HiroFriends.log.count_bribe += count;
									++ HiroFriends.log.times_bribe;
								}
								break;
							default:
								HiroFriends.log.count_other += count;
								HiroFriends.log.received += count;
						}
					});
				} });
			}
			this.log.lastLog = maxDate;
			Chat.Request.Nop();
		},
		display: function(sort) {
			var friend_time, server_time = Game.getServerTime();
			var maindiv = $('<div class="hiro_friends_maindiv" />');
			if(!this.friends.length) $('<h1 style="text-align: center; color: #990000; margin-bottom: 80px;">'+this.localeMsg('noFriends')+'</h1>').appendTo(maindiv);
			else {
				var hiroTable;
				switch(sort) {
					case "name" 	:	this.friends.sort(this.nameCompare); break;
					case "name_desc":	this.friends.sort(this.nameCompare).reverse(); break;
					case "recv" 	:	this.friends.sort(this.recvCompare); break;
					case "recv_asc"	:	this.friends.sort(this.recvCompare).reverse(); break;
					case "time_asc"	:	this.friends.sort(this.timeCompare).reverse(); break;
					case "time"	:
					default		:	sort = "time"; this.friends.sort(this.timeCompare);
				}
				var thName = $('<a href="javascript:void(0);"><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; });
				var thAction = $('<a href="javascript:void(0);"><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; });
				var thRecv = $('<a href="javascript:void(0);" 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; });
				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;');
				var idx = 1;
				$.each(this.friends, function(key, val) {
					var actionCell, recvCell;
					friend_time = val.activation_time + HiroFriends.eventInfo.cooldown - server_time;
					if(friend_time > HiroFriends.timeLeft) actionCell = '('+HiroFriends.localeMsg('nextYear')+')';
					else if(friend_time > 0) actionCell = '('+friend_time.formatDurationBuffWay()+')';
					else {
						actionCell = $('<a href="javascript:void(0);">'+HiroFriends.eventInfo.label+'</a>').click({ id: val.id, ev: HiroFriends.eventName }, function(e) {
							$(this).parent().parent().remove();
							Ajax.remoteCall("friendsbar", "event", { player_id: val.id, event: HiroFriends.eventName }, function(response) {
								if(response.error) return MessageError(response.msg).show();
								MessageSuccess(response.msg).show();
								val.activation_time = Date.now()/1e3;
								if(HiroFriends.avail) -- HiroFriends.avail;
								HiroFriends.update();
								if(WestUi.FriendsBar.friendsBarUi !== null)
									WestUi.FriendsBar.friendsBarUi.friendsBar.eventActivations[val.id][HiroFriends.eventName] = response.activationTime;
							});
							return false;
						});
					}
					if(val.recv) {
						var recv_list = '<ol style=&quot;list-style-type: decimal; padding: 0 0 0 20px;&quot;>';
						HiroFriends.log.friendLog[val.id].dates.sort(function(a, b){
							return new Date(a)-new Date(b);
						});
						$.each(HiroFriends.log.friendLog[val.id].dates, function(dkey, dval) {
							recv_list += '<li style=&quot;display: list-item; white-space: nowrap;&quot;>' + new Date(dval * 1e3).toDateTimeStringNice() + '</li>';
						});
						recv_list += '<ol>';
						recvCell = '<span title="'+recv_list+'" style="cursor: help;">'+val.recv+'</span>';
					}
					else recvCell = val.recv;
					hiroTable.appendRow(null, 'hiroFriendRow_'+val.id)
						.appendToCell(-1, "hf_idx", idx)
						.appendToCell(-1, "hf_player", '<a href="javascript:void(PlayerProfileWindow.open('+val.id+'));">' + val.name + '</a>')
						.appendToCell(-1, "hf_action", actionCell)
						.appendToCell(-1, "hf_log", recvCell)
						.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>');
					++ idx;
				});
				hiroTable.appendToCell('foot', 'hf_idx', '<a target="_blank" href="'+installURL+'"><img src="'+this.cdnBase+'/images/icons/link.png" alt=""></a>');
				hiroTable.appendToCell('foot', 'hf_player', '<a target="_blank" href="'+installURL+'">TW Friends</a> '+this.localeMsg('version')+' ' + this.version.toFixed(2));
				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>');
				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>');
				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>');
				hiroTable.appendToCell('foot', 'hf_log', $('<a href="javascript:void(0);">'+HiroFriends.localeMsg('exporter')+'</a>').click(function() {
					HiroFriends.log.entries.sort(function(a,b) { return a.date - b.date; });
					new west.gui.Dialog(HiroFriends.localeMsg('exporter'),'<b>'+HiroFriends.localeMsg('friends')+'</b>:<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();
					return false;
				}) );
			}
			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><span style="white-space: nowrap;">'+this.localeMsg('timerReset')+': <b>'+this.log.count_reset+'</b> (#'+this.log.times_reset+'),</span> <span style="white-space: nowrap;">'+this.localeMsg('bribe')+': <b>'+this.log.count_bribe+'</b> (#'+this.log.times_bribe+')</span></td></tr>' : '') + '</table>').appendTo(maindiv);
			var hiroPane = new west.gui.Scrollpane();
			hiroPane.appendContent(maindiv);
			var hiroWindow = wman.open("HiroFriends_"+this.eventName, null, "noreload").setMiniTitle(this.eventInfo.label).setTitle(this.eventInfo.label).appendToContentPane(hiroPane.getMainDiv());
		},
		open: function() {
			if(!WestUi.FriendsBar.hidden) WestUi.FriendsBar.toggle();
			this.getLog();
			return this.fetch().done(function() {
				HiroFriends.getPendingInvitations().done(function() {
					HiroFriends.display('time');
				})
			});
		},
		nameCompare: function(a, b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); },
		recvCompare: function(a, b) { return b.recv - a.recv; },
		timeCompare: function(a, b) { return a.activation_time - b.activation_time; },
		updateTimer: function() {
			this.timeLeft = this.eventEndStamp - Game.getServerTime();
			if(this.timeLeft <= 0) {
				this.spanTimeLeft.html(this.localeMsg('theEnd'));
				this.fetch();
				return;
			}
			this.spanTimeLeft.html(this.timeLeft.formatDurationBuffWay());
			var seconds = 0;
			if(this.timeLeft < 70) seconds = 1;
			else if(this.timeLeft < 3660) seconds = 10;
			else if(this.timeLeft < 86520) seconds = 60;
			else seconds = 120;
			setTimeout(function() { HiroFriends.updateTimer(); }, seconds * 1e3);
		},
		update: function() {
			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>');
		},
		removeFriend: function(charId) {
			new west.gui.Dialog(HiroFriends.localeMsg('removeFriend'), HiroFriends.localeMsg('removeConfirm')).setIcon(west.gui.Dialog.SYS_QUESTION).addButton("yes", function() {
				Ajax.remoteCall('character', 'cancel_friendship', { friend_id: charId }, function(json) {
					if(json["result"]) {
						new UserMessage(HiroFriends.localeMsg('removeSuccess'), UserMessage.TYPE_SUCCESS).show();
						$("div.hiroFriendRow_" + charId).remove();
						$("div.friendData_" + charId, FriendslistWindow.DOM).remove();
						if(HiroFriends.avail) -- HiroFriends.avail;
						if(HiroFriends.total) -- HiroFriends.total;
						HiroFriends.update();
						Chat.Friendslist.removeFriend(charId);
					}
					else new UserMessage(HiroFriends.localeMsg('removeFailed'), UserMessage.TYPE_ERROR).show();
				})
			}).addButton("no").show();
		},
		scriptInit: function(tries, maxTries) {
			var ev, eventName;
			if(tries >= maxTries) return false;
			if(Game && Game.loaded && Character.playerId) {
				this.locale = (undefined === Game.locale || undefined == this.messages[Game.locale]) ? "en_US" : Game.locale;
				this.api.setGui(this.localeMsg('description'));
				this.getPendingInvitations();
				try {
					$.getScript(versionURL).done(function() {
						if (HiroFriends.latestVersion && HiroFriends.latestVersion > VERSION) {
							var upgradeDialog = new west.gui.Dialog(scriptName, HiroFriends.localeMsg('upgrade'), west.gui.Dialog.SYS_WARNING).addButton('ok', function () {
								try { upgradeDialog.hide(); location.href = codeURL; } catch (e) {}
							}).addButton('cancel').show();
						}
					});
				}
				catch (e) { }
				for(eventName in Game.sesData) {
					if(!Game.sesData.hasOwnProperty(eventName)) continue;
					var ev = Game.sesData[eventName];
					if(!ev.friendsbar) continue;
					if('Hearts' == eventName || 'Easter' == eventName || 'Independence' == eventName || 'DayOfDead' == eventName) {
						if(this.eventManager(eventName)) this.fetch();
						return false;
					}
				}
				return true;
			}
			++ tries;
			setTimeout(function() { HiroFriends.scriptInit(tries, maxTries); }, tries * 1e3);
		},
	}
	HiroFriends.scriptInit(0, 100);
});