130 lines
5.5 KiB
GDScript
130 lines
5.5 KiB
GDScript
class_name StatResolver
|
|
extends RefCounted
|
|
|
|
const JudgementPolicyResource := preload("res://resources/judgement_policy.tres")
|
|
|
|
|
|
static func resolve_damage(base_attack: float, action: Resource, judgement: Variant = {}, buffs: Variant = null, burst: Variant = null) -> float:
|
|
var judgement_dict := _as_dict(judgement)
|
|
var action_mult := _resource_float(action, "damage_mult", 1.0)
|
|
var judgement_mult := _judgement_channel_mult(judgement_dict, &"damage", "damage_mult", 1.0)
|
|
var buff_mult := _provider_mult(buffs, "damage_mult", action)
|
|
var burst_mult := _provider_mult(burst, "damage_mult", action)
|
|
return base_attack * action_mult * judgement_mult * buff_mult * burst_mult
|
|
|
|
|
|
static func resolve_cost(action: Resource, judgement: Variant = {}, provider: Variant = null) -> float:
|
|
var resolved_provider: Variant = provider
|
|
var judgement_dict := _as_dict(judgement)
|
|
if not (judgement is Dictionary) and provider == null:
|
|
resolved_provider = judgement
|
|
var base_cost := _resource_float(action, "base_cost", 0.0)
|
|
var judgement_mult := _judgement_channel_mult(judgement_dict, &"cost", "cost_mult", 1.0)
|
|
var provider_mult := _provider_mult(resolved_provider, "cost_mult", action)
|
|
return maxf(0.0, base_cost * judgement_mult * provider_mult)
|
|
|
|
|
|
static func resolve_reward(action: Resource, judgement: Variant = {}, provider: Variant = null) -> float:
|
|
var judgement_dict := _as_dict(judgement)
|
|
var reward := _resource_float(action, "base_reward", 0.0)
|
|
var judgement_mult := _judgement_channel_mult(judgement_dict, &"reward", "reward_mult", 1.0)
|
|
var provider_mult := _provider_mult(provider, "reward_mult", action)
|
|
return maxf(0.0, reward * judgement_mult * provider_mult)
|
|
|
|
|
|
static func resolve_move(action: Resource, judgement: Variant = {}, burst: Variant = null) -> Vector2:
|
|
var judgement_dict := _as_dict(judgement)
|
|
var judgement_mult := _dict_float(judgement_dict, "move_mult", 1.0)
|
|
var burst_mult := _provider_mult(burst, "move_mult", action)
|
|
return Vector2(
|
|
_resource_float(action, "move_mult_x", 0.0),
|
|
_resource_float(action, "move_mult_y", 0.0)
|
|
) * judgement_mult * burst_mult
|
|
|
|
|
|
static func resolve_knockback(action: Resource, judgement: Variant, base_knockback: Vector2, provider: Variant = null) -> Vector2:
|
|
var judgement_dict := _as_dict(judgement)
|
|
# 击退跟随伤害判定通道(good 0.85 / bad 0.7),可被 judgement 里的显式
|
|
# knockback_mult 覆盖 —— 与 test_combat_manager_resolvers 的契约一致。
|
|
var judgement_mult := _judgement_channel_mult(judgement_dict, &"damage", "knockback_mult", 1.0)
|
|
var provider_mult := _provider_mult(provider, "knockback_mult", action)
|
|
return Vector2(
|
|
base_knockback.x * _resource_float(action, "knockback_mult_x", 0.0),
|
|
base_knockback.y * _resource_float(action, "knockback_mult_y", 0.0)
|
|
) * judgement_mult * provider_mult
|
|
|
|
|
|
static func resolve_action_snapshot(action: Resource, judgement: Variant = {}, provider: Variant = null) -> Dictionary:
|
|
var resolved_provider: Variant = provider
|
|
var judgement_dict := _as_dict(judgement)
|
|
if not (judgement is Dictionary) and provider == null:
|
|
resolved_provider = judgement
|
|
return {
|
|
"cost": resolve_cost(action, judgement_dict, resolved_provider),
|
|
"reward": resolve_reward(action, judgement_dict, resolved_provider),
|
|
"move": resolve_move(action, judgement_dict, resolved_provider),
|
|
"startup_beats": _resolved_stat(action, "startup_beats", resolved_provider, 0.0),
|
|
"active_beats": _resolved_stat(action, "active_beats", resolved_provider, 0.0),
|
|
"recovery_beats": _resolved_stat(action, "recovery_beats", resolved_provider, 0.0),
|
|
}
|
|
|
|
|
|
static func _judgement_channel_mult(judgement: Dictionary, channel: StringName, override_key: String, fallback: float) -> float:
|
|
if _dict_has(judgement, override_key):
|
|
return _dict_float(judgement, override_key, fallback)
|
|
var label := _judgement_label(judgement)
|
|
if label.is_empty() or JudgementPolicyResource == null or not JudgementPolicyResource.has_method("multiplier"):
|
|
return fallback
|
|
return float(JudgementPolicyResource.call("multiplier", label, channel, fallback))
|
|
|
|
|
|
static func _resource_float(resource: Resource, property_name: String, fallback: float) -> float:
|
|
if resource == null:
|
|
return fallback
|
|
var value = resource.get(property_name)
|
|
if value == null:
|
|
return fallback
|
|
return float(value)
|
|
|
|
|
|
static func _dict_float(values: Dictionary, key: String, fallback: float) -> float:
|
|
if values.has(key):
|
|
return float(values[key])
|
|
var name_key := StringName(key)
|
|
if values.has(name_key):
|
|
return float(values[name_key])
|
|
return fallback
|
|
|
|
|
|
static func _dict_has(values: Dictionary, key: String) -> bool:
|
|
return values.has(key) or values.has(StringName(key))
|
|
|
|
|
|
static func _judgement_label(judgement: Dictionary) -> StringName:
|
|
if judgement.has("label"):
|
|
return StringName(str(judgement["label"]).to_lower())
|
|
if judgement.has(&"label"):
|
|
return StringName(str(judgement[&"label"]).to_lower())
|
|
return &""
|
|
|
|
|
|
static func _as_dict(value: Variant) -> Dictionary:
|
|
if value is Dictionary:
|
|
return value
|
|
return {}
|
|
|
|
|
|
static func _resolved_stat(action: Resource, property_name: String, provider: Variant, fallback: float) -> float:
|
|
var base_value := _resource_float(action, property_name, fallback)
|
|
return maxf(0.0, base_value * _provider_mult(provider, property_name, action))
|
|
|
|
|
|
static func _provider_mult(provider: Variant, method_name: String, action: Resource) -> float:
|
|
if provider == null:
|
|
return 1.0
|
|
if provider.has_method(method_name):
|
|
return float(provider.call(method_name, action))
|
|
if provider.has_method("stat_multiplier"):
|
|
return float(provider.call("stat_multiplier", StringName(method_name), action))
|
|
return 1.0
|