diff --git a/town.js b/town.js
new file mode 100644
index 0000000..fb81c5a
--- /dev/null
+++ b/town.js
@@ -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 = `
+
+ `;
+
+ 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();
+ });
+
+})();