Files
slopvivors/scenes/weapons/weapon_base.gd
2025-08-22 20:50:11 +02:00

105 lines
2.6 KiB
GDScript

class_name WeaponBase
extends Node2D
enum WeaponTag {
CAN_RETURN,
CAN_BLEED,
CAN_CHAIN,
CAN_FORK,
}
@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 return_chance: float = 0.0
@export var bleed_chance: float = 0.0
@export var bleed_duration: float = 5.0
@export var chain_chance: float = 0.0
@export var tags: Array[String] = []
@export var modifiers: Array[WeaponModBase] = []
@onready var active_cd_timer: Timer = $ActiveCDTimer
var _player: Player
func _ready() -> void:
_player = get_tree().get_first_node_in_group(GlobalConst.GROUP_PLAYER)
func _on_attack_cd_timer_timeout() -> void:
do_attack()
func do_attack() -> void:
push_error("%s does not implement do_attack" % self)
func do_active() -> void:
if not active_cd_timer.is_stopped():
return
active_cd_timer.start()
_do_active()
func add_mod(mod: WeaponModBase) -> void:
modifiers.append(mod)
func _do_active() -> void:
push_error("%s does not implement do_active" % self)
func find_target_in_radius() -> EnemyBase:
var space_state: PhysicsDirectSpaceState2D = get_world_2d().direct_space_state
var shape := CircleShape2D.new()
shape.radius = attack_range
var query := PhysicsShapeQueryParameters2D.new()
query.shape = shape
query.transform = Transform2D(0, global_position)
query.collision_mask = 2
query.collide_with_bodies = true
var results := space_state.intersect_shape(query)
if len(results) < 1:
return null
var closest: PhysicsBody2D = results[0]["collider"]
for r in results:
var c: PhysicsBody2D = r["collider"]
if not c.is_in_group(GlobalConst.GROUP_ENEMY):
continue
if (
c.global_position.distance_to(global_position)
< closest.global_position.distance_to(global_position)
):
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
func did_crit() -> bool:
var weapon_crit = get_calculated("attack_crit_chance")
var player_crit = _player.player_stats.get_final("crit_chance", _player.modifiers)
return randf() >= 1 - weapon_crit + player_crit
func did_bleed() -> bool:
return randf() >= 1 - bleed_chance
func base_damage() -> Array[Variant]:
var damage = get_calculated("attack_damage")
var is_crit := did_crit()
if is_crit:
damage *= _player.player_stats.get_final("crit_multiplier", _player.modifiers)
return [damage, is_crit]