diff --git a/src/classes/mutual_action/conversation.py b/src/classes/mutual_action/conversation.py index 9f49df1..dcfecf7 100644 --- a/src/classes/mutual_action/conversation.py +++ b/src/classes/mutual_action/conversation.py @@ -109,7 +109,8 @@ class Conversation(MutualAction): set_event = Event( self.world.month_stamp, f"{target.name} 与 {self.avatar.name} 的关系变为:{relation_display_names.get(rel, str(rel))}", - related_avatars=[self.avatar.id, target.id] + related_avatars=[self.avatar.id, target.id], + is_major=True ) EventHelper.push_pair(set_event, initiator=self.avatar, target=target, to_sidebar_once=True) @@ -122,7 +123,8 @@ class Conversation(MutualAction): cancel_event = Event( self.world.month_stamp, f"{target.name} 与 {self.avatar.name} 取消了关系:{relation_display_names.get(rel, str(rel))}", - related_avatars=[self.avatar.id, target.id] + related_avatars=[self.avatar.id, target.id], + is_major=True ) EventHelper.push_pair(cancel_event, initiator=self.avatar, target=target, to_sidebar_once=True) diff --git a/src/classes/nickname.py b/src/classes/nickname.py index 21ebb3b..e6fcf24 100644 --- a/src/classes/nickname.py +++ b/src/classes/nickname.py @@ -40,8 +40,8 @@ def can_get_nickname(avatar: "Avatar") -> bool: major_threshold = CONFIG.nickname.major_event_threshold minor_threshold = CONFIG.nickname.minor_event_threshold - major_events = em.get_major_events_by_avatar(avatar.id) - minor_events = em.get_minor_events_by_avatar(avatar.id) + major_events = em.get_major_events_by_avatar(avatar.id, limit=major_threshold) + minor_events = em.get_minor_events_by_avatar(avatar.id, limit=minor_threshold) major_count = len(major_events) minor_count = len(minor_events) @@ -115,7 +115,7 @@ async def process_avatar_nickname(avatar: "Avatar") -> Optional[Event]: # 生成事件:角色获得绰号 event = Event( avatar.world.month_stamp, - f"{avatar.name}在修仙界中闯出名号,被人称为'{nickname}'。", + f"{avatar.name}在修仙界中闯出名号,被人称为「{nickname}」。", related_avatars=[avatar.id], is_major=True ) diff --git a/src/sim/load/avatar_load_mixin.py b/src/sim/load/avatar_load_mixin.py index eb11b49..c44db46 100644 --- a/src/sim/load/avatar_load_mixin.py +++ b/src/sim/load/avatar_load_mixin.py @@ -185,5 +185,8 @@ class AvatarLoadMixin: # relations需要在外部单独重建(因为需要所有avatar都加载完成) avatar.relations = {} + # 加载完成后重新计算effects(确保数值正确) + avatar.recalc_effects() + return avatar diff --git a/static/config.yml b/static/config.yml index f000acc..2a814d3 100644 --- a/static/config.yml +++ b/static/config.yml @@ -20,8 +20,8 @@ ai: game: init_npc_num: 6 sect_num: 2 # init_npc_num大于sect_num时,会随机选择sect_num个宗门 - npc_birth_rate_per_month: 0.001 - fortune_probability: 0.001 + npc_birth_rate_per_month: 0.01 + fortune_probability: 0.005 df: ids_separator: ";" @@ -34,8 +34,8 @@ social: minor_event_context_num: 10 # 小事(短期记忆)展示数量 nickname: - major_event_threshold: 10 # 获得绰号需要的长期事件数量 - minor_event_threshold: 50 # 获得绰号需要的短期事件数量 + major_event_threshold: 3 # 获得绰号需要的长期事件数量 + minor_event_threshold: 20 # 获得绰号需要的短期事件数量 save: max_events_to_save: 1000 diff --git a/static/templates/nickname.txt b/static/templates/nickname.txt index 6e47333..92ba753 100644 --- a/static/templates/nickname.txt +++ b/static/templates/nickname.txt @@ -2,7 +2,7 @@ 绰号是修仙界中对一个人物的评价和称谓,要求: 1. 符合修仙世界观,具有仙侠风格 -2. 体现角色的特点、行为、性格或事迹 +2. 可以有多种不同角度,比如角色的性格、行为、事迹、关系、武器、长相、功法、宗门等 3. 简洁有力,朗朗上口、2~5个字 4. 要帅气、有意境、多种多样 diff --git a/web/src/components/game/panels/info/AvatarDetail.vue b/web/src/components/game/panels/info/AvatarDetail.vue index b1116e3..d6ad3ce 100644 --- a/web/src/components/game/panels/info/AvatarDetail.vue +++ b/web/src/components/game/panels/info/AvatarDetail.vue @@ -71,7 +71,7 @@ async function handleClearObjective() {
- + diff --git a/web/src/components/game/panels/info/InfoPanelContainer.vue b/web/src/components/game/panels/info/InfoPanelContainer.vue index 3797f80..7ff980b 100644 --- a/web/src/components/game/panels/info/InfoPanelContainer.vue +++ b/web/src/components/game/panels/info/InfoPanelContainer.vue @@ -26,8 +26,8 @@ const title = computed(() => { }); const subTitle = computed(() => { - if (uiStore.detailData && 'nickname' in uiStore.detailData) { - return uiStore.detailData.nickname; + if (uiStore.detailData && 'nickname' in uiStore.detailData && uiStore.detailData.nickname) { + return `「${uiStore.detailData.nickname}」`; } return ''; }); diff --git a/web/src/stores/world.ts b/web/src/stores/world.ts index a554813..f77454c 100644 --- a/web/src/stores/world.ts +++ b/web/src/stores/world.ts @@ -42,12 +42,10 @@ export const useWorldStore = defineStore('world', () => { if (existing) { // Merge next.set(av.id, { ...existing, ...av } as AvatarSummary); - } else { - // Insert (ensure required fields exist if possible, otherwise cast) - // 在 Tick 中出现的新 Avatar 可能是完整的 - next.set(av.id, av as AvatarSummary); + changed = true; } - changed = true; + // Else: ignore. Do NOT insert new avatars from tick updates, + // as tick data is incomplete (position only) and might be from a stale game state (Race Condition). } if (changed) { @@ -66,9 +64,9 @@ export const useWorldStore = defineStore('world', () => { year: e.year ?? year.value, month: e.month ?? month.value, timestamp: (e.year ?? year.value) * 12 + (e.month ?? month.value), - relatedAvatarIds: e.relatedAvatarIds || [], - isMajor: e.isMajor, - isStory: e.isStory + relatedAvatarIds: e.related_avatar_ids || [], + isMajor: e.is_major, + isStory: e.is_story })); // 排序并保留最新的 N 条 @@ -80,6 +78,8 @@ export const useWorldStore = defineStore('world', () => { } function handleTick(payload: TickPayloadDTO) { + if (!isLoaded.value) return; + setTime(payload.year, payload.month); if (payload.avatars) updateAvatars(payload.avatars); if (payload.events) addEvents(payload.events);