From 9f66ab0a73698d8419b062a76dfe38bf9ddf57c7 Mon Sep 17 00:00:00 2001 From: Dan Baker Date: Wed, 7 May 2025 15:08:11 +0100 Subject: [PATCH] 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. --- combat/modifiers/_scripts/modifier_manager.gd | 38 ++--------- .../modifiers/modifiers/fire_rate_additive.gd | 12 ++++ .../modifiers/fire_rate_additive.gd.uid | 0 .../modifiers/fire_rate_multiplicative.gd | 0 .../modifiers/fire_rate_multiplicative.gd.uid | 0 .../modifiers}/modifiers/modifier.gd | 0 .../modifiers}/modifiers/modifier.gd.uid | 0 .../modifiers}/modifiers/piercing.gd | 0 .../modifiers}/modifiers/piercing.gd.uid | 0 .../modifiers/projectile_size_additive.gd | 21 ++++++ .../modifiers/projectile_size_additive.gd.uid | 0 .../projectile_size_multiplicative.gd | 0 .../projectile_size_multiplicative.gd.uid | 0 .../_scripts/ranged_weapon_component.gd | 6 ++ entities/scripts/stats_component.gd | 65 ++++++++++++++++++- player/modifiers/fire_rate_additive.gd | 13 ---- player/modifiers/projectile_size_additive.gd | 25 ------- player/scripts/modifier_management.gd | 2 +- player/scripts/player.gd | 12 ++-- player/scripts/player_combat.gd | 2 +- player/weapons/ranged_weapon.gd | 36 +++++----- 21 files changed, 135 insertions(+), 97 deletions(-) create mode 100644 combat/modifiers/modifiers/fire_rate_additive.gd rename {player => combat/modifiers}/modifiers/fire_rate_additive.gd.uid (100%) rename {player => combat/modifiers}/modifiers/fire_rate_multiplicative.gd (100%) rename {player => combat/modifiers}/modifiers/fire_rate_multiplicative.gd.uid (100%) rename {player => combat/modifiers}/modifiers/modifier.gd (100%) rename {player => combat/modifiers}/modifiers/modifier.gd.uid (100%) rename {player => combat/modifiers}/modifiers/piercing.gd (100%) rename {player => combat/modifiers}/modifiers/piercing.gd.uid (100%) create mode 100644 combat/modifiers/modifiers/projectile_size_additive.gd rename {player => combat/modifiers}/modifiers/projectile_size_additive.gd.uid (100%) rename {player => combat/modifiers}/modifiers/projectile_size_multiplicative.gd (100%) rename {player => combat/modifiers}/modifiers/projectile_size_multiplicative.gd.uid (100%) delete mode 100644 player/modifiers/fire_rate_additive.gd delete mode 100644 player/modifiers/projectile_size_additive.gd diff --git a/combat/modifiers/_scripts/modifier_manager.gd b/combat/modifiers/_scripts/modifier_manager.gd index 4d5ca30..f1937c7 100644 --- a/combat/modifiers/_scripts/modifier_manager.gd +++ b/combat/modifiers/_scripts/modifier_manager.gd @@ -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) diff --git a/combat/modifiers/modifiers/fire_rate_additive.gd b/combat/modifiers/modifiers/fire_rate_additive.gd new file mode 100644 index 0000000..125538e --- /dev/null +++ b/combat/modifiers/modifiers/fire_rate_additive.gd @@ -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) diff --git a/player/modifiers/fire_rate_additive.gd.uid b/combat/modifiers/modifiers/fire_rate_additive.gd.uid similarity index 100% rename from player/modifiers/fire_rate_additive.gd.uid rename to combat/modifiers/modifiers/fire_rate_additive.gd.uid diff --git a/player/modifiers/fire_rate_multiplicative.gd b/combat/modifiers/modifiers/fire_rate_multiplicative.gd similarity index 100% rename from player/modifiers/fire_rate_multiplicative.gd rename to combat/modifiers/modifiers/fire_rate_multiplicative.gd diff --git a/player/modifiers/fire_rate_multiplicative.gd.uid b/combat/modifiers/modifiers/fire_rate_multiplicative.gd.uid similarity index 100% rename from player/modifiers/fire_rate_multiplicative.gd.uid rename to combat/modifiers/modifiers/fire_rate_multiplicative.gd.uid diff --git a/player/modifiers/modifier.gd b/combat/modifiers/modifiers/modifier.gd similarity index 100% rename from player/modifiers/modifier.gd rename to combat/modifiers/modifiers/modifier.gd diff --git a/player/modifiers/modifier.gd.uid b/combat/modifiers/modifiers/modifier.gd.uid similarity index 100% rename from player/modifiers/modifier.gd.uid rename to combat/modifiers/modifiers/modifier.gd.uid diff --git a/player/modifiers/piercing.gd b/combat/modifiers/modifiers/piercing.gd similarity index 100% rename from player/modifiers/piercing.gd rename to combat/modifiers/modifiers/piercing.gd diff --git a/player/modifiers/piercing.gd.uid b/combat/modifiers/modifiers/piercing.gd.uid similarity index 100% rename from player/modifiers/piercing.gd.uid rename to combat/modifiers/modifiers/piercing.gd.uid diff --git a/combat/modifiers/modifiers/projectile_size_additive.gd b/combat/modifiers/modifiers/projectile_size_additive.gd new file mode 100644 index 0000000..0dcddca --- /dev/null +++ b/combat/modifiers/modifiers/projectile_size_additive.gd @@ -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 diff --git a/player/modifiers/projectile_size_additive.gd.uid b/combat/modifiers/modifiers/projectile_size_additive.gd.uid similarity index 100% rename from player/modifiers/projectile_size_additive.gd.uid rename to combat/modifiers/modifiers/projectile_size_additive.gd.uid diff --git a/player/modifiers/projectile_size_multiplicative.gd b/combat/modifiers/modifiers/projectile_size_multiplicative.gd similarity index 100% rename from player/modifiers/projectile_size_multiplicative.gd rename to combat/modifiers/modifiers/projectile_size_multiplicative.gd diff --git a/player/modifiers/projectile_size_multiplicative.gd.uid b/combat/modifiers/modifiers/projectile_size_multiplicative.gd.uid similarity index 100% rename from player/modifiers/projectile_size_multiplicative.gd.uid rename to combat/modifiers/modifiers/projectile_size_multiplicative.gd.uid diff --git a/combat/weapons/_scripts/ranged_weapon_component.gd b/combat/weapons/_scripts/ranged_weapon_component.gd index 892a5ca..a1504c5 100644 --- a/combat/weapons/_scripts/ranged_weapon_component.gd +++ b/combat/weapons/_scripts/ranged_weapon_component.gd @@ -9,3 +9,9 @@ class_name RangedWeaponComponent func _ready() -> void: Log.pr("RangedWeaponComponent initialized") modifier_manager.set_stats(stats) + +func add_modifier(modifier: Modifier) -> void: + modifier_manager.add_modifier(modifier) + +func remove_modifier(modifier_id: String) -> void: + modifier_manager.remove_modifier(modifier_id) \ No newline at end of file diff --git a/entities/scripts/stats_component.gd b/entities/scripts/stats_component.gd index f202eda..e32d430 100644 --- a/entities/scripts/stats_component.gd +++ b/entities/scripts/stats_component.gd @@ -2,7 +2,7 @@ extends Node2D class_name StatsComponent -var stats: Dictionary[String, Variant] = { +var base_stats: Dictionary[String, Variant] = { "base": { "health": 100, "max_health": 100, @@ -30,3 +30,66 @@ var stats: Dictionary[String, Variant] = { "pierce_count": 0 } } + +var stats: Dictionary + +func _init() -> void: + if not stats: + reset_stats() + +func reset_stats() -> void: + stats = base_stats.duplicate() + Log.pr("StatsComponent reset to base stats") + +func get_stat(stat_name: String) -> Variant: + var stat = get_nested_stat(stat_name) + if stat: + return stat + else: + Log.pr("Stat not found: ", stat_name) + return null + +func update_stat(stat_name: String, value: Variant) -> void: + var updating_stat = get_nested_stat(stat_name) + if updating_stat: + set_nested_stat(stat_name, value) + Log.pr("Updated stat: ", stat_name, " to ", value) + else: + Log.pr("Stat not found: ", stat_name) + +func get_nested_stat(path: String) -> Variant: + var keys = path.split(".") + var current = stats + + for key in keys: + if current is Dictionary and current.has(key): + current = current[key] + else: + return null # Path doesn't exist + + return current + +func set_nested_stat(path: String, value) -> bool: + var keys = path.split(".") + var current = stats + + # Navigate to the parent of the final key + for i in range(keys.size() - 1): + var key = keys[i] + + # Check if key exists and is a dictionary + if not current.has(key) or not current[key] is Dictionary: + Log.error("Invalid stat path: " + path + " (key '" + key + "' doesn't exist or isn't a dictionary)") + return false + + current = current[key] + + # Check if final key exists + var final_key = keys[keys.size() - 1] + if not current.has(final_key): + Log.error("Invalid stat path: " + path + " (key '" + final_key + "' doesn't exist)") + return false + + # Set the value at the final key + current[final_key] = value + return true \ No newline at end of file diff --git a/player/modifiers/fire_rate_additive.gd b/player/modifiers/fire_rate_additive.gd deleted file mode 100644 index aa62830..0000000 --- a/player/modifiers/fire_rate_additive.gd +++ /dev/null @@ -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 \ No newline at end of file diff --git a/player/modifiers/projectile_size_additive.gd b/player/modifiers/projectile_size_additive.gd deleted file mode 100644 index cac295b..0000000 --- a/player/modifiers/projectile_size_additive.gd +++ /dev/null @@ -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) \ No newline at end of file diff --git a/player/scripts/modifier_management.gd b/player/scripts/modifier_management.gd index 173547d..c1df5db 100644 --- a/player/scripts/modifier_management.gd +++ b/player/scripts/modifier_management.gd @@ -1,4 +1,4 @@ -class_name ModifierManager extends Node +class_name ModifierManagerOLD extends Node signal modifier_added(modifier) signal modifier_removed(modifier) diff --git a/player/scripts/player.gd b/player/scripts/player.gd index bcd6739..3c50a14 100644 --- a/player/scripts/player.gd +++ b/player/scripts/player.gd @@ -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): diff --git a/player/scripts/player_combat.gd b/player/scripts/player_combat.gd index 06b283f..7b5658a 100644 --- a/player/scripts/player_combat.gd +++ b/player/scripts/player_combat.gd @@ -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() diff --git a/player/weapons/ranged_weapon.gd b/player/weapons/ranged_weapon.gd index fb9e5ee..6db4862 100644 --- a/player/weapons/ranged_weapon.gd +++ b/player/weapons/ranged_weapon.gd @@ -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