fix spider bat boss alittle
This commit is contained in:
172
src/scripts/attack_web_shot.gd
Normal file
172
src/scripts/attack_web_shot.gd
Normal file
@@ -0,0 +1,172 @@
|
||||
extends Area2D
|
||||
|
||||
# Web shot from boss: frame 568 in shade_spell_effects (105h x 79v). 8x8 collision.
|
||||
# Flies to target; on hit player or arrival: animate 568->573.
|
||||
# If arrived at point: stay 30s, fade out at end (net doesn't stick during fade).
|
||||
# If hit player: player stuck 5s (frame 679 netted), fade last 0.3s; other player can cut net.
|
||||
# Netted player cannot attack with main weapon.
|
||||
|
||||
var target_position: Vector2 = Vector2.ZERO
|
||||
var speed: float = 140.0
|
||||
var state: String = "flying" # flying | impact_anim | landed_net | hit_player
|
||||
var impact_frame: int = 568
|
||||
var impact_frame_end: int = 573
|
||||
var landed_lifetime: float = 30.0
|
||||
var landed_timer: float = 0.0
|
||||
var fade_start: float = 4.0 # Start fade this many seconds before end
|
||||
var fired_by_boss: Node = null
|
||||
var hit_player: Node = null # When state == hit_player, the netted player
|
||||
var netted_duration: float = 5.0
|
||||
var netted_timer: float = 0.0
|
||||
var netted_fade_start: float = 0.3
|
||||
|
||||
const TILE_SIZE: int = 16
|
||||
const HFRAMES: int = 105
|
||||
const VFRAMES: int = 79
|
||||
|
||||
@onready var sprite: Sprite2D = $Sprite2D
|
||||
@onready var sfx_webbed: AudioStreamPlayer2D = $SfxWebbed
|
||||
@onready var anim_timer: float = 0.0
|
||||
var anim_frame: int = 568
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# Collision: detect players (layer 1)
|
||||
collision_layer = 0
|
||||
collision_mask = 1
|
||||
body_entered.connect(_on_body_entered)
|
||||
anim_frame = impact_frame
|
||||
if sprite:
|
||||
sprite.hframes = HFRAMES
|
||||
sprite.vframes = VFRAMES
|
||||
sprite.frame = impact_frame
|
||||
sprite.centered = true
|
||||
|
||||
|
||||
func set_target(pos: Vector2) -> void:
|
||||
target_position = pos
|
||||
|
||||
|
||||
func set_fired_by_boss(boss: Node) -> void:
|
||||
fired_by_boss = boss
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if state == "flying":
|
||||
var dir = (target_position - global_position).normalized()
|
||||
var dist = global_position.distance_to(target_position)
|
||||
if dist <= speed * delta:
|
||||
global_position = target_position
|
||||
_impact_at_point()
|
||||
else:
|
||||
global_position += dir * speed * delta
|
||||
return
|
||||
if state == "impact_anim":
|
||||
anim_timer += delta
|
||||
var frame_count = impact_frame_end - impact_frame + 1
|
||||
var duration = 0.25
|
||||
var t = clamp(anim_timer / duration, 0.0, 1.0)
|
||||
var idx = impact_frame + int(t * (frame_count - 1))
|
||||
if sprite:
|
||||
sprite.frame = idx
|
||||
if anim_timer >= duration:
|
||||
state = "landed_net"
|
||||
landed_timer = 0.0
|
||||
collision_layer = 1 # Can be hit by other players to cut?
|
||||
collision_mask = 1 # Detect players (for cutting / fade stick logic)
|
||||
return
|
||||
if state == "landed_net":
|
||||
landed_timer += delta
|
||||
# Fade during last fade_start seconds
|
||||
if landed_timer >= landed_lifetime - fade_start:
|
||||
var fade_t = (landed_timer - (landed_lifetime - fade_start)) / fade_start
|
||||
if sprite:
|
||||
sprite.modulate.a = 1.0 - fade_t
|
||||
# During fade, net doesn't stick - no collision with player for stick
|
||||
if landed_timer >= landed_lifetime:
|
||||
queue_free()
|
||||
return
|
||||
if state == "hit_player":
|
||||
netted_timer += delta
|
||||
# Keep net at player position
|
||||
if hit_player and is_instance_valid(hit_player):
|
||||
global_position = hit_player.global_position
|
||||
# Fade last 0.3s
|
||||
if netted_timer >= netted_duration - netted_fade_start:
|
||||
var fade_t = (netted_timer - (netted_duration - netted_fade_start)) / netted_fade_start
|
||||
if sprite:
|
||||
sprite.modulate.a = 1.0 - fade_t
|
||||
if netted_timer >= netted_duration:
|
||||
_release_netted_player()
|
||||
queue_free()
|
||||
else:
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_body_entered(body: Node2D) -> void:
|
||||
if state == "flying":
|
||||
if body.is_in_group("player"):
|
||||
_impact_on_player(body)
|
||||
return
|
||||
# Reached target (or hit wall) - treat as impact at point
|
||||
if global_position.distance_to(target_position) < 24.0:
|
||||
_impact_at_point()
|
||||
return
|
||||
if state == "landed_net" and body.is_in_group("player"):
|
||||
_impact_on_player(body)
|
||||
|
||||
|
||||
func _impact_at_point() -> void:
|
||||
state = "impact_anim"
|
||||
anim_timer = 0.0
|
||||
# Stop moving; play 568->573
|
||||
collision_layer = 0
|
||||
collision_mask = 0
|
||||
# After anim, stay 30s then fade (handled in _process)
|
||||
|
||||
|
||||
func _impact_on_player(player: Node2D) -> void:
|
||||
if not player.is_in_group("player"):
|
||||
return
|
||||
# Already netted?
|
||||
if "netted_by_web" in player and player.netted_by_web != null:
|
||||
return
|
||||
state = "hit_player"
|
||||
hit_player = player
|
||||
netted_timer = 0.0
|
||||
if sfx_webbed:
|
||||
sfx_webbed.play()
|
||||
# Netted: cannot move? User said "player gets stuck" - so disable movement and main weapon
|
||||
if player.has_method("_web_net_apply"):
|
||||
player._web_net_apply(self)
|
||||
else:
|
||||
# Fallback: set a flag player script can check
|
||||
player.set_meta("netted_by_web", self)
|
||||
# Show net on player (frame 679) - player script will show overlay
|
||||
if player.has_method("_web_net_show_netted_frame"):
|
||||
player._web_net_show_netted_frame(true)
|
||||
# Impact anim 568->573 briefly
|
||||
anim_timer = 0.0
|
||||
if sprite:
|
||||
sprite.frame = impact_frame
|
||||
# Layer 8 so player attack areas (punch/sword/axe mask 8) can hit and cut the net
|
||||
collision_layer = 8
|
||||
collision_mask = 0
|
||||
|
||||
|
||||
func _release_netted_player() -> void:
|
||||
if hit_player and is_instance_valid(hit_player):
|
||||
if hit_player.has_method("_web_net_release"):
|
||||
hit_player._web_net_release(self)
|
||||
else:
|
||||
hit_player.remove_meta("netted_by_web")
|
||||
if hit_player.has_method("_web_net_show_netted_frame"):
|
||||
hit_player._web_net_show_netted_frame(false)
|
||||
hit_player = null
|
||||
|
||||
|
||||
# Called when another player attacks this web (to cut the net)
|
||||
func cut_by_attack(_from_player: Node2D) -> void:
|
||||
if state == "hit_player":
|
||||
_release_netted_player()
|
||||
queue_free()
|
||||
Reference in New Issue
Block a user