123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- extends Area2D
- class_name Demon
- @onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
- @onready var vision: ShapeCast2D = $Vision
- @onready var vision_polygon: Polygon2D = $Vision/Polygon2D
- @onready var gun_shot_sound: AudioStreamPlayer = $GunShotSound
- @export var shot_probability: float = 0.5
- var sp_modifier: float = 0.0
- var ammo: int = 0
- enum State {
- STATE_IDLE,
- STATE_SHOOTING,
- STATE_RELOADING,
- }
- var state: State = State.STATE_IDLE
- var is_being_dragged: bool = false
- func _ready() -> void:
- ammo = Game.max_ammo
- func _process(_delta: float) -> void:
- vision_polygon.visible = GlobalInput.visible_vision
- func _physics_process(_delta: float) -> void:
- if state != State.STATE_IDLE:
- return
-
- vision.force_shapecast_update()
- if not vision.is_colliding():
- return
-
- var foe = vision.get_collider(0)
- if foe == null || not (foe is Area2D) || not foe.visible:
- return
-
- var value = randf()
- var actual_probability = shot_probability + sp_modifier
- if value <= actual_probability:
- sp_modifier = 0.0
- await shoot_at(foe as Area2D)
- else:
- sp_modifier += 0.1
- print("%s: not shooting (%.2f > %.2f)" % [name, value, actual_probability])
- func _on_mouse_entered():
- if not GlobalInput.is_dragging():
- # TODO: add custom cursor image
- Input.set_custom_mouse_cursor(null, Input.CURSOR_MOVE)
- func _on_mouse_exited():
- if not GlobalInput.is_dragging():
- # TODO: add custom cursor image
- Input.set_custom_mouse_cursor(null, Input.CURSOR_ARROW)
- func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):
- if event is InputEventMouseButton:
- handle_click(event)
- func handle_click(event: InputEventMouseButton):
- if event.button_index != MOUSE_BUTTON_LEFT:
- return
-
- if event.pressed && not GlobalInput.is_dragging():
- is_being_dragged = true
- GlobalInput.start_dragging(self)
- elif not event.pressed && is_being_dragged:
- is_being_dragged = false
- GlobalInput.stop_dragging()
- func reload() -> void:
- state = State.STATE_RELOADING
- print("%s: reloading (%.2f seconds)" % [name, Game.reload_time])
- await get_tree().create_timer(Game.reload_time).timeout
- print(name + ": done reloading")
- ammo = Game.max_ammo
- state = State.STATE_IDLE
- func shoot_at(foe: Area2D) -> void:
- if state != State.STATE_IDLE:
- return
-
- print("%s: Ammo = %d/%d" % [name, ammo, Game.max_ammo])
-
- if ammo <= 0:
- await reload()
- else:
- state = State.STATE_SHOOTING
- ammo -= 1
- gun_shot_sound.play()
- sprite.play("shoot")
-
- var distance: float = clampf((foe.global_position - global_position).length(), 140.0, 250.0)
- var distance_percent: float = 1.0 - ((distance - 140.0) / 110.0)
- #print(distance_percent)
- var speed: float = minf(foe.speed, 100.0)
- var speed_percent: float = 1.0 - ((speed - 64.0) / 36.0)
- #print(speed_percent)
- var base = Game.base_accuracy
- var rest = (1.0 - base) / 2.0
- var hit_chance: float = Game.base_accuracy + distance_percent * rest + speed_percent * rest
- print("%s: Shooting at %s with %.2f hit chance" % [name, foe.name, hit_chance])
-
- var hit: float = randf()
- if hit > hit_chance:
- print("%s: missed shot (%.2f > %.2f)" % [name, hit, hit_chance])
- else:
- if foe.has_method("die"):
- foe.die()
- else:
- foe.queue_free()
-
- await sprite.animation_finished
- if ammo <= 0:
- await reload()
- else:
- state = State.STATE_IDLE
- func _on_animation_finished():
- sprite.animation = "idle"
- sprite.frame = 0
-
|