""" Ledger (动态资产与负债账本) NovelMaster Core Engine - 状态管理器 管理角色资产、负债、Hook/Cool-point 追踪 """ from dataclasses import dataclass, field from typing import List, Dict, Set, Optional, Any from enum import Enum import time class AssetType(Enum): SKILL = "skill" ITEM = "item" RELATIONSHIP = "relationship" STATUS = "status" KNOWLEDGE = "knowledge" POWER = "power" class LiabilityType(Enum): DEBT = "debt" PROMISE = "promise" UNRESOLVED_CONFLICT = "unresolved_conflict" SECRET = "secret" WEAKNESS = "weakness" @dataclass class Asset: """资产""" id: str type: AssetType name: str description: str value: int # 1-100 acquired_at_tick: int owner_id: str tags: List[str] = field(default_factory=list) @dataclass class Liability: """负债""" id: str type: LiabilityType name: str description: str severity: int # 1-100 created_at_tick: int due_tick: Optional[int] = None creditor_id: Optional[str] = None tags: List[str] = field(default_factory=list) @dataclass class LedgerEntry: """账本条目""" asset: Optional[Asset] = None liability: Optional[Liability] = None delta: float = 0 reason: str = "" tick: int = 0 @dataclass class CharacterLedger: """角色账本""" character_id: str assets: Dict[str, Asset] = field(default_factory=dict) liabilities: Dict[str, Liability] = field(default_factory=dict) history: List[LedgerEntry] = field(default_factory=list) class HookType(Enum): SETUP = "setup" BUILDUP = "buildup" CLIFFHANGER = "cliffhanger" @dataclass class Hook: """钩子""" id: str type: HookType description: str chapter_introduced: int tension_weight: int # 1-100 resolved: bool = False resolution_chapter: Optional[int] = None @dataclass class CoolPoint: """爽点""" id: str type: str # payoff, subversion, escalation description: str chapter_delivered: int satisfaction_weight: int # 1-100 def create_asset( asset_id: str, asset_type: AssetType, name: str, value: int, owner_id: str, description: str = "" ) -> Asset: """创建资产""" return Asset( id=asset_id, type=asset_type, name=name, description=description, value=max(1, min(100, value)), acquired_at_tick=0, owner_id=owner_id, tags=[] ) def create_liability( liability_id: str, liability_type: LiabilityType, name: str, severity: int, description: str = "" ) -> Liability: """创建负债""" return Liability( id=liability_id, type=liability_type, name=name, description=description, severity=max(1, min(100, severity)), created_at_tick=0, tags=[] ) def calculate_net_worth(ledger: CharacterLedger) -> int: """计算角色净值""" asset_value = sum(asset.value for asset in ledger.assets.values()) liability_value = sum(liab.severity for liab in ledger.liabilities.values()) return asset_value - liability_value def add_hook(hooks: List[Hook], hook: Hook) -> List[Hook]: """添加钩子""" return [*hooks, hook] def add_cool_point(cool_points: List[CoolPoint], cool_point: CoolPoint) -> List[CoolPoint]: """添加爽点""" return [*cool_points, cool_point] def calculate_hook_pressure(hooks: List[Hook]) -> int: """计算钩子压强""" unresolved = [h for h in hooks if not h.resolved] return sum(h.tension_weight for h in unresolved) def resolve_hook(hooks: List[Hook], hook_id: str, resolution_chapter: int) -> List[Hook]: """解决钩子""" return [ {**hook.__dict__, "resolved": True, "resolution_chapter": resolution_chapter} if hook.id == hook_id else hook for hook in hooks ] def check_genesis_compatibility(asset: Asset, ethical_inversion: Dict[str, Any]) -> float: """检查资产与创世契约的兼容性""" incompatible_norms = ethical_inversion.get("inverted_norms", []) # 简单检查:资产名称是否与反转的道德规范冲突 for norm in incompatible_norms: if norm.lower() in asset.name.lower(): return 0.3 # 低兼容 return 1.0 # 完全兼容 @dataclass class HooksPool: """钩子池""" hooks: List[Hook] = field(default_factory=list) cool_points: List[CoolPoint] = field(default_factory=list) def add_hook(self, hook: Hook) -> None: self.hooks.append(hook) def resolve_hook(self, hook_id: str, chapter: int) -> bool: for h in self.hooks: if h.id == hook_id: h.resolved = True h.resolution_chapter = chapter return True return False @property def pressure(self) -> int: return calculate_hook_pressure(self.hooks) @property def unresolved_count(self) -> int: return sum(1 for h in self.hooks if not h.resolved)