Hivemind audio and behavior fixes, boss item drops, duplicate run item handling, out of stock handling
This commit is contained in:
@@ -389,6 +389,9 @@ func _tick_active(delta: float) -> void:
|
||||
func _tick_teleport(delta: float) -> void:
|
||||
match _tp_state:
|
||||
TeleportState.IDLE:
|
||||
# Don't start teleport during beam attack
|
||||
if _beam_telegraphing or _beam_active:
|
||||
return
|
||||
_teleport_timer -= delta
|
||||
if _teleport_timer <= 0.0:
|
||||
_start_fade_out()
|
||||
@@ -404,6 +407,7 @@ func _tick_teleport(delta: float) -> void:
|
||||
|
||||
|
||||
func _start_fade_out() -> void:
|
||||
AudioManager.play("hivemind_teleport")
|
||||
_tp_state = TeleportState.FADING_OUT
|
||||
_fade_timer = FADE_OUT_TIME
|
||||
|
||||
@@ -987,11 +991,24 @@ func _die() -> void:
|
||||
queue_free()
|
||||
|
||||
func _spawn_item_drop() -> void:
|
||||
var chosen: String = ALL_ITEM_PATHS[randi() % ALL_ITEM_PATHS.size()]
|
||||
# Filter out already collected items
|
||||
var available: Array[String] = []
|
||||
for path in ALL_ITEM_PATHS:
|
||||
var already_collected := false
|
||||
for collected in RunManager.run_items:
|
||||
if collected.resource_path == path:
|
||||
already_collected = true
|
||||
break
|
||||
if not already_collected:
|
||||
available.append(path)
|
||||
if available.is_empty():
|
||||
return
|
||||
var chosen: String = available[randi() % available.size()]
|
||||
var pickup = RUN_ITEM_PICKUP.instantiate()
|
||||
pickup.item = load(chosen)
|
||||
pickup.global_position = global_position + Vector2(-30, 0)
|
||||
get_parent().add_child(pickup)
|
||||
var spawn_pos := global_position + Vector2(-30, 0)
|
||||
get_parent().call_deferred("add_child", pickup)
|
||||
pickup.set_deferred("global_position", spawn_pos)
|
||||
|
||||
func _spawn_body_part_drop() -> void:
|
||||
var unacquired: Array[String] = []
|
||||
@@ -1003,5 +1020,6 @@ func _spawn_body_part_drop() -> void:
|
||||
var chosen: String = unacquired[randi() % unacquired.size()]
|
||||
var pickup = BODY_PART_PICKUP.instantiate()
|
||||
pickup.part = load(chosen)
|
||||
pickup.global_position = global_position + Vector2(30, 0)
|
||||
get_parent().add_child(pickup)
|
||||
var spawn_pos := global_position + Vector2(30, 0)
|
||||
get_parent().call_deferred("add_child", pickup)
|
||||
pickup.set_deferred("global_position", spawn_pos)
|
||||
|
||||
@@ -466,11 +466,24 @@ func _die() -> void:
|
||||
queue_free()
|
||||
|
||||
func _spawn_item_drop() -> void:
|
||||
var chosen: String = ALL_ITEM_PATHS[randi() % ALL_ITEM_PATHS.size()]
|
||||
# Filter out already collected items
|
||||
var available: Array[String] = []
|
||||
for path in ALL_ITEM_PATHS:
|
||||
var already_collected := false
|
||||
for collected in RunManager.run_items:
|
||||
if collected.resource_path == path:
|
||||
already_collected = true
|
||||
break
|
||||
if not already_collected:
|
||||
available.append(path)
|
||||
if available.is_empty():
|
||||
return
|
||||
var chosen: String = available[randi() % available.size()]
|
||||
var pickup = RUN_ITEM_PICKUP.instantiate()
|
||||
pickup.item = load(chosen)
|
||||
pickup.global_position = global_position + Vector2(-30, 0)
|
||||
get_parent().add_child(pickup)
|
||||
var spawn_pos := global_position + Vector2(-30, 0)
|
||||
get_parent().call_deferred("add_child", pickup)
|
||||
pickup.set_deferred("global_position", spawn_pos)
|
||||
|
||||
func _spawn_body_part_drop() -> void:
|
||||
var unacquired: Array[String] = []
|
||||
@@ -482,5 +495,6 @@ func _spawn_body_part_drop() -> void:
|
||||
var chosen: String = unacquired[randi() % unacquired.size()]
|
||||
var pickup = BODY_PART_PICKUP.instantiate()
|
||||
pickup.part = load(chosen)
|
||||
pickup.global_position = global_position + Vector2(30, 0)
|
||||
get_parent().add_child(pickup)
|
||||
var spawn_pos := global_position + Vector2(30, 0)
|
||||
get_parent().call_deferred("add_child", pickup)
|
||||
pickup.set_deferred("global_position", spawn_pos)
|
||||
|
||||
@@ -420,11 +420,24 @@ func _die() -> void:
|
||||
queue_free()
|
||||
|
||||
func _spawn_item_drop() -> void:
|
||||
var chosen: String = ALL_ITEM_PATHS[randi() % ALL_ITEM_PATHS.size()]
|
||||
# Filter out already collected items
|
||||
var available: Array[String] = []
|
||||
for path in ALL_ITEM_PATHS:
|
||||
var dominated := false
|
||||
for collected in RunManager.run_items:
|
||||
if collected.resource_path == path:
|
||||
dominated = true
|
||||
break
|
||||
if not dominated:
|
||||
available.append(path)
|
||||
if available.is_empty():
|
||||
return
|
||||
var chosen: String = available[randi() % available.size()]
|
||||
var pickup = RUN_ITEM_PICKUP.instantiate()
|
||||
pickup.item = load(chosen)
|
||||
pickup.global_position = global_position + Vector2(-30, 0)
|
||||
get_parent().add_child(pickup)
|
||||
var spawn_pos := global_position + Vector2(-30, 0)
|
||||
get_parent().call_deferred("add_child", pickup)
|
||||
pickup.set_deferred("global_position", spawn_pos)
|
||||
|
||||
func _spawn_body_part_drop() -> void:
|
||||
var unacquired: Array[String] = []
|
||||
@@ -436,8 +449,9 @@ func _spawn_body_part_drop() -> void:
|
||||
var chosen: String = unacquired[randi() % unacquired.size()]
|
||||
var pickup = BODY_PART_PICKUP.instantiate()
|
||||
pickup.part = load(chosen)
|
||||
pickup.global_position = global_position + Vector2(30, 0)
|
||||
get_parent().add_child(pickup)
|
||||
var spawn_pos := global_position + Vector2(30, 0)
|
||||
get_parent().call_deferred("add_child", pickup)
|
||||
pickup.set_deferred("global_position", spawn_pos)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Visual — phase-aware tints (overrides EnemyBase._tick_flash)
|
||||
|
||||
+86
-15
@@ -397,19 +397,64 @@ func _spawn_body_part_drop() -> void:
|
||||
contents.add_child(pickup)
|
||||
|
||||
func _spawn_run_item() -> void:
|
||||
# Exclude Patch Kit from item rooms (shop-only item)
|
||||
# Exclude Patch Kit from item rooms (shop-only item) and already collected items
|
||||
const PATCH_KIT_PATH := "res://data/run_items/patch_kit.tres"
|
||||
var item_pool: Array[String] = []
|
||||
for p in ALL_ITEM_PATHS:
|
||||
if p != PATCH_KIT_PATH:
|
||||
if p == PATCH_KIT_PATH:
|
||||
continue
|
||||
var already_collected := false
|
||||
for collected in RunManager.run_items:
|
||||
if collected.resource_path == p:
|
||||
already_collected = true
|
||||
break
|
||||
if not already_collected:
|
||||
item_pool.append(p)
|
||||
|
||||
if item_pool.is_empty():
|
||||
_spawn_out_of_stock_marker(Vector2.ZERO)
|
||||
return
|
||||
|
||||
var chosen: String = item_pool[randi() % item_pool.size()]
|
||||
var pickup = RUN_ITEM_PICKUP.instantiate()
|
||||
pickup.item = load(chosen)
|
||||
pickup.position = Vector2.ZERO
|
||||
contents.add_child(pickup)
|
||||
|
||||
func _spawn_out_of_stock_marker(pos: Vector2) -> void:
|
||||
var marker := Node2D.new()
|
||||
marker.position = pos
|
||||
|
||||
# Grey pedestal
|
||||
var pedestal := Polygon2D.new()
|
||||
pedestal.polygon = PackedVector2Array([
|
||||
Vector2(-14, -14), Vector2(14, -14),
|
||||
Vector2(14, 14), Vector2(-14, 14)
|
||||
])
|
||||
pedestal.color = Color(0.3, 0.3, 0.3)
|
||||
marker.add_child(pedestal)
|
||||
|
||||
# X mark
|
||||
var x_line := Line2D.new()
|
||||
x_line.points = PackedVector2Array([Vector2(-10, -10), Vector2(10, 10)])
|
||||
x_line.default_color = Color(0.5, 0.5, 0.5)
|
||||
x_line.width = 2.0
|
||||
marker.add_child(x_line)
|
||||
var x_line2 := Line2D.new()
|
||||
x_line2.points = PackedVector2Array([Vector2(10, -10), Vector2(-10, 10)])
|
||||
x_line2.default_color = Color(0.5, 0.5, 0.5)
|
||||
x_line2.width = 2.0
|
||||
marker.add_child(x_line2)
|
||||
|
||||
# Label
|
||||
var lbl := Label.new()
|
||||
lbl.text = "OUT OF STOCK"
|
||||
lbl.position = Vector2(-48, -40)
|
||||
lbl.modulate = Color(0.6, 0.6, 0.6)
|
||||
marker.add_child(lbl)
|
||||
|
||||
contents.add_child(marker)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Environmental hazards — spawned in combat rooms
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -555,11 +600,18 @@ func _make_exposed_wiring() -> void:
|
||||
# Shop spawning — 2 random items + 1 Patch Kit, spaced horizontally
|
||||
# ---------------------------------------------------------------------------
|
||||
func _spawn_shop() -> void:
|
||||
# Item slot paths (exclude Patch Kit from the random pool)
|
||||
# Item slot paths (exclude Patch Kit and already collected items from the random pool)
|
||||
const PATCH_KIT_PATH := "res://data/run_items/patch_kit.tres"
|
||||
var item_pool: Array[String] = []
|
||||
for p in ALL_ITEM_PATHS:
|
||||
if p != PATCH_KIT_PATH:
|
||||
if p == PATCH_KIT_PATH:
|
||||
continue
|
||||
var already_collected := false
|
||||
for collected in RunManager.run_items:
|
||||
if collected.resource_path == p:
|
||||
already_collected = true
|
||||
break
|
||||
if not already_collected:
|
||||
item_pool.append(p)
|
||||
item_pool.shuffle()
|
||||
|
||||
@@ -570,20 +622,39 @@ func _spawn_shop() -> void:
|
||||
Vector2( 200, 0),
|
||||
]
|
||||
|
||||
var chosen: Array[String] = [
|
||||
item_pool[0],
|
||||
item_pool[1],
|
||||
PATCH_KIT_PATH,
|
||||
]
|
||||
# Check if Patch Kit was already collected
|
||||
var patch_kit_collected := false
|
||||
for collected in RunManager.run_items:
|
||||
if collected.resource_path == PATCH_KIT_PATH:
|
||||
patch_kit_collected = true
|
||||
break
|
||||
|
||||
var prices: Array[int] = [20, 20, 10]
|
||||
|
||||
for i in 3:
|
||||
var pedestal := Area2D.new()
|
||||
pedestal.set_script(SHOP_PEDESTAL_SCR)
|
||||
pedestal.position = positions[i]
|
||||
pedestal.set("item", load(chosen[i]))
|
||||
pedestal.set("price", prices[i])
|
||||
contents.add_child(pedestal)
|
||||
var pos: Vector2 = positions[i]
|
||||
if i == 2:
|
||||
# Patch Kit slot
|
||||
if patch_kit_collected:
|
||||
_spawn_out_of_stock_marker(pos)
|
||||
else:
|
||||
var pedestal := Area2D.new()
|
||||
pedestal.set_script(SHOP_PEDESTAL_SCR)
|
||||
pedestal.position = pos
|
||||
pedestal.set("item", load(PATCH_KIT_PATH))
|
||||
pedestal.set("price", prices[i])
|
||||
contents.add_child(pedestal)
|
||||
else:
|
||||
# Random item slots
|
||||
if i < item_pool.size():
|
||||
var pedestal := Area2D.new()
|
||||
pedestal.set_script(SHOP_PEDESTAL_SCR)
|
||||
pedestal.position = pos
|
||||
pedestal.set("item", load(item_pool[i]))
|
||||
pedestal.set("price", prices[i])
|
||||
contents.add_child(pedestal)
|
||||
else:
|
||||
_spawn_out_of_stock_marker(pos)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Door locking
|
||||
|
||||
Reference in New Issue
Block a user