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,13 +0,0 @@
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(final_stats: Dictionary, _base_stats: Dictionary) -> void:
if final_stats.has("fire_rate"):
final_stats.fire_rate += fire_rate_bonus

View file

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

View file

@ -1,13 +0,0 @@
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

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

View file

@ -1,31 +0,0 @@
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

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

View file

@ -1,18 +0,0 @@
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

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

View file

@ -1,25 +0,0 @@
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(final_stats: Dictionary, base_stats: Dictionary) -> void:
if final_stats.has("projectile_size"):
final_stats.projectile_size += size_increase
func modify_projectile(projectile) -> void:
# 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):
# Add a trail effect for larger projectiles
if projectile.scale.x > 1.2:
pass
#var trail = preload("res://scenes/projectile_trail.tscn").instantiate()
#projectile.add_child(trail)

View file

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

View file

@ -1,14 +0,0 @@
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

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

View file

@ -1,4 +1,4 @@
class_name ModifierManager extends Node
class_name ModifierManagerOLD extends Node
signal modifier_added(modifier)
signal modifier_removed(modifier)

View file

@ -5,7 +5,6 @@ extends CharacterBody2D
@export var ranged: RangedWeaponComponent
@export var melee: MeleeWeaponComponent
var weapon: RangedWeapon
var movement: PlayerMovement
var combat: PlayerCombat
@ -15,7 +14,6 @@ var last_direction = Vector2.DOWN
@onready var animated_sprite = $PlayerSprite
func _ready():
weapon = $RangedWeapon
combat = PlayerCombat.new()
movement = PlayerMovement.new()
@ -27,14 +25,14 @@ func _ready():
combat.animated_sprite = animated_sprite
Log.pr("Adding projectile size additive modifier")
#weapon.add_modifier(ProjectileSizeAdditive.new())
Log.pr(weapon.stats.get_stat("projectile_size")) # Size is now 1.0 + 0.5 = 1.5
ranged.add_modifier(ProjectileSizeAdditive.new())
#Log.pr(weapon.stats.get_stat("projectile_size")) # Size is now 1.0 + 0.5 = 1.5
# Size is now 1.0 + 0.5 = 1.5
# Add the multiplicative size modifier (1.5x multiplier)
Log.pr("Adding projectile size multiplicative modifier")
#weapon.add_modifier(ProjectileSizeMultiplicative.new())
Log.pr(weapon.stats.get_stat("projectile_size"))
#Log.pr(weapon.stats.get_stat("projectile_size"))
# Size is now 1.5 * 1.5 = 2.25
# Add another additive size modifier (+0.7 or 70% increase)
@ -42,9 +40,9 @@ func _ready():
var another_size_mod = ProjectileSizeAdditive.new()
another_size_mod.size_increase = 0.7
#weapon.add_modifier(another_size_mod)
Log.pr(weapon.stats.get_stat("projectile_size"))
#Log.pr(weapon.stats.get_stat("projectile_size"))
#weapon.add_modifier(FireRateAdditive.new())
ranged.add_modifier(FireRateAdditive.new())
func _physics_process(delta):

View file

@ -11,7 +11,7 @@ func process(_delta):
var direction = mouse_position - player_position
var normalized_direction = direction.normalized()
player.weapon.fire(normalized_direction, mouse_position)
player.ranged.fire(normalized_direction, mouse_position)
# Update animation
#update_animation()

View file

@ -17,15 +17,14 @@ var base_stats = {
}
# Components
var stats: ModifierManager
#var stats: ModifierManager
var can_fire: bool = true
var fire_timer: Timer
func _init() -> void:
stats = ModifierManager.new(base_stats)
Log.pr(stats)
add_child(stats)
#stats = ModifierManager.new(base_stats)
#Log.pr(stats)
#add_child(stats)
# Setup fire timer
fire_timer = Timer.new()
add_child(fire_timer)
@ -34,7 +33,7 @@ func _init() -> void:
projectile_scene = preload("res://assets/projectiles/projectile_lightning.tscn")
func _ready():
stats.connect("stats_updated", _on_stats_updated)
#stats.connect("stats_updated", _on_stats_updated)
fire_timer.connect("timeout", _on_fire_timer_timeout)
# Initial update
@ -48,13 +47,13 @@ func fire(direction: Vector2, target_position: Vector2):
_spawn_projectile(global_position, direction, target_position)
can_fire = false
Log.pr("Cooldown", stats.get_stat("fire_rate"))
fire_timer.start(stats.get_stat("fire_rate"))
#Log.pr("Cooldown", stats.get_stat("fire_rate"))
#fire_timer.start(stats.get_stat("fire_rate"))
func _spawn_projectile(spawn_position: Vector2, spawn_direction: Vector2, target_position: Vector2):
# Get projectile quantity and spread from stats
var quantity = stats.get_stat("projectile_quantity")
var spread_angle = stats.get_stat("projectile_spread")
var quantity = 1 # stats.get_stat("projectile_quantity")
var spread_angle = 0 # stats.get_stat("projectile_spread")
# Calculate the angle between each projectile
var angle_step = 0.0
@ -79,18 +78,18 @@ func _spawn_projectile(spawn_position: Vector2, spawn_direction: Vector2, target
projectile.direction = direction
# Apply stats to projectile
projectile.speed = stats.get_stat("projectile_speed")
projectile.damage = stats.get_stat("damage")
projectile.lifetime = stats.get_stat("projectile_lifetime")
projectile.speed = 200 # stats.get_stat("projectile_speed")
projectile.damage = 10 # stats.get_stat("damage")
projectile.lifetime = 200 # stats.get_stat("projectile_lifetime")
projectile.source_weapon = self
# Set base size
var size = stats.get_stat("projectile_size")
var size = 1 # stats.get_stat("projectile_size")
projectile.set_projectile_scale(Vector2(size, size))
# Allow modifiers to directly modify the projectile
for modifier in stats.modifiers:
modifier.modify_projectile(projectile)
#for modifier in stats.modifiers:
# modifier.modify_projectile(projectile)
# Add to scene tree
if get_tree() and get_tree().get_root():
@ -102,10 +101,11 @@ func _spawn_projectile(spawn_position: Vector2, spawn_direction: Vector2, target
func add_modifier(modifier: Modifier):
Log.pr("Adding modifier: ", modifier)
stats.add_modifier(modifier)
#stats.add_modifier(modifier)
func remove_modifier(modifier_id: String):
stats.remove_modifier(modifier_id)
pass
#stats.remove_modifier(modifier_id)
func _on_stats_updated():
# Update any visual components based on new stats