霓虹华尔街 8.0 - 终极赛博操盘手
by RapidPanda65777 lines43.7 KB
<!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.