From 1d75a850bf2379db3f6493f4e3b5e0a3acd06e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Thu, 21 Aug 2025 19:49:07 +0200 Subject: [PATCH] game: add weapon mod system --- scenes/player.gd | 5 ++++ scenes/weapons/weapon_base.gd | 23 +++++++++++++++++ scenes/weapons/weapon_mod_base.gd | 36 +++++++++++++++++++++++++++ scenes/weapons/weapon_mod_base.gd.uid | 1 + scenes/weapons/weapon_sword.gd | 11 ++++---- 5 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 scenes/weapons/weapon_mod_base.gd create mode 100644 scenes/weapons/weapon_mod_base.gd.uid diff --git a/scenes/player.gd b/scenes/player.gd index 3d3c373..60a7d3e 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -29,6 +29,11 @@ func _ready() -> void: if not weapon: weapon = WEAPON_SWORD.instantiate() add_child(weapon) + var mod = WeaponModBase.new() + mod.mod_property = "attack_damage" + mod.mod_value = 10.0 + mod.mod_type = WeaponModBase.ModType.ADDITIVE + weapon.add_mod(mod) func _physics_process(delta: float) -> void: diff --git a/scenes/weapons/weapon_base.gd b/scenes/weapons/weapon_base.gd index 623f248..36b8695 100644 --- a/scenes/weapons/weapon_base.gd +++ b/scenes/weapons/weapon_base.gd @@ -1,11 +1,19 @@ class_name WeaponBase extends Node2D +enum WeaponTag { + CAN_RETURN, + CAN_BLEED, +} + @export var attack_cd: float @export var attack_damage: float @export var attack_aoe: float @export var attack_duration: float @export var attack_range: float +@export var attack_crit_chance: float = 0.05 +@export var tags: Array[String] = [] +@export var modifiers: Array[WeaponModBase] = [] @onready var active_cd_timer: Timer = $ActiveCDTimer @@ -25,6 +33,10 @@ func do_active() -> void: _do_active() +func add_mod(mod: WeaponModBase) -> void: + modifiers.append(mod) + + func _do_active() -> void: push_error("%s does not implement do_active" % self) @@ -53,3 +65,14 @@ func find_target_in_radius() -> EnemyBase: ): closest = c return closest + + +func get_calculated(key: String) -> Variant: + return WeaponModBase.get_calculated(self, key) + + +func has_property(key: String) -> bool: + for prop in get_property_list(): + if prop.name == key: + return true + return false diff --git a/scenes/weapons/weapon_mod_base.gd b/scenes/weapons/weapon_mod_base.gd new file mode 100644 index 0000000..f8ca1e8 --- /dev/null +++ b/scenes/weapons/weapon_mod_base.gd @@ -0,0 +1,36 @@ +class_name WeaponModBase +extends Resource + +enum ModType { ADDITIVE, MULTIPLICATIVE, ABSOLUTE, BOOL } + +@export var name: String = "Unnamed mod" +@export var description: String = "" +@export var icon: Texture2D +@export var mod_property: String +@export var mod_value: float +@export var mod_value_bool: bool = false +@export var mod_type: ModType = ModType.MULTIPLICATIVE +@export var mod_extra_tags: Array[WeaponBase.WeaponTag] = [] + + +static func get_calculated(weapon: WeaponBase, key: String) -> Variant: + assert( + weapon.has_property(key), + "tried calculate property '%s' where base value does not exist on %s" % [key, weapon] + ) + var base_value = weapon.get(key) + + var add = 0.0 + var mul = 1.0 + for mod in weapon.modifiers: + if mod.mod_property == key: + match mod.mod_type: + ModType.ADDITIVE: + add += mod.mod_value + ModType.MULTIPLICATIVE: + mul *= mod.mod_value + ModType.ABSOLUTE: + return mod.mod_value + ModType.BOOL: + return mod.mod_value_bool + return (base_value + add) * mul diff --git a/scenes/weapons/weapon_mod_base.gd.uid b/scenes/weapons/weapon_mod_base.gd.uid new file mode 100644 index 0000000..7e29c73 --- /dev/null +++ b/scenes/weapons/weapon_mod_base.gd.uid @@ -0,0 +1 @@ +uid://b1cg1bhnt6xk4 diff --git a/scenes/weapons/weapon_sword.gd b/scenes/weapons/weapon_sword.gd index a8d081b..5e0fa99 100644 --- a/scenes/weapons/weapon_sword.gd +++ b/scenes/weapons/weapon_sword.gd @@ -44,12 +44,13 @@ func _do_active() -> void: func deal_damage(enemy: EnemyBase, damage_mult: float): - var crit_chance = _player.player_stats.get_final("crit_chance", _player.modifiers) - var damage_dealt = attack_damage * damage_mult - var is_crit = randf() >= 1 - crit_chance + var weapon_crit = get_calculated("attack_crit_chance") + var player_crit = _player.player_stats.get_final("crit_chance", _player.modifiers) + var damage = get_calculated("attack_damage") + var is_crit = randf() >= 1 - weapon_crit + player_crit if is_crit: - damage_dealt *= _player.player_stats.get_final("crit_multiplier", _player.modifiers) - enemy.take_damage(damage_dealt, is_crit) + damage *= _player.player_stats.get_final("crit_multiplier", _player.modifiers) + enemy.take_damage(damage * damage_mult, is_crit) func _on_projectile_hit(projectile: WeaponSwordProjectile, enemy: EnemyBase, damage_mult: float):