Add town.js
This commit is contained in:
175
town.js
Normal file
175
town.js
Normal file
@@ -0,0 +1,175 @@
|
||||
// ==UserScript==
|
||||
// @name Grepolis Town Stats Extended Clean (with Sea, Buildings, Researches)
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.4
|
||||
// @description Sends town stats with coords, sea, full building orders, and researches
|
||||
// @author Dimitrios
|
||||
// @match https://*.grepolis.com/game/*
|
||||
// @grant unsafeWindow
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const uw = unsafeWindow || window;
|
||||
let paused = false;
|
||||
|
||||
console.log("🚀 Town Stats Extended Clean (with Sea, Buildings, Researches) loaded");
|
||||
|
||||
// -----------------------------
|
||||
// Toolbar pause/resume button
|
||||
// -----------------------------
|
||||
const toolbarButtonHtml = `
|
||||
<div class="divider"></div>
|
||||
<div class="activity" id="tsbutton"
|
||||
style="filter: brightness(70%) sepia(100%) hue-rotate(-50deg) saturate(1000%) contrast(0.8);">
|
||||
<p id="tslabel" style="position: relative; top: -8px; font-weight: bold; z-index:6;">TownScan</p>
|
||||
</div>`;
|
||||
|
||||
function togglePause() {
|
||||
paused = !paused;
|
||||
const label = document.getElementById('tslabel');
|
||||
const btn = document.getElementById('tsbutton');
|
||||
|
||||
if (paused) {
|
||||
label.textContent = 'Paused';
|
||||
btn.style.filter = 'brightness(70%) sepia(100%) hue-rotate(-50deg) saturate(1000%) contrast(0.8)';
|
||||
} else {
|
||||
label.textContent = 'TownScan';
|
||||
btn.style.filter = 'brightness(294%) sepia(100%) hue-rotate(15deg) saturate(1000%) contrast(0.8)';
|
||||
}
|
||||
|
||||
console.log(`🔘 TownScan is now ${paused ? 'paused' : 'running'}`);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (!document.getElementById('tsbutton')) {
|
||||
uw.$('.tb_activities, .toolbar_activities').find('.middle').append(toolbarButtonHtml);
|
||||
}
|
||||
}, 4000);
|
||||
|
||||
uw.$(document).on('click', '#tsbutton', togglePause);
|
||||
|
||||
// -----------------------------
|
||||
// Compute Sea from x,y
|
||||
// -----------------------------
|
||||
function computeSea(x, y) {
|
||||
const seaY = Math.floor(y / 100);
|
||||
const seaX = Math.floor(x / 100);
|
||||
return seaY * 10 + seaX;
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Gather Town Stats
|
||||
// -----------------------------
|
||||
function gatherTownStats() {
|
||||
const towns = uw.ITowns?.towns || {};
|
||||
const player = uw.Game?.player_name || "unknown";
|
||||
const player_id = uw.Game?.player_id || "unknown";
|
||||
|
||||
const townStats = Object.values(towns).map(town => {
|
||||
const res = town.resources();
|
||||
const buildings = town.buildings()?.attributes ?? {};
|
||||
|
||||
// Units fix
|
||||
const unitsObj = {};
|
||||
const units = town.units();
|
||||
if (units) {
|
||||
Object.keys(units).forEach(type => {
|
||||
if (typeof units[type] === 'number') {
|
||||
unitsObj[type] = units[type];
|
||||
} else if (typeof units[type]?.getAmount === 'function') {
|
||||
unitsObj[type] = units[type].getAmount();
|
||||
} else {
|
||||
unitsObj[type] = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Coordinates & sea
|
||||
const x = town.getIslandCoordinateX ? town.getIslandCoordinateX() : null;
|
||||
const y = town.getIslandCoordinateY ? town.getIslandCoordinateY() : null;
|
||||
const sea = (x !== null && y !== null) ? computeSea(x, y) : null;
|
||||
|
||||
// Full building orders
|
||||
let buildingOrder = [];
|
||||
if (typeof town.buildingOrders === "function") {
|
||||
const bo = town.buildingOrders();
|
||||
if (bo && bo.models) {
|
||||
buildingOrder = bo.models.map(m => m.attributes);
|
||||
}
|
||||
}
|
||||
|
||||
// Researches
|
||||
let researches = {};
|
||||
if (typeof town.researches === "function") {
|
||||
researches = town.researches();
|
||||
}
|
||||
|
||||
return {
|
||||
town_id: town.id,
|
||||
town_name: town.name,
|
||||
x, y, sea,
|
||||
wood: res.wood,
|
||||
stone: res.stone,
|
||||
iron: res.iron,
|
||||
population: res.population,
|
||||
points: town.points || 0,
|
||||
buildings,
|
||||
units: unitsObj,
|
||||
buildingOrder,
|
||||
researches,
|
||||
has_premium: town.hasPremium?.() || false,
|
||||
bonuses: town.getBonus ? town.getBonus() : {},
|
||||
wonder_points: town.wonder_points || 0
|
||||
};
|
||||
});
|
||||
|
||||
return { player, player_id, towns: townStats };
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Send Data
|
||||
// -----------------------------
|
||||
function sendData() {
|
||||
if (paused) return console.log("⏸️ TownScan is paused — skipping data send");
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
type: "extended",
|
||||
timestamp: new Date().toISOString(),
|
||||
...gatherTownStats(),
|
||||
server_received_at: new Date().toISOString()
|
||||
};
|
||||
|
||||
console.log("📤 Sending payload:", payload);
|
||||
|
||||
fetch("https://grepo.haunter-pets.top/api/grepolis-data", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(txt => console.log("✅ Data sent:", txt))
|
||||
.catch(err => console.error("❌ Failed to send:", err));
|
||||
} catch (e) {
|
||||
console.error("💥 Error sending stats:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Main Loop
|
||||
// -----------------------------
|
||||
function startCycle() {
|
||||
setInterval(() => {
|
||||
console.log("🕒 TownScan cycle tick");
|
||||
sendData();
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
console.log("🚀 TownScan booting...");
|
||||
startCycle();
|
||||
});
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user