Add floating combat text
This commit is contained in:
@@ -6,6 +6,7 @@ const DataCatalogScript := preload("res://scripts/core/data_catalog.gd")
|
||||
signal changed
|
||||
signal log_added(message: String)
|
||||
signal dialogue_requested(lines: Array)
|
||||
signal combat_feedback_requested(unit_id: String, text: String, kind: String)
|
||||
|
||||
const TEAM_PLAYER := "player"
|
||||
const TEAM_ENEMY := "enemy"
|
||||
@@ -848,6 +849,7 @@ func _resolve_skill_support(caster: Dictionary, target: Dictionary, skill_id: St
|
||||
target["name"],
|
||||
_format_support_effects(skill)
|
||||
])
|
||||
_emit_combat_feedback(target, _format_support_popup(skill), "support")
|
||||
return true
|
||||
|
||||
|
||||
@@ -887,6 +889,24 @@ func _format_support_effects(skill: Dictionary) -> String:
|
||||
return _join_strings(parts, ", ")
|
||||
|
||||
|
||||
func _format_support_popup(skill: Dictionary) -> String:
|
||||
var parts := []
|
||||
for effect in skill.get("effects", []):
|
||||
if typeof(effect) != TYPE_DICTIONARY:
|
||||
continue
|
||||
if str(effect.get("type", "")) != "stat_bonus":
|
||||
continue
|
||||
var stat := str(effect.get("stat", ""))
|
||||
var amount := int(effect.get("amount", 0))
|
||||
if not _is_supported_status_stat(stat) or amount == 0:
|
||||
continue
|
||||
var sign := "+" if amount > 0 else ""
|
||||
parts.append("%s %s%d" % [stat.to_upper(), sign, amount])
|
||||
if parts.is_empty():
|
||||
return "Support"
|
||||
return _join_strings(parts, ", ")
|
||||
|
||||
|
||||
func _format_active_status_effects(unit: Dictionary) -> String:
|
||||
var parts := []
|
||||
for effect in _active_status_effects(unit):
|
||||
@@ -1621,11 +1641,13 @@ func _apply_item_effects(user: Dictionary, target: Dictionary, item: Dictionary)
|
||||
if healed > 0:
|
||||
applied = true
|
||||
_emit_log("%s recovers %d HP." % [target["name"], healed])
|
||||
_emit_combat_feedback(target, "+%d HP" % healed, "heal")
|
||||
elif effect_type == "heal_mp":
|
||||
var restored := _apply_item_mp_heal(target, int(effect.get("amount", 0)))
|
||||
if restored > 0:
|
||||
applied = true
|
||||
_emit_log("%s recovers %d MP." % [target["name"], restored])
|
||||
_emit_combat_feedback(target, "+%d MP" % restored, "mp")
|
||||
if not applied:
|
||||
_emit_log("%s has no effect on %s." % [item.get("name", "Item"), target["name"]])
|
||||
return applied
|
||||
@@ -1997,14 +2019,17 @@ func _resolve_attack(attacker: Dictionary, target: Dictionary, is_counter := fal
|
||||
var verb := "counterattacks" if is_counter else "attacks"
|
||||
if rng.randi_range(1, 100) > hit_chance:
|
||||
_emit_log("%s %s %s but misses. Hit %d%%." % [attacker["name"], verb, target["name"], hit_chance])
|
||||
_emit_combat_feedback(target, "MISS", "miss")
|
||||
return {"hit": false, "defeated": false}
|
||||
var damage := calculate_damage(attacker, target)
|
||||
target["hp"] = max(0, int(target["hp"]) - damage)
|
||||
_emit_log("%s %s %s for %d damage. Hit %d%%." % [attacker["name"], verb, target["name"], damage, hit_chance])
|
||||
_emit_combat_feedback(target, "-%d" % damage, "damage")
|
||||
|
||||
if int(target["hp"]) <= 0:
|
||||
target["alive"] = false
|
||||
_emit_log("%s is defeated." % target["name"])
|
||||
_emit_combat_feedback(target, "DOWN", "defeat")
|
||||
return {"hit": true, "defeated": true}
|
||||
return {"hit": true, "defeated": false}
|
||||
|
||||
@@ -2018,10 +2043,12 @@ func _resolve_skill_damage(caster: Dictionary, target: Dictionary, skill: Dictio
|
||||
target["name"],
|
||||
damage
|
||||
])
|
||||
_emit_combat_feedback(target, "-%d" % damage, "damage")
|
||||
|
||||
if int(target["hp"]) <= 0:
|
||||
target["alive"] = false
|
||||
_emit_log("%s is defeated." % target["name"])
|
||||
_emit_combat_feedback(target, "DOWN", "defeat")
|
||||
return true
|
||||
return false
|
||||
|
||||
@@ -2035,6 +2062,7 @@ func _resolve_skill_heal(caster: Dictionary, target: Dictionary, skill: Dictiona
|
||||
target["name"],
|
||||
healed
|
||||
])
|
||||
_emit_combat_feedback(target, "+%d HP" % healed, "heal")
|
||||
return healed
|
||||
|
||||
|
||||
@@ -2060,6 +2088,7 @@ func _level_up(unit: Dictionary) -> void:
|
||||
for stat in ["atk", "def", "int", "agi"]:
|
||||
unit[stat] = int(unit.get(stat, 0)) + _growth_gain(unit, stat, 1)
|
||||
_emit_log("%s reaches Lv.%d." % [unit["name"], unit["level"]])
|
||||
_emit_combat_feedback(unit, "Lv.%d" % int(unit["level"]), "progress")
|
||||
if str(unit.get("team", "")) == TEAM_PLAYER:
|
||||
_record_progression_event({
|
||||
"type": "level_up",
|
||||
@@ -2095,6 +2124,7 @@ func _try_promote_unit(unit: Dictionary) -> void:
|
||||
unit["class_id"] = next_class_id
|
||||
_apply_class_runtime_fields(unit, next_class_id)
|
||||
_emit_log("%s promotes to %s." % [unit["name"], unit["class"]])
|
||||
_emit_combat_feedback(unit, "PROMOTE", "progress")
|
||||
if str(unit.get("team", "")) == TEAM_PLAYER:
|
||||
_record_progression_event({
|
||||
"type": "promotion",
|
||||
@@ -2526,6 +2556,7 @@ func _expire_status_effects_for_team(team: String) -> void:
|
||||
unit["status_effects"] = kept_effects
|
||||
for expired_effect_name in expired_names:
|
||||
_emit_log("%s's %s fades." % [unit["name"], expired_effect_name])
|
||||
_emit_combat_feedback(unit, "FADES", "fade")
|
||||
|
||||
|
||||
func _manhattan(a: Vector2i, b: Vector2i) -> int:
|
||||
@@ -2549,5 +2580,14 @@ func _emit_log(message: String) -> void:
|
||||
log_added.emit(message)
|
||||
|
||||
|
||||
func _emit_combat_feedback(unit: Dictionary, text: String, kind: String) -> void:
|
||||
if unit.is_empty() or text.is_empty():
|
||||
return
|
||||
var unit_id := str(unit.get("id", ""))
|
||||
if unit_id.is_empty():
|
||||
return
|
||||
combat_feedback_requested.emit(unit_id, text, kind)
|
||||
|
||||
|
||||
func _notify_changed() -> void:
|
||||
changed.emit()
|
||||
|
||||
Reference in New Issue
Block a user