Refactors modifier system to use StatsComponent

Moves modifier logic to utilize a central StatsComponent for managing and applying stat modifications.

This change centralizes stat management and simplifies the application of modifiers, enhancing code maintainability and reducing redundancy.
It also moves modifier files to the correct directory.
This commit is contained in:
Dan Baker 2025-05-07 15:08:11 +01:00
parent 19cc8cb573
commit 9f66ab0a73
21 changed files with 135 additions and 97 deletions

View file

@ -1,28 +1,22 @@
@icon("res://assets/editor/64x64/fc1098.png")
extends Node2D
class_name ModifierManagerTwo
class_name ModifierManager
signal modifier_added(modifier)
signal modifier_removed(modifier)
signal stats_updated()
var stats: StatsComponent
var stats_component: StatsComponent
# Stores all active modifiers
var modifiers: Array[Modifier] = []
# Base stats (before modifiers)
var base_stats: Dictionary = {}
# Final calculated stats
var final_stats: Dictionary = {}
func _ready() -> void:
Log.pr("ModifierManager initialized")
Log.pr("Stats: ", stats)
Log.pr("StatsComponent: ", stats_component)
func set_stats(stats_component: StatsComponent) -> void:
self.stats = stats_component
func set_stats(stats: StatsComponent) -> void:
self.stats_component = stats
func add_modifier(modifier: Modifier) -> void:
modifiers.append(modifier)
@ -42,7 +36,7 @@ func remove_modifier(modifier_id: String) -> void:
func recalculate_stats() -> void:
# Reset stats to base values
final_stats = base_stats.duplicate()
stats_component.reset_stats()
# Sort modifiers by priority
modifiers.sort_custom(func(a, b): return a.priority > b.priority)
@ -67,26 +61,8 @@ func recalculate_stats() -> void:
if modifier.modifier_type == Modifier.ModifierType.CONDITIONAL:
_apply_modifier_stats(modifier)
# Apply caps and floors to stats
_apply_stat_limits()
emit_signal("stats_updated")
func _apply_modifier_stats(modifier: Modifier) -> void:
if modifier.has_method("apply_stats_modification"):
modifier.apply_stats_modification(final_stats, base_stats)
func _apply_stat_limits() -> void:
pass
# Example: Cap fire rate
#if final_stats.has("fire_rate"):
# final_stats.fire_rate = min(final_stats.fire_rate, 20.0) # Max 20 shots per second
# final_stats.fire_rate = max(final_stats.fire_rate, 0.5) # Min 0.5 shots per second
# Example: Cap projectile size
#if final_stats.has("projectile_size"):
# final_stats.projectile_size = min(final_stats.projectile_size, 5.0) # Max 5x normal size
# final_stats.projectile_size = max(final_stats.projectile_size, 0.2) # Min 0.2x normal size
func get_stat(stat_name: String, default_value = 0):
return final_stats.get(stat_name, default_value)
modifier.apply_stats_modification(stats_component)

View file

@ -0,0 +1,12 @@
class_name FireRateAdditive extends Modifier
@export var fire_rate_bonus: float = 1.0 # +1 shot per second
func _init():
id = "fire_rate_additive"
display_name = "Rapid Fire"
description = "Increases fire rate by %0.1f shots per second" % fire_rate_bonus
modifier_type = ModifierType.ADDITIVE
func apply_stats_modification(stats: StatsComponent) -> void:
stats.update_stat("ranged.attack_rate", stats.get_stat("ranged.attack_rate") + fire_rate_bonus)

View file

@ -0,0 +1 @@
uid://cqamoc42g8sam

View file

@ -0,0 +1,13 @@
class_name FireRateMultiplicative extends Modifier
@export var fire_rate_multiplier: float = 1.2 # 20% faster firing
func _init():
id = "fire_rate_multiplicative"
display_name = "Frenzy"
description = "Increases fire rate by %d%%" % ((fire_rate_multiplier - 1.0) * 100)
modifier_type = ModifierType.MULTIPLICATIVE
func apply_stats_modification(final_stats: Dictionary, _base_stats: Dictionary) -> void:
if final_stats.has("fire_rate"):
final_stats.fire_rate *= fire_rate_multiplier

View file

@ -0,0 +1 @@
uid://bbqp2rhogkicu

View file

@ -0,0 +1,31 @@
class_name Modifier extends Resource
enum ModifierType {
ADDITIVE, # Simply adds values (e.g., +5 damage)
MULTIPLICATIVE, # Multiplies by a percentage (e.g., 20% more damage)
OVERRIDE, # Completely replaces the value
CONDITIONAL # Applies under certain conditions
}
@export var id: String
@export var display_name: String
@export var description: String
@export var icon: Texture
@export var rarity: int
@export var modifier_type: ModifierType = ModifierType.ADDITIVE
@export var priority: int = 0 # Higher priority modifiers apply first
# Called when the modifier is added to a weapon or ability
func on_equip(_owner) -> void:
pass
# Called when the modifier is removed
func on_unequip(_owner) -> void:
pass
# Override in child classes for specific modification logic
func modify_projectile(_projectile) -> void:
pass
func modify_ability(_ability) -> void:
pass

View file

@ -0,0 +1 @@
uid://c2vpdeqk0vvrg

View file

@ -0,0 +1,18 @@
class_name PiercingModifier extends Modifier
@export var pierce_count: int = 2
func _init():
id = "piercing"
display_name = "Piercing Shot"
description = "Projectiles pass through %d enemies" % pierce_count
func modify_projectile(projectile):
projectile.pierce_count = pierce_count
projectile.connect("on_hit", _on_projectile_hit)
func _on_projectile_hit(projectile, _target):
projectile.pierce_count -= 1
if projectile.pierce_count <= 0:
projectile.pierce_count = 0
projectile.set_piercing(false)

View file

@ -0,0 +1 @@
uid://b60nonvh7ml2o

View file

@ -0,0 +1,21 @@
class_name ProjectileSizeAdditive extends Modifier
@export var size_increase: float = 0.5 # +50% bigger
func _init():
id = "size_additive"
display_name = "Enlarged Projectiles"
description = "Increases projectile size by %d%%" % (size_increase * 100)
modifier_type = ModifierType.ADDITIVE
func apply_stats_modification(stats: StatsComponent) -> void:
stats.update_stat("ranged.projectile_size", stats.get_stat("ranged.projectile_size") + size_increase)
func modify_projectile(_projectile) -> void:
pass
# This will be called when the projectile is created
# Scale is often handled in the recalculate_stats method, but we can also add visual effects here
#projectile.connect("on_spawned", _on_projectile_spawned)
func _on_projectile_spawned(_projectile) -> void:
pass

View file

@ -0,0 +1 @@
uid://hsl3es4bcvqf

View file

@ -0,0 +1,14 @@
class_name ProjectileSizeMultiplicative extends Modifier
@export var size_multiplier: float = 1.5 # 50% bigger
func _init():
id = "size_multiplicative"
display_name = "Giant Projectiles"
description = "Multiplies projectile size by %0.1fx" % size_multiplier
modifier_type = ModifierType.MULTIPLICATIVE
priority = 10 # Higher priority than the additive version
func apply_stats_modification(final_stats: Dictionary, base_stats: Dictionary) -> void:
if final_stats.has("projectile_size"):
final_stats.projectile_size *= size_multiplier

View file

@ -0,0 +1 @@
uid://bvfir8srnaraa