Files
whale-town/scripts/CharacterStatusManager.gd
2025-12-05 19:00:14 +08:00

289 lines
7.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node
class_name CharacterStatusManager
## 角色状态和心情管理器
## 处理角色的状态变化、心情系统和相关UI
# 状态持续时间(秒)
const STATUS_DURATIONS = {
"busy": 300, # 5分钟
"away": 900, # 15分钟
}
# 心情自动变化的触发条件
const MOOD_TRIGGERS = {
"achievement_earned": "happy",
"level_up": "excited",
"long_idle": "tired",
"social_interaction": "happy",
"problem_solved": "excited"
}
# 心情持续时间(秒)
const MOOD_DURATION = 600 # 10分钟
# 当前管理的角色数据
var character_data: Dictionary = {}
var status_timer: Timer
var mood_timer: Timer
# 信号
signal status_changed(old_status: String, new_status: String)
signal mood_changed(old_mood: String, new_mood: String)
signal status_expired(status: String)
func _ready():
"""初始化状态管理器"""
_setup_timers()
## 设置定时器
func _setup_timers():
"""设置状态和心情定时器"""
# 状态定时器
status_timer = Timer.new()
status_timer.one_shot = true
status_timer.timeout.connect(_on_status_timer_timeout)
add_child(status_timer)
# 心情定时器
mood_timer = Timer.new()
mood_timer.one_shot = true
mood_timer.timeout.connect(_on_mood_timer_timeout)
add_child(mood_timer)
## 设置角色数据
func set_character_data(data: Dictionary):
"""
设置要管理的角色数据
@param data: 角色数据字典
"""
character_data = data
# 检查当前状态是否需要定时器
var current_status = data.get(CharacterData.FIELD_STATUS, "active")
if current_status in STATUS_DURATIONS:
var duration = STATUS_DURATIONS[current_status]
status_timer.start(duration)
## 设置角色状态
func set_status(new_status: String, auto_revert: bool = true):
"""
设置角色状态
@param new_status: 新状态
@param auto_revert: 是否自动恢复到active状态
"""
if character_data.is_empty():
push_error("No character data set")
return
var old_status = character_data.get(CharacterData.FIELD_STATUS, "active")
if old_status == new_status:
return
# 更新状态
CharacterData.set_status(character_data, new_status)
status_changed.emit(old_status, new_status)
# 停止现有定时器
status_timer.stop()
# 如果需要自动恢复且状态有持续时间
if auto_revert and new_status in STATUS_DURATIONS:
var duration = STATUS_DURATIONS[new_status]
status_timer.start(duration)
print("Character status changed from %s to %s" % [old_status, new_status])
## 设置角色心情
func set_mood(new_mood: String, duration: float = MOOD_DURATION):
"""
设置角色心情
@param new_mood: 新心情
@param duration: 心情持续时间(秒)
"""
if character_data.is_empty():
push_error("No character data set")
return
var old_mood = character_data.get(CharacterData.FIELD_MOOD, "neutral")
if old_mood == new_mood:
return
# 更新心情
CharacterData.set_mood(character_data, new_mood)
mood_changed.emit(old_mood, new_mood)
# 设置心情恢复定时器
mood_timer.stop()
if new_mood != "neutral" and duration > 0:
mood_timer.start(duration)
print("Character mood changed from %s to %s" % [old_mood, new_mood])
## 触发心情变化
func trigger_mood_change(trigger: String):
"""
根据触发条件改变心情
@param trigger: 触发条件
"""
if trigger in MOOD_TRIGGERS:
var new_mood = MOOD_TRIGGERS[trigger]
set_mood(new_mood)
## 获取当前状态
func get_current_status() -> String:
"""获取当前状态"""
return character_data.get(CharacterData.FIELD_STATUS, "active")
## 获取当前心情
func get_current_mood() -> String:
"""获取当前心情"""
return character_data.get(CharacterData.FIELD_MOOD, "neutral")
## 获取状态显示文本
func get_status_display_text() -> String:
"""获取状态的显示文本"""
var status = get_current_status()
var mood = get_current_mood()
var status_text = ""
match status:
"active":
status_text = "在线"
"busy":
status_text = "忙碌"
"away":
status_text = "离开"
"offline":
status_text = "离线"
_:
status_text = status
var personalization = preload("res://scripts/CharacterPersonalization.gd")
var mood_emoji = personalization.get_mood_emoji(mood)
return "%s %s" % [status_text, mood_emoji]
## 获取状态颜色
func get_status_color() -> Color:
"""获取状态对应的颜色"""
var status = get_current_status()
var personalization = preload("res://scripts/CharacterPersonalization.gd")
return personalization.get_status_color(status)
## 状态定时器超时
func _on_status_timer_timeout():
"""状态定时器超时恢复到active状态"""
var current_status = get_current_status()
set_status("active", false)
status_expired.emit(current_status)
## 心情定时器超时
func _on_mood_timer_timeout():
"""心情定时器超时恢复到neutral心情"""
set_mood("neutral", 0)
## 处理活动事件
func handle_activity_event(event_type: String, _data: Dictionary = {}):
"""
处理角色活动事件,可能触发状态或心情变化
@param event_type: 事件类型
@param _data: 事件数据(暂未使用)
"""
match event_type:
"dialogue_started":
# 开始对话时设为忙碌
set_status("busy")
trigger_mood_change("social_interaction")
"dialogue_ended":
# 对话结束后恢复活跃
set_status("active")
"achievement_earned":
trigger_mood_change("achievement_earned")
"level_up":
trigger_mood_change("level_up")
"idle_too_long":
trigger_mood_change("long_idle")
"problem_solved":
trigger_mood_change("problem_solved")
"manual_away":
# 手动设置离开状态
set_status("away")
"manual_busy":
# 手动设置忙碌状态
set_status("busy")
## 创建状态选择菜单
func create_status_menu() -> PopupMenu:
"""
创建状态选择菜单
@return: PopupMenu节点
"""
var menu = PopupMenu.new()
menu.add_item("🟢 在线", 0)
menu.add_item("🟡 忙碌", 1)
menu.add_item("🟠 离开", 2)
menu.id_pressed.connect(_on_status_menu_selected)
return menu
## 状态菜单选择回调
func _on_status_menu_selected(id: int):
"""状态菜单选择回调"""
match id:
0:
set_status("active", false)
1:
handle_activity_event("manual_busy")
2:
handle_activity_event("manual_away")
## 创建心情选择菜单
func create_mood_menu() -> PopupMenu:
"""
创建心情选择菜单
@return: PopupMenu节点
"""
var menu = PopupMenu.new()
menu.add_item("😊 开心", 0)
menu.add_item("😢 难过", 1)
menu.add_item("🤩 兴奋", 2)
menu.add_item("😴 疲惫", 3)
menu.add_item("😐 平静", 4)
menu.id_pressed.connect(_on_mood_menu_selected)
return menu
## 心情菜单选择回调
func _on_mood_menu_selected(id: int):
"""心情菜单选择回调"""
var moods = ["happy", "sad", "excited", "tired", "neutral"]
if id >= 0 and id < moods.size():
set_mood(moods[id])
## 获取状态统计信息
func get_status_stats() -> Dictionary:
"""
获取状态统计信息
@return: 统计信息字典
"""
return {
"current_status": get_current_status(),
"current_mood": get_current_mood(),
"status_display": get_status_display_text(),
"status_color": get_status_color(),
"has_active_timer": not status_timer.is_stopped(),
"timer_remaining": status_timer.time_left if not status_timer.is_stopped() else 0.0
}