feat: initial commit

This commit is contained in:
2026-06-23 20:29:02 +08:00
commit ea8f6066c4
217 changed files with 60754 additions and 0 deletions
+212
View File
@@ -0,0 +1,212 @@
"""
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)