Files
mtd/PCs/PathEditTool/path_edit_tool.gd
2025-06-13 00:06:51 +10:00

186 lines
5.7 KiB
GDScript

class_name PathEditTool extends Node3D
@export var hero: Hero
@export var inventory: Inventory
@export var ray: RayCast3D
@export var wall_preview: TowerBase
@export var progress_bar: TextureProgressBar
var enabled: bool = true
var point: FlowNode = null
var obstacle_last_point: int = -1
var valid_point: bool = false # a point is valid if the path would still be traversable overall if this point was made untraversable
var tower_preview: Tower
var ray_collider: Object
var ray_point: Vector3
var last_point: FlowNode = null
var last_tower_base: TowerBase
var interact_key_held: bool = false
var interacted_once: bool = false
var interact_held_time: float = 0.0
var interact_hold_time: float = 0.4
func _ready() -> void:
var c: Color = Color.GREEN
c.a = 0.8
wall_preview.set_color(c)
wall_preview.set_float(0.0)
wall_preview.toggle_collision()
func _process(delta: float) -> void:
if !enabled:
ray_collider = null
wall_preview.set_visible(false)
return
if interact_key_held:
if !interacted_once:
if valid_point and hero.currency >= Data.wall_cost and ray.is_colliding() and point.buildable:
interact_held_time += delta
set_progress_percent(interact_held_time / interact_hold_time)
wall_preview.set_float(interact_held_time / interact_hold_time)
if interact_held_time >= interact_hold_time:
set_progress_percent(0)
interacted_once = true
build_wall()
elif ray.is_colliding() and ray.get_collider() is TowerBase:
interact_held_time += delta
set_progress_percent(interact_held_time / interact_hold_time)
if interact_held_time >= interact_hold_time:
set_progress_percent(0)
interacted_once = true
refund_wall(ray.get_collider())
else:
interact_held_time = 0.0
interacted_once = false
set_progress_percent(0)
wall_preview.set_float(0.0)
if !interacted_once and ray.is_colliding():
#if statement makes sure once the building animation has started then
#the position the wall builds in is already decided and moving the mouse
#around isnt going to make the resulting
#wall teleport to the new mouse location
if !interact_key_held:
wall_preview.set_visible(true)
if is_instance_valid(ray_collider) and ray_collider is TowerBase:
Game.level.walls[ray_collider.point].set_float(1.0)
ray_collider = ray.get_collider()
ray_point = ray.get_collision_point()
if ray_collider is TowerBase:
process_looking_at_tower()
elif Game.level:
process_looking_at_level()
else:
if is_instance_valid(ray_collider) and ray_collider is TowerBase and Game.level.walls.has(ray_collider.point):
Game.level.walls[ray_collider.point].set_float(1.0)
ray_collider = null
delete_tower_preview()
wall_preview.set_visible(false)
clear_previous_point()
last_point = null
if !valid_point:
wall_preview.set_visible(false)
func process_looking_at_level() -> void:
if tower_preview:
delete_tower_preview()
point = Game.level.flow_field.get_closest_buildable_point(ray_point)
if Game.level.walls.has(point) or !point.buildable or hero.currency < Data.wall_cost:
wall_preview.set_visible(false)
valid_point = false
clear_previous_point()
last_point = point
else:
wall_preview.global_position = point.global_position
wall_preview.global_rotation = Vector3.ZERO
if last_point != point:
clear_previous_point()
last_point = point
if !Game.level.walls.has(point) and Game.level.flow_field.traversable_after_blocking_point(point):
Game.level.flow_field.toggle_traversable(point)
wall_preview.set_float(0.0)
valid_point = true
else:
valid_point = false
func clear_previous_point() -> void:
if last_point and !Game.level.walls.has(last_point) and !last_point.traversable:
Game.level.flow_field.toggle_traversable(last_point)
func process_looking_at_tower() -> void:
valid_point = false
point = ray_collider.point
if last_point != point:
clear_previous_point()
if tower_preview:
delete_tower_preview()
wall_preview.set_visible(false)
ray_collider.set_color(Color.RED)
ray_collider.set_float(0.0)
if inventory.contents.size() > 0 and !ray_collider.has_card:
if ray_collider != last_tower_base or inventory.selected_item != inventory.contents.keys()[hero.inventory_selected_index]:
spawn_tower_preview()
func spawn_tower_preview() -> void:
delete_tower_preview()
last_tower_base = ray_collider
var card: Card = inventory.contents.keys()[hero.inventory_selected_index]
tower_preview = card.turret_scene.instantiate() as Tower
tower_preview.stats = card.tower_stats
tower_preview.position = Vector3.UP
tower_preview.preview_range(true)
ray_collider.add_child(tower_preview)
func delete_tower_preview() -> void:
last_tower_base = null
if is_instance_valid(tower_preview):
tower_preview.queue_free()
tower_preview = null
func interact() -> void:
if ray_collider is TowerBase:
var tower_base: TowerBase = ray_collider as TowerBase
put_card_in_tower_base(tower_base)
func build_wall() -> void:
if point and valid_point and hero.currency >= Data.wall_cost:
hero.currency -= Data.wall_cost
Game.level.set_wall(point, multiplayer.get_unique_id())
wall_preview.visible = false
func refund_wall(wall: TowerBase) -> void:
if !is_instance_valid(wall):
return
if wall.has_card:
wall.remove_card()
Game.level.remove_wall(wall.point)
func put_card_in_tower_base(tower_base: TowerBase) -> void:
if tower_base.has_card:
tower_base.remove_card()
elif inventory.size > 0:
var card: Card = inventory.remove_at(hero.inventory_selected_index)
if !inventory.contents.has(card):
hero.decrement_selected()
tower_base.add_card(card, multiplayer.get_unique_id())
hero.place_card_audio.play()
func set_progress_percent(value: float) -> void:
progress_bar.value = progress_bar.max_value * value