Torn Framework

Framework with proper script communication

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey, Greasemonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

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

คุณจะต้องติดตั้งส่วนขยาย เช่น Tampermonkey หรือ Violentmonkey เพื่อติดตั้งสคริปต์นี้

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

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.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Torn Framework
// @version      2.1
// @namespace    http://tampermonkey.net/
// @description  Framework with proper script communication
// @author
// @match        https://www.torn.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        unsafeWindow
// @run-at document-body
// ==/UserScript==

(function () {
    'use strict';

    console.log('=== TORN FRAMEWORK VERSION STARTING ===');

    // Use unsafeWindow to ensure global access
    const globalWindow = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

    // Prevent multiple instances
    if (globalWindow.TornFramework) {
        console.log('WARNING: TornFramework already exists!', globalWindow.TornFramework);
        return;
    }

    // Global framework object
    globalWindow.TornFramework = {
        version: '2.1-FIXED',
        modules: new Map(),
        initialized: false,
        debug: true
    };

    console.log('Framework object created on globalWindow:', globalWindow.TornFramework);

    // Settings
    let settings = {
        consoleEnabled: GM_getValue('consoleEnabled', true),
        menuVisible: GM_getValue('menuVisible', false)
    };

    function saveSettings() {
        Object.keys(settings).forEach(key => {
            GM_setValue(key, settings[key]);
        });
    }

    // =========================
    // LOGGING SYSTEM
    // =========================
    const logDiv = document.createElement("div");
    logDiv.id = 'torn-framework-console';
    logDiv.style.cssText = `
        position: fixed;
        bottom: 0;
        left: 0;
        width: 450px;
        max-height: 300px;
        overflow-y: auto;
        background: linear-gradient(135deg, rgba(0,0,0,0.95), rgba(20,20,20,0.95));
        color: white;
        font-size: 11px;
        z-index: 999999;
        padding: 12px;
        border-radius: 0 12px 0 0;
        font-family: 'Consolas', 'Monaco', monospace;
        border: 2px solid #37b24d;
        box-shadow: 0 4px 20px rgba(55,178,77,0.3);
        backdrop-filter: blur(10px);
        display: ${settings.consoleEnabled ? 'block' : 'none'};
    `;
    document.body.appendChild(logDiv);

    function log(msg, type = 'info', module = 'FRAMEWORK') {
        try {
            const timestamp = new Date().toLocaleTimeString();
            const p = document.createElement("div");

            const colors = {
                'error': '#ff6b6b',
                'success': '#51cf66',
                'warning': '#ffd43b',
                'info': '#74c0fc',
                'debug': '#9775fa'
            };

            p.style.cssText = `
                color: ${colors[type] || '#ccc'};
                padding: 3px 0;
                border-bottom: 1px solid rgba(255,255,255,0.1);
                font-size: 10px;
                line-height: 1.3;
            `;

            const moduleColor = module === 'FRAMEWORK' ? '#37b24d' : '#f59f00';
            p.innerHTML = `<span style="color: #666;">[${timestamp}]</span> <span style="color: ${moduleColor}; font-weight: bold;">[${module}]</span> ${msg}`;

            logDiv.appendChild(p);
            logDiv.scrollTop = logDiv.scrollHeight;

            // Limit to 100 logs
            while (logDiv.children.length > 100) {
                logDiv.removeChild(logDiv.firstChild);
            }

            console.log(`[TornFramework:${module}] ${msg}`);
        } catch (error) {
            console.error('Framework logging failed:', error);
        }
    }

    globalWindow.TornFramework.log = log;
    log('Framework logging system initialized', 'success');

    // =========================
    // MAIN MENU SYSTEM
    // =========================
    const modMenu = document.createElement("div");
    modMenu.id = 'torn-framework-menu';
    modMenu.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        width: 420px;
        max-height: 85vh;
        overflow-y: auto;
        background: linear-gradient(135deg, rgba(0,0,0,0.95), rgba(20,20,20,0.95));
        color: white;
        font-size: 12px;
        z-index: 1000000;
        padding: 20px;
        border-radius: 12px;
        font-family: 'Segoe UI', Arial, sans-serif;
        border: 2px solid #37b24d;
        box-shadow: 0 8px 32px rgba(55,178,77,0.4);
        backdrop-filter: blur(10px);
        display: none;
    `;

    modMenu.innerHTML = `
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 2px solid #37b24d; padding-bottom: 15px;">
            <h3 style="margin: 0; color: #37b24d; text-shadow: 0 2px 4px rgba(0,0,0,0.5);">Torn Framework v${globalWindow.TornFramework.version}</h3>
            <button id="closeMenu" style="background: linear-gradient(45deg, #f03e3e, #c92a2a); border: none; color: white; padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 12px;">✕</button>
        </div>

        <!-- FRAMEWORK STATUS -->
        <div style="margin-bottom: 15px; padding: 12px; background: linear-gradient(45deg, rgba(55,178,77,0.1), rgba(116,184,22,0.1)); border-radius: 8px; border: 1px solid #37b24d;">
            <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; font-size: 10px; margin-bottom: 8px;">
                <div>Modules: <span id="moduleCount">0</span></div>
                <div>Active: <span id="activeCount">0</span></div>
                <div>Uptime: <span id="uptimeDisplay">0s</span></div>
            </div>
            <div id="moduleList" style="max-height: 80px; overflow-y: auto; font-size: 9px; color: #ccc;"></div>
        </div>

        <!-- FRAMEWORK SETTINGS -->
        <div style="margin-bottom: 15px; border: 1px solid #37b24d; padding: 12px; border-radius: 8px;">
            <h4 style="margin: 0 0 12px 0; color: #37b24d;">Framework Settings</h4>
            <label style="display: flex; align-items: center; cursor: pointer; margin-bottom: 8px;">
                <input type="checkbox" id="consoleEnabled" ${settings.consoleEnabled ? 'checked' : ''}>
                <span style="margin-left: 8px;">Debug Console</span>
            </label>
        </div>

        <!-- MODULE SECTIONS WILL BE INJECTED HERE -->
        <div id="moduleMenuSections"></div>
    `;
    document.body.appendChild(modMenu);

    // Menu toggle button
    const menuBtn = document.createElement("button");
    menuBtn.innerHTML = "⚙️";
    menuBtn.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        z-index: 999999;
        background: linear-gradient(135deg, #37b24d, #51cf66);
        color: white;
        border: none;
        padding: 12px 14px;
        border-radius: 50%;
        cursor: pointer;
        font-size: 16px;
        box-shadow: 0 4px 16px rgba(55,178,77,0.4);
        transition: all 0.3s ease;
    `;
    menuBtn.onclick = () => {
        const isVisible = modMenu.style.display !== 'none';
        modMenu.style.display = isVisible ? 'none' : 'block';
        menuBtn.style.right = isVisible ? '10px' : '440px';
        if (!isVisible) updateFrameworkStatus();
        settings.menuVisible = !isVisible;
        saveSettings();
    };
    document.body.appendChild(menuBtn);

    // =========================
    // MODULE MANAGEMENT
    // =========================
    globalWindow.TornFramework.registerModule = function (moduleConfig) {
        const {
            name,
            version = '1.0',
            description = '',
            menuSection = null,
            initialize = null,
            cleanup = null,
            isActive = () => false
        } = moduleConfig;

        log(`Module registration attempt: ${name}`, 'info');

        if (!name) {
            log('Module registration failed: name is required', 'error');
            return false;
        }

        if (globalWindow.TornFramework.modules.has(name)) {
            log(`Module ${name} already registered, updating...`, 'warning');
        }

        const module = { name, version, description, menuSection, initialize, cleanup, isActive, registered: Date.now() };
        globalWindow.TornFramework.modules.set(name, module);
        log(`Module registered: ${name} v${version}`, 'success');

        if (menuSection) addModuleMenuSection(name, menuSection);

        if (initialize && typeof initialize === 'function') {
            try {
                initialize();
                log(`Module ${name} initialized`, 'success');
            } catch (error) {
                log(`Module ${name} initialization failed: ${error.message}`, 'error');
            }
        }

        updateFrameworkStatus();
        return true;
    };

    function addModuleMenuSection(moduleName, sectionHTML) {
        const container = document.getElementById('moduleMenuSections');
        if (!container) return;

        const existing = document.getElementById(`module-${moduleName}`);
        if (existing) existing.remove();

        const section = document.createElement('div');
        section.id = `module-${moduleName}`;
        section.style.cssText = 'margin-bottom: 15px; border: 1px solid #f59f00; padding: 12px; border-radius: 8px;';
        section.innerHTML = sectionHTML;

        container.appendChild(section);
        log(`Menu section added for module: ${moduleName}`, 'debug');
    }

    function updateFrameworkStatus() {
        try {
            const moduleCount = globalWindow.TornFramework.modules.size;
            const activeCount = Array.from(globalWindow.TornFramework.modules.values())
                .filter(module => module.isActive()).length;
            const uptime = Math.floor((Date.now() - globalWindow.TornFramework.startTime) / 1000);

            document.getElementById('moduleCount').textContent = moduleCount;
            document.getElementById('activeCount').textContent = activeCount;
            document.getElementById('uptimeDisplay').textContent = `${uptime}s`;

            const moduleList = document.getElementById('moduleList');
            if (moduleList) {
                const moduleInfo = Array.from(globalWindow.TornFramework.modules.values())
                    .map(module => {
                        const status = module.isActive() ? '🟢' : '🔴';
                        return `${status} ${module.name} v${module.version}`;
                    }).join('<br>');
                moduleList.innerHTML = moduleInfo || 'No modules loaded';
            }
        } catch (error) {
            log(`Status update failed: ${error.message}`, 'error');
        }
    }

    // =========================
    // SETTINGS EVENTS
    // =========================
    function setupFrameworkEvents() {
        document.getElementById('closeMenu').onclick = () => {
            modMenu.style.display = 'none';
            menuBtn.style.right = '10px';
            settings.menuVisible = false;
            saveSettings();
        };

        document.getElementById('consoleEnabled').onchange = function () {
            settings.consoleEnabled = this.checked;
            logDiv.style.display = settings.consoleEnabled ? 'block' : 'none';
            saveSettings();
        };
    }

    // =========================
    // INITIALIZATION
    // =========================
    function initFramework() {
        if (globalWindow.TornFramework.initialized) return;

        log('Initializing Torn Framework...', 'success');

        globalWindow.TornFramework.startTime = Date.now();
        globalWindow.TornFramework.initialized = true;

        setupFrameworkEvents();

        if (settings.menuVisible) {
            modMenu.style.display = 'block';
            menuBtn.style.right = '440px';
        }

        log('Framework ready! Modules can now register.', 'success');
        updateFrameworkStatus();

        // Periodically update status
        setInterval(updateFrameworkStatus, 5000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            log('DOM loaded, initializing framework');
            setTimeout(initFramework, 500);
        });
    } else {
        log('DOM already loaded, initializing framework');
        setTimeout(initFramework, 500);
    }

    log('Framework script completed loading');
})();