0.1.40: 天命系统 + NPC演化增强 + 建筑专精 (P0-1~P1-1)

This commit is contained in:
2026-09-13 14:05:28 +08:00
parent dcd2345192
commit dc970ff13b
12 changed files with 1137 additions and 30 deletions
+8 -1
View File
@@ -8,6 +8,7 @@ import { combatPowerOf } from '../../game/engine/runtime/Systems/combat'
import { FORMATIONS, FormationId } from '../../game/data/formations'
import { buildingById } from '../../game/data/buildings'
import { ModalShell } from './ModalShell'
import { isMandateEvent, mandateEventCategoryName } from '../../game/engine/runtime/Systems/mandate'
const RES_NAME: Record<string, string> = {
lingcao: '灵草', lingkuang: '灵矿', beastcore: '兽核', stones: '灵石',
@@ -63,6 +64,8 @@ export function EventModal() {
// 0.1.39:飞升事件视觉强化——金色辉光标题 + 仙韵边框 + 金边选项
const isAscension = pendingEventId.startsWith('ev-ascension-')
// 0.1.40:天命事件视觉强化——紫金辉光标题 + 天命边框 + 不可回避
const isMandate = isMandateEvent(pendingEventId)
const raidIdx = pendingEventDef.options.findIndex((o) => o.eff.raid || o.eff.tournament)
const squadPool: Character[] =
@@ -99,6 +102,8 @@ export function EventModal() {
}
const dorm = () => {
// 天命不可回避——不可"稍后再议"
if (isMandate) return
// 「稍后再议」:把事件按回队列,不消灭、不误弃
world.requeueEvent(pendingEventId)
closeModal()
@@ -112,7 +117,7 @@ export function EventModal() {
allowOuter={false}
onClose={dorm}
closeLabel="稍后再议"
className={isAscension ? 'modal-ascension' : undefined}
className={isAscension ? 'modal-ascension' : isMandate ? 'modal-mandate' : undefined}
footer={
squadPicking ? (
<>
@@ -129,6 +134,8 @@ export function EventModal() {
{squadSel.length === 0 ? '族中无可战之人' : `出战!(共${squadSel.length}人)`}
</button>
</>
) : isMandate ? (
<div className="dim2" style={{ fontSize: '0.82rem' }}></div>
) : (
<button className="btn" onClick={dorm}></button>
)
+1 -1
View File
@@ -160,7 +160,7 @@ export default function MarketPanel() {
<div className="help-text">
+++
</div>
<h4 className="dim" style={{ margin: '8px 0 4px' }}> {fam.buildings['danfang'] ?? 0} · {Math.round(bonusOf('danfang', 'craftChance', fam.buildings['danfang'] ?? 0) * 100)}%</h4>
<h4 className="dim" style={{ margin: '8px 0 4px' }}> {fam.buildings['danfang'] ?? 0} · {Math.round(bonusOf('danfang', 'craftChance', fam.buildings['danfang'] ?? 0, fam.flag['buildingSpecialty'] as string | undefined) * 100)}%</h4>
<table className="market-table">
<thead>
<tr><th></th><th></th><th></th><th></th><th></th></tr>
+24 -3
View File
@@ -1,5 +1,5 @@
import { useGameStore } from '../store'
import { BUILDINGS, buildingById, listBuildingDefs } from '../../game/data/buildings'
import { BUILDINGS, buildingById, listBuildingDefs, SPECIALTY_MULT } from '../../game/data/buildings'
import { useMemo } from 'react'
export default function TerritoryPanel() {
@@ -32,12 +32,13 @@ export default function TerritoryPanel() {
!!cost &&
fam.stones >= cost.stones &&
fam.inventory['lingkuang'] >= cost.lingkuang
const isSpecialtyBuilding = fam.flag['buildingSpecialty'] === id
return (
<div key={id} className={`bld-card ${built ? '' : 'uc'}`}>
<div key={id} className={`bld-card ${built ? '' : 'uc'} ${isSpecialtyBuilding ? 'bld-specialty' : ''}`}>
<div className="bld-head">
<span className="bld-icon">{def.icon}</span>
<div>
<div>{def.name}</div>
<div>{def.name}{isSpecialtyBuilding && <span className="gold" style={{ marginLeft: 4, fontSize: '0.75rem' }}></span>}</div>
<div className="dim2" style={{ fontSize: '0.75rem' }}>{def.kind === 'produce' ? '产出' : '功效'}</div>
</div>
<span className="bld-lv">{built ? `${level}` : ''}</span>
@@ -95,6 +96,26 @@ export default function TerritoryPanel() {
{world.state.year - ((fam.flag['lastRiteYear'] as number) ?? -9) < 2 ? '(冷却)' : '150灵石'}
</button>
)}
{built && def.extra && Object.keys(def.extra).length > 0 && (
<button
className="btn btn-sm"
style={{ marginLeft: 4, fontSize: '0.7rem' }}
disabled={isSpecialtyBuilding ? false : fam.stones < 200}
title={isSpecialtyBuilding ? '取消专精(免费)' : `设为专精(耗200灵石)· extra 加成 ×${SPECIALTY_MULT}`}
onClick={() => {
if (isSpecialtyBuilding) {
delete fam.flag['buildingSpecialty']
} else {
if (fam.stones < 200) return
fam.stones -= 200
fam.flag['buildingSpecialty'] = id
}
bump()
}}
>
{isSpecialtyBuilding ? '取消专精' : '设为专精'}
</button>
)}
<span className="dim2" style={{ marginLeft: 'auto' }}>{levelLabel(level)}</span>
</>
) : (
+36
View File
@@ -1050,6 +1050,10 @@ html[data-blade] .battle-lines {
color: #4a3d29;
filter: saturate(0.6);
}
.bld-card.bld-specialty { /* 0.1.40 专精建筑 */
border-color: #c9a227;
box-shadow: 0 0 0 1px rgba(201, 162, 39, 0.25), 0 2px 8px rgba(201, 162, 39, 0.1);
}
/* ============================================================
坊市 / 外交 / 探秘
@@ -1942,3 +1946,35 @@ html[data-blade] .battle-lines {
background: linear-gradient(180deg, #3a3018, #241e0d);
border-color: #8a6d2f;
}
/* ---------- 0.1.40 天命叙事视觉强化(紫金辉光) ---------- */
.modal-mandate .modal-title {
color: #6b4c9a;
text-shadow: 0 0 14px rgba(107, 76, 154, 0.45), 0 1px 0 rgba(245, 240, 255, 0.7);
letter-spacing: 6px;
}
.modal-mandate .modal-text {
border-top-color: rgba(107, 76, 154, 0.4);
border-bottom-color: rgba(107, 76, 154, 0.3);
color: #2a1e3d;
}
.modal-mandate .modal-cat {
color: #7a5aa8;
}
.modal-mandate .opt-btn {
border-color: #8b6db5;
background: linear-gradient(180deg, #f8f5fd, #f0ebf8);
}
.modal-mandate .opt-btn:hover {
border-color: #6b4c9a;
background: #f3edfa;
box-shadow: 0 0 0 1px rgba(107, 76, 154, 0.3), inset 0 1px 0 rgba(255, 250, 255, 0.6);
}
.modal-mandate .opt-btn .hint {
color: #6b4c9a;
}
.modal-mandate::before,
.modal-mandate::after {
background: linear-gradient(180deg, #2a1e3d, #1a1228);
border-color: #6b4c9a;
}