110 lines
2.6 KiB
GDScript
110 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]
|