🎮ArcadeLab

霓虹华尔街 8.0 - 终极赛博操盘手

by RapidPanda65
777 lines43.7 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>霓虹华尔街 8.0 - 终极赛博操盘手</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        :root {
            --bg-color: #050510;
            --panel-bg: rgba(15, 15, 25, 0.9);
            --text-main: #e0e0ff;
            --neon-blue: #00f3ff;
            --neon-pink: #ff00ea;
            --neon-green: #39ff14;
            --neon-red: #ff3333;
            --neon-yellow: #ffee00;
            --neon-orange: #ff9900;
            --neon-purple: #b026ff;
        }

        body {
            font-family: 'Courier New', Courier, monospace;
            background-color: var(--bg-color);
            color: var(--text-main);
            margin: 0; padding: 0; overflow-x: hidden;
            background-image: linear-gradient(0deg, transparent 24%, rgba(0, 243, 255, 0.05) 25%, rgba(0, 243, 255, 0.05) 26%, transparent 27%, transparent 74%, rgba(0, 243, 255, 0.05) 75%, rgba(0, 243, 255, 0.05) 76%, transparent 77%, transparent), linear-gradient(90deg, transparent 24%, rgba(0, 243, 255, 0.05) 25%, rgba(0, 243, 255, 0.05) 26%, transparent 27%, transparent 74%, rgba(0, 243, 255, 0.05) 75%, rgba(0, 243, 255, 0.05) 76%, transparent 77%, transparent);
            background-size: 50px 50px;
        }

        .screen { display: none; width: 100vw; min-height: 100vh; box-sizing: border-box; }
        .screen.active { display: flex; flex-direction: column; align-items: center; }

        /* --- 主菜单 --- */
        #screen-menu { justify-content: center; background: radial-gradient(circle, rgba(15,15,35,0.85) 0%, rgba(5,5,16,1) 100%); }
        .menu-title { font-size: 3.2em; color: var(--neon-blue); text-shadow: 0 0 20px var(--neon-blue); margin-bottom: 5px; text-transform: uppercase; letter-spacing: 4px; }
        .menu-subtitle { color: var(--neon-pink); font-size: 1.1em; margin-bottom: 35px; text-shadow: 0 0 8px var(--neon-pink); }
        .menu-btn-group { display: flex; flex-direction: column; gap: 15px; width: 300px; }
        
        .btn-cyber {
            padding: 12px 20px; font-size: 1.05em; font-family: inherit; font-weight: bold;
            background: transparent; border: 2px solid var(--neon-blue); color: var(--neon-blue);
            box-shadow: 0 0 10px rgba(0,243,255,0.2); cursor: pointer; transition: all 0.2s;
            text-align: center; text-transform: uppercase;
        }
        .btn-cyber:hover:not(:disabled) { background: var(--neon-blue); color: #000; box-shadow: 0 0 20px var(--neon-blue); transform: scale(1.03); }
        .btn-cyber:disabled { border-color: #444; color: #555; cursor: not-allowed; box-shadow: none; }

        /* --- 设置界面 --- */
        .settings-panel { width: 100%; max-width: 500px; background: var(--panel-bg); border: 1px solid var(--neon-blue); padding: 30px; margin-top: 50px; box-shadow: 0 0 20px rgba(0,243,255,0.2); }
        .setting-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }

        /* --- 制作人员滚屏 --- */
        #screen-credits { position: relative; overflow: hidden; height: 100vh; background: #000; justify-content: center; }
        .credits-container { position: absolute; width: 100%; text-align: center; animation: scrollCredits 25s linear infinite; }
        .credits-section { margin-bottom: 50px; }
        .credits-role { color: var(--neon-pink); font-size: 1.1em; margin-bottom: 8px; }
        .credits-name { color: #fff; font-size: 1.3em; font-weight: bold; }
        .btn-back-fixed { position: fixed; bottom: 30px; z-index: 10; }
        @keyframes scrollCredits { 0% { top: 100%; transform: translateY(0); } 100% { top: 0%; transform: translateY(-100%); } }

        /* --- 游戏交易大厅 --- */
        #screen-game { padding: 15px; }
        .header-bar { display: flex; justify-content: space-between; align-items: center; width: 100%; max-width: 1250px; margin-bottom: 12px; background: var(--panel-bg); padding: 10px 20px; border: 1px solid var(--neon-blue); box-sizing: border-box; }
        .time-badge { font-size: 1.1em; color: var(--neon-yellow); font-weight: bold; }
        .status-badge { padding: 4px 8px; border-radius: 3px; font-weight: bold; font-size: 0.9em; }
        .status-open { background: rgba(57, 255, 20, 0.2); color: var(--neon-green); border: 1px solid var(--neon-green); }
        .status-closed { background: rgba(255, 153, 0, 0.2); color: var(--neon-orange); border: 1px solid var(--neon-orange); }
        .status-halt { background: rgba(255, 51, 51, 0.2); color: var(--neon-red); border: 1px solid var(--neon-red); }

        .dashboard { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; width: 100%; max-width: 1250px; }
        .panel { background-color: var(--panel-bg); border: 1px solid var(--neon-blue); padding: 12px; box-shadow: 0 0 10px rgba(0, 243, 255, 0.1); }
        .chart-container { grid-column: span 2; height: 260px; }
        
        h2 { font-size: 1em; margin-top: 0; color: #fff; border-bottom: 1px solid #333; padding-bottom: 5px; display: flex; justify-content: space-between; align-items: center; }
        table { width: 100%; border-collapse: collapse; font-size: 0.82em; text-align: center; }
        th, td { padding: 6px 2px; border-bottom: 1px solid rgba(0, 243, 255, 0.15); }
        th { color: var(--neon-blue); font-weight: normal; }
        
        .up { color: var(--neon-green); }
        .down { color: var(--neon-red); }
        .limit-flag { font-size: 0.75em; padding: 1px 3px; border-radius: 2px; }

        .controls { display: flex; gap: 8px; margin-top: 10px; justify-content: center; align-items: center; background: rgba(0,0,0,0.4); padding: 8px; border-radius: 4px;}
        select, input[type="number"] { padding: 5px; background: #111; border: 1px solid var(--neon-blue); color: #fff; outline: none; }
        
        .action-btn { padding: 5px 10px; cursor: pointer; font-weight: bold; border: none; transition: 0.2s; font-family: inherit; }
        .btn-buy { background: transparent; border: 1px solid var(--neon-green); color: var(--neon-green); }
        .btn-buy:hover { background: var(--neon-green); color: #000; }
        .btn-sell { background: transparent; border: 1px solid var(--neon-red); color: var(--neon-red); }
        .btn-sell:hover { background: var(--neon-red); color: #000; }

        /* 庄家操盘控制台(模式三专享) */
        #god-panel { grid-column: span 2; background: rgba(25, 5, 30, 0.9); border-color: var(--neon-purple); display: none; }
        .god-controls { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
        .btn-god { background: rgba(176,38,255,0.2); border: 1px solid var(--neon-purple); color: #fff; padding: 5px 10px; cursor: pointer; font-size: 0.85em; }
        .btn-god:hover { background: var(--neon-purple); color: #000; }

        /* AI 对手面板(模式一专享) */
        #rivals-panel { grid-column: span 2; display: none; }

        #log-panel { grid-column: span 2; height: 130px; overflow-y: auto; font-size: 0.85em; background: rgba(5,5,15,0.95); border: 1px solid var(--neon-purple); }
        .log-news-up { color: var(--neon-green); font-weight: bold; }
        .log-news-down { color: var(--neon-red); font-weight: bold; }
        .log-rumor { color: var(--neon-purple); font-weight: bold; }
        .log-fake { color: var(--neon-orange); font-style: italic; }
        .log-sys { color: #aaa; }

        /* 弹窗通用样式 */
        .modal-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.85); display: none; justify-content: center; align-items: center; z-index: 100; }
        .modal-box { background: var(--panel-bg); border: 2px solid var(--neon-blue); padding: 25px; width: 440px; text-align: center; box-shadow: 0 0 25px var(--neon-blue); }
        .mode-option { border: 1px solid #444; padding: 12px; margin: 10px 0; text-align: left; cursor: pointer; transition: 0.2s; }
        .mode-option:hover, .mode-option.selected { border-color: var(--neon-pink); background: rgba(255,0,234,0.1); }
        .mode-title { font-weight: bold; color: var(--neon-yellow); margin-bottom: 4px; }
        .mode-desc { font-size: 0.8em; color: #aaa; }
    </style>
</head>
<body>

    <div id="screen-menu" class="screen active">
        <div class="menu-title">Neon WallStreet</div>
        <div class="menu-subtitle">霓虹华尔街 8.0 - 终极资本终端</div>
        
        <div class="menu-btn-group">
            <button class="btn-cyber" onclick="openModeModal()">新游戏</button>
            <button class="btn-cyber" id="btn-continue" onclick="loadGame()" disabled>继续游戏</button>
            <button class="btn-cyber" onclick="switchScreen('screen-settings')">系统设置</button>
            <button class="btn-cyber" onclick="switchScreen('screen-credits')">制作人员</button>
        </div>
    </div>

    <div id="screen-settings" class="screen">
        <h1 style="margin-top: 40px; color: var(--neon-blue);">系统参数设置</h1>
        <div class="settings-panel">
            <div class="setting-row"><label>音频主音量</label><input type="range" min="0" max="100" value="80"></div>
            <div class="setting-row"><label>暗网网络节点接入</label><input type="checkbox" checked></div>
            <div class="setting-row"><label>高频交易手续费率</label><span>0.1% (Min $5)</span></div>
            <div style="text-align: center; margin-top: 25px;">
                <button class="btn-cyber" onclick="switchScreen('screen-menu')">返回主菜单</button>
            </div>
        </div>
    </div>

    <div id="screen-credits" class="screen">
        <div class="credits-container">
            <div class="credits-section"><div class="credits-role">— 游戏总策划 & 主程序员 —</div><div class="credits-name">Gemini & You</div></div>
            <div class="credits-section"><div class="credits-role">— 算法建模与AI对手逻辑 —</div><div class="credits-name">Cyber Quant Engine 8.0</div></div>
            <div class="credits-section"><div class="credits-role">— 赛博朋克 UI & 视觉美术 —</div><div class="credits-name">Neon Cyber Design</div></div>
            <div class="credits-section"><div class="credits-role">— 特别鸣谢 —</div><div class="credits-name">所有抗争在华尔街第一线的赛博韭菜们</div></div>
        </div>
        <button class="btn-cyber btn-back-fixed" onclick="switchScreen('screen-menu')">退出播放</button>
    </div>

    <div id="screen-game" class="screen">
        <div class="header-bar">
            <div><span id="current-day" class="time-badge">Day 1</span> | <span id="current-time" class="time-badge">09:30</span></div>
            <div style="display:flex; gap:5px;">
                <button id="btn-pause" onclick="setSpeed(0)" style="background:#222; color:#fff; border:1px solid #555; padding:4px 8px; cursor:pointer;">⏸ 暂停</button>
                <button id="btn-1x" class="active" onclick="setSpeed(1)" style="background:#222; color:#fff; border:1px solid #555; padding:4px 8px; cursor:pointer;">▶ 1x</button>
                <button id="btn-2x" onclick="setSpeed(2)" style="background:#222; color:#fff; border:1px solid #555; padding:4px 8px; cursor:pointer;">▶▶ 2x</button>
                <button id="btn-3x" onclick="setSpeed(3)" style="background:#222; color:#fff; border:1px solid #555; padding:4px 8px; cursor:pointer;">▶▶▶ 3x</button>
                <button id="btn-skip" onclick="skipNight()" style="display:none; background:rgba(255,153,0,0.2); color:var(--neon-orange); border:1px solid var(--neon-orange); cursor:pointer;">⏭ 结算并进入次日</button>
            </div>
            <div>
                <span id="market-status-badge" class="status-badge status-open">正常交易中</span>
                <button class="btn-cyber" onclick="handleExitGame()" style="margin-left: 10px; padding: 3px 8px; font-size:0.8em; border-color:var(--neon-red); color:var(--neon-red);">🚪 退出</button>
            </div>
        </div>

        <div class="dashboard">
            <div class="panel chart-container">
                <h2><span>📊 相对势能走势图 (归一化%)</span> <span id="game-mode-tag" style="color:var(--neon-pink); font-size:0.8em;">[模式]</span></h2>
                <canvas id="marketChart"></canvas>
            </div>

            <div class="panel" id="rivals-panel">
                <h2>⚔️ 对手金融机构实时动态</h2>
                <table>
                    <thead><tr><th>机构名称</th><th>现金余额</th><th>总净资产</th><th>状态</th><th>操作</th></tr></thead>
                    <tbody id="rivals-body"></tbody>
                </table>
            </div>

            <div class="panel" id="god-panel">
                <h2 style="color:var(--neon-purple);">👁️ 庄家幕后操盘控制台</h2>
                <div class="god-controls">
                    <select id="god-stock-select" style="padding:3px; background:#111; color:#fff; border:1px solid var(--neon-purple);"></select>
                    <button class="btn-god" onclick="godManipulate('pump')">🚀 强行拉盘 (+5%)</button>
                    <button class="btn-god" onclick="godManipulate('dump')">📉 恶意砸盘 (-5%)</button>
                    <button class="btn-god" onclick="godManipulate('rumor_bull')">🤫 发布假利好传言</button>
                    <button class="btn-god" onclick="godManipulate('rumor_bear')">🤡 发布假利空传言</button>
                    <button class="btn-god" onclick="godManipulate('halt')" style="border-color:var(--neon-red); color:var(--neon-red);">⚡ 强行拉闸熔断</button>
                </div>
            </div>

            <div class="panel">
                <h2>📈 市场盘口 (1手=100股)</h2>
                <table>
                    <thead><tr><th style="text-align:left;">代码</th><th>昨收</th><th>今开</th><th>现价</th><th>涨跌幅</th><th>成交量</th><th>状态</th></tr></thead>
                    <tbody id="market-body"></tbody>
                </table>
                <div class="controls">
                    <select id="stock-select"></select>
                    <input type="number" id="trade-qty" min="1" value="1" style="width: 55px;">
                    <span>手</span>
                    <button class="action-btn btn-buy" onclick="executeTrade('buy')">买入</button>
                    <button class="action-btn btn-sell" onclick="executeTrade('sell')">卖出</button>
                </div>
            </div>

            <div class="panel">
                <h2>💼 个人资产终端 (T+1)</h2>
                <div style="display:flex; justify-content:space-around; margin-bottom:10px;">
                    <div style="text-align:center;"><div style="font-size:0.75em; color:var(--neon-blue);">总净资产</div><div id="net-worth" style="font-size:1.2em; font-weight:bold; color:var(--neon-pink);">$10000.00</div></div>
                    <div style="text-align:center;"><div style="font-size:0.75em; color:var(--neon-blue);">可用现金</div><div id="cash-balance" style="font-size:1.2em; font-weight:bold; color:var(--neon-pink);">$10000.00</div></div>
                </div>
                <table>
                    <thead><tr><th style="text-align:left;">代码</th><th>可用/冻结(手)</th><th>持仓均价</th><th>市值</th><th>未结盈亏</th></tr></thead>
                    <tbody id="portfolio-body"></tbody>
                </table>
            </div>

            <div class="panel" id="log-panel">
                <h2>📡 暗网情报与新闻中心</h2>
                <div id="logs"></div>
            </div>
        </div>
    </div>

    <div id="mode-modal" class="modal-overlay">
        <div class="modal-box">
            <h2 style="color:var(--neon-blue); margin-top:0;">选择游戏模式</h2>
            
            <div class="mode-option selected" id="opt-mode-1" onclick="selectModeOption(1)">
                <div class="mode-title">⚔️ 模式一:机构博弈</div>
                <div class="mode-desc">同 2~4 家 AI 对冲基金竞争,收购或逼爆对手,净资产清零则输。</div>
                <div id="rival-count-box" style="margin-top:8px;">
                    <label style="font-size:0.8em; color:#fff;">对手数量:</label>
                    <select id="rival-count-select" style="background:#111; color:#fff; border:1px solid var(--neon-blue);">
                        <option value="2">2 家 AI 机构</option>
                        <option value="3" selected>3 家 AI 机构</option>
                        <option value="4">4 家 AI 机构</option>
                    </select>
                </div>
            </div>

            <div class="mode-option" id="opt-mode-2" onclick="selectModeOption(2)">
                <div class="mode-title">♾️ 模式二:无尽沙盒</div>
                <div class="mode-desc">经典自由交易模式,挑战财富上限,资金清零则破产。</div>
            </div>

            <div class="mode-option" id="opt-mode-3" onclick="selectModeOption(3)">
                <div class="mode-title">👁️ 模式三:庄家操盘 (上帝模式)</div>
                <div class="mode-desc">解锁幕后操盘台,可随意拉盘砸盘、制造假新闻与强行熔断。</div>
            </div>

            <div style="margin-top: 20px; display:flex; gap:10px; justify-content:center;">
                <button class="btn-cyber" style="border-color:var(--neon-green); color:var(--neon-green);" onclick="confirmStartGame()">开始游戏</button>
                <button class="btn-cyber" style="border-color:#666; color:#888;" onclick="closeModal('mode-modal')">取消</button>
            </div>
        </div>
    </div>

    <div id="save-modal" class="modal-overlay">
        <div class="modal-box" style="border-color:var(--neon-orange);">
            <h3 style="color:var(--neon-orange); margin-top:0;">⚠️ 检测到旧存档</h3>
            <p style="font-size:0.85em; color:#ccc;">系统发现本地已有保存的游戏进度,请选择:</p>
            <div style="display:flex; flex-direction:column; gap:10px; margin-top:15px;">
                <button class="btn-cyber" style="border-color:var(--neon-green); color:var(--neon-green);" onclick="confirmSaveAndExit(true)">覆盖原存档并退出</button>
                <button class="btn-cyber" style="border-color:var(--neon-red); color:var(--neon-red);" onclick="confirmSaveAndExit(false)">保留原存档 (放弃本次进度)</button>
                <button class="btn-cyber" onclick="closeModal('save-modal')">返回游戏</button>
            </div>
        </div>
    </div>

    <script>
        const SAVE_KEY = "NEON_WALLSTREET_SAVE_V8";
        const LOT_SIZE = 100;

        let selectedMode = 1;
        let gameState = {};
        let stocks = [];
        let aiRivals = [];
        let pendingRumors = [];
        let gameSpeed = 1; 
        let baseTickRate = 1200; 
        let tickerId = null;
        let chartInstance = null;

        const defaultStocks = [
            { symbol: 'NEX', name: '赛博科技', price: 150.00, openPrice: 150.00, prevClose: 150.00, vol: 0.004, volume: 0, sentiment: 0, color: '#00f3ff', status: 'NORMAL' },
            { symbol: 'BIA', name: '基因义体', price: 85.00, openPrice: 85.00, prevClose: 85.00, vol: 0.006, volume: 0, sentiment: 0, color: '#ff00ea', status: 'NORMAL' },
            { symbol: 'GEN', name: '大众消费', price: 40.00, openPrice: 40.00, prevClose: 40.00, vol: 0.002, volume: 0, sentiment: 0, color: '#39ff14', status: 'NORMAL' },
            { symbol: 'SMC', name: '微晶半导', price: 210.00, openPrice: 210.00, prevClose: 210.00, vol: 0.007, volume: 0, sentiment: 0, color: '#ffee00', status: 'NORMAL' },
            { symbol: 'IDX', name: '泛亚指数', price: 300.00, openPrice: 300.00, prevClose: 300.00, vol: 0.001, volume: 0, sentiment: 0, color: '#ffffff', status: 'NORMAL' }
        ];

        const aiRivalNames = ["黑石资本", "量子对冲", "荒坂创投", "高盛光电"];

        function switchScreen(screenId) {
            document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
            document.getElementById(screenId).classList.add('active');
            checkSaveStatus();
        }

        function checkSaveStatus() {
            document.getElementById('btn-continue').disabled = (localStorage.getItem(SAVE_KEY) === null);
        }

        function openModeModal() { document.getElementById('mode-modal').style.display = 'flex'; }
        function closeModal(id) { document.getElementById(id).style.display = 'none'; }

        function selectModeOption(mode) {
            selectedMode = mode;
            [1,2,3].forEach(m => document.getElementById('opt-mode-' + m).classList.remove('selected'));
            document.getElementById('opt-mode-' + mode).classList.add('selected');
        }

        // --- 开始新游戏 ---
        function confirmStartGame() {
            closeModal('mode-modal');
            
            gameState = {
                mode: selectedMode,
                cash: 10000.00, portfolio: {}, day: 1, minute: 0,
                isHalted: false, haltTimer: 0, status: 'OPEN'
            };
            
            stocks = JSON.parse(JSON.stringify(defaultStocks));
            pendingRumors = [];
            aiRivals = [];

            if (selectedMode === 1) {
                const count = parseInt(document.getElementById('rival-count-select').value);
                for (let i = 0; i < count; i++) {
                    aiRivals.push({
                        name: aiRivalNames[i], cash: 10000.00, portfolio: {}, netWorth: 10000.00, isBankrupt: false
                    });
                }
            }

            switchScreen('screen-game');
            setupUIForMode();
            initChart();
            
            document.getElementById('logs').innerHTML = `<span class="log-sys">[SYSTEM] 8.0 终端就绪。模式: ${getModeName(selectedMode)}已加载。</span><br>`;
            renderUI();
            setSpeed(1);
        }

        function getModeName(m) {
            return m === 1 ? "⚔️ 机构博弈" : (m === 2 ? "♾️ 无尽沙盒" : "👁️ 庄家操盘");
        }

        function setupUIForMode() {
            document.getElementById('game-mode-tag').innerText = `[${getModeName(gameState.mode)}]`;
            document.getElementById('rivals-panel').style.display = gameState.mode === 1 ? 'block' : 'none';
            document.getElementById('god-panel').style.display = gameState.mode === 3 ? 'block' : 'none';

            if (gameState.mode === 3) {
                const godSelect = document.getElementById('god-stock-select');
                godSelect.innerHTML = '';
                stocks.forEach(s => {
                    let o = document.createElement('option'); o.value = s.symbol; o.text = s.symbol; godSelect.appendChild(o);
                });
            }
        }

        // --- 存档与读档系统 ---
        function saveGameToStorage() {
            const saveData = { gameState, stocks, aiRivals, pendingRumors, logsHTML: document.getElementById('logs').innerHTML };
            localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
        }

        function loadGame() {
            const dataStr = localStorage.getItem(SAVE_KEY);
            if (!dataStr) return;
            
            const data = JSON.parse(dataStr);
            gameState = data.gameState;
            stocks = data.stocks;
            aiRivals = data.aiRivals || [];
            pendingRumors = data.pendingRumors || [];

            switchScreen('screen-game');
            setupUIForMode();
            initChart();
            document.getElementById('logs').innerHTML = data.logsHTML || `<span class="log-sys">[SYSTEM] 存档读取成功!</span><br>`;
            renderUI();
            setSpeed(1);
        }

        function handleExitGame() {
            setSpeed(0);
            if (localStorage.getItem(SAVE_KEY) !== null) {
                document.getElementById('save-modal').style.display = 'flex';
            } else {
                saveGameToStorage();
                alert("进度已自动保存!");
                switchScreen('screen-menu');
            }
        }

        function confirmSaveAndExit(shouldOverwrite) {
            if (shouldOverwrite) saveGameToStorage();
            closeModal('save-modal');
            switchScreen('screen-menu');
        }

        // --- 格式化与日志 ---
        function formatMoney(num) { return '$' + num.toFixed(2); }
        function formatVol(vol) { return vol >= 10000 ? (vol/10000).toFixed(1) + '万' : vol; }
        function formatTimeByMinute(minute) {
            let totalMinutes = 9 * 60 + 30 + minute;
            return `${Math.floor(totalMinutes / 60).toString().padStart(2, '0')}:${(totalMinutes % 60).toString().padStart(2, '0')}`;
        }
        function getFormattedTime() { return formatTimeByMinute(gameState.minute); }

        function log(msg, type = 'sys') {
            const logs = document.getElementById('logs');
            let css = 'log-sys';
            if (type === 'news-up') css = 'log-news-up';
            if (type === 'news-down') css = 'log-news-down';
            if (type === 'rumor') css = 'log-rumor';
            if (type === 'fake') css = 'log-fake';
            logs.innerHTML = `<span style="color:#666;">[D${gameState.day} ${getFormattedTime()}]</span> <span class="${css}">${msg}</span><br>` + logs.innerHTML;
        }

        function setSpeed(speed) {
            gameSpeed = speed;
            ['btn-pause', 'btn-1x', 'btn-2x', 'btn-3x'].forEach(id => {
                let el = document.getElementById(id);
                if(el) el.style.borderColor = "#555";
            });
            let activeBtn = document.getElementById(speed === 0 ? 'btn-pause' : 'btn-' + speed + 'x');
            if(activeBtn) activeBtn.style.borderColor = "var(--neon-blue)";

            if (tickerId) clearInterval(tickerId);
            if (speed > 0 && gameState.status !== 'CLOSED') {
                tickerId = setInterval(tick, baseTickRate / speed);
            }
        }

        function skipNight() {
            if (gameState.status !== 'CLOSED') return;
            for (let symbol in gameState.portfolio) {
                let item = gameState.portfolio[symbol];
                if (item.locked > 0) { item.available += item.locked; item.locked = 0; }
            }
            gameState.day++; gameState.minute = 0; gameState.status = 'OPEN';
            stocks.forEach(s => {
                s.prevClose = s.price; s.openPrice = s.price; s.status = 'NORMAL'; 
                s.volume = 0; s.sentiment = 0;
            });
            pendingRumors = [];
            
            document.getElementById('btn-skip').style.display = 'none';
            document.getElementById('market-status-badge').className = "status-badge status-open";
            document.getElementById('market-status-badge').innerText = "正常交易中";
            if(chartInstance) { chartInstance.data.labels = []; chartInstance.data.datasets.forEach(ds => ds.data = []); }
            renderUI(); setSpeed(gameSpeed === 0 ? 1 : gameSpeed);
        }

        function initChart() {
            const ctx = document.getElementById('marketChart').getContext('2d');
            if(chartInstance) chartInstance.destroy();
            chartInstance = new Chart(ctx, {
                type: 'line',
                data: { labels: [], datasets: stocks.map(s => ({ label: s.symbol, data: [], borderColor: s.color, borderWidth: 2, tension: 0.1, pointRadius: 0 })) },
                options: {
                    responsive: true, maintainAspectRatio: false, animation: false,
                    scales: { x: { display: true, ticks: {color: '#555'} }, y: { grid: { color: '#222' }, ticks: { color: '#aaa', callback: v => v + '%' } } },
                    plugins: { legend: { labels: { color: '#fff', boxWidth: 10 } } }
                }
            });
        }

        // --- 完全复原:随机事件与暗网内幕引擎 ---
        function triggerRandomEvents() {
            if (Math.random() < 0.08) {
                let targetStock = stocks[Math.floor(Math.random() * (stocks.length - 1))]; // 排除指数
                let isPositive = Math.random() > 0.5;
                let isRumor = Math.random() > 0.35;
                let baseShock = 0.02 + (Math.random() * 0.03);

                if (isRumor) {
                    let delay = 15 + Math.floor(Math.random() * 30);
                    let triggerMin = gameState.minute + delay;
                    if (triggerMin >= 330) return;
                    
                    pendingRumors.push({ time: triggerMin, stock: targetStock.symbol, isTrue: Math.random() > 0.4, isPositive, shock: baseShock });
                    log(`🤫 [暗网情报] 传言 ${targetStock.symbol} 将在 ${formatTimeByMinute(triggerMin)} 爆出重磅${isPositive?'利好':'利空'}!`, 'rumor');
                } else {
                    targetStock.sentiment += (isPositive ? baseShock : -baseShock);
                    log(`📰 [突发新闻] ${targetStock.symbol} ${isPositive ? '获突破性订单,买盘大增' : '遭受监管调查,出现恐慌抛盘'}!`, isPositive ? 'news-up' : 'news-down');
                }
            }
        }

        function processPendingEvents() {
            let remaining = [];
            for (let r of pendingRumors) {
                if (gameState.minute >= r.time) {
                    let s = stocks.find(st => st.symbol === r.stock);
                    if (r.isTrue) {
                        s.sentiment += (r.isPositive ? r.shock * 1.5 : -r.shock * 1.5);
                        log(`📰 [新闻证实] 关于 ${r.stock} 的${r.isPositive?'利好':'利空'}情报已兑现!`, r.isPositive ? 'news-up' : 'news-down');
                    } else {
                        s.sentiment += (r.isPositive ? -r.shock * 0.8 : r.shock * 0.8);
                        log(`🤡 [官方辟谣] 关于 ${r.stock} 的传言系捏造!预期落空触发反向抛压!`, 'fake');
                    }
                } else { remaining.push(r); }
            }
            pendingRumors = remaining;
        }

        // --- 模式一:AI 机构博弈逻辑 ---
        function simulateAIRivals() {
            if (gameState.mode !== 1) return;

            aiRivals.forEach(rival => {
                if (rival.isBankrupt) return;

                // 随机决定买卖策略
                if (Math.random() < 0.3) {
                    let stock = stocks[Math.floor(Math.random() * (stocks.length - 1))];
                    let lots = Math.floor(Math.random() * 3) + 1;
                    let cost = stock.price * lots * LOT_SIZE;

                    if (rival.cash >= cost && stock.status !== 'LIMIT_UP') {
                        rival.cash -= cost;
                        rival.portfolio[stock.symbol] = (rival.portfolio[stock.symbol] || 0) + (lots * LOT_SIZE);
                    }
                }

                // 实时更新净资产
                let stockVal = 0;
                for (let sym in rival.portfolio) {
                    let st = stocks.find(s => s.symbol === sym);
                    stockVal += rival.portfolio[sym] * st.price;
                }
                rival.netWorth = rival.cash + stockVal;

                // 破产判定
                if (rival.netWorth <= 0) {
                    rival.isBankrupt = true;
                    log(`💥 [破产公告] 金融机构【${rival.name}】资金链断裂,已被清算出局!`, 'news-down');
                }
            });
        }

        function buyoutRival(index) {
            let rival = aiRivals[index];
            let price = rival.netWorth * 1.15; // 溢价15%收购
            if (gameState.cash < price) { alert("可用现金不足以支付收购款!"); return; }

            gameState.cash -= price;
            rival.isBankrupt = true;
            log(`⚔️ [恶意收购] 你花费 ${formatMoney(price)} 成功吞并了【${rival.name}】!`, 'news-up');
            renderUI();
        }

        // --- 模式三:庄家操盘命令 ---
        function godManipulate(action) {
            const symbol = document.getElementById('god-stock-select').value;
            const stock = stocks.find(s => s.symbol === symbol);

            if (action === 'pump') { stock.sentiment += 0.05; log(`👁️ [庄家操盘] 你注入巨资对 ${symbol} 进行强行拉盘!`, 'news-up'); }
            if (action === 'dump') { stock.sentiment -= 0.05; log(`👁️ [庄家操盘] 你疯狂砸盘 ${symbol},砸出恐慌盘!`, 'news-down'); }
            if (action === 'rumor_bull') { pendingRumors.push({ time: gameState.minute + 10, stock: symbol, isTrue: true, isPositive: true, shock: 0.04 }); log(`👁️ [庄家操盘] 散布利好传闻预告...`, 'rumor'); }
            if (action === 'rumor_bear') { pendingRumors.push({ time: gameState.minute + 10, stock: symbol, isTrue: false, isPositive: false, shock: 0.04 }); log(`👁️ [庄家操盘] 散布利空传闻预告...`, 'rumor'); }
            if (action === 'halt') {
                gameState.isHalted = true; gameState.haltTimer = 15; gameState.status = 'HALTED';
                document.getElementById('market-status-badge').className = "status-badge status-halt";
                document.getElementById('market-status-badge').innerText = "⚡ 强行拉闸熔断";
                log(`⚡ [庄家操盘] 强行切断大盘交易,触发熔断!`, 'news-down');
            }
            renderUI();
        }

        // --- 行情模拟核心 ---
        function simulateMarket() {
            let totalMarketChange = 0;

            stocks.forEach((stock, index) => {
                if (stock.status === 'HALTED' || gameState.status === 'CLOSED') return;

                let noise = (Math.random() - 0.5) * stock.vol;
                let momentum = ((stock.price - stock.prevClose) / stock.prevClose) * 0.01; 
                let meanReversion = ((stock.openPrice - stock.price) / stock.openPrice) * 0.02; 
                stock.sentiment *= 0.85; 

                let netDemand = noise + momentum + meanReversion + stock.sentiment;
                let newPrice = stock.price * (1 + netDemand);

                let maxPrice = stock.prevClose * 1.10; let minPrice = stock.prevClose * 0.90;
                if (newPrice >= maxPrice) { newPrice = maxPrice; stock.status = 'LIMIT_UP'; } 
                else if (newPrice <= minPrice) { newPrice = minPrice; stock.status = 'LIMIT_DOWN'; } 
                else { stock.status = 'NORMAL'; }

                stock.price = newPrice;
                stock.volume += Math.floor(Math.random() * (stock.vol * 10000) * (1 + Math.abs(stock.sentiment * 100)));

                let normalizedValue = ((stock.price - stock.openPrice) / stock.openPrice) * 100;
                chartInstance.data.datasets[index].data.push(normalizedValue);
                if (chartInstance.data.datasets[index].data.length > 50) chartInstance.data.datasets[index].data.shift();
                
                totalMarketChange += (stock.price - stock.prevClose) / stock.prevClose;
            });

            // 7% 大盘熔断机制
            let avgChange = totalMarketChange / stocks.length;
            if (avgChange <= -0.07 && !gameState.isHalted && gameState.status === 'OPEN') {
                gameState.isHalted = true; gameState.haltTimer = 15; gameState.status = 'HALTED';
                document.getElementById('market-status-badge').className = "status-badge status-halt";
                document.getElementById('market-status-badge').innerText = "⚡ 熔断冷却中";
                log("⚡ 警告:大盘跌幅超 7%,触发自动熔断!", 'news-down');
            }
        }

        function tick() {
            if (gameState.status === 'HALTED') {
                gameState.haltTimer--;
                if (gameState.haltTimer <= 0) {
                    gameState.isHalted = false; gameState.status = 'OPEN';
                    document.getElementById('market-status-badge').className = "status-badge status-open";
                    document.getElementById('market-status-badge').innerText = "正常交易中";
                }
                return;
            }

            if (gameState.status === 'OPEN') {
                gameState.minute += 5; 
                
                processPendingEvents();
                triggerRandomEvents();
                simulateAIRivals();

                if (gameState.minute >= 330) {
                    gameState.status = 'CLOSED'; clearInterval(tickerId); setSpeed(0);
                    document.getElementById('market-status-badge').className = "status-badge status-closed";
                    document.getElementById('market-status-badge').innerText = "休市 (待结算)";
                    document.getElementById('btn-skip').style.display = 'inline-block';
                    log("🔔 15:00 市场收盘。");
                    renderUI(); return;
                }
                
                simulateMarket();
                chartInstance.data.labels.push(getFormattedTime());
                if (chartInstance.data.labels.length > 50) chartInstance.data.labels.shift();
                chartInstance.update(); renderUI();
            }
        }

        function executeTrade(type) {
            if (gameState.status !== 'OPEN') { alert("非交易时间!"); return; }
            const symbol = document.getElementById('stock-select').value;
            const lots = parseInt(document.getElementById('trade-qty').value);
            const stock = stocks.find(s => s.symbol === symbol);

            if (isNaN(lots) || lots <= 0) return;
            const shares = lots * LOT_SIZE; const totalValue = stock.price * shares; 
            const fee = Math.max(totalValue * 0.001, 5);

            if (type === 'buy') {
                if (stock.status === 'LIMIT_UP') { log(`❌ ${symbol} 涨停锁定,无法买入!`); return; }
                const totalCost = totalValue + fee;
                if (gameState.cash >= totalCost) {
                    gameState.cash -= totalCost; stock.volume += lots;
                    if (!gameState.portfolio[symbol]) gameState.portfolio[symbol] = { available: 0, locked: 0, avgCost: 0 };
                    let p = gameState.portfolio[symbol];
                    let totalOwned = p.available + p.locked;
                    p.avgCost = ((totalOwned * p.avgCost) + totalCost) / (totalOwned + shares);
                    p.locked += shares;
                    log(`✅ 买入 ${lots}手 ${symbol}。手续费:${formatMoney(fee)}`);
                } else { log(`❌ 现金不足支付订单及手续费!`); }
            } else if (type === 'sell') {
                if (stock.status === 'LIMIT_DOWN') { log(`❌ ${symbol} 跌停锁定,无法卖出!`); return; }
                let p = gameState.portfolio[symbol];
                if (p && p.available >= shares) {
                    p.available -= shares; stock.volume += lots;
                    gameState.cash += (totalValue - fee);
                    if (p.available === 0 && p.locked === 0) delete gameState.portfolio[symbol];
                    log(`✅ 卖出 ${lots}手 ${symbol}。扣佣净得:${formatMoney(totalValue - fee)}`);
                } else { log(`❌ 可用头寸不足 (受到 T+1 锁定)`); }
            }
            renderUI();
        }

        function renderUI() {
            document.getElementById('current-day').innerText = `Day ${gameState.day}`;
            document.getElementById('current-time').innerText = getFormattedTime();
            
            // 渲染盘口
            const marketBody = document.getElementById('market-body'); marketBody.innerHTML = '';
            const select = document.getElementById('stock-select');
            if (select.options.length === 0) { stocks.forEach(s => { let o = document.createElement('option'); o.value = s.symbol; o.text = s.symbol; select.appendChild(o); }); }

            stocks.forEach(stock => {
                const tr = document.createElement('tr');
                const change = stock.price - stock.prevClose; const changePct = (change / stock.prevClose) * 100;
                let colorClass = change >= 0 ? 'up' : 'down';
                let flag = stock.status === 'LIMIT_UP' ? `<span class="limit-flag" style="background:var(--neon-green); color:#000;">涨停</span>` :
                          (stock.status === 'LIMIT_DOWN' ? `<span class="limit-flag" style="background:var(--neon-red); color:#fff;">跌停</span>` : '正常');

                tr.innerHTML = `
                    <td style="color:${stock.color}; font-weight:bold; text-align:left;">${stock.symbol}</td>
                    <td>${formatMoney(stock.prevClose)}</td>
                    <td>${formatMoney(stock.openPrice)}</td>
                    <td class="${colorClass}" style="font-weight:bold;">${formatMoney(stock.price)}</td>
                    <td class="${colorClass}">${change>=0?'+':''}${changePct.toFixed(2)}%</td>
                    <td>${formatVol(stock.volume)}</td>
                    <td>${flag}</td>
                `;
                marketBody.appendChild(tr);
            });

            // 渲染资产
            const portBody = document.getElementById('portfolio-body'); portBody.innerHTML = ''; let totalStockValue = 0;
            for (let symbol in gameState.portfolio) {
                let p = gameState.portfolio[symbol]; let stock = stocks.find(s => s.symbol === symbol);
                let totalShares = p.available + p.locked; let currentValue = totalShares * stock.price; totalStockValue += currentValue;
                let profit = currentValue - (totalShares * p.avgCost);
                
                const tr = document.createElement('tr');
                tr.innerHTML = `
                    <td style="color:${stock.color}; font-weight:bold; text-align:left;">${symbol}</td>
                    <td>${p.available / LOT_SIZE} / ${p.locked / LOT_SIZE}</td>
                    <td>${formatMoney(p.avgCost)}</td>
                    <td>${formatMoney(currentValue)}</td>
                    <td class="${profit>=0?'up':'down'}">${formatMoney(profit)}</td>
                `;
                portBody.appendChild(tr);
            }
            
            let myNetWorth = gameState.cash + totalStockValue;
            document.getElementById('cash-balance').innerText = formatMoney(gameState.cash);
            document.getElementById('net-worth').innerText = formatMoney(myNetWorth);

            // 胜负与破产检查
            if (myNetWorth <= 0) {
                setSpeed(0);
                alert("💥 你已资金链断裂宣告破产!GAME OVER");
                switchScreen('screen-menu');
                return;
            }

            // 渲染模式一 AI 对手面板
            if (gameState.mode === 1) {
                const rivalBody = document.getElementById('rivals-body'); rivalBody.innerHTML = '';
                let activeRivals = 0;

                aiRivals.forEach((rival, idx) => {
                    if (!rival.isBankrupt) activeRivals++;
                    const tr = document.createElement('tr');
                    tr.innerHTML = `
                        <td style="font-weight:bold; color:var(--neon-yellow);">${rival.name}</td>
                        <td>${formatMoney(rival.cash)}</td>
                        <td style="color:var(--neon-pink);">${formatMoney(rival.netWorth)}</td>
                        <td>${rival.isBankrupt ? '<span class="down">破产</span>' : '<span class="up">正常</span>'}</td>
                        <td>${rival.isBankrupt ? '-' : `<button class="action-btn btn-sell" onclick="buyoutRival(${idx})">吞并收购</button>`}</td>
                    `;
                    rivalBody.appendChild(tr);
                });

                if (activeRivals === 0) {
                    setSpeed(0);
                    alert("🏆 恭喜!你已成功清算吞并所有对手机构,独霸华尔街!VICTORY!");
                }
            }
        }

        checkSaveStatus();
    </script>
</body>
</html>

Game Source: 霓虹华尔街 8.0 - 终极赛博操盘手

Creator: RapidPanda65

Libraries: none

Complexity: complex (777 lines, 43.7 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: 8-0-rapidpanda65" to link back to the original. Then publish at arcadelab.ai/publish.