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

661 lines
21 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 RelationshipNetwork
## 角色关系网络
## 管理角色之间的复杂关系和社交网络
# 关系类型枚举
enum RelationshipType {
FRIEND, # 好友
CLOSE_FRIEND, # 密友
ACQUAINTANCE, # 熟人
COLLEAGUE, # 同事
MENTOR, # 导师
STUDENT, # 学生
RIVAL, # 竞争对手
NEUTRAL, # 中性
DISLIKE # 不喜欢
}
# 关系数据结构
class Relationship:
var from_character: String
var to_character: String
var relationship_type: RelationshipType
var strength: float = 0.0 # 关系强度 -100 到 100
var trust_level: float = 0.0 # 信任度 0 到 100
var interaction_history: Array[Dictionary] = []
var shared_experiences: Array[String] = []
var created_at: float
var last_updated: float
var tags: Array[String] = [] # 关系标签
func _init(from_char: String, to_char: String, rel_type: RelationshipType = RelationshipType.NEUTRAL):
from_character = from_char
to_character = to_char
relationship_type = rel_type
created_at = Time.get_unix_time_from_system()
last_updated = created_at
strength = _get_default_strength(rel_type)
trust_level = _get_default_trust(rel_type)
func _get_default_strength(rel_type: RelationshipType) -> float:
match rel_type:
RelationshipType.FRIEND: return 30.0
RelationshipType.CLOSE_FRIEND: return 60.0
RelationshipType.ACQUAINTANCE: return 10.0
RelationshipType.COLLEAGUE: return 20.0
RelationshipType.MENTOR: return 40.0
RelationshipType.STUDENT: return 25.0
RelationshipType.RIVAL: return -20.0
RelationshipType.DISLIKE: return -40.0
_: return 0.0
func _get_default_trust(rel_type: RelationshipType) -> float:
match rel_type:
RelationshipType.FRIEND: return 50.0
RelationshipType.CLOSE_FRIEND: return 80.0
RelationshipType.ACQUAINTANCE: return 20.0
RelationshipType.COLLEAGUE: return 40.0
RelationshipType.MENTOR: return 70.0
RelationshipType.STUDENT: return 30.0
RelationshipType.RIVAL: return 10.0
RelationshipType.DISLIKE: return 5.0
_: return 25.0
# 网络数据存储
var relationships: Dictionary = {} # "from_id:to_id" -> Relationship
var character_connections: Dictionary = {} # character_id -> Array[character_id]
var relationship_groups: Dictionary = {} # group_name -> Array[character_id]
var influence_scores: Dictionary = {} # character_id -> float
# 数据持久化
var network_file_path: String = "user://relationship_network.json"
# 信号
signal relationship_created(from_character: String, to_character: String, relationship_type: RelationshipType)
signal relationship_updated(from_character: String, to_character: String, old_strength: float, new_strength: float)
signal relationship_type_changed(from_character: String, to_character: String, old_type: RelationshipType, new_type: RelationshipType)
signal influence_score_changed(character_id: String, old_score: float, new_score: float)
signal group_formed(group_name: String, members: Array[String])
signal group_disbanded(group_name: String)
func _ready():
"""初始化关系网络"""
load_network_data()
print("RelationshipNetwork initialized")
## 创建或更新关系
func create_relationship(from_character: String, to_character: String, rel_type: RelationshipType = RelationshipType.NEUTRAL) -> bool:
"""
创建或更新角色之间的关系
@param from_character: 源角色ID
@param to_character: 目标角色ID
@param rel_type: 关系类型
@return: 是否成功创建/更新
"""
if from_character == to_character:
print("Cannot create relationship with self")
return false
var relationship_key = _get_relationship_key(from_character, to_character)
var existing_relationship = relationships.get(relationship_key)
if existing_relationship:
# 更新现有关系
var old_type = existing_relationship.relationship_type
existing_relationship.relationship_type = rel_type
existing_relationship.strength = existing_relationship._get_default_strength(rel_type)
existing_relationship.trust_level = existing_relationship._get_default_trust(rel_type)
existing_relationship.last_updated = Time.get_unix_time_from_system()
relationship_type_changed.emit(from_character, to_character, old_type, rel_type)
print("Relationship updated: ", from_character, " -> ", to_character, " (", RelationshipType.keys()[rel_type], ")")
else:
# 创建新关系
var relationship = Relationship.new(from_character, to_character, rel_type)
relationships[relationship_key] = relationship
# 更新连接索引
_add_connection(from_character, to_character)
relationship_created.emit(from_character, to_character, rel_type)
print("Relationship created: ", from_character, " -> ", to_character, " (", RelationshipType.keys()[rel_type], ")")
# 重新计算影响力分数
_recalculate_influence_scores()
# 保存数据
save_network_data()
return true
## 记录互动
func record_interaction(from_character: String, to_character: String, interaction_type: String, data: Dictionary = {}) -> void:
"""
记录角色之间的互动
@param from_character: 源角色ID
@param to_character: 目标角色ID
@param interaction_type: 互动类型
@param data: 互动数据
"""
var relationship_key = _get_relationship_key(from_character, to_character)
var relationship = relationships.get(relationship_key)
if not relationship:
# 如果关系不存在,创建一个中性关系
create_relationship(from_character, to_character, RelationshipType.NEUTRAL)
relationship = relationships[relationship_key]
# 记录互动
var interaction_record = {
"type": interaction_type,
"timestamp": Time.get_unix_time_from_system(),
"data": data
}
relationship.interaction_history.append(interaction_record)
relationship.last_updated = interaction_record.timestamp
# 限制历史记录长度
if relationship.interaction_history.size() > 100:
relationship.interaction_history.pop_front()
# 根据互动类型调整关系强度
_adjust_relationship_strength(relationship, interaction_type, data)
# 保存数据
save_network_data()
## 调整关系强度
func _adjust_relationship_strength(relationship: Relationship, interaction_type: String, _data: Dictionary) -> void:
"""
根据互动类型调整关系强度
@param relationship: 关系对象
@param interaction_type: 互动类型
@param _data: 互动数据 (暂未使用)
"""
var old_strength = relationship.strength
var strength_change = 0.0
var trust_change = 0.0
match interaction_type:
"chat":
strength_change = 1.0
trust_change = 0.5
"private_chat":
strength_change = 2.0
trust_change = 1.0
"group_activity":
strength_change = 1.5
trust_change = 0.8
"help_given":
strength_change = 5.0
trust_change = 3.0
"help_received":
strength_change = 3.0
trust_change = 2.0
"conflict":
strength_change = -3.0
trust_change = -2.0
"collaboration":
strength_change = 4.0
trust_change = 2.5
"gift_given":
strength_change = 3.0
trust_change = 1.5
"shared_achievement":
strength_change = 6.0
trust_change = 3.0
_:
strength_change = 0.5
# 应用变化
relationship.strength = clamp(relationship.strength + strength_change, -100.0, 100.0)
relationship.trust_level = clamp(relationship.trust_level + trust_change, 0.0, 100.0)
# 检查关系类型是否需要更新
_check_relationship_type_change(relationship)
# 发射信号
if abs(relationship.strength - old_strength) > 0.1:
relationship_updated.emit(relationship.from_character, relationship.to_character, old_strength, relationship.strength)
## 检查关系类型变化
func _check_relationship_type_change(relationship: Relationship) -> void:
"""
根据关系强度检查是否需要改变关系类型
@param relationship: 关系对象
"""
var old_type = relationship.relationship_type
var new_type = old_type
# 根据强度和信任度确定新的关系类型
if relationship.strength >= 70 and relationship.trust_level >= 70:
new_type = RelationshipType.CLOSE_FRIEND
elif relationship.strength >= 40 and relationship.trust_level >= 50:
new_type = RelationshipType.FRIEND
elif relationship.strength >= 15:
new_type = RelationshipType.ACQUAINTANCE
elif relationship.strength <= -30:
new_type = RelationshipType.DISLIKE
elif relationship.strength <= -10:
new_type = RelationshipType.RIVAL
else:
new_type = RelationshipType.NEUTRAL
# 如果类型发生变化,更新并发射信号
if new_type != old_type:
relationship.relationship_type = new_type
relationship_type_changed.emit(relationship.from_character, relationship.to_character, old_type, new_type)
print("Relationship type changed: ", relationship.from_character, " -> ", relationship.to_character,
" (", RelationshipType.keys()[old_type], " -> ", RelationshipType.keys()[new_type], ")")
## 获取关系信息
func get_relationship(from_character: String, to_character: String) -> Dictionary:
"""
获取两个角色之间的关系信息
@param from_character: 源角色ID
@param to_character: 目标角色ID
@return: 关系信息字典
"""
var relationship_key = _get_relationship_key(from_character, to_character)
var relationship = relationships.get(relationship_key)
if not relationship:
return {}
return {
"from_character": relationship.from_character,
"to_character": relationship.to_character,
"type": relationship.relationship_type,
"type_name": RelationshipType.keys()[relationship.relationship_type],
"strength": relationship.strength,
"trust_level": relationship.trust_level,
"interaction_count": relationship.interaction_history.size(),
"shared_experiences": relationship.shared_experiences.duplicate(),
"created_at": relationship.created_at,
"last_updated": relationship.last_updated,
"tags": relationship.tags.duplicate()
}
## 获取角色的所有关系
func get_character_relationships(character_id: String) -> Array[Dictionary]:
"""
获取指定角色的所有关系
@param character_id: 角色ID
@return: 关系信息数组
"""
var character_relationships = []
for relationship_key in relationships:
var relationship = relationships[relationship_key]
if relationship.from_character == character_id:
character_relationships.append(get_relationship(relationship.from_character, relationship.to_character))
# 按关系强度排序
character_relationships.sort_custom(func(a, b): return a.strength > b.strength)
return character_relationships
## 获取最强关系
func get_strongest_relationships(character_id: String, limit: int = 5) -> Array[Dictionary]:
"""
获取指定角色的最强关系
@param character_id: 角色ID
@param limit: 限制返回数量
@return: 关系信息数组
"""
var all_relationships = get_character_relationships(character_id)
if limit <= 0 or limit >= all_relationships.size():
return all_relationships
return all_relationships.slice(0, limit)
## 查找共同好友
func find_mutual_connections(character1: String, character2: String) -> Array[String]:
"""
查找两个角色的共同好友
@param character1: 角色1 ID
@param character2: 角色2 ID
@return: 共同好友ID数组
"""
var connections1 = character_connections.get(character1, [])
var connections2 = character_connections.get(character2, [])
var mutual = []
for connection in connections1:
if connection in connections2:
mutual.append(connection)
return mutual
## 计算关系路径
func find_relationship_path(from_character: String, to_character: String, max_depth: int = 3) -> Array[String]:
"""
查找两个角色之间的关系路径
@param from_character: 源角色ID
@param to_character: 目标角色ID
@param max_depth: 最大搜索深度
@return: 关系路径角色ID数组
"""
if from_character == to_character:
return [from_character]
# 使用广度优先搜索
var queue = [[from_character]]
var visited = {from_character: true}
while queue.size() > 0:
var path = queue.pop_front()
var current = path[-1]
if path.size() > max_depth:
continue
var connections = character_connections.get(current, [])
for connection in connections:
if connection == to_character:
path.append(connection)
return path
if not visited.has(connection):
visited[connection] = true
var new_path = path.duplicate()
new_path.append(connection)
queue.append(new_path)
return [] # 没有找到路径
## 创建关系群组
func create_relationship_group(group_name: String, members: Array[String]) -> bool:
"""
创建关系群组
@param group_name: 群组名称
@param members: 成员ID数组
@return: 是否成功创建
"""
if relationship_groups.has(group_name):
print("Group already exists: ", group_name)
return false
if members.size() < 2:
print("Group must have at least 2 members")
return false
relationship_groups[group_name] = members.duplicate()
# 为群组成员之间创建或加强关系
for i in range(members.size()):
for j in range(i + 1, members.size()):
var member1 = members[i]
var member2 = members[j]
# 记录群组活动互动
record_interaction(member1, member2, "group_activity", {"group": group_name})
record_interaction(member2, member1, "group_activity", {"group": group_name})
# 保存数据
save_network_data()
# 发射信号
group_formed.emit(group_name, members)
print("Relationship group created: ", group_name, " with ", members.size(), " members")
return true
## 解散关系群组
func disband_relationship_group(group_name: String) -> bool:
"""
解散关系群组
@param group_name: 群组名称
@return: 是否成功解散
"""
if not relationship_groups.has(group_name):
print("Group not found: ", group_name)
return false
relationship_groups.erase(group_name)
# 保存数据
save_network_data()
# 发射信号
group_disbanded.emit(group_name)
print("Relationship group disbanded: ", group_name)
return true
## 计算影响力分数
func _recalculate_influence_scores() -> void:
"""重新计算所有角色的影响力分数"""
var new_scores = {}
# 为每个角色计算影响力分数
for character_id in character_connections:
var score = _calculate_influence_score(character_id)
var old_score = influence_scores.get(character_id, 0.0)
new_scores[character_id] = score
if abs(score - old_score) > 0.1:
influence_score_changed.emit(character_id, old_score, score)
influence_scores = new_scores
## 计算单个角色的影响力分数
func _calculate_influence_score(character_id: String) -> float:
"""
计算角色的影响力分数
@param character_id: 角色ID
@return: 影响力分数
"""
var score = 0.0
var connections = character_connections.get(character_id, [])
# 基础分数:连接数量
score += connections.size() * 10.0
# 关系质量加成
for connection in connections:
var relationship_key = _get_relationship_key(character_id, connection)
var relationship = relationships.get(relationship_key)
if relationship:
# 根据关系强度和类型加分
score += relationship.strength * 0.5
match relationship.relationship_type:
RelationshipType.CLOSE_FRIEND:
score += 20.0
RelationshipType.FRIEND:
score += 15.0
RelationshipType.MENTOR:
score += 25.0
RelationshipType.COLLEAGUE:
score += 10.0
# 群组参与加成
for group_name in relationship_groups:
var members = relationship_groups[group_name]
if character_id in members:
score += members.size() * 5.0
return score
## 获取影响力排行
func get_influence_ranking(limit: int = 10) -> Array[Dictionary]:
"""
获取影响力排行榜
@param limit: 限制返回数量
@return: 排行信息数组
"""
var ranking = []
for character_id in influence_scores:
ranking.append({
"character_id": character_id,
"influence_score": influence_scores[character_id]
})
# 按影响力分数排序
ranking.sort_custom(func(a, b): return a.influence_score > b.influence_score)
if limit > 0 and limit < ranking.size():
ranking = ranking.slice(0, limit)
return ranking
## 添加连接
func _add_connection(from_character: String, to_character: String) -> void:
"""
添加角色连接到索引
@param from_character: 源角色ID
@param to_character: 目标角色ID
"""
if not character_connections.has(from_character):
character_connections[from_character] = []
var connections = character_connections[from_character]
if not to_character in connections:
connections.append(to_character)
## 获取关系键
func _get_relationship_key(from_character: String, to_character: String) -> String:
"""
生成关系键(确保一致性)
@param from_character: 源角色ID
@param to_character: 目标角色ID
@return: 关系键
"""
return from_character + ":" + to_character
## 保存网络数据
func save_network_data() -> void:
"""保存关系网络数据到本地文件"""
var data = {
"relationships": {},
"character_connections": character_connections,
"relationship_groups": relationship_groups,
"influence_scores": influence_scores
}
# 序列化关系数据
for relationship_key in relationships:
var relationship = relationships[relationship_key]
data.relationships[relationship_key] = {
"from_character": relationship.from_character,
"to_character": relationship.to_character,
"relationship_type": relationship.relationship_type,
"strength": relationship.strength,
"trust_level": relationship.trust_level,
"interaction_history": relationship.interaction_history,
"shared_experiences": relationship.shared_experiences,
"created_at": relationship.created_at,
"last_updated": relationship.last_updated,
"tags": relationship.tags
}
var file = FileAccess.open(network_file_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(data)
file.store_string(json_string)
file.close()
print("Relationship network data saved")
else:
print("Failed to save relationship network data")
## 加载网络数据
func load_network_data() -> void:
"""从本地文件加载关系网络数据"""
if not FileAccess.file_exists(network_file_path):
print("No relationship network data file found, starting fresh")
return
var file = FileAccess.open(network_file_path, FileAccess.READ)
if file:
var json_string = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result == OK:
var data = json.data
# 加载关系数据
if data.has("relationships"):
for relationship_key in data.relationships:
var rel_data = data.relationships[relationship_key]
var relationship = Relationship.new(
rel_data.get("from_character", ""),
rel_data.get("to_character", ""),
rel_data.get("relationship_type", RelationshipType.NEUTRAL)
)
relationship.strength = rel_data.get("strength", 0.0)
relationship.trust_level = rel_data.get("trust_level", 0.0)
# 正确处理类型化数组的赋值
var history_data = rel_data.get("interaction_history", [])
relationship.interaction_history.clear()
for item in history_data:
if item is Dictionary:
relationship.interaction_history.append(item)
var experiences_data = rel_data.get("shared_experiences", [])
relationship.shared_experiences.clear()
for item in experiences_data:
if item is String:
relationship.shared_experiences.append(item)
var tags_data = rel_data.get("tags", [])
relationship.tags.clear()
for item in tags_data:
if item is String:
relationship.tags.append(item)
relationship.created_at = rel_data.get("created_at", Time.get_unix_time_from_system())
relationship.last_updated = rel_data.get("last_updated", relationship.created_at)
relationships[relationship_key] = relationship
# 加载连接索引
if data.has("character_connections"):
character_connections = data.character_connections
# 加载群组数据
if data.has("relationship_groups"):
relationship_groups = data.relationship_groups
# 加载影响力分数
if data.has("influence_scores"):
influence_scores = data.influence_scores
print("Relationship network data loaded: ", relationships.size(), " relationships, ", relationship_groups.size(), " groups")
else:
print("Failed to parse relationship network data JSON")
else:
print("Failed to open relationship network data file")
## 获取统计信息
func get_statistics() -> Dictionary:
"""
获取关系网络统计信息
@return: 统计信息字典
"""
var type_counts = {}
var total_interactions = 0
for relationship_key in relationships:
var relationship = relationships[relationship_key]
var type_name = RelationshipType.keys()[relationship.relationship_type]
type_counts[type_name] = type_counts.get(type_name, 0) + 1
total_interactions += relationship.interaction_history.size()
return {
"total_relationships": relationships.size(),
"total_characters": character_connections.size(),
"total_groups": relationship_groups.size(),
"total_interactions": total_interactions,
"relationship_types": type_counts,
"average_connections": float(relationships.size()) / max(character_connections.size(), 1)
}