diff --git a/combat/modifiers/_scripts/modifier_manager.gd b/combat/modifiers/_scripts/modifier_manager.gd index 955fe0d..4d5ca30 100644 --- a/combat/modifiers/_scripts/modifier_manager.gd +++ b/combat/modifiers/_scripts/modifier_manager.gd @@ -2,5 +2,91 @@ extends Node2D class_name ModifierManagerTwo -func _init() -> void: - Log.pr("ModifierManagerTwo initialized") \ No newline at end of file +signal modifier_added(modifier) +signal modifier_removed(modifier) +signal stats_updated() + +var stats: 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) + +func set_stats(stats_component: StatsComponent) -> void: + self.stats = stats_component + +func add_modifier(modifier: Modifier) -> void: + modifiers.append(modifier) + modifier.on_equip(get_parent()) + emit_signal("modifier_added", modifier) + recalculate_stats() + +func remove_modifier(modifier_id: String) -> void: + for i in range(modifiers.size()): + if modifiers[i].id == modifier_id: + var modifier = modifiers[i] + modifier.on_unequip(get_parent()) + modifiers.remove_at(i) + emit_signal("modifier_removed", modifier) + recalculate_stats() + break + +func recalculate_stats() -> void: + # Reset stats to base values + final_stats = base_stats.duplicate() + + # Sort modifiers by priority + modifiers.sort_custom(func(a, b): return a.priority > b.priority) + + # First pass: Apply OVERRIDE modifiers (highest priority first) + for modifier in modifiers: + if modifier.modifier_type == Modifier.ModifierType.OVERRIDE: + _apply_modifier_stats(modifier) + + # Second pass: Apply ADDITIVE modifiers + for modifier in modifiers: + if modifier.modifier_type == Modifier.ModifierType.ADDITIVE: + _apply_modifier_stats(modifier) + + # Third pass: Apply MULTIPLICATIVE modifiers + for modifier in modifiers: + if modifier.modifier_type == Modifier.ModifierType.MULTIPLICATIVE: + _apply_modifier_stats(modifier) + + # Last pass: Apply CONDITIONAL modifiers + for modifier in modifiers: + 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) diff --git a/combat/projectiles/_scripts/projectile_base.gd b/combat/projectiles/_scripts/projectile_base.gd index 1451a4a..ad7be2c 100644 --- a/combat/projectiles/_scripts/projectile_base.gd +++ b/combat/projectiles/_scripts/projectile_base.gd @@ -3,12 +3,26 @@ class_name ProjectileBaseTwo var lifetime_timer: Timer +var direction: Vector2 +var target_position: Vector2 +var ELEMENTS = Global.ELEMENTS + +var has_collided: bool = false + var stats = { "speed": 500.0, "damage": 10.0, + "element": ELEMENTS.NONE, "lifetime": 2, + "pierce_count": 0 } +func set_stat(stat_name: String, value: Variant): + stats[stat_name] = value + +func get_stat(stat_name: String) -> Variant: + return stats.get(stat_name, null) + func destroy(): emit_signal("on_destroyed", self) queue_free() diff --git a/combat/projectiles/rock/RockProjectile.tscn b/combat/projectiles/rock/RockProjectile.tscn index 9372e7b..bd7b6ae 100644 --- a/combat/projectiles/rock/RockProjectile.tscn +++ b/combat/projectiles/rock/RockProjectile.tscn @@ -4,9 +4,3 @@ [node name="RockProjectile" type="Node2D"] script = ExtResource("1_8myby") -speed = null -damage = null -lifetime = null -direction = null -target_position = null -is_friendly = null diff --git a/combat/projectiles/rock/scripts/rock_projectile.gd b/combat/projectiles/rock/scripts/rock_projectile.gd index fde1073..44e2441 100644 --- a/combat/projectiles/rock/scripts/rock_projectile.gd +++ b/combat/projectiles/rock/scripts/rock_projectile.gd @@ -5,7 +5,7 @@ func _ready(): lifetime_timer = Timer.new() add_child(lifetime_timer) lifetime_timer.one_shot = true - lifetime_timer.wait_time = lifetime + lifetime_timer.wait_time = stats.lifetime lifetime_timer.connect("timeout", _on_lifetime_timeout) lifetime_timer.start() @@ -13,7 +13,19 @@ func _ready(): connect("body_entered", _on_body_entered) func _physics_process(delta): - position += direction * speed * delta + position += direction * stats.speed * delta + +func _on_body_entered(body): + if body.is_in_group("enemies"): + body.take_damage(stats.damage) + + ## Check if the projectile is piercing + if not get_stat("pierce_count"): + # If not piercing, destroy the projectile + destroy() + else: + # If piercing, reduce the pierce count + set_stat("pierce_count", get_stat("pierce_count") - 1) func _on_lifetime_timeout(): super._on_lifetime_timeout() diff --git a/combat/weapons/_scripts/melee_weapon_component.gd b/combat/weapons/_scripts/melee_weapon_component.gd index 8601446..0137586 100644 --- a/combat/weapons/_scripts/melee_weapon_component.gd +++ b/combat/weapons/_scripts/melee_weapon_component.gd @@ -1,18 +1,6 @@ @icon("res://assets/editor/64x64/fc728.png") -extends WeaponComponent +extends Node2D class_name MeleeWeaponComponent -var stats = { - "piercing": 3, -} -var combined_stats = {} - func _init() -> void: Log.pr("MeleeWeaponComponent initialized") - super._init() - - # Combine the base stats with the stats from the parent class - combined_stats = base_stats.duplicate() - combined_stats.merge(stats) - - Log.pr("Combined stats: ", combined_stats) \ No newline at end of file diff --git a/combat/weapons/_scripts/ranged_weapon_component.gd b/combat/weapons/_scripts/ranged_weapon_component.gd index cc6c05e..892a5ca 100644 --- a/combat/weapons/_scripts/ranged_weapon_component.gd +++ b/combat/weapons/_scripts/ranged_weapon_component.gd @@ -1,25 +1,11 @@ @icon("res://assets/editor/64x64/fc1515.png") -extends WeaponComponent +extends Node2D class_name RangedWeaponComponent -var stats = { - "projectile_speed": 500.0, - "projectile_size": 1.0, - "projectile_lifetime": 1.0, - "projectile_quantity": 1, - "projectile_spread": 33, - "max_pierce": 0 -} -var combined_stats = {} +@export var stats: StatsComponent -func _init() -> void: +@onready var modifier_manager = $ModifierManager + +func _ready() -> void: Log.pr("RangedWeaponComponent initialized") - super._init() - - # Combine the base stats with the stats from the parent class - combined_stats = base_stats.duplicate() - combined_stats.merge(stats) - - Log.pr("Combined stats: ", combined_stats) - - Log.pr("ModifierManager: ", modifier_manager) \ No newline at end of file + modifier_manager.set_stats(stats) diff --git a/combat/weapons/_scripts/weapon_component.gd b/combat/weapons/_scripts/weapon_component.gd deleted file mode 100644 index a912cf9..0000000 --- a/combat/weapons/_scripts/weapon_component.gd +++ /dev/null @@ -1,18 +0,0 @@ -@icon("res://assets/editor/64x64/fc729.png") -extends Node2D -class_name WeaponComponent - -var modifier_manager - -var base_stats = { - "damage": 10.0, - "attack_rate": 3.0 -} - -func _init() -> void: - Log.pr("WeaponComponent initialized") - -func _ready() -> void: - await get_tree().process_frame - modifier_manager = $ModifierManager - Log.pr("ModifierManager: ", modifier_manager) diff --git a/combat/weapons/_scripts/weapon_component.gd.uid b/combat/weapons/_scripts/weapon_component.gd.uid deleted file mode 100644 index 392a122..0000000 --- a/combat/weapons/_scripts/weapon_component.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dl3kvbu0rwxky diff --git a/entities/StatsComponent.tscn b/entities/StatsComponent.tscn new file mode 100644 index 0000000..74bc246 --- /dev/null +++ b/entities/StatsComponent.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://bjybfg0xrowb5"] + +[ext_resource type="Script" uid="uid://bd63bbuh27fj0" path="res://entities/scripts/stats_component.gd" id="1_ll8eh"] + +[node name="StatsComponent" type="Node2D"] +script = ExtResource("1_ll8eh") diff --git a/entities/scripts/stats_component.gd b/entities/scripts/stats_component.gd new file mode 100644 index 0000000..f202eda --- /dev/null +++ b/entities/scripts/stats_component.gd @@ -0,0 +1,32 @@ +@icon("res://assets/editor/64x64/fc681.png") +extends Node2D +class_name StatsComponent + +var stats: Dictionary[String, Variant] = { + "base": { + "health": 100, + "max_health": 100, + "armor": 0, + "max_armor": 0, + "energy": 100, + "max_energy": 100, + "speed": 200.0, + }, + "melee": { + "damage": 10, + "attack_rate": 1, + "element": Global.ELEMENTS.NONE, + }, + "ranged": { + "damage": 10, + "attack_rate": 1, + "element": Global.ELEMENTS.NONE, + "projectile_speed": 500.0, + "projectile_size": 1.0, + "projectile_lifetime": 1.0, + "projectile_quantity": 1, + "projectile_explode_quantity": 0, + "projectile_explode_damage": 0.5, + "pierce_count": 0 + } +} diff --git a/entities/scripts/stats_component.gd.uid b/entities/scripts/stats_component.gd.uid new file mode 100644 index 0000000..85ab3c1 --- /dev/null +++ b/entities/scripts/stats_component.gd.uid @@ -0,0 +1 @@ +uid://bd63bbuh27fj0 diff --git a/player/player.tscn b/player/player.tscn index 6f348ce..e469c46 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=85 format=3 uid="uid://bo5aw2cad3akl"] +[gd_scene load_steps=86 format=3 uid="uid://bo5aw2cad3akl"] [ext_resource type="Script" uid="uid://bq038uo4cm6nv" path="res://player/scripts/player.gd" id="1_oul6g"] [ext_resource type="Texture2D" uid="uid://dqgq2c1h6yk3k" path="res://assets/sprites/characters/pink/Pink_Monster_Attack1_4.png" id="2_yllr7"] @@ -16,6 +16,7 @@ [ext_resource type="PackedScene" uid="uid://cgxn1f4p4vik6" path="res://assets/weapons/ranged_weapon.tscn" id="14_kb6p2"] [ext_resource type="PackedScene" uid="uid://dud7c465danl4" path="res://combat/weapons/RangedWeaponComponent.tscn" id="15_wodsf"] [ext_resource type="PackedScene" uid="uid://dqful6et42ok8" path="res://combat/weapons/MeleeWeaponComponent.tscn" id="16_32hag"] +[ext_resource type="PackedScene" uid="uid://bjybfg0xrowb5" path="res://entities/StatsComponent.tscn" id="17_tqiix"] [sub_resource type="CircleShape2D" id="CircleShape2D_rkbax"] @@ -565,6 +566,9 @@ zoom = Vector2(2, 2) [node name="RangedWeapon" parent="." instance=ExtResource("14_kb6p2")] -[node name="RangedWeaponComponent" parent="." instance=ExtResource("15_wodsf")] +[node name="RangedWeaponComponent" parent="." node_paths=PackedStringArray("stats") instance=ExtResource("15_wodsf")] +stats = NodePath("../StatsComponent") [node name="MeleeWeaponComponent" parent="." instance=ExtResource("16_32hag")] + +[node name="StatsComponent" parent="." instance=ExtResource("17_tqiix")] diff --git a/utility/Globals.gd b/utility/Globals.gd index 534d90f..d63192a 100644 --- a/utility/Globals.gd +++ b/utility/Globals.gd @@ -11,4 +11,13 @@ const MAP_EMPTY = 0 const MAP_PATH = 1 const MAP_START = 2 const MAP_FINISH = 4 -const MAP_UP_CELL = 3 \ No newline at end of file +const MAP_UP_CELL = 3 + +const ELEMENTS = { + "NONE": 0, + "FIRE": 1, + "WATER": 2, + "EARTH": 3, + "AIR": 4, + "THUNDER": 5, +} \ No newline at end of file