Moon Lust Note Pad

Floating moon notepad for war targets & reminders

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Moon Lust Note Pad
// @namespace    https://www.torn.com
// @version      1.3
// @description  Floating moon notepad for war targets & reminders
// @author       You
// @match        https://www.torn.com/*
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    GM_addStyle(`
        #moon-lust-icon {
            position: fixed;
            top: 150px;
            left: 50px;
            z-index: 999999;
            cursor: move;
            user-select: none;
            filter: drop-shadow(0 0 8px #000);
        }
        .moon-container {
            width: 68px;
            height: 68px;
            background: radial-gradient(circle at 40% 40%, #f4f4f4, #c5c5c5 40%, #a8a8a8);
            border-radius: 50%;
            border: 3px solid #3a0000;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            box-shadow: 0 4px 12px rgba(0,0,0,0.6),
                        inset 0 0 15px #fff,
                        inset -10px -10px 20px rgba(0,0,0,0.4);
            color: #3a0000;
            font-family: Georgia, serif;
            text-align: center;
            line-height: 1;
        }
        .moon-container span { font-size: 42px; margin-bottom: -4px; }
        .moon-container .label {
            font-size: 9px;
            letter-spacing: 1.5px;
            font-weight: bold;
            text-transform: uppercase;
            margin-top: 2px;
        }

        #moon-lust-modal {
            display: none;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 1000000;
            width: 640px;
            height: 560px;
            background: linear-gradient(#3a0000, #1f0000);
            border: 14px solid #1f0000;
            border-radius: 8px;
            box-shadow: 0 0 30px rgba(0,0,0,0.9),
                        inset 0 0 80px rgba(139,0,0,0.3);
            overflow: hidden;
            animation: bookOpen 0.5s ease-out forwards;
        }
        @keyframes bookOpen {
            from { opacity: 0; transform: translate(-50%, -50%) scale(0.7) rotate(-8deg); }
            to   { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0deg); }
        }
        #moon-lust-modal::before {
            content: '';
            position: absolute;
            top: 0; left: 0; right: 0; bottom: 0;
            background: radial-gradient(circle at 30% 20%, rgba(255,255,255,0.12) 0%, transparent 50%),
                        linear-gradient(#f5e8c7 0%, #f0d9a8 100%);
            opacity: 0.94;
            z-index: 1;
            box-shadow: inset 0 0 60px rgba(0,0,0,0.5);
        }
        #moon-lust-modal::after {
            content: '';
            position: absolute;
            top: -20px; left: 50%;
            width: 6px; height: 40px;
            background: linear-gradient(transparent, #8B0000, #5c0000);
            animation: bloodDrip 4s linear infinite;
            z-index: 3; opacity: 0.6;
            box-shadow: 0 0 8px #8B0000;
        }
        @keyframes bloodDrip { 0% { transform: translateY(-30px); } 100% { transform: translateY(620px); } }
        .blood-drip {
            position: absolute;
            width: 4px; height: 25px;
            background: #8B0000;
            animation: bloodDrip2 3.5s linear infinite;
            z-index: 3; opacity: 0.4;
        }

        .modal-content {
            position: relative;
            z-index: 2;
            height: 100%;
            padding: 20px;
            display: flex;
            flex-direction: column;
            color: #8B0000;
            font-family: Georgia, serif;
            box-sizing: border-box;
        }
        .modal-header {
            display: flex; justify-content: space-between; align-items: center;
            margin-bottom: 15px; border-bottom: 3px solid #8B0000; padding-bottom: 8px;
        }
        .modal-header h1 {
            font-size: 28px; margin: 0; color: #8B0000;
            text-shadow: 2px 2px 4px #3a0000; letter-spacing: 2px;
        }
        .close-btn { font-size: 32px; cursor: pointer; color: #8B0000; }
        .close-btn:hover { color: #5c0000; }

        .tabs { display: flex; margin-bottom: 15px; border-bottom: 2px solid #8B0000; }
        .tab {
            padding: 10px 22px; cursor: pointer; font-size: 17px;
            background: #f5e8c7; border: 3px solid #8B0000; border-bottom: none;
            border-radius: 8px 8px 0 0; margin-right: 4px; position: relative;
        }
        .tab.active { background: #f0d9a8; font-weight: bold; }
        .tab-badge {
            position: absolute; top: -8px; right: -8px;
            background: #5c0000; color: #f5e8c7; font-size: 11px;
            padding: 1px 6px; border-radius: 50%; border: 2px solid #3a0000;
        }

        .tab-content {
            flex: 1; background: #f5e8c7; border: 3px solid #8B0000;
            padding: 15px; border-radius: 0 8px 8px 8px;
            overflow-y: auto; box-shadow: inset 0 0 30px rgba(0,0,0,0.3);
        }
        .add-row { display: flex; gap: 8px; margin-bottom: 12px; }
        .add-row input {
            flex: 1; padding: 9px; border: 2px solid #8B0000;
            background: #fffef0; font-family: Georgia, serif; font-size: 15px;
        }
        .add-btn {
            padding: 9px 18px; background: #8B0000; color: #f5e8c7;
            border: 2px solid #3a0000; cursor: pointer; font-weight: bold;
        }
        ul { list-style: none; padding: 0; margin: 0; }
        li {
            padding: 9px 12px; background: #fffef0; margin-bottom: 6px;
            border: 2px solid #8B0000; display: flex; align-items: center;
            font-size: 16px; gap: 10px;
        }
        li.done { opacity: 0.75; }
        li.done span.text { text-decoration: line-through; color: #5c0000; }
        .checkbox {
            width: 18px; height: 18px; border: 2px solid #8B0000;
            background: #fff; cursor: pointer; flex-shrink: 0;
            display: flex; align-items: center; justify-content: center;
            font-size: 14px;
        }
        .delete-btn { margin-left: auto; color: #8B0000; cursor: pointer; font-size: 19px; }
        .clear-btn {
            margin-top: 12px; padding: 7px 16px;
            background: #8B0000; color: #f5e8c7;
            border: 2px solid #3a0000; cursor: pointer; float: right;
        }
        li.editing { padding: 4px; }
        li.editing input {
            flex: 1; background: #fffef0; border: 2px solid #5c0000;
            color: #8B0000; font-family: Georgia, serif;
        }

        /* Resize handles */
        .resize-handle {
            position: absolute; z-index: 1000001; background: transparent;
        }
        .n  { top: -4px; left: 0; right: 0; height: 8px; cursor: ns-resize; }
        .s  { bottom: -4px; left: 0; right: 0; height: 8px; cursor: ns-resize; }
        .e  { right: -4px; top: 0; bottom: 0; width: 8px; cursor: ew-resize; }
        .w  { left: -4px; top: 0; bottom: 0; width: 8px; cursor: ew-resize; }
        .nw { top: -6px; left: -6px; width: 12px; height: 12px; cursor: nwse-resize; }
        .ne { top: -6px; right: -6px; width: 12px; height: 12px; cursor: nesw-resize; }
        .sw { bottom: -6px; left: -6px; width: 12px; height: 12px; cursor: nesw-resize; }
        .se { bottom: -6px; right: -6px; width: 12px; height: 12px; cursor: nwse-resize; }
    `);

    // ==================== FLOATING MOON ====================
    const icon = document.createElement('div');
    icon.id = 'moon-lust-icon';
    icon.innerHTML = `<div class="moon-container"><span>🌕</span><div class="label">MOON LUST</div></div>`;
    document.body.appendChild(icon);

    // Load position
    let savedPos = localStorage.getItem('moonlust_position');
    if (savedPos) {
        const pos = JSON.parse(savedPos);
        icon.style.top = pos.top + 'px';
        icon.style.left = pos.left + 'px';
    }

    // Draggable icon
    let isDraggingIcon = false;
    let offsetX, offsetY;
    icon.addEventListener('mousedown', e => {
        isDraggingIcon = true;
        offsetX = e.clientX - icon.getBoundingClientRect().left;
        offsetY = e.clientY - icon.getBoundingClientRect().top;
        icon.style.transition = 'none';
    });
    document.addEventListener('mousemove', e => {
        if (isDraggingIcon) {
            let t = Math.max(0, Math.min(e.clientY - offsetY, window.innerHeight - 80));
            let l = Math.max(0, Math.min(e.clientX - offsetX, window.innerWidth - 80));
            icon.style.top = t + 'px';
            icon.style.left = l + 'px';
        }
    });
    document.addEventListener('mouseup', () => {
        if (isDraggingIcon) {
            isDraggingIcon = false;
            icon.style.transition = 'top 0.2s, left 0.2s';
            localStorage.setItem('moonlust_position', JSON.stringify({
                top: parseFloat(icon.style.top),
                left: parseFloat(icon.style.left)
            }));
        }
    });

    // ==================== MODAL ====================
    const modal = document.createElement('div');
    modal.id = 'moon-lust-modal';
    modal.innerHTML = `
        <div class="modal-content">
            <div class="modal-header">
                <h1>🌕 MOON LUST NOTE PAD</h1>
                <div class="close-btn">✕</div>
            </div>
            <div class="tabs">
                <div class="tab active" data-tab="war">War List <span class="tab-badge" id="badge-war">0</span></div>
                <div class="tab" data-tab="reminders">Reminders <span class="tab-badge" id="badge-reminders">0</span></div>
                <div class="tab" data-tab="notes">Quick Notes <span class="tab-badge" id="badge-notes">0</span></div>
            </div>

            <div id="war-content" class="tab-content">
                <div class="add-row"><input type="text" id="war-input" placeholder="Player name or ID"><button class="add-btn">ADD</button></div>
                <ul id="war-list"></ul>
                <button class="clear-btn">CLEAR ALL WAR LIST</button>
            </div>
            <div id="reminders-content" class="tab-content" style="display:none;">
                <div class="add-row"><input type="text" id="reminder-input" placeholder="Reminder text"><button class="add-btn">ADD</button></div>
                <ul id="reminder-list"></ul>
                <button class="clear-btn">CLEAR ALL REMINDERS</button>
            </div>
            <div id="notes-content" class="tab-content" style="display:none;">
                <div class="add-row"><input type="text" id="note-input" placeholder="Quick note..."><button class="add-btn">ADD</button></div>
                <ul id="note-list"></ul>
                <button class="clear-btn">CLEAR ALL NOTES</button>
            </div>
        </div>

        <!-- Resize handles -->
        <div class="resize-handle n" data-dir="n"></div>
        <div class="resize-handle s" data-dir="s"></div>
        <div class="resize-handle e" data-dir="e"></div>
        <div class="resize-handle w" data-dir="w"></div>
        <div class="resize-handle nw" data-dir="nw"></div>
        <div class="resize-handle ne" data-dir="ne"></div>
        <div class="resize-handle sw" data-dir="sw"></div>
        <div class="resize-handle se" data-dir="se"></div>
    `;
    document.body.appendChild(modal);

    // Load saved size
    modal.style.width = (localStorage.getItem('moonlust_width') || 640) + 'px';
    modal.style.height = (localStorage.getItem('moonlust_height') || 560) + 'px';

    // Extra blood drips
    for (let i = 0; i < 3; i++) {
        const drip = document.createElement('div');
        drip.className = 'blood-drip';
        drip.style.left = (35 + i * 22) + '%';
        drip.style.animationDelay = (i * 0.6) + 's';
        modal.appendChild(drip);
    }

    // Tab switching
    const tabs = modal.querySelectorAll('.tab');
    const contents = {
        war: modal.querySelector('#war-content'),
        reminders: modal.querySelector('#reminders-content'),
        notes: modal.querySelector('#notes-content')
    };
    tabs.forEach(tab => tab.addEventListener('click', () => {
        tabs.forEach(t => t.classList.remove('active'));
        tab.classList.add('active');
        Object.keys(contents).forEach(k => contents[k].style.display = (tab.dataset.tab === k) ? 'block' : 'none');
    }));

    // Data
    let warListData = JSON.parse(localStorage.getItem('moonlust_warlist')) || [];
    let reminderListData = JSON.parse(localStorage.getItem('moonlust_reminders')) || [];
    let noteListData = JSON.parse(localStorage.getItem('moonlust_notes')) || [];

    function updateBadges() {
        modal.querySelector('#badge-war').textContent = warListData.length;
        modal.querySelector('#badge-reminders').textContent = reminderListData.length;
        modal.querySelector('#badge-notes').textContent = noteListData.length;
    }

    function renderWarList() {
        const ul = modal.querySelector('#war-list'); ul.innerHTML = '';
        warListData.forEach((item, i) => {
            const li = document.createElement('li');
            li.innerHTML = `${item}<span class="delete-btn" data-index="${i}" data-tab="war">✕</span>`;
            li.dataset.index = i; li.dataset.tab = 'war';
            ul.appendChild(li);
        });
        updateBadges();
    }

    function renderReminderList() {
        const ul = modal.querySelector('#reminder-list'); ul.innerHTML = '';
        reminderListData.forEach((item, i) => {
            const li = document.createElement('li');
            li.className = item.done ? 'done' : '';
            li.innerHTML = `
                <div class="checkbox" data-index="${i}">${item.done ? '✔' : ''}</div>
                <span class="text">${item.text}</span>
                <span class="delete-btn" data-index="${i}" data-tab="reminders">✕</span>
            `;
            li.dataset.index = i; li.dataset.tab = 'reminders';
            ul.appendChild(li);
        });
        updateBadges();
    }

    function renderNoteList() {
        const ul = modal.querySelector('#note-list'); ul.innerHTML = '';
        noteListData.forEach((item, i) => {
            const li = document.createElement('li');
            li.innerHTML = `${item}<span class="delete-btn" data-index="${i}" data-tab="notes">✕</span>`;
            li.dataset.index = i; li.dataset.tab = 'notes';
            ul.appendChild(li);
        });
        updateBadges();
    }

    // Add functions
    function addWar() {
        const input = modal.querySelector('#war-input');
        if (input.value.trim()) { warListData.unshift(input.value.trim()); localStorage.setItem('moonlust_warlist', JSON.stringify(warListData)); renderWarList(); input.value = ''; }
    }
    function addReminder() {
        const input = modal.querySelector('#reminder-input');
        if (input.value.trim()) { reminderListData.unshift({text: input.value.trim(), done: false}); localStorage.setItem('moonlust_reminders', JSON.stringify(reminderListData)); renderReminderList(); input.value = ''; }
    }
    function addNote() {
        const input = modal.querySelector('#note-input');
        if (input.value.trim()) { noteListData.unshift(input.value.trim()); localStorage.setItem('moonlust_notes', JSON.stringify(noteListData)); renderNoteList(); input.value = ''; }
    }

    // Click handlers
    modal.addEventListener('click', e => {
        if (e.target.classList.contains('checkbox')) {
            const idx = parseInt(e.target.dataset.index);
            reminderListData[idx].done = !reminderListData[idx].done;
            localStorage.setItem('moonlust_reminders', JSON.stringify(reminderListData));
            renderReminderList();
        }
        if (e.target.classList.contains('delete-btn')) {
            const idx = parseInt(e.target.dataset.index);
            const tab = e.target.dataset.tab;
            if (tab === 'war') { warListData.splice(idx, 1); localStorage.setItem('moonlust_warlist', JSON.stringify(warListData)); renderWarList(); }
            else if (tab === 'reminders') { reminderListData.splice(idx, 1); localStorage.setItem('moonlust_reminders', JSON.stringify(reminderListData)); renderReminderList(); }
            else if (tab === 'notes') { noteListData.splice(idx, 1); localStorage.setItem('moonlust_notes', JSON.stringify(noteListData)); renderNoteList(); }
        }
        if (e.target.textContent.includes('CLEAR ALL WAR')) { warListData = []; localStorage.setItem('moonlust_warlist', '[]'); renderWarList(); }
        if (e.target.textContent.includes('CLEAR ALL REMINDERS')) { reminderListData = []; localStorage.setItem('moonlust_reminders', '[]'); renderReminderList(); }
        if (e.target.textContent.includes('CLEAR ALL NOTES')) { noteListData = []; localStorage.setItem('moonlust_notes', '[]'); renderNoteList(); }
    });

    // Double-click to edit
    modal.addEventListener('dblclick', e => {
        let li = e.target.closest('li');
        if (!li) return;
        const tab = li.dataset.tab;
        const idx = parseInt(li.dataset.index);
        const input = document.createElement('input');
        input.value = tab === 'war' ? warListData[idx] : (tab === 'notes' ? noteListData[idx] : reminderListData[idx].text);
        li.classList.add('editing');
        li.innerHTML = '';
        li.appendChild(input);
        input.focus();
        input.select();

        const save = () => {
            const newVal = input.value.trim();
            if (newVal) {
                if (tab === 'war') warListData[idx] = newVal;
                else if (tab === 'notes') noteListData[idx] = newVal;
                else reminderListData[idx].text = newVal;
                localStorage.setItem('moonlust_' + tab, JSON.stringify(tab === 'war' ? warListData : tab === 'notes' ? noteListData : reminderListData));
            }
            if (tab === 'war') renderWarList();
            else if (tab === 'notes') renderNoteList();
            else renderReminderList();
        };
        input.addEventListener('blur', save);
        input.addEventListener('keypress', ev => { if (ev.key === 'Enter') save(); });
    });

    // Resize
    let isResizing = false, startX, startY, startW, startH, resizeDir;
    modal.addEventListener('mousedown', e => {
        const handle = e.target.closest('.resize-handle');
        if (handle) {
            isResizing = true;
            resizeDir = handle.dataset.dir;
            startX = e.clientX; startY = e.clientY;
            startW = modal.offsetWidth; startH = modal.offsetHeight;
            e.stopImmediatePropagation();
        }
    });
    document.addEventListener('mousemove', e => {
        if (!isResizing) return;
        let newW = startW, newH = startH;
        if (resizeDir.includes('e')) newW = Math.max(380, startW + (e.clientX - startX));
        if (resizeDir.includes('w')) newW = Math.max(380, startW - (e.clientX - startX));
        if (resizeDir.includes('s')) newH = Math.max(320, startH + (e.clientY - startY));
        if (resizeDir.includes('n')) newH = Math.max(320, startH - (e.clientY - startY));
        modal.style.width = newW + 'px';
        modal.style.height = newH + 'px';
    });
    document.addEventListener('mouseup', () => {
        if (isResizing) {
            isResizing = false;
            localStorage.setItem('moonlust_width', modal.offsetWidth);
            localStorage.setItem('moonlust_height', modal.offsetHeight);
        }
    });

    // Open modal on icon click
    icon.addEventListener('click', e => {
        if (isDraggingIcon) return;
        renderWarList();
        renderReminderList();
        renderNoteList();
        modal.style.display = 'block';
    });

    modal.querySelector('.close-btn').addEventListener('click', () => modal.style.display = 'none');

    // Enter key support
    modal.addEventListener('keypress', e => {
        if (e.key === 'Enter') {
            const active = modal.querySelector('.tab.active').dataset.tab;
            if (active === 'war') addWar();
            else if (active === 'reminders') addReminder();
            else if (active === 'notes') addNote();
        }
    });

    modal.querySelectorAll('.add-btn').forEach(btn => {
        btn.addEventListener('click', () => {
            const active = modal.querySelector('.tab.active').dataset.tab;
            if (active === 'war') addWar();
            else if (active === 'reminders') addReminder();
            else if (active === 'notes') addNote();
        });
    });

    console.log('%c🌕 Moon Lust Note Pad v1.3 - fully working + resizable', 'color:#8B0000; font-family:Georgia');
})();