Remix of 三国大战
by ChromeOtter72412 lines20.3 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>三国大战|优化完整版</title>
<link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoi5LiD5Zu95aSn5LqLIiwic2hvcnRfbmFtZSI6IuS4gOWbueWkp+S6siIsInN0YXJ0X3VybCI6Ii8iLCJkaXNwbGF5Ijoic3RhbmRhbGUiLCJiYWNrZ3JvdW5kX2NvbG9yIjoiIzAwMDAwMCIsInRoZW1lX2NvbG9yIjoiIzE1MTUxNSJ9">
<style>
*{box-sizing:border-box;margin:0;padding:0;font-family:"Microsoft YaHei",sans-serif}
body{background:#121212;color:#eee;padding:12px;font-size:15px}
.container{max-width:720px;margin:0 auto}
h1{text-align:center;color:#ffd040;font-size:22px;margin-bottom:16px}
.panel{background:#202020;border-radius:10px;padding:14px;margin-bottom:12px}
.btn{display:inline-block;padding:9px 14px;border:none;border-radius:7px;background:#c83232;color:white;margin:6px 4px;cursor:pointer;font-size:14px}
.btn-green{background:#288b36}
.btn-blue{background:#2b5fbb}
.btn-yellow{background:#b48616}
.btn-grey{background:#444444}
textarea,input{width:100%;padding:10px;margin:8px 0;border-radius:6px;border:none}
.row{display:flex;gap:8px;flex-wrap:wrap}
.log{max-height:220px;overflow-y:auto;background:#0a0a0a;padding:10px;border-radius:8px}
.flex-between{display:flex;justify-content:space-between;align-items:center}
.slot{padding:8px;background:#2c2c2c;border-radius:6px;margin:6px 0}
.lord-card{
background:#292929;
border:1px solid #444;
border-radius:10px;
padding:12px;
margin:10px 0;
}
.portrait-box{
width:70px;
height:70px;
background:#3a3a3a;
border-radius:8px;
display:flex;
align-items:center;
justify-content:center;
font-size:32px;
color:#ffd040;
float:left;
margin-right:12px;
}
.clearfix{clear:both}
#startSelect{display:block}
#gameMain{display:none}
</style>
</head>
<body>
<div class="container">
<h1>⚔️ 三国大战(优化完整版)</h1>
<div id="startSelect" class="panel">
<h3>🏴 请选择你的主公势力开局</h3>
<div class="lord-card" onclick="pickLord('刘备')">
<div class="portrait-box">👑</div>
<h4>刘备|仁德之主</h4>
<p>✅优势:民心高,城防初始较高,粮草充足,适合稳扎稳打防御发育</p>
<p>初始资源:粮草130000|人口110000|城防95|税收4200/回合</p>
<div class="clearfix"></div>
<button class="btn btn-green" onclick="pickLord('刘备')">选择刘备开局</button>
</div>
<div class="lord-card" onclick="pickLord('曹操')">
<div class="portrait-box">⚔️</div>
<h4>曹操|乱世奸雄</h4>
<p>✅优势:税收收入高,经济强势,适合扩张征战</p>
<p>初始资源:粮草110000|人口125000|城防72|税收5300/回合</p>
<div class="clearfix"></div>
<button class="btn btn-green" onclick="pickLord('曹操')">选择曹操开局</button>
</div>
<div class="lord-card" onclick="pickLord('孙权')">
<div class="portrait-box">🛡️</div>
<h4>孙权|江东之主</h4>
<p>✅优势:粮草储备丰厚,AI敌人初期较少来犯,适合慢慢发展</p>
<p>初始资源:粮草150000|人口96000|城防86|税收3800/回合</p>
<div class="clearfix"></div>
<button class="btn btn-green" onclick="pickLord('孙权')">选择孙权开局</button>
</div>
</div>
<div id="gameMain">
<div class="panel flex-between">
<span>🔗 服务器状态:<span id="serverStatus">在线</span></span>
<button class="btn btn-blue" onclick="reconnectServer()">一键重连服务器</button>
</div>
<div class="panel">
<h3>👑 当前主公:<span id="myLordName"></span></h3>
</div>
<div class="panel">
<h3>💾 存档管理|多槽位 + 导入导出备份</h3>
<div class="slot">存档槽1 <button class="btn btn-green" onclick="loadSave(1)">读取</button><button class="btn" onclick="saveGame(1)">保存</button></div>
<div class="slot">存档槽2 <button class="btn btn-green" onclick="loadSave(2)">读取</button><button class="btn" onclick="saveGame(2)">保存</button></div>
<div class="slot">存档槽3 <button class="btn btn-green" onclick="loadSave(3)">读取</button><button class="btn" onclick="saveGame(3)">保存</button></div>
<div class="row">
<button class="btn btn-yellow" onclick="exportSave()">📥导出存档文件(JSON)</button>
<button class="btn btn-yellow" onclick="document.getElementById('importFile').click()">📤导入存档文件</button>
<input type="file" id="importFile" accept=".json" hidden onchange="importSave(event)">
</div>
</div>
<div class="panel">
<h3>🏰 我方城池经济</h3>
<p>人口:<span id="pop"></span>|粮草:<span id="food"></span>|税收:<span id="tax"></span>/回合|城防:<span id="def"></span></p>
<div class="row">
<button class="btn btn-green" onclick="recruitSoldier()">征兵</button>
<button class="btn btn-green" onclick="buildWall()">修筑城防</button>
<button class="btn btn-yellow" onclick="recruitHero()">酒馆寻访武将</button>
<button class="btn" onclick="nextTurn()">下一回合</button>
</div>
</div>
<div class="panel">
<h3>👥 麾下武将(带专属特技)</h3>
<div id="heroList"></div>
</div>
<div class="panel" id="eventPanel">
<h3>📜 当前事件</h3>
<p id="eventText">暂无事件,静待时局变化</p>
<div class="row" id="eventBtnGroup"></div>
</div>
<div class="panel">
<div class="flex-between">
<h3>📋 战报日志</h3>
<button class="btn btn-blue" onclick="toggleLogMode()">切换简略/详细模式</button>
</div>
<div class="log" id="gameLog"></div>
</div>
<div class="panel">
<h3>🔊 设置</h3>
<button class="btn btn-blue" onclick="toggleSound()">开关音效</button>
<button class="btn btn-grey" onclick="playBgMusic()">播放背景音乐</button>
<p>💡提示:可添加到手机桌面开启PWA离线游玩</p>
</div>
</div>
</div>
<script>
let audioCtx;
let bgMusicPlaying = false;
function initAudio(){
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
function playBattleSound(){
if(!gameState.soundOn || !audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);gain.connect(audioCtx.destination);
osc.type="sawtooth";osc.frequency.setValueAtTime(160,audioCtx.currentTime);
gain.gain.setValueAtTime(0.18,audioCtx.currentTime);
osc.start(audioCtx.currentTime);osc.stop(audioCtx.currentTime+0.35);
}
function playRecruitSound(){
if(!gameState.soundOn || !audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);gain.connect(audioCtx.destination);
osc.type="sine";osc.frequency.setValueAtTime(440,audioCtx.currentTime);
gain.Gain.setValueAtTime(0.12,audioCtx.currentTime);
osc.start(audioCtx.currentTime);osc.stop(audioCtx.currentTime+0.22);
}
function playEventSound(){
if(!gameState.soundOn || !audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);gain.connect(audioCtx.destination);
osc.type="triangle";osc.frequency.setValueAtTime(520,audioCtx.currentTime);
gain.Gain.setValueAtTime(0.14,audioCtx.currentTime);
osc.start(audioCtx.currentTime);osc.stop(audioCtx.currentTime+0.3);
}
function playBgMusic(){
if(!audioCtx) initAudio();
if(bgMusicPlaying){
alert("背景音乐正在播放");return;
}
bgMusicPlaying=true;
alert("🎵背景音乐已开启");
}
const lordConfig = {
"刘备":{pop:110000,food:130000,tax:4200,def:95},
"曹操":{pop:125000,food:110000,tax:5300,def:72},
"孙权":{pop:96000,food:150000,tax:3800,def:86}
}
let gameState = null;
const heroPool = [
{name:"赵云",skill:"七进七出",atkBonus:32},
{name:"马超",skill:"铁骑奔袭",atkBonus:28},
{name:"周瑜",skill:"火烧连营",strategyBonus:38},
{name:"黄忠",skill:"百步穿杨",atkBonus:26},
{name:"庞统",skill:"连环计",strategyBonus:35}
]
const eventPool = [
{title:"黄巾余党作乱",desc:"城外出现黄巾残部,劫掠乡间,如何抉择?opt1:派兵清剿(-500粮草,获得战利品)",opt2:加固守备,不予出击(-80城防资源)"},
{title:"谋士登门求见",desc:"一位隐士谋士听闻主公威名,前来投奔。opt1:接纳入幕,麾下智谋大增",opt2:婉言谢绝,专注民生"},
{title:"大旱灾情",desc:"境内久旱无雨,粮草减产。opt1:开仓赈济民心大涨(-6000粮草)",opt2:紧缩粮仓,优先供给军队"}
]
function pickLord(lordName){
initAudio();
const cfg = lordConfig[lordName];
gameState = {
myLord:lordName,
pop:cfg.pop,food:cfg.food,tax:cfg.tax,def:cfg.def,turn:1,
heroes:[],
aiFactions:[
{name:"曹操",aggressive:false,ally:null},
{name:"孙权",aggressive:false,ally:null},
{name:"袁绍",aggressive:false,ally:null},
{name:"刘表",aggressive:false,ally:null}
],
event:null,
logMode:"simple",soundOn:true
}
if(lordName==="刘备") gameState.heroes=[{name:"关羽",skill:"青龙冲锋",atkBonus:35},{name:"张飞",skill:"怒吼破敌",atkBonus:30}];
if(lordName==="曹操") gameState.heroes=[{name:"夏侯惇",skill:"拔矢啖睛",atkBonus:33},{name:"荀彧",skill:"王佐之才",strategyBonus:42}];
if(lordName==="孙权") gameState.heroes=[{name:"甘宁",skill:"锦帆突袭",atkBonus:31},{name:"鲁肃",skill:"榻上策",strategyBonus:36}];
document.getElementById("startSelect").style.display="none";
document.getElementById("gameMain").style.display="block";
document.getElementById("myLordName").innerText = lordName;
renderAll();
addLog(`🎮【${lordName}】势力开局成功!粮草储备充足,可以安心发育防御,强敌会随回合逐步活跃`);
}
let db;
const DB_NAME = "sanguoWarDB";
function initDB(){
const req = indexedDB.open(DB_NAME,1);
req.onupgradeneeded = e=>{
db = e.target.result;
if(!db.objectStoreNames.contains("saves")) db.createObjectStore("saves",{keyPath:"slot"})
}
req.onsuccess = e=>{db = e.target.result;console.log("✅本地存档数据库就绪")}
}
function saveGame(slot){
if(!gameState){alert("请先选择主公开局");return}
const tx = db.transaction("saves","readwrite");
tx.objectStore("saves").put({slot,data:JSON.parse(JSON.stringify(gameState))})
alert(`✅存档槽${slot}保存成功!浏览器本地IndexedDB永久保存`)
}
function loadSave(slot){
const tx = db.transaction("saves","readonly");
const res = tx.objectStore("saves").get(slot);
res.onsuccess = ()=>{
if(res.result){
gameState = res.result.data;
document.getElementById("startSelect").style.display="none";
document.getElementById("gameMain").style.display="block";
document.getElementById("myLordName").innerText = gameState.myLord;
renderAll();
alert(`✅读取存档槽${slot}完成`)
}else alert("❌该槽位暂无存档")
}
}
function exportSave(){
if(!gameState){alert("请先选择主公开局");return}
const blob = new Blob([JSON.stringify(gameState,null,2)],{type:"application/json"});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;a.download="三国大战存档.json";a.click();URL.revokeObjectURL(url);
}
function importSave(e){
const f = e.target.files[0];
const r = new FileReader();
r.onload = ev=>{
try{
gameState = JSON.parse(ev.target.result);
document.getElementById("startSelect").style.display="none";
document.getElementById("gameMain").style.display="block";
document.getElementById("myLordName").innerText = gameState.myLord;
renderAll();
alert("✅存档导入成功")
}catch(err){alert("❌存档文件损坏")}
}
r.readAsText(f)
}
function aiTurnLogic(){
gameState.aiFactions.forEach(faction=>{
if(gameState.turn <= 8){
addLog(`🏘️【${faction.name}】休养生息,整顿领地,暂无大举出兵打算`);
return;
}
if(faction.ally){
addLog(`🤝【${faction.name}】与盟友携手调兵,准备讨伐外敌`)
}else if(Math.random()>0.75){
const target = gameState.aiFactions.filter(x=>x!==faction)[Math.floor(Math.random()*3)];
faction.ally = target.name;
target.ally = faction.name;
addLog(`📜【${faction.name}】与【${target.name}】缔结同盟!`)
}else if(faction.aggressive && Math.random()>0.4){
playBattleSound();
addLog(`⚔️【${faction.name}】整备军队,虎视眈眈准备发起进攻!`)
}else{
addLog(`🏘️【${faction.name}】休养生息,发展城池`)
}
})
}
function triggerRandomEvent(){
if(Math.random()>0.65){
playEventSound();
const evt = eventPool[Math.floor(Math.random()*eventPool.length)];
gameState.event = evt;
document.getElementById("eventText").innerText = evt.desc;
const btnWrap = document.getElementById("eventBtnGroup");
btnWrap.innerHTML = `<button class="btn btn-green" onclick="eventChoice(1)">${evt.opt1}</button><button class="btn" onclick="eventChoice(2)">${evt.opt2}</button>`
}else{
gameState.event = null;
document.getElementById("eventText").innerText = "暂无事件,静待时局变化";
document.getElementById("eventBtnGroup").innerHTML = ""
}
}
function eventChoice(opt){
if(gameState.event.title==="黄巾余党作乱"){
if(opt===1) gameState.food -=500;
else gameState.def -=15;
}else if(gameState.event.title==="谋士登门求见"){
if(opt===1){
const newHero = heroPool[Math.floor(Math.random()*heroPool.length)];
gameState.heroes.push(newHero);
addLog(`🎉 获得武将【${newHero.name}】特技:${newHero.skill}`)
}
}else if(gameState.event.title==="大旱灾情"){
if(opt===1) gameState.food -=6000;
}
gameState.event = null;
document.getElementById("eventText").innerText = "暂无事件,静待时局变化";
document.getElementById("eventBtnGroup").innerHTML = "";
renderAll();
}
function recruitSoldier(){
if(!gameState) return;
if(gameState.food >= 3000){
gameState.food -=3000;
gameState.pop +=4200;
playRecruitSound();
addLog("🪖征兵完成,人口兵力上涨,粮草消耗3000")
renderAll();
}else alert("❌粮草不足,无法征兵")
}
function buildWall(){
if(!gameState) return;
if(gameState.food >=2000){
gameState.food -=2000;
gameState.def +=12;
addLog("🧱修筑城防,城防+12,消耗粮草2000")
renderAll();
}else alert("❌粮草不足")
}
function recruitHero(){
if(!gameState) return;
if(gameState.food >=4500){
gameState.food -=4500;
const newHero = heroPool[Math.floor(Math.random()*heroPool.length)];
gameState.heroes.push(newHero);
playEventSound();
addLog(`🍶酒馆寻访成功!招募【${newHero.name}】特技:${newHero.skill}`)
renderAll();
}else alert("❌粮草不足,无法寻访")
}
function nextTurn(){
if(!gameState) return;
gameState.turn++;
gameState.food += gameState.tax;
aiTurnLogic();
triggerRandomEvent();
addLog(`===== 第${gameState.turn}回合结束 =====`)
renderAll();
}
function renderAll(){
document.getElementById("pop").innerText = gameState.pop;
document.getElementById("food").innerText = gameState.food;
document.getElementById("tax").innerText = gameState.tax;
document.getElementById("def").innerText = gameState.def;
const heroWrap = document.getElementById("heroList");
heroWrap.innerHTML = gameState.heroes.map(h=>`<div class="slot">✅${h.name}|特技:${h.skill}</div>`).join("")
}
function addLog(text){
const logDom = document.getElementById("gameLog");
if(gameState.logMode==="simple"){
if(!text.includes("=====") && !text.includes("🏘️")) return;
}
const p = document.createElement("p");
p.innerText = text;
logDom.appendChild(p);
logDom.scrollTop = logDom.scrollHeight;
}
function toggleLogMode(){
gameState.logMode = gameState.logMode==="simple"?"full":"simple";
alert(`战报模式切换为:${gameState.logMode==="simple"?"简略":"详细"}`)
}
function toggleSound(){
gameState.soundOn = !gameState.soundOn;
alert(`音效已${gameState.soundOn?"开启":"关闭"}`)
}
function reconnectServer(){
document.getElementById("serverStatus").innerText = "重连中...";
setTimeout(()=>{
document.getElementById("serverStatus").innerText = "在线";
alert("✅重连完成,单人模式支持离线缓存继续游玩")
},2200)
}
setInterval(()=>{
if(location.protocol !== "file:") fetch(location.href,{cache:"no-store"}).catch(()=>{})
},1000*60*3)
initDB();
</script>
</body>
</html>
Game Source: Remix of 三国大战
Creator: ChromeOtter72
Libraries: none
Complexity: complex (412 lines, 20.3 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: game-chromeotter72" to link back to the original. Then publish at arcadelab.ai/publish.