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

387 lines
9.8 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 CharacterData
## 角色数据模型
## 定义角色数据结构和验证函数
# 角色数据字段
const FIELD_ID = "id"
const FIELD_NAME = "name"
const FIELD_OWNER_ID = "owner_id"
const FIELD_POSITION = "position"
const FIELD_IS_ONLINE = "is_online"
const FIELD_APPEARANCE = "appearance"
const FIELD_CREATED_AT = "created_at"
const FIELD_LAST_SEEN = "last_seen"
# 个性化字段
const FIELD_PERSONALITY = "personality"
const FIELD_STATUS = "status"
const FIELD_MOOD = "mood"
const FIELD_ATTRIBUTES = "attributes"
const FIELD_SKILLS = "skills"
const FIELD_ACHIEVEMENTS = "achievements"
const FIELD_LEVEL = "level"
const FIELD_EXPERIENCE = "experience"
# 名称验证规则
const MIN_NAME_LENGTH = 2
const MAX_NAME_LENGTH = 20
## 生成唯一角色 ID
static func generate_id() -> String:
"""
生成唯一的角色 ID使用时间戳 + 随机数)
@return: 唯一 ID 字符串
"""
var timestamp = Time.get_unix_time_from_system()
var random_part = randi()
return "char_%d_%d" % [timestamp, random_part]
## 创建角色数据
static func create(char_name: String, owner_id: String, position: Vector2 = Vector2.ZERO) -> Dictionary:
"""
创建新的角色数据
@param char_name: 角色名称
@param owner_id: 所有者 ID
@param position: 初始位置
@return: 角色数据字典
"""
var now = Time.get_unix_time_from_system()
return {
FIELD_ID: generate_id(),
FIELD_NAME: char_name,
FIELD_OWNER_ID: owner_id,
FIELD_POSITION: {
"x": position.x,
"y": position.y
},
FIELD_IS_ONLINE: true,
FIELD_APPEARANCE: {
"sprite": "character_01",
"color": "#FFFFFF",
"body_color": "#4A90E2",
"head_color": "#F5E6D3",
"hair_color": "#8B4513",
"clothing_color": "#2E8B57"
},
FIELD_PERSONALITY: {
"traits": ["friendly", "curious"],
"bio": "",
"favorite_activity": "exploring"
},
FIELD_STATUS: "active", # active, busy, away, offline
FIELD_MOOD: "neutral", # happy, sad, excited, tired, neutral
FIELD_ATTRIBUTES: {
"charisma": 5,
"intelligence": 5,
"creativity": 5,
"energy": 5
},
FIELD_SKILLS: {
"communication": 1,
"problem_solving": 1,
"leadership": 1,
"collaboration": 1
},
FIELD_ACHIEVEMENTS: [],
FIELD_LEVEL: 1,
FIELD_EXPERIENCE: 0,
FIELD_CREATED_AT: now,
FIELD_LAST_SEEN: now
}
## 验证角色名称
static func validate_name(char_name: String) -> bool:
"""
验证角色名称是否有效
@param char_name: 角色名称
@return: 是否有效
"""
# 检查是否为空或仅包含空白字符
if char_name.strip_edges().is_empty():
return false
# 检查长度
var trimmed_name = char_name.strip_edges()
if trimmed_name.length() < MIN_NAME_LENGTH or trimmed_name.length() > MAX_NAME_LENGTH:
return false
return true
## 验证角色数据完整性
static func validate(data: Dictionary) -> bool:
"""
验证角色数据是否完整且有效
@param data: 角色数据字典
@return: 是否有效
"""
# 检查必需字段
if not data.has(FIELD_ID) or not data[FIELD_ID] is String:
return false
if not data.has(FIELD_NAME) or not data[FIELD_NAME] is String:
return false
if not data.has(FIELD_OWNER_ID) or not data[FIELD_OWNER_ID] is String:
return false
if not data.has(FIELD_POSITION) or not data[FIELD_POSITION] is Dictionary:
return false
if not data.has(FIELD_IS_ONLINE) or not data[FIELD_IS_ONLINE] is bool:
return false
# 验证名称
if not validate_name(data[FIELD_NAME]):
return false
# 验证位置数据
var pos = data[FIELD_POSITION]
if not pos.has("x") or not pos.has("y"):
return false
return true
## 从字典创建 Vector2 位置
static func get_position(data: Dictionary) -> Vector2:
"""
从角色数据中提取位置
@param data: 角色数据字典
@return: Vector2 位置
"""
if data.has(FIELD_POSITION):
var pos = data[FIELD_POSITION]
return Vector2(pos.get("x", 0), pos.get("y", 0))
return Vector2.ZERO
## 更新角色位置
static func set_position(data: Dictionary, position: Vector2) -> void:
"""
更新角色数据中的位置
@param data: 角色数据字典
@param position: 新位置
"""
data[FIELD_POSITION] = {
"x": position.x,
"y": position.y
}
## 更新在线状态
static func set_online_status(data: Dictionary, is_online: bool) -> void:
"""
更新角色在线状态
@param data: 角色数据字典
@param is_online: 是否在线
"""
data[FIELD_IS_ONLINE] = is_online
data[FIELD_LAST_SEEN] = Time.get_unix_time_from_system()
## 序列化为 JSON
static func to_json(data: Dictionary) -> String:
"""
将角色数据序列化为 JSON
@param data: 角色数据字典
@return: JSON 字符串
"""
return JSON.stringify(data)
## 从 JSON 反序列化
static func from_json(json_string: String) -> Dictionary:
"""
从 JSON 反序列化角色数据
@param json_string: JSON 字符串
@return: 角色数据字典,失败返回空字典
"""
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result == OK:
var data = json.data
if validate(data):
return data
else:
push_error("Invalid character data in JSON")
else:
push_error("Failed to parse character JSON")
return {}
## 克隆角色数据
static func clone(data: Dictionary) -> Dictionary:
"""
深度克隆角色数据
@param data: 原始角色数据
@return: 克隆的角色数据
"""
return from_json(to_json(data))
## 个性化相关函数
## 更新角色外观
static func set_appearance(data: Dictionary, appearance: Dictionary) -> void:
"""
更新角色外观
@param data: 角色数据字典
@param appearance: 外观数据
"""
if not data.has(FIELD_APPEARANCE):
data[FIELD_APPEARANCE] = {}
for key in appearance:
data[FIELD_APPEARANCE][key] = appearance[key]
## 设置角色状态
static func set_status(data: Dictionary, status: String) -> void:
"""
设置角色状态
@param data: 角色数据字典
@param status: 状态 (active, busy, away, offline)
"""
var valid_statuses = ["active", "busy", "away", "offline"]
if status in valid_statuses:
data[FIELD_STATUS] = status
## 设置角色心情
static func set_mood(data: Dictionary, mood: String) -> void:
"""
设置角色心情
@param data: 角色数据字典
@param mood: 心情 (happy, sad, excited, tired, neutral)
"""
var valid_moods = ["happy", "sad", "excited", "tired", "neutral"]
if mood in valid_moods:
data[FIELD_MOOD] = mood
## 更新角色属性
static func set_attribute(data: Dictionary, attribute: String, value: int) -> void:
"""
设置角色属性值
@param data: 角色数据字典
@param attribute: 属性名称
@param value: 属性值 (1-10)
"""
if not data.has(FIELD_ATTRIBUTES):
data[FIELD_ATTRIBUTES] = {}
# 限制属性值范围
value = clamp(value, 1, 10)
data[FIELD_ATTRIBUTES][attribute] = value
## 更新角色技能
static func set_skill(data: Dictionary, skill: String, level: int) -> void:
"""
设置角色技能等级
@param data: 角色数据字典
@param skill: 技能名称
@param level: 技能等级 (1-10)
"""
if not data.has(FIELD_SKILLS):
data[FIELD_SKILLS] = {}
# 限制技能等级范围
level = clamp(level, 1, 10)
data[FIELD_SKILLS][skill] = level
## 添加成就
static func add_achievement(data: Dictionary, achievement: Dictionary) -> void:
"""
添加成就
@param data: 角色数据字典
@param achievement: 成就数据 {id, name, description, earned_at}
"""
if not data.has(FIELD_ACHIEVEMENTS):
data[FIELD_ACHIEVEMENTS] = []
# 检查是否已有此成就
for existing in data[FIELD_ACHIEVEMENTS]:
if existing.get("id") == achievement.get("id"):
return # 已有此成就
achievement["earned_at"] = Time.get_unix_time_from_system()
data[FIELD_ACHIEVEMENTS].append(achievement)
## 增加经验值
static func add_experience(data: Dictionary, experience: int) -> bool:
"""
增加经验值,如果升级返回 true
@param data: 角色数据字典
@param experience: 经验值
@return: 是否升级
"""
if not data.has(FIELD_EXPERIENCE):
data[FIELD_EXPERIENCE] = 0
if not data.has(FIELD_LEVEL):
data[FIELD_LEVEL] = 1
data[FIELD_EXPERIENCE] += experience
# 检查是否升级
var current_level = data[FIELD_LEVEL]
var required_exp = get_required_experience(current_level)
if data[FIELD_EXPERIENCE] >= required_exp:
data[FIELD_LEVEL] += 1
data[FIELD_EXPERIENCE] -= required_exp
return true
return false
## 获取升级所需经验值
static func get_required_experience(level: int) -> int:
"""
获取升级到下一级所需的经验值
@param level: 当前等级
@return: 所需经验值
"""
return level * 100 + (level - 1) * 50 # 递增的经验需求
## 获取角色总体评分
static func get_character_score(data: Dictionary) -> int:
"""
计算角色的总体评分
@param data: 角色数据字典
@return: 总体评分
"""
var score = 0
# 等级贡献
score += data.get(FIELD_LEVEL, 1) * 10
# 属性贡献
var attributes = data.get(FIELD_ATTRIBUTES, {})
for value in attributes.values():
score += value
# 技能贡献
var skills = data.get(FIELD_SKILLS, {})
for value in skills.values():
score += value * 2
# 成就贡献
var achievements = data.get(FIELD_ACHIEVEMENTS, [])
score += achievements.size() * 5
return score
## 获取个性化数据摘要
static func get_personality_summary(data: Dictionary) -> String:
"""
获取角色个性化数据的摘要
@param data: 角色数据字典
@return: 个性化摘要文本
"""
var summary = []
# 等级和经验
var level = data.get(FIELD_LEVEL, 1)
var experience = data.get(FIELD_EXPERIENCE, 0)
summary.append("等级 %d (%d 经验)" % [level, experience])
# 状态和心情
var status = data.get(FIELD_STATUS, "active")
var mood = data.get(FIELD_MOOD, "neutral")
summary.append("状态: %s, 心情: %s" % [status, mood])
# 成就数量
var achievements = data.get(FIELD_ACHIEVEMENTS, [])
if achievements.size() > 0:
summary.append("%d 个成就" % achievements.size())
return " | ".join(summary)