汉末三国之君临天下
by ChromeOtter72647 lines32.8 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>汉末三国之君临天下</title>
<meta name="capacitor" content="true">
<style>
*{box-sizing:border-box;margin:0;padding:0;font-family:"Microsoft Yahei",sans-serif}
body{background:#121629;color:#eef;height:100vh;display:flex;flex-direction:column;font-size:14px}
#topBar{height:52px;background:#0f1425;display:flex;align-items:center;padding:0 12px;gap:10px;flex-wrap:wrap}
#mainWrap{flex:1;display:grid;grid-template-columns:62% 38%;overflow:hidden}
#mapBox{position:relative;background:#0b2240;padding:8px;overflow:auto}
#infoPanel{background:#0f1425;padding:12px;overflow-y:auto}
.city-item{border:1px solid #345;border-radius:6px;padding:8px;margin:6px;cursor:pointer;background:#162b4b;transition:0.2s}
.city-item:hover{background:#203b63}
.city-item.occupied-player{border-color:#4c9;border-left:4px solid #4c9}
.city-item.occupied-wei{border-color:#66a;border-left:4px solid #66a}
.city-item.occupied-shu{border-color:#c84;border-left:4px solid #c84}
.city-item.occupied-wu{border-color:#48c;border-left:4px solid #48c}
.city-item.selected{box-shadow:0 0 0 2px #ffd700}
.hero-card{border:1px solid #2c385a;border-radius:6px;padding:8px;margin:8px 0;background:#131b33}
h3{margin:6px 0;color:#ffd700;font-size:16px}
.tag{display:inline-block;font-size:12px;padding:2px 6px;background:#1b3828;color:#9f9;border-radius:99px;margin:2px}
.tag-red{background:#381b1b;color:#f99}
.tag-blue{background:#1b2c38;color:#9cf}
.tag-yellow{background:#38301b;color:#fd9}
.btn{padding:7px 11px;background:#d63b50;border:none;border-radius:4px;color:white;cursor:pointer;margin:4px;font-size:14px}
.btn:disabled{background:#444;cursor:not-allowed}
.btn-green{background:#2b884c}
.btn-blue{background:#2b5888}
.btn-orange{background:#946020}
hr{border-color:#253250;margin:10px 0}
.event-box{background:#252040;border:1px solid #547;border-radius:6px;padding:10px;margin:8px 0}
.equip-slot{display:inline-block;padding:4px 6px;background:#222;border-radius:4px;margin:3px;font-size:12px}
.stat-row{display:flex;justify-content:space-between;padding:3px 0}
.log-item{padding:4px 6px;border-bottom:1px solid #246;font-size:13px}
.modal-mask{position:fixed;inset:0;background:rgba(0,0,0,0.75);display:flex;align-items:center;justify-content:center;z-index:999}
.modal-box{background:#16203b;padding:16px;border-radius:8px;width:90%;max-width:520px;max-height:80vh;overflow-y:auto}
.hide{display:none}
@media(max-width:768px){
#mainWrap{grid-template-columns:100%;grid-template-rows:48% 52%}
}
</style>
</head>
<body>
<div id="topBar">
<span>汉末三国之君临天下|回合:<span id="turnNum">1</span></span>
<button class="btn btn-green" onclick="nextTurn()">下一回合</button>
<button class="btn" onclick="saveGame()">存档</button>
<button class="btn" onclick="loadGame()">读档</button>
<button class="btn btn-blue" onclick="openPolicyPanel()">国策事件</button>
<button class="btn btn-orange" onclick="openStrategyPanel()">计略</button>
<button class="btn btn-green" onclick="openDiplomacyPanel()">外交</button>
<button class="btn" onclick="openScriptSelect()">剧本</button>
</div>
<div id="mainWrap">
<div id="mapBox">
<h3>📍 十三州城池据点(点击选中城池)</h3>
<div id="cityList"></div>
</div>
<div id="infoPanel">
<h3>📜 选中城池详情</h3>
<div id="detailPanel">请点击左侧城池查看详情</div>
<hr>
<h3>👥 我方武将</h3>
<div id="heroPanel"></div>
<hr>
<h3>⚔️ 装备库存</h3>
<div id="equipPanel"></div>
<hr>
<h3>📋 消息日志</h3>
<div id="logBox" style="max-height:160px;overflow-y:auto;"></div>
</div>
</div>
<!-- 弹窗容器 -->
<div id="modalMask" class="modal-mask hide">
<div id="modalContent" class="modal-box"></div>
</div>
<script>
// ========== 基础配置 地图原始数据 ==========
const mapRawData = [
{state:"司隶校尉部",capital:"洛阳",cities:["长安","弘农","河东","河内"],pass:"函谷关、潼关",terrain:"关中盆地、多要塞",buff:"山地行军-30%,关隘防御+40%"},
{state:"豫州",capital:"谯县",cities:["许昌","汝南","颍川","梁国"],pass:"汝水渡口、鸿沟",terrain:"中原大平原,高粮产,无险可守",buff:"平原行军+15%"},
{state:"冀州",capital:"邺",cities:["巨鹿","常山","中山","渤海"],pass:"井陉关、滹沱渡口",terrain:"华北平原,适合骑兵作战",buff:"平原行军+15%"},
{state:"兖州",capital:"鄄城",cities:["陈留","东郡","泰山","任城"],pass:"济水渡口",terrain:"平原+局部山地,早期群雄混战区域",buff:"山地地块行军-30%"},
{state:"青州",capital:"临淄",cities:["北海","东莱","平原郡"],pass:"淄水渡口",terrain:"山东半岛,临海,渔粮加成",buff:"粮产小幅加成"},
{state:"徐州",capital:"下邳",cities:["彭城","广陵","琅琊"],pass:"泗水渡口、淮水北岸渡口",terrain:"江淮缓冲地带",buff:"无特殊地形buff"},
{state:"扬州",capital:"寿春",cities:["建业","庐江","吴郡","会稽","豫章"],pass:"濡须口、长江各渡口",terrain:"水网密布、丘陵,水战加成",buff:"水战战力+30%"},
{state:"荆州",capital:"襄阳",cities:["南阳","江陵","长沙","零陵","桂阳"],pass:"夷陵隘口、汉津渡口",terrain:"天下腹心,水陆要道",buff:"水陆皆可通行"},
{state:"益州",capital:"成都",cities:["汉中","巴郡","广汉","永昌"],pass:"剑阁",terrain:"盆地环山,易守难攻,汉中北门",buff:"外部进攻粮草消耗+35%"},
{state:"凉州",capital:"姑臧",cities:["金城","武威","安定","汉阳"],pass:"祁山道隘口",terrain:"戈壁山地,骑兵产地,粮产低",buff:"骑兵战力+12%,本地粮产降低"},
{state:"并州",capital:"晋阳",cities:["上党","雁门","西河"],pass:"雁门关、壶关",terrain:"黄土山地,战马产出高",buff:"骑兵战力+12%"},
{state:"幽州",capital:"蓟",cities:["涿郡","渔阳","辽东","右北平"],pass:"碣石古道",terrain:"北部边塞,骑兵战力加成",buff:"骑兵战力+12%"},
{state:"交州",capital:"番禺",cities:["苍梧","南海","交趾"],pass:"珠江渡口",terrain:"岭南丘陵,远征行军惩罚巨大",buff:"外来势力行军消耗大幅增加"}
];
// ========== 武将原始库 ==========
const heroRawData = [
{name:"刘备",camp:"蜀汉",char:"仁德、坚韧、重情、略显保守",desc:"出身微末,早年屡遭挫败,以兴复汉室为旗帜,极善笼络人心,在乱世聚拢一众死士,逐步建立基业。",talent:"人才投奔概率提升;外交结盟好感获取更快;势力内部稳定度不易下跌",atk:65,def:55,intel:82},
{name:"曹操",camp:"曹魏",char:"多疑、雄才、果断、冷酷",desc:"宦官之后,平定北方群雄,文韬武略兼备,用人不拘一格,行事狠辣,是汉末实力最强霸主。",talent:"主动进攻部队攻击加成;谍报成功率提升;麾下忠诚度上限浮动较大",atk:70,def:60,intel:88},
{name:"孙权",camp:"东吴",char:"稳重、冷静、善用人、偏防守",desc:"继承父兄江东基业,擅长制衡朝堂各方势力,大局观强,偏好稳固领地,伺机而动。",talent:"城池防御加成;领地经济粮草收益提升;主动宣战代价更高",atk:58,def:72,intel:80},
{name:"关羽",camp:"蜀汉",char:"忠义、高傲、重诺、刚正",desc:"五虎上将之首,武艺冠绝天下,义薄云天,水淹七军威震华夏,性格孤傲轻敌埋下败亡隐患。",talent:"部队攻击高;守城属性优秀;容易拒绝低水平人才招揽",atk:94,def:85,intel:68},
{name:"张飞",camp:"蜀汉",char:"暴躁、勇猛、嫉恶如仇、粗中有细",desc:"桃园结义,长坂喝退曹军,攻坚破城能力极强,但对待底层部下严苛,隐患极高。",talent:"攻城破防加成;先锋冲锋战力爆炸;麾下士卒有概率触发兵变事件",atk:92,def:80,intel:55},
{name:"诸葛亮",camp:"蜀汉",char:"谨慎、智慧、忠诚、事必躬亲",desc:"隆中对定天下大计,辅佐刘备立国,治国治军一流,用兵谨慎,后勤调度能力顶尖。",talent:"领地粮草、治安大幅增益;计谋类计策成功率上升;北伐长途行军消耗小幅降低",atk:40,def:45,intel:98},
{name:"赵云",camp:"蜀汉",char:"沉稳、忠勇、冷静、执行力强",desc:"一身是胆,长坂坡救主,行事稳重,极少冒进,兼顾护卫与领兵作战。",talent:"部队伤亡降低;突击机动加成;护卫主公时大幅降低刺杀风险",atk:88,def:86,intel:74},
{name:"马超",camp:"蜀汉",char:"勇猛、骄傲、复仇心强、统兵有方",desc:"西凉马腾之子,少年成名,统领西凉铁骑,擅长塞外、平原骑兵会战。",talent:"骑兵部队战力加成;关口突击伤害提升;忠诚度存在波动风险",atk:90,def:78,intel:62},
{name:"黄忠",camp:"蜀汉",char:"沉稳、坚毅、不服老、重情义",desc:"老当益壮,箭术无双,定军山阵斩夏侯渊,暮年依旧勇冠三军。",talent:"远程部队伤害提升;可无视部分城防减伤;拉锯消耗战优势明显",atk:87,def:75,intel:66},
{name:"夏侯惇",camp:"曹魏",char:"刚烈、忠诚、勇猛、治军严整",desc:"曹操族弟,自起兵便跟随左右,忠心不二,擅长镇守后方、稳固战线。",talent:"驻守城池防御高额加成;军队军纪稳定度提升",atk:82,def:84,intel:60},
{name:"张辽",camp:"曹魏",char:"冷静、果断、勇猛、善于料敌",desc:"合肥之战八百破十万,威震江东,智勇兼备,擅长以少击多。",talent:"少量兵力作战攻击buff;降低敌方军队士气;压制敌军冲锋",atk:86,def:82,intel:76},
{name:"周瑜",camp:"东吴",char:"英武、风雅、果断、气量偏狭",desc:"赤壁之战总指挥,一把火奠定三足鼎立,精通水战,战略眼光出众。",talent:"水域作战战力大额加成;火计计策成功率上升;与部分武将存在矛盾事件",atk:78,def:70,intel:91},
{name:"鲁肃",camp:"东吴",char:"宽厚、远见、务实、善于平衡",desc:"东吴战略家,长久坚持联刘抗曹,眼光长远,擅长外交谈判,平衡各方势力。",talent:"外交强;联盟成功率高;提升势力关系",atk:42,def:50,intel:89}
];
// ========== 装备库 ==========
const equipLibrary = [
{id:"spear1",name:"铁枪",type:"武器",atk:8,def:0,intel:0},
{id:"sword1",name:"环首刀",type:"武器",atk:6,def:2,intel:0},
{id:"armor1",name:"皮甲",type:"护甲",atk:0,def:10,intel:0},
{id:"book1",name:"兵书",type:"兵书",atk:0,def:0,intel:12},
{id:"steed1",name:"战马",type:"坐骑",atk:4,def:4,intel:0}
];
// ========== 计略库 ==========
const stratLibrary = [
{id:"fire",name:"火攻",cost:80,desc:"对目标城池发动火攻,降低敌方兵力与城防",requireIntel:80},
{id:"sabotage",name:"谍报破坏",cost:50,desc:"派遣细作,降低目标城池粮草储备",requireIntel:70},
{id:"reward",name:"安抚军心",cost:40,desc:"提升我方城池稳定度,减少补给损耗",requireIntel:60}
];
// ========== 国策随机事件库 ==========
const eventLibrary = [
{title:"流民来投",desc:"大量流民迁入领地,人口+800,粮草-30",effect:{pop:800,grain:-30}},
{title:"丰收之年",desc:"今年风调雨顺,领地粮草大幅增收",effect:{grain:120}},
{title:"粮草灾荒",desc:"局部干旱,粮草减产",effect:{grain:-60}},
{title:"名士自荐",desc:"一名人才慕名前来投奔,武将招募概率临时上升",effect:{recruitBonus:true}}
];
// ========== 剧本配置 ==========
const scriptList = [
{name:"群雄割据",desc:"天下大乱,多势力瓜分地盘",setup:function(gs){
gs.cityList[0].owner="wei";gs.cityList[1].owner="neutral";gs.cityList[2].owner="wei";
gs.cityList[8].owner="player";gs.cityList[6].owner="wu";
}},
{name:"赤壁对峙",desc:"赤壁战后,三足雏形显现",setup:function(gs){
gs.cityList[0].owner="wei";gs.cityList[6].owner="wu";gs.cityList[7].owner="player";gs.cityList[8].owner="player";
}},
{name:"三分天下",desc:"魏蜀吴鼎足而立",setup:function(gs){
gs.cityList[0].owner="wei";gs.cityList[2].owner="wei";gs.cityList[8].owner="player";gs.cityList[6].owner="wu";
}}
];
// ========== 兵种定义 ==========
const troopTypeDef = {infantry:{name:"步兵",atk:10,def:12,cost:6},cavalry:{name:"骑兵",atk:16,def:8,cost:12},archer:{name:"弓兵",atk:14,def:5,cost:9}};
// ========== 城池建筑定义 ==========
const buildingDef = {barn:{name:"粮仓",costGrain:60,costPop:120,effect:"每回合粮草+25"},barracks:{name:"兵营",costGrain:80,costPop:180,effect:"每回合兵力+18"},fort:{name:"城防工事",costGrain:70,costPop:150,effect:"城防+18"}};
// ========== 游戏状态(存档核心,全部字段纳入存档) ==========
let gameState = {
turn:1,
playerFaction:"蜀汉",
selectedCityIndex:null,
vassalList:[],
cityList:[],
heroList:[],
ownedEquip:JSON.parse(JSON.stringify(equipLibrary)),
diplomacy:{wei:{relation:0,ally:false},wu:{relation:0,ally:false}},
log:[],
scriptIndex:0,
troop:{infantry:0,cavalry:0,archer:0},
cityBuildings:{}
};
// ========== 弹窗控制 ==========
function openModal(html){
document.getElementById("modalContent").innerHTML = html;
document.getElementById("modalMask").classList.remove("hide");
}
function closeModal(){
document.getElementById("modalMask").classList.add("hide");
}
// ========== 添加游戏日志 ==========
function addLog(text){
gameState.log.push(`【回合${gameState.turn}】${text}`);
if(gameState.log.length>40) gameState.log.shift();
renderLog();
}
function renderLog(){
const wrap = document.getElementById("logBox");
wrap.innerHTML = gameState.log.map(x=>`<div class="log-item">${x}</div>`).join("");
}
// ========== 初始化城池实例 ==========
function initCities(){
gameState.cityList = [];
mapRawData.forEach((item,idx)=>{
let city = {
idx,
stateName:item.state,
capital:item.capital,
subCities:item.cities,
pass:item.pass,
terrain:item.terrain,
buff:item.buff,
owner:"neutral",
pop:Math.floor(Math.random()*4000)+2000,
grain:Math.floor(Math.random()*200)+80,
soldier:Math.floor(Math.random()*300)+50,
defense:Math.floor(Math.random()*40)+60,
supplyLine:true,
stability:75,
buildings:[],
troop:{infantry:0,cavalry:0,archer:0}
};
gameState.cityList.push(city);
})
}
// ========== 初始化武将实例 ==========
function initHeroes(){
gameState.heroList = [];
heroRawData.forEach(h=>{
let hero = JSON.parse(JSON.stringify(h));
hero.equip = {weapon:null,armor:null,book:null,steed:null};
hero.owner = h.camp==="蜀汉"?"player":h.camp;
hero.hurt = false;
gameState.heroList.push(hero);
})
}
// ========== 补给线连通判定:相邻城池是否属于玩家领地 ==========
function calcSupplyLine(){
//简化相邻索引映射,可后续替换真实地理邻接表
const neighborMap = [
[1,8],[0,2],[1,3],[2,4],[3,5],[4,6],[5,7],[6,8],[7,9],[8,10],[9,11],[10,12],[11]
];
gameState.cityList.forEach((city,idx)=>{
if(city.owner!=="player") return;
let connected = neighborMap[idx].some(n=>gameState.cityList[n] && gameState.cityList[n].owner==="player");
city.supplyLine = connected;
})
}
// ========== 渲染地图城池列表 ==========
function renderMap(){
calcSupplyLine();
const wrap = document.getElementById("cityList");
wrap.innerHTML = "";
gameState.cityList.forEach((city,idx)=>{
let div = document.createElement("div");
div.className = "city-item";
if(city.owner==="player") div.classList.add("occupied-player");
if(city.owner==="wei") div.classList.add("occupied-wei");
if(city.owner==="shu") div.classList.add("occupied-shu");
if(city.owner==="wu") div.classList.add("occupied-wu");
if(gameState.selectedCityIndex===idx) div.classList.add("selected");
let ownerText = {player:"我方",wei:"曹魏",shu:"蜀汉",wu:"东吴",neutral:"无主"}[city.owner];
div.innerHTML = `<b>${city.stateName}</b>|治所:${city.capital}【${ownerText}】<br>人口:${city.pop}|粮草:${city.grain}|兵力:${city.soldier}|城防:${city.defense}<br>补给线:${city.supplyLine?"✅通畅":"❌阻断"}|稳定度:${city.stability}<br>关隘渡口:${city.pass}`;
div.onclick = ()=>selectCity(idx);
wrap.appendChild(div);
})
}
// ========== 选中城池,刷新详情面板 + 建造按钮 ==========
function selectCity(idx){
gameState.selectedCityIndex = idx;
const city = gameState.cityList[idx];
const detailWrap = document.getElementById("detailPanel");
let ownerText = {player:"我方",wei:"曹魏",shu:"蜀汉",wu:"东吴",neutral:"无主"}[city.owner];
let buildBtnHtml = "";
if(city.owner==="player"){
buildBtnHtml = `<br><button class="btn btn-blue" onclick="openBuildPanel(${idx})">城池建造</button>
<button class="btn btn-orange" onclick="setVassal(${idx})">设为附庸藩属</button>`;
}else{
buildBtnHtml = `<br><button class="btn btn-green" onclick="attackCity(${idx})">进攻此城</button>`;
}
detailWrap.innerHTML = `
<div class="stat-row"><span>州名:</span><span>${city.stateName}</span></div>
<div class="stat-row"><span>治所:</span><span>${city.capital}</span></div>
<div class="stat-row"><span>归属:</span><span>${ownerText}</span></div>
<div class="stat-row"><span>人口:</span><span>${city.pop}</span></div>
<div class="stat-row"><span>粮草:</span><span>${city.grain}</span></div>
<div class="stat-row"><span>兵力:</span><span>${city.soldier}</span></div>
<div class="stat-row"><span>城防:</span><span>${city.defense}</span></div>
<div class="stat-row"><span>补给线:</span><span>${city.supplyLine?"✅通畅":"❌阻断"}</span></div>
<div class="stat-row"><span>稳定度:</span><span>${city.stability}</span></div>
<hr>
<p>地形特性:${city.terrain}</p>
<p>地形buff:${city.buff}</p>
${buildBtnHtml}
`;
renderMap();
}
// ========== 渲染武将面板 + 穿戴装备弹窗入口 ==========
function renderHero(){
const wrap = document.getElementById("heroPanel");
wrap.innerHTML = "";
gameState.heroList.filter(h=>h.owner==="player").forEach(h=>{
let card = document.createElement("div");
card.className = "hero-card";
let equipText = [];
if(h.equip.weapon) equipText.push(h.equip.weapon.name);
if(h.equip.armor) equipText.push(h.equip.armor.name);
if(h.equip.book) equipText.push(h.equip.book.name);
if(h.equip.steed) equipText.push(h.equip.steed.name);
card.innerHTML = `<h3>${h.name} ${h.hurt?"【负伤】":""}</h3>
<span class="tag">${h.char}</span>
<p>攻:${h.atk}|防:${h.def}|智:${h.intel}</p>
<p>${h.desc}</p>
<p><b>天赋:</b>${h.talent}</p>
<p>已装备:${equipText.length>0?equipText.join("、"):"无"}</p>
<button class="btn btn-blue" onclick="openEquipPanel('${h.name}')">装配/卸下装备</button>`;
wrap.appendChild(card);
})
}
// ========== 渲染装备库存面板 ==========
function renderEquip(){
const wrap = document.getElementById("equipPanel");
wrap.innerHTML = "";
gameState.ownedEquip.forEach(e=>{
let div = document.createElement("div");
div.className = "equip-slot";
div.innerText = `${e.name}(${e.type}) 攻${e.atk} 防${e.def} 智${e.intel}`;
wrap.appendChild(div);
})
}
// ========== 装备装配弹窗【完整可视化穿戴界面】 ==========
function openEquipPanel(heroName){
const hero = gameState.heroList.find(x=>x.name===heroName);
if(!hero) return;
let html = `<h3>${heroName} 装备管理</h3>`;
const typeMap = {"武器":"weapon","护甲":"armor","兵书":"book","坐骑":"steed"};
for(let [dispType,sysKey] of Object.entries(typeMap)){
html += `<p><b>${dispType}</b>:当前:${hero.equip[sysKey]?.name||"无"}</p>`;
html += `<div>`;
gameState.ownedEquip.filter(e=>e.type===dispType).forEach(e=>{
html += `<button class="btn btn-green" onclick="wearEquip('${heroName}','${e.id}','${sysKey}')">穿戴${e.name}</button>`;
})
if(hero.equip[sysKey]) html += `<button class="btn" onclick="unloadEquip('${heroName}','${sysKey}')">卸下</button>`;
html += `</div>`;
}
html += `<hr><button class="btn" onclick="closeModal()">关闭</button>`;
openModal(html);
}
function wearEquip(heroName,equipId,sysKey){
const hero = gameState.heroList.find(x=>x.name===heroName);
const equip = gameState.ownedEquip.find(x=>x.id===equipId);
if(!hero||!equip) return;
if(hero.equip[sysKey]) gameState.ownedEquip.push(hero.equip[sysKey]);
hero.equip[sysKey] = equip;
gameState.ownedEquip = gameState.ownedEquip.filter(x=>x.id!==equipId);
addLog(`${heroName}穿戴装备【${equip.name}】`);
openEquipPanel(heroName);renderHero();renderEquip();
}
function unloadEquip(heroName,sysKey){
const hero = gameState.heroList.find(x=>x.name===heroName);
if(!hero||!hero.equip[sysKey]) return;
gameState.ownedEquip.push(hero.equip[sysKey]);
hero.equip[sysKey] = null;
addLog(`${heroName}卸下装备`);
openEquipPanel(heroName);renderHero();renderEquip();
}
// ========== 城池建造弹窗 ==========
function openBuildPanel(cityIdx){
const city = gameState.cityList[cityIdx];
let html = `<h3>${city.stateName}|城池建造</h3>`;
Object.entries(buildingDef).forEach(([bid,b])=>{
html += `<div class="event-box">
<b>${b.name}</b><br>消耗:粮草${b.costGrain}|人口${b.costPop}<br>效果:${b.effect}<br>
<button class="btn btn-green" onclick="buildAtCity(${cityIdx},'${bid}')">建造</button>
</div>`;
})
html += `<button class="btn" onclick="closeModal()">关闭</button>`;
openModal(html);
}
function buildAtCity(cityIdx,buildId){
const city = gameState.cityList[cityIdx];
const b = buildingDef[buildId];
if(city.grain < b.costGrain || city.pop < b.costPop){
alert("资源不足,无法建造!");return;
}
city.grain -= b.costGrain;
city.pop -= b.costPop;
city.buildings.push(buildId);
addLog(`${city.stateName}建造【${b.name}】完成`);
selectCity(cityIdx);closeModal();
}
// ========== 下一回合逻辑:资源产出、补给消耗、随机事件、AI行动、藩属贡赋 ==========
function nextTurn(){
gameState.turn++;
//回合资源结算 + 建筑效果 + 补给线判定消耗
gameState.cityList.forEach(city=>{
if(city.owner==="player"){
let supplyCost = city.supplyLine ? 12 : 24;
let grainGain = Math.floor(city.pop/60);
city.buildings.forEach(bid=>{
if(bid==="barn") grainGain +=25;
if(bid==="barracks") city.soldier +=18;
if(bid==="fort") city.defense +=18;
})
city.grain += grainGain - supplyCost;
city.soldier += city.stability>70 ? Math.floor(city.pop/200) : 0;
if(city.grain<0) city.stability -= 5;
}
})
//附庸藩属每回合贡赋
gameState.vassalList.forEach(vIdx=>{
const vc = gameState.cityList[vIdx];
if(vc && vc.owner==="player"){
vc.grain +=15;
addLog(`藩属【${vc.stateName}】上缴贡赋粮草+15`);
}
})
//AI势力自动行动简易逻辑
aiAutoAction();
//随机国策事件
if(Math.random()>0.55){
triggerRandomEvent();
}
//武将随机事件:负伤/投奔
if(Math.random()>0.75) heroRandomEvent();
document.getElementById("turnNum").innerText = gameState.turn;
renderMap();renderHero();renderEquip();renderLog();
addLog(`回合${gameState.turn}结算完成`);
}
// ========== AI势力回合行动 ==========
function aiAutoAction(){
["wei","wu"].forEach(aiFaction=>{
const aiCities = gameState.cityList.filter(c=>c.owner===aiFaction);
if(aiCities.length===0) return;
const target = gameState.cityList.find(c=>c.owner==="neutral");
if(target && Math.random()>0.6){
addLog(`【${aiFaction}】出兵尝试争夺${target.stateName}`);
target.owner = aiFaction;
}
})
}
// ========== 武将随机事件 ==========
function heroRandomEvent(){
const playerHero = gameState.heroList.filter(h=>h.owner==="player");
if(playerHero.length===0) return;
const rh = playerHero[Math.floor(Math.random()*playerHero.length)];
if(Math.random()>0.65){
rh.hurt = true;
addLog(`武将【${rh.name}】意外负伤,战力暂时受损`);
}
}
// ========== 随机国策事件触发 ==========
function triggerRandomEvent(){
const evt = eventLibrary[Math.floor(Math.random()*eventLibrary.length)];
addLog(`【国策事件】${evt.title}:${evt.desc}`);
gameState.cityList.forEach(city=>{
if(city.owner==="player"){
if(evt.effect.pop) city.pop += evt.effect.pop;
if(evt.effect.grain) city.grain = (city.grain||0)+evt.effect.grain;
}
})
}
// ========== 进攻城池简易战斗逻辑 ==========
function attackCity(targetIdx){
const target = gameState.cityList[targetIdx];
const playerCities = gameState.cityList.filter(c=>c.owner==="player");
if(playerCities.length===0) return alert("你没有可出兵的城池!");
let myTotalSoldier = playerCities.reduce((s,c)=>s+c.soldier,0);
let powerMy = myTotalSoldier * 1.1;
let powerEnemy = target.soldier + target.defense*2;
if(powerMy>powerEnemy){
target.owner = "player";
target.soldier = Math.max(0,target.soldier-120);
addLog(`✅ 攻城胜利!${target.stateName}归入我方势力`);
}else{
playerCities[0].soldier = Math.max(0,playerCities[0].soldier-80);
addLog(`❌ 攻城失利,我方兵力受损`);
}
selectCity(targetIdx);
}
// ========== 设置附庸藩属 ==========
function setVassal(idx){
const city = gameState.cityList[idx];
if(gameState.vassalList.includes(idx)) return alert("该城池已经是附庸藩属");
gameState.vassalList.push(idx);
city.stability -= 8;
addLog(`✅ ${city.stateName}设为附庸藩属,稳定度小幅下降,每回合自动收取贡赋`);
selectCity(idx);
}
// ========== 计略面板 + 目标施放交互 ==========
function openStrategyPanel(){
let html = `<h3>📜 计略施放</h3>`;
stratLibrary.forEach(s=>{
html += `<div class="event-box">
<b>${s.name}</b>|消耗${s.cost}|智力门槛${s.requireIntel}<br>${s.desc}<br>
<button class="btn btn-green" onclick="pickTargetForStrat('${s.id}')">选择目标城池施放</button>
</div>`;
})
html += `<button class="btn" onclick="closeModal()">关闭</button>`;
openModal(html);
}
function pickTargetForStrat(stratId){
const strat = stratLibrary.find(x=>x.id===stratId);
if(!strat) return;
openModal(`<h3>选择目标城池施放【${strat.name}】</h3>`+gameState.cityList.map((c,i)=>`<button class="btn btn-orange" onclick="executeStrat(${i},'${stratId}')">${c.stateName}【${{player:"我方",wei:"曹魏",wu:"东吴",neutral:"无主"}[c.owner]}】</button>`).join("")+`<br><button class="btn" onclick="openStrategyPanel()">返回计略列表</button>`);
}
function executeStrat(targetIdx,stratId){
const strat = stratLibrary.find(x=>x.id===stratId);
const targetCity = gameState.cityList[targetIdx];
const myIntelAvg = gameState.heroList.filter(h=>h.owner==="player").reduce((s,h)=>s+h.intel,0)/Math.max(1,gameState.heroList.filter(h=>h.owner==="player").length);
const successRate = Math.min(0.95,Math.max(0.25, (myIntelAvg-strat.requireIntel)/100 +0.5));
if(Math.random() < successRate){
if(stratId==="fire"){
targetCity.soldier = Math.max(0,targetCity.soldier-70);
targetCity.defense = Math.max(0,targetCity.defense-12);
addLog(`✅火攻成功!${targetCity.stateName}兵力、城防受损`);
}else if(stratId==="sabotage"){
targetCity.grain = Math.max(0,targetCity.grain-45);
addLog(`✅谍报破坏成功!${targetCity.stateName}粮草被破坏`);
}else if(stratId==="reward" && targetCity.owner==="player"){
targetCity.stability +=12;
addLog(`✅安抚军心成功!城池稳定度提升`);
}
}else{
addLog(`❌计略【${strat.name}】执行失败,计谋被识破`);
}
closeModal();renderMap();
}
// ========== 完整外交面板:结盟、劝降、停战 ==========
function openDiplomacyPanel(){
let html = `<h3>🤝 外交系统</h3>
<div class="event-box">曹魏|好感:${gameState.diplomacy.wei.relation}|结盟:${gameState.diplomacy.wei.ally?"✅是":"❌否"}<br>
<button class="btn btn-green" onclick="diplomacyAction('wei','ally')">提议结盟</button>
<button class="btn btn-orange" onclick="diplomacyAction('wei','surrender')">劝降</button>
</div>
<div class="event-box">东吴|好感:${gameState.diplomacy.wu.relation}|结盟:${gameState.diplomacy.wu.ally?"✅是":"❌否"}<br>
<button class="btn btn-green" onclick="diplomacyAction('wu','ally')">提议结盟</button>
<button class="btn btn-orange" onclick="diplomacyAction('wu','surrender')">劝降</button>
</div>
<button class="btn" onclick="closeModal()">关闭</button>`;
openModal(html);
}
function diplomacyAction(faction,actType){
const rel = gameState.diplomacy[faction];
if(actType==="ally"){
if(Math.random()>0.45){
rel.ally = true;
rel.relation +=20;
addLog(`✅与【${faction}】结盟成功!`);
}else{
rel.relation -=10;
addLog(`❌【${faction}】拒绝结盟提议,好感下降`);
}
}else if(actType==="surrender"){
if(Math.random()>0.78){
gameState.cityList.forEach(c=>{if(c.owner===faction) c.owner="player";});
addLog(`🎉【${faction}】势力被劝降,领地全部归顺!`);
}else{
rel.relation -=18;
addLog(`❌劝降失败,【${faction}】对你敌意加深`);
}
}
openDiplomacyPanel();renderMap();
}
// ========== 剧本选择弹窗 ==========
function openScriptSelect(){
let html = `<h3>📖 选择开局剧本(会重置游戏进度!)</h3>`;
scriptList.forEach((sc,idx)=>{
html += `<div class="event-box">
<b>${sc.name}</b><br>${sc.desc}<br>
<button class="btn btn-green" onclick="loadScript(${idx})">加载此剧本,重新开局</button>
</div>`;
})
html += `<button class="btn" onclick="closeModal()">关闭</button>`;
openModal(html);
}
function loadScript(scriptIdx){
gameState.scriptIndex = scriptIdx;
gameState.turn = 1;
gameState.vassalList = [];
gameState.log = [];
gameState.diplomacy = {wei:{relation:0,ally:false},wu:{relation:0,ally:false}};
initCities();initHeroes();
scriptList[scriptIdx].setup(gameState);
addLog(`加载剧本【${scriptList[scriptIdx].name}】完成,新游戏开局`);
document.getElementById("turnNum").innerText = gameState.turn;
closeModal();renderMap();renderHero();renderEquip();renderLog();
}
// ========== 国策事件面板 ==========
function openPolicyPanel(){
alert("国策事件面板\n已内置随机事件系统,每回合概率触发\n附庸藩属列表ID:"+gameState.vassalList.join(","));
}
// ========== 存档读档(localStorage,Capacitor APP兼容,完整保存全部新增字段) ==========
function saveGame(){
localStorage.setItem("sanguoSave",JSON.stringify(gameState));
alert("✅ 存档成功|网页/安卓APP双端通用");
}
function loadGame(){
let raw = localStorage.getItem("sanguoSave");
if(!raw) return alert("❌ 未找到存档");
gameState = JSON.parse(raw);
document.getElementById("turnNum").innerText = gameState.turn;
renderMap();renderHero();renderEquip();renderLog();
alert("✅ 读档成功,进度已恢复(剧本、外交、建筑、装备、藩属全部读取)");
}
// ========== Capacitor APP环境检测 & 音频预留接口 ==========
async function checkAppEnv(){
if(window.Capacitor){
console.log("👉 当前运行于 Capacitor 安卓APP环境,音频API预留就绪");
}else{
console.log("👉 当前运行于网页浏览器环境");
}
}
// ========== 游戏初始化 ==========
window.onload = ()=>{
initCities();
initHeroes();
scriptList[0].setup(gameState);
addLog("游戏初始化完成,当前剧本:群雄割据");
renderMap();
renderHero();
renderEquip();
renderLog();
checkAppEnv();
}
</script>
</body>
</html>
Game Source: 汉末三国之君临天下
Creator: ChromeOtter72
Libraries: none
Complexity: complex (647 lines, 32.8 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-mv6engps" to link back to the original. Then publish at arcadelab.ai/publish.