enabled enforced static typing

This commit is contained in:
2024-02-22 06:22:22 +11:00
parent e1a867d2a9
commit a93660f755
1645 changed files with 24730 additions and 2078 deletions

View File

@ -1,44 +1,43 @@
extends Node3D
class_name AStarGraph3D
class_name AStarGraph3D extends Node3D
@export var grid_size := Vector2i(15, 7)
@export var point_gap := 2.0
var non_build_locations = []
var astar := AStar3D.new()
@export var grid_size: Vector2i = Vector2i(15, 7)
@export var point_gap: float = 2.0
var non_build_locations: Array = []
var astar: AStar3D = AStar3D.new()
#TODO generalize this better
@export var start : Node3D
@export var end : Node3D
@export var spawner : EnemySpawner
@export var visualized_path : VisualizedPath
@export var tower_path : Node
var tower_base_scene = load("res://Scenes/tower_base.tscn")
var tower_frame_scene = load("res://Scenes/tower_frame.tscn")
var tower_bases = []
var tower_base_ids = {}
var tower_frames = []
var wall_id = 0
@export var start: Node3D
@export var end: Node3D
@export var spawner: EnemySpawner
@export var visualized_path: VisualizedPath
@export var tower_path: Node
var tower_base_scene: PackedScene = load("res://Scenes/tower_base.tscn")
var tower_frame_scene: PackedScene = load("res://Scenes/tower_frame.tscn")
var tower_bases: Array = []
var tower_base_ids: Dictionary = {}
var tower_frames: Array = []
var wall_id: int = 0
func toggle_point(point_id, caller_id):
func toggle_point(point_id: int, caller_id: int) -> void:
networked_toggle_point.rpc(point_id, caller_id)
func remove_wall(wall : TowerBase):
func remove_wall(wall: TowerBase) -> void:
networked_remove_wall.rpc(wall.point_id)
toggle_point(wall.point_id, multiplayer.get_unique_id())
func point_is_build_location(point_id):
func point_is_build_location(point_id: int) -> bool:
return !non_build_locations.has(point_id)
func test_path_if_point_toggled(point_id) -> bool:
func test_path_if_point_toggled(point_id: int) -> bool:
if astar.is_point_disabled(point_id):
astar.set_point_disabled(point_id, false)
else:
astar.set_point_disabled(point_id, true)
var result = find_path()
var result: bool = find_path()
if astar.is_point_disabled(point_id):
astar.set_point_disabled(point_id, false)
else:
@ -47,7 +46,7 @@ func test_path_if_point_toggled(point_id) -> bool:
@rpc("reliable", "any_peer", "call_local")
func networked_toggle_point(point_id, caller_id):
func networked_toggle_point(point_id: int, caller_id: int) -> void:
if astar.is_point_disabled(point_id):
astar.set_point_disabled(point_id, false)
else:
@ -59,46 +58,46 @@ func networked_toggle_point(point_id, caller_id):
wall_id += 1
func get_north_point(point_id) -> int:
var x = point_id / grid_size.y
var y = point_id % grid_size.y
func get_north_point(point_id: int) -> int:
var x: int = floori(float(point_id) / float(grid_size.y))
var y: int = point_id % grid_size.y
if x - 1 >= 0: #if the north point id could possibly exist as a neighbor
return (x - 1) * grid_size.y + y
return -1
func get_south_point(point_id) -> int:
var x = point_id / grid_size.y
var y = point_id % grid_size.y
func get_south_point(point_id: int) -> int:
var x: int = floori(float(point_id) / float(grid_size.y))
var y: int = point_id % grid_size.y
if x + 1 <= grid_size.x - 1: #if the south point id could possibly exist as a neighbor
return (x + 1) * grid_size.y + y
return -1
func get_west_point(point_id) -> int:
var x = point_id / grid_size.y
var y = point_id % grid_size.y
func get_west_point(point_id: int) -> int:
var x: int = floori(float(point_id) / float(grid_size.y))
var y: int = point_id % grid_size.y
if y + 1 <= grid_size.y - 1: #if the east point id could possibly exist as a neighbor
return x * grid_size.y + y + 1
return -1
func get_east_point(point_id) -> int:
var x = point_id / grid_size.y
var y = point_id % grid_size.y
func get_east_point(point_id: int) -> int:
var x: int = floori(float(point_id) / float(grid_size.y))
var y: int = point_id % grid_size.y
if y - 1 >= 0: #if the west point id could possibly exist as a neighbor
return x * grid_size.y + y - 1
return -1
func count_valid_neighbours(point_id) -> int:
func count_valid_neighbours(point_id: int) -> int:
if !point_id:
return 0
var valid_neighbours = 0
var north_point = get_north_point(point_id)
var south_point = get_south_point(point_id)
var east_point = get_east_point(point_id)
var west_point = get_west_point(point_id)
var valid_neighbours: int = 0
var north_point: int = get_north_point(point_id)
var south_point: int = get_south_point(point_id)
var east_point: int = get_east_point(point_id)
var west_point: int = get_west_point(point_id)
if north_point and !astar.is_point_disabled(north_point):
valid_neighbours += 1
@ -118,102 +117,102 @@ func count_valid_neighbours(point_id) -> int:
return valid_neighbours
func disable_all_tower_frames():
for frame in tower_frames:
func disable_all_tower_frames() -> void:
for frame: Node3D in tower_frames:
frame.set_visible(false)
func enable_non_path_tower_frames():
for frame in tower_frames:
func enable_non_path_tower_frames() -> void:
for frame: Node3D in tower_frames:
if !astar.is_point_disabled(tower_frames.find(frame)):
frame.set_visible(true)
disable_path_tower_frames()
func disable_path_tower_frames():
for id in astar.get_id_path(astar.get_point_count() - 2, astar.get_point_count() - 1):
func disable_path_tower_frames() -> void:
for id: int in astar.get_id_path(astar.get_point_count() - 2, astar.get_point_count() - 1):
if id < (grid_size.x * grid_size.y) and !test_path_if_point_toggled(id):
tower_frames[id].set_visible(false)
@rpc("reliable", "call_local")
func networked_spawn_wall(pos : Vector3, name_id : int, caller_id : int):
var base = tower_base_scene.instantiate() as TowerBase
func networked_spawn_wall(pos: Vector3, name_id: int, caller_id: int) -> void:
var base: TowerBase = tower_base_scene.instantiate() as TowerBase
base.position = pos
base.name = "Wall" + str(name_id)
base.owner_id = caller_id
var point_id = astar.get_closest_point(pos, true)
var point_id: int = astar.get_closest_point(pos, true)
base.point_id = point_id
tower_base_ids[point_id] = base
tower_bases.append(base)
tower_path.add_child(base)
var north_point = get_north_point(point_id)
var south_point = get_south_point(point_id)
var east_point = get_east_point(point_id)
var west_point = get_west_point(point_id)
if north_point >= 0 and astar.is_point_disabled(north_point):
var north_point: int = get_north_point(point_id)
var south_point: int = get_south_point(point_id)
var east_point: int = get_east_point(point_id)
var west_point: int = get_west_point(point_id)
if north_point >= 0 and tower_base_ids.has(north_point) and astar.is_point_disabled(north_point):
base.set_north_wall(true)
tower_base_ids[north_point].set_south_wall(true)
if south_point >= 0 and astar.is_point_disabled(south_point):
if south_point >= 0 and tower_base_ids.has(south_point) and astar.is_point_disabled(south_point):
base.set_south_wall(true)
tower_base_ids[south_point].set_north_wall(true)
if east_point >= 0 and astar.is_point_disabled(east_point):
if east_point >= 0 and tower_base_ids.has(east_point) and astar.is_point_disabled(east_point):
base.set_east_wall(true)
tower_base_ids[east_point].set_west_wall(true)
if west_point >= 0 and astar.is_point_disabled(west_point):
if west_point >= 0 and tower_base_ids.has(west_point) and astar.is_point_disabled(west_point):
base.set_west_wall(true)
tower_base_ids[west_point].set_east_wall(true)
@rpc("reliable", "call_local", "any_peer")
func networked_remove_wall(new_wall_id: int):
var wall = tower_base_ids[new_wall_id]
func networked_remove_wall(new_wall_id: int) -> void:
var wall: TowerBase = tower_base_ids[new_wall_id]
Game.connected_players_nodes[wall.owner_id].currency += Data.wall_cost
tower_bases.erase(wall)
tower_base_ids.erase(new_wall_id)
wall.queue_free()
var north_point = get_north_point(new_wall_id)
var south_point = get_south_point(new_wall_id)
var east_point = get_east_point(new_wall_id)
var west_point = get_west_point(new_wall_id)
if north_point >= 0 and astar.is_point_disabled(north_point):
var north_point: int = get_north_point(new_wall_id)
var south_point: int = get_south_point(new_wall_id)
var east_point: int = get_east_point(new_wall_id)
var west_point: int = get_west_point(new_wall_id)
if north_point >= 0 and tower_base_ids.has(north_point) and astar.is_point_disabled(north_point):
tower_base_ids[north_point].set_south_wall(false)
if south_point >= 0 and astar.is_point_disabled(south_point):
if south_point >= 0 and tower_base_ids.has(south_point) and astar.is_point_disabled(south_point):
tower_base_ids[south_point].set_north_wall(false)
if east_point >= 0 and astar.is_point_disabled(east_point):
if east_point >= 0 and tower_base_ids.has(east_point) and astar.is_point_disabled(east_point):
tower_base_ids[east_point].set_west_wall(false)
if west_point >= 0 and astar.is_point_disabled(west_point):
if west_point >= 0 and tower_base_ids.has(west_point) and astar.is_point_disabled(west_point):
tower_base_ids[west_point].set_east_wall(false)
func build_random_maze(block_limit):
var untested_point_ids = []
for index in (grid_size.x * grid_size.y):
func build_random_maze(block_limit: int) -> void:
var untested_point_ids: Array = []
for index: int in (grid_size.x * grid_size.y):
untested_point_ids.append(index)
if block_limit <= 0 or block_limit > untested_point_ids.size():
block_limit = untested_point_ids.size()
for index in block_limit:
var random_point = untested_point_ids.pick_random()
for index: int in block_limit:
var random_point: int = untested_point_ids.pick_random()
untested_point_ids.erase(random_point)
if test_path_if_point_toggled(random_point):
networked_toggle_point.rpc(random_point, multiplayer.get_unique_id())
func place_random_towers(tower_limit):
var untowered_bases = tower_bases.duplicate()
func place_random_towers(tower_limit: int) -> void:
var untowered_bases: Array = tower_bases.duplicate()
if tower_limit <= 0 or tower_limit > untowered_bases.size():
tower_limit = untowered_bases.size()
for index in tower_limit:
var random_base = untowered_bases.pick_random() as TowerBase
for index: int in tower_limit:
var random_base: TowerBase = untowered_bases.pick_random() as TowerBase
untowered_bases.erase(random_base)
random_base.add_card(Data.cards.pick_random(), multiplayer.get_unique_id())
func find_path() -> bool:
var path = astar.get_point_path(astar.get_point_count() - 2, astar.get_point_count() - 1)
var path: PackedVector3Array = astar.get_point_path(astar.get_point_count() - 2, astar.get_point_count() - 1)
if !path.is_empty():
var curve = Curve3D.new()
for point in path:
var curve: Curve3D = Curve3D.new()
for point: Vector3 in path:
curve.add_point(point)
spawner.path.curve = curve
spawner.path.spawn_visualizer_points()
@ -221,37 +220,37 @@ func find_path() -> bool:
return false
func make_grid():
for x in grid_size.x:
for y in grid_size.y:
var point_position = Vector3((x - floori(grid_size.x / 2)) * point_gap, 0.5, (y - floori(grid_size.y / 2)) * point_gap)
func make_grid() -> void:
for x: int in grid_size.x:
for y: int in grid_size.y:
var point_position: Vector3 = Vector3((x - floori(grid_size.x / 2.0)) * point_gap, 0.5, (y - floori(grid_size.y / 2.0)) * point_gap)
astar.add_point(int(x * grid_size.y + y), point_position)
var frame = tower_frame_scene.instantiate()
var frame: Node3D = tower_frame_scene.instantiate()
frame.position = point_position
tower_frames.append(frame)
add_child(frame)
for x in grid_size.x:
for y in grid_size.y:
var point_id = grid_size.y * x + y
for x: int in grid_size.x:
for y: int in grid_size.y:
var point_id: int = grid_size.y * x + y
if x > 0:
var north_point_id = grid_size.y * (x - 1) + y
var north_point_id: int = grid_size.y * (x - 1) + y
astar.connect_points(point_id, north_point_id, false)
if x < grid_size.x - 1:
var south_point_id = grid_size.y * (x + 1) + y
var south_point_id: int = grid_size.y * (x + 1) + y
astar.connect_points(point_id, south_point_id, false)
if y > 0:
var east_point_id = grid_size.y * x + (y - 1)
var east_point_id: int = grid_size.y * x + (y - 1)
astar.connect_points(point_id, east_point_id, false)
if y < grid_size.y - 1:
var west_point_id = grid_size.y * x + (y + 1)
var west_point_id: int = grid_size.y * x + (y + 1)
astar.connect_points(point_id, west_point_id, false)
non_build_locations.append(astar.get_point_count())
astar.add_point(astar.get_point_count(), start.global_position)
for x in grid_size.y:
for x: int in grid_size.y:
astar.connect_points(int(astar.get_point_count() - 1), x)
non_build_locations.append(astar.get_point_count())
astar.add_point(astar.get_point_count(), end.global_position)
for x in grid_size.y:
for x: int in grid_size.y:
astar.connect_points(astar.get_point_count() - 1, int(grid_size.y * (grid_size.x - 1) + x))

View File

@ -1,15 +1,14 @@
extends Node3D
class_name CinematicCamManager
class_name CinematicCamManager extends Node3D
@export var path_follows : Array[PathFollow3D]
@export var cameras : Array[Camera3D]
@export var pan_speed := 1.0
var current_cam := 0
var does_its_thing := true
@export var path_follows: Array[PathFollow3D]
@export var cameras: Array[Camera3D]
@export var pan_speed: float = 1.0
var current_cam: int = 0
var does_its_thing: bool = true
func _ready() -> void:
for path_follow in path_follows:
for path_follow: PathFollow3D in path_follows:
path_follow.progress_ratio = 0.0
if does_its_thing:
cameras[0].make_current()

View File

@ -1,10 +1,9 @@
@tool
extends MeshInstance3D
class_name DebugMesh
class_name DebugMesh extends MeshInstance3D
func _ready():
var mat = StandardMaterial3D.new()
func _ready() -> void:
var mat: StandardMaterial3D = StandardMaterial3D.new()
mesh = ImmediateMesh.new()
mat.no_depth_test = true
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
@ -13,7 +12,7 @@ func _ready():
set_material_override(mat)
func clear():
func clear() -> void:
mesh.clear_surfaces()
@ -28,15 +27,15 @@ func draw_line(begin_pos: Vector3, end_pos: Vector3, color: Color = Color.RED) -
func draw_sphere(center: Vector3, radius: float = 1.0, color: Color = Color.RED) -> void:
var step: int = 30
var sppi: float = 2 * PI / step
var axes = [
var axes: Array = [
[Vector3.UP, Vector3.RIGHT],
[Vector3.RIGHT, Vector3.FORWARD],
[Vector3.FORWARD, Vector3.UP]
]
for axis in axes:
for axis: Array in axes:
mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP)
mesh.surface_set_color(color)
for i in range(step + 1):
for i: int in range(step + 1):
mesh.surface_add_vertex(center + (axis[0] * radius)
.rotated(axis[1], sppi * (i % step)))
mesh.surface_end()

View File

@ -1,8 +1,7 @@
extends EnemyMovement
class_name BeeliningController
class_name BeeliningController extends EnemyMovement
var goal : Node3D
var direction : Vector3
var goal: Node3D
var direction: Vector3
func _ready() -> void:
@ -11,6 +10,6 @@ func _ready() -> void:
func _physics_process(delta: float) -> void:
var distance_travelled = (character.stats.movement_speed * clampf(character.movement_speed_penalty, 0.0, 1.0)) * delta
var distance_travelled: float = (character.stats.movement_speed * clampf(character.movement_speed_penalty, 0.0, 1.0)) * delta
distance_remaining -= distance_travelled
character.global_position = character.global_position + (direction * distance_travelled)

View File

@ -1,6 +1,5 @@
extends Node
class_name EnemyMovement
class_name EnemyMovement extends Node
@export var character : CharacterBody3D
@export var character: CharacterBody3D
var distance_remaining := 0.0
var distance_remaining: float = 0.0

View File

@ -1,8 +1,7 @@
extends EnemyMovement
class_name PathingController
class_name PathingController extends EnemyMovement
var path : Curve3D
var path_progress = 0.0
var path: Curve3D
var path_progress: float = 0.0
func _ready() -> void:
@ -13,9 +12,9 @@ func _ready() -> void:
func _physics_process(delta: float) -> void:
if !path:
return
var distance_travelled = (character.stats.movement_speed * clampf(character.movement_speed_penalty, 0.0, 1.0)) * delta
var distance_travelled: float = (character.stats.movement_speed * clampf(character.movement_speed_penalty, 0.0, 1.0)) * delta
distance_remaining -= distance_travelled
path_progress += distance_travelled
var sample = path.sample_baked_with_rotation(path_progress, true)
var sample: Transform3D = path.sample_baked_with_rotation(path_progress, true)
character.global_position = sample.origin
character.look_at(character.global_position + -sample.basis.z)

View File

@ -1,50 +1,49 @@
extends CanvasLayer
class_name HUD
class_name HUD extends CanvasLayer
var last_lives_count = 120
@export var wave_count : Label
@export var lives_count : Label
@export var currency_count : Label
@export var minimap_outline : TextureRect
@export var crosshair : Control
@export var minimap : TextureRect
@export var minimap_cam : MinimapCamera3D
@export var minimap_viewport : SubViewport
@export var fps_label : Label
@export var hover_text : Label
var minimap_anchor : Node3D
var enemy_names = []
@export var enemy_sprites : Array[TextureRect]
@export var enemy_counts : Array[Label]
@export var weapon_energy_bar : TextureProgressBar
@export var offhand_energy_bar : TextureProgressBar
@export var pickup_notif_scene : PackedScene
@export var wave_start_label : Label
var last_lives_count: int = 120
@export var wave_count: Label
@export var lives_count: Label
@export var currency_count: Label
@export var minimap_outline: TextureRect
@export var crosshair: Control
@export var minimap: TextureRect
@export var minimap_cam: MinimapCamera3D
@export var minimap_viewport: SubViewport
@export var fps_label: Label
@export var hover_text: Label
var minimap_anchor: Node3D
var enemy_names: Array[String]
@export var enemy_sprites: Array[TextureRect]
@export var enemy_counts: Array[Label]
@export var weapon_energy_bar: TextureProgressBar
@export var offhand_energy_bar: TextureProgressBar
@export var pickup_notif_scene: PackedScene
@export var wave_start_label: Label
func set_energy_visible(value):
func set_energy_visible(value: bool) -> void:
weapon_energy_bar.set_visible(value)
func set_offhand_energy_visible(value):
func set_offhand_energy_visible(value: bool) -> void:
offhand_energy_bar.set_visible(value)
func _process(delta: float) -> void:
func _process(_delta: float) -> void:
fps_label.text = "FPS: " + str(Engine.get_frames_per_second())
wave_start_label.text = "Press [" + Data.player_keymap.ready.as_text_key_label() + "] to start wave"
func grow_wave_start_label():
func grow_wave_start_label() -> void:
tween_label(300.0)
func shrink_wave_start_label():
func shrink_wave_start_label() -> void:
tween_label(0.0)
func tween_label(x: float) -> void:
var tween = create_tween()
var tween: Tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT)
tween.set_trans(Tween.TRANS_QUAD)
if x > 0.0:
@ -55,45 +54,45 @@ func tween_label(x: float) -> void:
tween.tween_callback(wave_start_label.set_visible.bind(false))
func set_hover_text(text):
func set_hover_text(text: String) -> void:
hover_text.text = text
hover_text.set_visible(true)
func unset_hover_text():
func unset_hover_text() -> void:
hover_text.set_visible(false)
func set_wave_count(value):
func set_wave_count(value: int) -> void:
wave_count.text = str(value)
func set_lives_count(value):
func set_lives_count(value: int) -> void:
lives_count.text = str(value)
for x in last_lives_count - value:
for x: int in last_lives_count - value:
$LivesBar.take_life()
last_lives_count = value
func enemy_count_down(enemy):
var index = enemy_names.find(enemy.title)
var num = enemy_counts[index].text.to_int() - 1
func enemy_count_down(enemy: Enemy) -> void:
var index: int = enemy_names.find(enemy.title)
var num: int = enemy_counts[index].text.to_int() - 1
enemy_counts[index].text = str(num)
if num == 0:
enemy_counts[index].set_visible(false)
enemy_sprites[index].set_visible(false)
func set_upcoming_wave(value):
var frame_count = 0
func set_upcoming_wave(value: Dictionary) -> void:
var frame_count: int = 0
enemy_names = []
var wave = {}
for index in value:
var wave: Dictionary = {}
for index: int in value:
wave[Data.enemies[index]] = value[index]
for x in enemy_sprites.size():
for x: int in enemy_sprites.size():
enemy_sprites[x].set_visible(false)
enemy_counts[x].set_visible(false)
for enemy in wave:
for enemy: Enemy in wave:
enemy_names.append(enemy.title)
enemy_sprites[frame_count].texture = enemy.icon
enemy_counts[frame_count].text = str(wave[enemy])
@ -102,23 +101,23 @@ func set_upcoming_wave(value):
frame_count += 1
func set_currency_count(value):
func set_currency_count(value: int) -> void:
currency_count.text = str(value)
func set_crosshair_visible(value : bool):
func set_crosshair_visible(value: bool) -> void:
crosshair.set_visible(value)
func set_weapon_energy(value):
func set_weapon_energy(value: int) -> void:
weapon_energy_bar.value = value
func set_offhand_energy(value):
func set_offhand_energy(value: int) -> void:
offhand_energy_bar.value = value
func maximise_minimap(anchor):
func maximise_minimap(anchor: Node3D) -> void:
minimap_cam.anchor = anchor
minimap.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
minimap.offset_bottom = -40
@ -131,7 +130,7 @@ func maximise_minimap(anchor):
currency_count.set_visible(false)
func minimize_minimap(anchor):
func minimize_minimap(anchor: Node3D) -> void:
minimap_cam.anchor = anchor
minimap.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
minimap.offset_right = -40
@ -145,6 +144,6 @@ func minimize_minimap(anchor):
func pickup(card: Card) -> void:
var notif = pickup_notif_scene.instantiate()
var notif: PickupNotification = pickup_notif_scene.instantiate()
notif.set_card(card)
$VBoxContainer.add_child(notif)

View File

@ -1,11 +1,10 @@
extends Projectile
class_name ExplosiveProjectile
class_name ExplosiveProjectile extends Projectile
@export var explosion_range := 3.0
@export var explosion_range: float = 3.0
var exploded := false
var sound_done := false
var particles_done := false
var exploded: bool = false
var sound_done: bool = false
var particles_done: bool = false
func _process(delta: float) -> void:
@ -18,12 +17,12 @@ func _on_body_entered(_body: Node) -> void:
explode()
func explode():
func explode() -> void:
if is_multiplayer_authority() and !exploded:
freeze = true
exploded = true
$CollisionShape3D.call_deferred("set_disabled", true)
for enemy in get_tree().get_nodes_in_group("Enemies"):
for enemy: EnemyController in get_tree().get_nodes_in_group("Enemies"):
if global_position.distance_to(enemy.global_position) <= explosion_range:
hit(enemy)
networked_hit.rpc(get_tree().root.get_path_to(enemy))
@ -33,7 +32,7 @@ func explode():
$AudioStreamPlayer.play()
func hit(target):
func hit(target: CharacterBody3D) -> void:
target.damage(damage)
if owner_id == 0:
if Data.preferences.display_tower_damage_indicators:
@ -47,13 +46,13 @@ func hit(target):
@rpc("reliable")
func networked_hit(target_node_path):
var target = get_tree().root.get_node(target_node_path)
func networked_hit(target_node_path: String) -> void:
var target: CharacterBody3D = get_tree().root.get_node(target_node_path)
hit(target)
@rpc("reliable")
func networked_kill():
func networked_kill() -> void:
$Sprite3D.set_visible(false)
$GPUParticles3D.emitting = true
$AudioStreamPlayer.play()

View File

@ -1,9 +1,8 @@
extends ExplosiveProjectile
class_name HomingProjectile
class_name HomingProjectile extends ExplosiveProjectile
var target : Node3D
var acceleration := 50.0
var max_speed := 13.0
var target: Node3D
var acceleration: float = 50.0
var max_speed: float = 13.0
func _physics_process(_delta: float) -> void:

View File

@ -1,15 +1,14 @@
extends RigidBody3D
class_name Projectile
class_name Projectile extends RigidBody3D
@export var collision_shape : CollisionShape3D
@export var collision_shape: CollisionShape3D
var damage_particle_scene = preload("res://Scenes/damage_particle.tscn")
var owner_id = 0 #should be left unchanged by towers, 1 for host, peer_id on peers
var direction := Vector3.FORWARD
var force := 2.0
var damage := 0.0
var lifetime := 10.0
var time_alive := 0.0
var damage_particle_scene: PackedScene = preload("res://Scenes/damage_particle.tscn")
var owner_id: int = 0 #should be left unchanged by towers, 1 for host, peer_id on peers
var direction: Vector3= Vector3.FORWARD
var force: float = 2.0
var damage: float = 0.0
var lifetime: float = 10.0
var time_alive: float = 0.0
func _ready() -> void:
@ -20,9 +19,9 @@ func _process(delta: float) -> void:
time_alive += delta
func spawn_damage_indicator(pos):
func spawn_damage_indicator(pos: Vector3) -> void:
if damage > 0:
var marker = damage_particle_scene.instantiate()
var marker: Node3D = damage_particle_scene.instantiate()
get_tree().root.add_child(marker)
marker.set_number(damage)
marker.position = pos
@ -33,5 +32,5 @@ func _on_body_entered(_body: Node) -> void:
@rpc("reliable")
func networked_kill():
func networked_kill() -> void:
queue_free()

View File

@ -1,15 +1,14 @@
extends ExplosiveProjectile
class_name StatusApplyingProjectile
class_name StatusApplyingProjectile extends ExplosiveProjectile
@export var status_stats : StatusStats
@export var status_stats: StatusStats
func hit(target):
func hit(target: CharacterBody3D) -> void:
super.hit(target)
target.status_manager.add_effect(build_status_object())
func build_status_object() -> StatusEffect:
var status = StatusEffect.new()
var status: StatusEffect = StatusEffect.new()
status.stats = status_stats
return status

View File

@ -1,11 +1,10 @@
extends Item
class_name Card
class_name Card extends Item
enum Faction {GENERIC = 0}
@export var rarity : Data.Rarity
@export var faction : Faction
@export var turret_scene : PackedScene
@export var weapon_scene : PackedScene
@export var weapon_stats : CardText
@export var tower_stats : CardText
@export var rarity: Data.Rarity
@export var faction: Faction
@export var turret_scene: PackedScene
@export var weapon_scene: PackedScene
@export var weapon_stats: CardText
@export var tower_stats: CardText

View File

@ -1,13 +1,12 @@
extends Resource
class_name CardText
class_name CardText extends Resource
@export var target_type : Data.TargetType
@export var attributes : Array[StatAttribute]
@export_multiline var text : String
@export var target_type: Data.TargetType
@export var attributes: Array[StatAttribute]
@export_multiline var text: String
func get_attribute(attribute : String) -> float:
for stat in attributes:
func get_attribute(attribute: String) -> float:
for stat: StatAttribute in attributes:
if stat.key == attribute:
return stat.value
return 0.0

View File

@ -1,13 +1,12 @@
extends Resource
class_name Enemy
class_name Enemy extends Resource
@export var title := "dog"
@export var title: String = "dog"
@export var target_type: Data.EnemyType
@export var icon: Texture
@export var death_sprite: Texture
@export var sprite: AtlasTexture
@export var spawn_power:= 10
@export var health := 100
@export var penalty := 10
@export var movement_speed := 0.5
@export var spawn_cooldown := 1.0
@export var spawn_power: int = 10
@export var health: int = 100
@export var penalty: int = 10
@export var movement_speed: float = 0.5
@export var spawn_cooldown: float = 1.0

View File

@ -1,7 +1,6 @@
extends Resource
class_name HeroClass
class_name HeroClass extends Resource
@export var hero_name : String = "Default"
@export var texture : Texture
@export var hand_texture : Texture
@export var deck : Array[Card]
@export var hero_name: String = "Default"
@export var texture: Texture
@export var hand_texture: Texture
@export var deck: Array[Card]

View File

@ -1,5 +1,4 @@
extends Resource
class_name Item
class_name Item extends Resource
@export var display_name : String
@export var icon : Texture
@export var display_name: String
@export var icon: Texture

View File

@ -1,20 +1,19 @@
extends Resource
class_name PlayerAudioSettings
class_name PlayerAudioSettings extends Resource
const SAVE_PATH := "user://audio_settings.tres"
const SAVE_PATH: String = "user://audio_settings.tres"
@export var master := 100.0
@export var music := 100.0
@export var sfx := 100.0
@export var master: float = 100.0
@export var music: float = 100.0
@export var sfx: float = 100.0
func apply_audio_settings():
func apply_audio_settings() -> void:
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), linear_to_db(master / 100.0))
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Music"), linear_to_db(music / 100.0))
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("SFX"), linear_to_db(sfx / 100.0))
func save_profile_to_disk():
func save_profile_to_disk() -> void:
ResourceSaver.save(self, SAVE_PATH)
static func load_profile_from_disk() -> PlayerAudioSettings:
if ResourceLoader.exists(SAVE_PATH):

View File

@ -1,15 +1,14 @@
extends Resource
class_name PlayerGraphicsSettings
class_name PlayerGraphicsSettings extends Resource
const SAVE_PATH := "user://graphics_settings.tres"
const SAVE_PATH: String = "user://graphics_settings.tres"
@export var hfov := 100.0
@export var vsync_mode := 1
@export var aa_mode := 0
@export var windowed_mode := 0
@export var hfov: float = 100.0
@export var vsync_mode: int = 1
@export var aa_mode: int = 0
@export var windowed_mode: int = 0
func apply_graphical_settings(viewport):
func apply_graphical_settings(viewport: Viewport) -> void:
DisplayServer.window_set_vsync_mode(vsync_mode)
match aa_mode:
0:
@ -30,7 +29,7 @@ func apply_graphical_settings(viewport):
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN)
func save_profile_to_disk():
func save_profile_to_disk() -> void:
ResourceSaver.save(self, SAVE_PATH)
static func load_profile_from_disk() -> PlayerGraphicsSettings:
if ResourceLoader.exists(SAVE_PATH):

View File

@ -1,60 +1,173 @@
extends Resource
class_name PlayerKeymap
class_name PlayerKeymap extends Resource
const SAVE_PATH := "user://keymap.tres"
const SAVE_PATH: String = "user://keymap.tres"
@export var title : String
@export var title: String
@export var move_forward : InputEventKey
@export var move_backward : InputEventKey
@export var move_left : InputEventKey
@export var move_right : InputEventKey
@export var jump : InputEventKey
@export var sprint : InputEventKey
@export var interact : InputEventKey
@export var open_text_chat : InputEventKey
@export var ready : InputEventKey
@export var pause : InputEventKey
@export var equip_card_in_gauntlet : InputEventKey
@export var view_map : InputEventKey
@export_category("Primary Bindings")
@export var move_forward: InputEvent
@export var move_backward: InputEvent
@export var move_left: InputEvent
@export var move_right: InputEvent
@export var jump: InputEvent
@export var sprint: InputEvent
@export var interact: InputEvent
@export var open_text_chat: InputEvent
@export var ready: InputEvent
@export var pause: InputEvent
@export var equip_card_in_gauntlet: InputEvent
@export var view_map: InputEvent
@export var fire1: InputEvent
@export var fire2: InputEvent
@export var select_next_card: InputEvent
@export var select_prev_card: InputEvent
@export_category("Secondary Bindings")
@export var secondary_move_forward: InputEvent
@export var secondary_move_backward: InputEvent
@export var secondary_move_left: InputEvent
@export var secondary_move_right: InputEvent
@export var secondary_jump: InputEvent
@export var secondary_sprint: InputEvent
@export var secondary_interact: InputEvent
@export var secondary_open_text_chat: InputEvent
@export var secondary_ready: InputEvent
@export var secondary_pause: InputEvent
@export var secondary_equip_card_in_gauntlet: InputEvent
@export var secondary_view_map: InputEvent
@export var secondary_fire1: InputEvent
@export var secondary_fire2: InputEvent
@export var secondary_select_next_card: InputEvent
@export var secondary_select_prev_card: InputEvent
func apply():
replace_action_event("Move Forward", move_forward)
replace_action_event("Move Backward", move_backward)
replace_action_event("Move Left", move_left)
replace_action_event("Move Right", move_right)
replace_action_event("Jump", jump)
replace_action_event("Sprint", sprint)
replace_action_event("Interact", interact)
replace_action_event("Open Text Chat", open_text_chat)
replace_action_event("Ready", ready)
replace_action_event("Pause", pause)
replace_action_event("Equip In Gauntlet", equip_card_in_gauntlet)
replace_action_event("View Map", view_map)
func apply() -> void:
replace_action_event("Move Forward", move_forward, secondary_move_forward)
replace_action_event("Move Backward", move_backward, secondary_move_backward)
replace_action_event("Move Left", move_left, secondary_move_left)
replace_action_event("Move Right", move_right, secondary_move_right)
replace_action_event("Jump", jump, secondary_jump)
replace_action_event("Sprint", sprint, secondary_sprint)
replace_action_event("Interact", interact, secondary_interact)
replace_action_event("Open Text Chat", open_text_chat, secondary_open_text_chat)
replace_action_event("Ready", ready, secondary_ready)
replace_action_event("Pause", pause, secondary_pause)
replace_action_event("Equip In Gauntlet", equip_card_in_gauntlet, secondary_equip_card_in_gauntlet)
replace_action_event("View Map", view_map, secondary_view_map)
replace_action_event("Primary Fire", fire1, secondary_fire1)
replace_action_event("Secondary Fire", fire2, secondary_fire2)
replace_action_event("Select Next Card", select_next_card, secondary_select_next_card)
replace_action_event("Select Previous Card", select_prev_card, secondary_select_prev_card)
func replace_action_event(action_string, event):
func replace_action_event(action_string: String, event: InputEvent, secondary_event: InputEvent) -> void:
InputMap.action_erase_events(action_string)
InputMap.action_add_event(action_string, event)
if event:
InputMap.action_add_event(action_string, event)
if secondary_event:
InputMap.action_add_event(action_string, secondary_event)
func get_current_input_map():
func set_primary_action_event(action_string: String, event: InputEvent) -> void:
var secondary_event: InputEvent
if InputMap.action_get_events(action_string).size() > 1:
secondary_event = InputMap.action_get_events(action_string)[1]
replace_action_event(action_string, event, secondary_event)
func set_secondary_action_event(action_string: String, event: InputEvent) -> void:
var primary_event: InputEvent
if InputMap.action_get_events(action_string).size() > 0:
primary_event = InputMap.action_get_events(action_string)[0]
replace_action_event(action_string, primary_event, event)
func append_input_map() -> void:
InputMap.action_add_event("Move Forward", move_forward)
InputMap.action_add_event("Move Backward", move_backward)
InputMap.action_add_event("Move Left", move_left)
InputMap.action_add_event("Move Right", move_right)
InputMap.action_add_event("Jump", jump)
InputMap.action_add_event("Sprint", sprint)
InputMap.action_add_event("Interact", interact)
InputMap.action_add_event("Open Text Chat", open_text_chat)
InputMap.action_add_event("Ready", ready)
InputMap.action_add_event("Pause", pause)
InputMap.action_add_event("Equip In Gauntlet", equip_card_in_gauntlet)
InputMap.action_add_event("View Map", view_map)
InputMap.action_add_event("Primary Fire", fire1)
InputMap.action_add_event("Secondary Fire", fire2)
InputMap.action_add_event("Select Next Card", select_next_card)
InputMap.action_add_event("Select Previous Card", select_prev_card)
func get_current_input_map() -> void:
move_forward = InputMap.action_get_events("Move Forward")[0]
if InputMap.action_get_events("Move Forward").size() > 1:
secondary_move_forward = InputMap.action_get_events("Move Forward")[1]
move_backward = InputMap.action_get_events("Move Backward")[0]
if InputMap.action_get_events("Move Backward").size() > 1:
secondary_move_backward = InputMap.action_get_events("Move Backward")[1]
move_left = InputMap.action_get_events("Move Left")[0]
if InputMap.action_get_events("Move Left").size() > 1:
secondary_move_left = InputMap.action_get_events("Move Left")[1]
move_right = InputMap.action_get_events("Move Right")[0]
if InputMap.action_get_events("Move Right").size() > 1:
secondary_move_right = InputMap.action_get_events("Move Right")[1]
jump = InputMap.action_get_events("Jump")[0]
if InputMap.action_get_events("Jump").size() > 1:
secondary_jump = InputMap.action_get_events("Jump")[1]
sprint = InputMap.action_get_events("Sprint")[0]
if InputMap.action_get_events("Sprint").size() > 1:
secondary_sprint = InputMap.action_get_events("Sprint")[1]
interact = InputMap.action_get_events("Interact")[0]
if InputMap.action_get_events("Interact").size() > 1:
secondary_interact = InputMap.action_get_events("Interact")[1]
open_text_chat = InputMap.action_get_events("Open Text Chat")[0]
if InputMap.action_get_events("Open Text Chat").size() > 1:
secondary_open_text_chat = InputMap.action_get_events("Open Text Chat")[1]
ready = InputMap.action_get_events("Ready")[0]
if InputMap.action_get_events("Ready").size() > 1:
secondary_ready = InputMap.action_get_events("Ready")[1]
pause = InputMap.action_get_events("Pause")[0]
if InputMap.action_get_events("Pause").size() > 1:
secondary_pause = InputMap.action_get_events("Pause")[1]
equip_card_in_gauntlet = InputMap.action_get_events("Equip In Gauntlet")[0]
if InputMap.action_get_events("Equip In Gauntlet").size() > 1:
secondary_equip_card_in_gauntlet = InputMap.action_get_events("Equip In Gauntlet")[1]
view_map = InputMap.action_get_events("View Map")[0]
if InputMap.action_get_events("View Map").size() > 1:
secondary_view_map = InputMap.action_get_events("View Map")[1]
fire1 = InputMap.action_get_events("Primary Fire")[0]
if InputMap.action_get_events("Primary Fire").size() > 1:
secondary_fire1 = InputMap.action_get_events("Primary Fire")[1]
fire2 = InputMap.action_get_events("Secondary Fire")[0]
if InputMap.action_get_events("Secondary Fire").size() > 1:
secondary_fire2 = InputMap.action_get_events("Secondary Fire")[1]
select_next_card = InputMap.action_get_events("Select Next Card")[0]
if InputMap.action_get_events("Select Next Card").size() > 1:
secondary_select_next_card = InputMap.action_get_events("Select Next Card")[1]
select_prev_card = InputMap.action_get_events("Select Previous Card")[0]
if InputMap.action_get_events("Select Previous Card").size() > 1:
secondary_select_prev_card = InputMap.action_get_events("Select Previous Card")[1]
func save_profile_to_disk():
func save_profile_to_disk() -> void:
get_current_input_map()
ResourceSaver.save(self, SAVE_PATH)
static func load_profile_from_disk() -> PlayerKeymap:

View File

@ -1,20 +1,19 @@
extends Resource
class_name PlayerPreferences
class_name PlayerPreferences extends Resource
const SAVE_PATH := "user://preferences.tres"
const SAVE_PATH: String = "user://preferences.tres"
@export var mouse_sens := 28.0
@export var invert_lookY := false
@export var invert_lookX := false
@export var toggle_sprint := false
@export var fixed_minimap := false
@export var display_tower_damage_indicators := true
@export var display_self_damage_indicators := true
@export var display_party_damage_indicators := true
@export var display_status_effect_damage_indicators := true
@export var mouse_sens: float = 28.0
@export var invert_lookY: bool = false
@export var invert_lookX: bool = false
@export var toggle_sprint: bool = false
@export var fixed_minimap: bool = false
@export var display_tower_damage_indicators: bool = true
@export var display_self_damage_indicators: bool = true
@export var display_party_damage_indicators: bool = true
@export var display_status_effect_damage_indicators: bool = true
func save_profile_to_disk():
func save_profile_to_disk() -> void:
ResourceSaver.save(self, SAVE_PATH)
static func load_profile_from_disk() -> PlayerPreferences:
if ResourceLoader.exists(SAVE_PATH):

View File

@ -1,45 +1,44 @@
extends Resource
class_name PlayerProfile
class_name PlayerProfile extends Resource
signal display_name_changed(old_name, new_name)
signal preferred_class_changed(old_class, new_class)
signal display_name_changed(old_name: String, new_name: String)
signal preferred_class_changed(old_class: int, new_class: int)
const SAVE_PATH := "user://profile.tres"
const SAVE_PATH: String = "user://profile.tres"
@export var display_name := "Charlie"
@export var preferred_class := 0
@export var display_name: String = "Charlie"
@export var preferred_class: int = 0
func to_dict() -> Dictionary:
var dict = {}
var dict: Dictionary = {}
dict["display_name"] = display_name
dict["preferred_class"] = preferred_class
return dict
static func from_dict(dict) -> PlayerProfile:
var output = PlayerProfile.new()
static func from_dict(dict: Dictionary) -> PlayerProfile:
var output: PlayerProfile = PlayerProfile.new()
output.display_name = dict["display_name"]
output.preferred_class = dict["preferred_class"]
return output
func set_display_name(new_display_name):
func set_display_name(new_display_name: String) -> void:
if new_display_name == display_name:
return
var old_name = display_name
var old_name: String = display_name
display_name = new_display_name
save_profile_to_disk()
display_name_changed.emit(old_name, display_name)
func get_display_name() -> String:
return display_name
func set_preferred_class(new_preferred_class):
func set_preferred_class(new_preferred_class: int) -> void:
if new_preferred_class == preferred_class:
return
var old_class = preferred_class
var old_class: int = preferred_class
preferred_class = new_preferred_class
preferred_class_changed.emit(old_class, preferred_class)
func get_preferred_class() -> int:
return preferred_class
func save_profile_to_disk():
func save_profile_to_disk() -> void:
ResourceSaver.save(self, SAVE_PATH)
static func load_profile_from_disk() -> PlayerProfile:
if ResourceLoader.exists(SAVE_PATH):

View File

@ -1,7 +1,6 @@
extends Resource
class_name SaveStats
class_name SaveStats extends Resource
const SAVE_PATH := "user://save_stats.tres"
const SAVE_PATH: String = "user://save_stats.tres"
@export var wins: int
@export var losses: int
@ -18,7 +17,7 @@ func add_game_outcome(outcome: bool) -> void:
twenty_game_history.pop_front()
func save_profile_to_disk():
func save_profile_to_disk() -> void:
ResourceSaver.save(self, SAVE_PATH)
static func load_profile_from_disk() -> SaveStats:
if ResourceLoader.exists(SAVE_PATH):

View File

@ -1,5 +1,4 @@
extends Resource
class_name StatAttribute
class_name StatAttribute extends Resource
@export var key : String
@export var value : float
@export var key: String
@export var value: float

View File

@ -1,9 +1,8 @@
extends Resource
class_name StatusStats
class_name StatusStats extends Resource
@export var name : String
@export var max_stacks := 0
@export var proc_cd := 0.0
@export var duration := 1.0
@export var potency := 1.0
@export var icon : Texture
@export var name: String
@export var max_stacks: int = 0
@export var proc_cd: float = 0.0
@export var duration: float = 1.0
@export var potency: float = 1.0
@export var icon: Texture

View File

@ -1,17 +1,16 @@
extends Node3D
class_name StatusEffector
class_name StatusEffector extends Node3D
@export var hbox : HBoxContainer
@export var enemy : EnemyController
@export var hbox: HBoxContainer
@export var enemy: EnemyController
var icon_scene = preload("res://Scenes/status_icon.tscn")
var immune : Array[StatusEffect] = []
var effects = {}
var icons = {}
var icon_scene: PackedScene = preload("res://Scenes/status_icon.tscn")
var immune: Array[StatusEffect] = []
var effects: Dictionary = {}
var icons: Dictionary = {}
func _process(delta: float) -> void:
for effect in effects:
for effect: StatusEffect in effects:
if effects[effect] == 0:
continue
effect.time_since_proc += delta
@ -27,25 +26,25 @@ func _process(delta: float) -> void:
effect.time_since_proc -= effect.stats.proc_cd
func force_proc(effect_to_proc : StatusEffect):
for effect in effects:
func force_proc(effect_to_proc: StatusEffect) -> void:
for effect: StatusEffect in effects:
if effect.stats == effect_to_proc.stats:
effect.proc(enemy, effects[effect], effects)
func add_effect(new_effect : StatusEffect):
for effect in immune:
func add_effect(new_effect: StatusEffect) -> void:
for effect: StatusEffect in immune:
if effect.stats == new_effect.stats:
return
var existing_effect
for effect in effects:
var existing_effect: StatusEffect
for effect: StatusEffect in effects:
if effect.stats == new_effect.stats:
existing_effect = effect
if !existing_effect:
existing_effect = new_effect
effects[new_effect] = 0
var icon = icon_scene.instantiate()
var icon: TextureRect = icon_scene.instantiate()
icon.texture = new_effect.stats.icon
icon.set_visible(false)
icons[new_effect] = icon

View File

@ -1,6 +1,5 @@
extends StatusEffect
class_name StatusDoT
class_name StatusDoT extends StatusEffect
func proc(affected, stacks, _existing_effects):
func proc(affected: EnemyController, stacks: int, _existing_effects: Dictionary) -> void:
affected.damage(stats.potency * stacks)

View File

@ -1,19 +1,18 @@
extends RefCounted
class_name StatusEffect
class_name StatusEffect extends RefCounted
var stats : StatusStats
var stats: StatusStats
var time_since_proc := 0.0
var time_existed := 0.0
var time_since_proc: float = 0.0
var time_existed: float = 0.0
func on_attached(_affected, _existing_effects):
func on_attached(_affected: EnemyController, _existing_effects: Dictionary) -> void:
pass
func on_removed(_affected, _existing_effects):
func on_removed(_affected: EnemyController, _existing_effects: Dictionary) -> void:
pass
func proc(_affected, _stacks, _existing_effects):
func proc(_affected: EnemyController, _stacks: int, _existing_effects: Dictionary) -> void:
pass

View File

@ -1,10 +1,9 @@
extends StatusEffect
class_name StatusSlow
class_name StatusSlow extends StatusEffect
func on_attached(affected, _existing_effects):
func on_attached(affected: EnemyController, _existing_effects: Dictionary) -> void:
affected.movement_speed_penalty -= stats.potency
func on_removed(affected, _existing_effects):
func on_removed(affected: EnemyController, _existing_effects: Dictionary) -> void:
affected.movement_speed_penalty += stats.potency

View File

@ -1,8 +1,7 @@
extends Tower
class_name HitscanTower
class_name HitscanTower extends Tower
func shoot():
func shoot() -> void:
super.shoot()
if targeted_enemy and is_instance_valid(targeted_enemy) and targeted_enemy.alive:
targeted_enemy.damage(damage)
@ -11,5 +10,5 @@ func shoot():
@rpc("reliable")
func networked_shoot():
func networked_shoot() -> void:
super.networked_shoot()

View File

@ -1,26 +1,25 @@
extends Tower
class_name ProjectileTower
class_name ProjectileTower extends Tower
@export var projectile_scene : PackedScene
@export var projectile_scene: PackedScene
var force := 150.0
var projectile_id := 0
var force: float = 150.0
var projectile_id: int = 0
func shoot():
func shoot() -> void:
if is_multiplayer_authority():
networked_spawn_projectile.rpc(multiplayer.get_unique_id())
@rpc("reliable")
func networked_shoot():
func networked_shoot() -> void:
super.networked_shoot()
shoot()
@rpc("reliable", "call_local")
func networked_spawn_projectile(peer_id):
var projectile = projectile_scene.instantiate() as Projectile
func networked_spawn_projectile(peer_id: int) -> Projectile:
var projectile: Projectile = projectile_scene.instantiate() as Projectile
projectile.position = yaw_model.global_position
projectile.damage = damage
projectile.direction = -yaw_model.global_transform.basis.z

View File

@ -1,27 +1,26 @@
extends StatusApplyingTower
class_name RangeAffectingTower
class_name RangeAffectingTower extends StatusApplyingTower
func _physics_process(_delta: float) -> void:
if !is_multiplayer_authority():
return
var enemies_in_range = []
for enemy in get_tree().get_nodes_in_group("Enemies"):
var enemies_in_range: Array = []
for enemy: EnemyController in get_tree().get_nodes_in_group("Enemies"):
if !is_instance_valid(enemy) or !enemy.alive or global_position.distance_to(enemy.global_position) > target_range:
continue
if enemy.stats.target_type & stats.target_type:
enemies_in_range.append(enemy)
if time_since_firing >= time_between_shots:
time_since_firing -= time_between_shots
for enemy in enemies_in_range:
for enemy: EnemyController in enemies_in_range:
fire(enemy)
func aim():
func aim() -> void:
pass
func fire(target):
func fire(target: EnemyController) -> void:
if is_instance_valid(target) and target.alive:
target.damage(damage)
target.status_manager.add_effect(build_status_object())
@ -32,6 +31,6 @@ func fire(target):
@rpc("reliable")
func networked_fire(target_node_path):
var target = get_tree().root.get_node(target_node_path)
func networked_fire(target_node_path: String) -> void:
var target: EnemyController = get_tree().root.get_node(target_node_path)
fire(target)

View File

@ -1,9 +1,8 @@
extends Tower
class_name ShapecastTower
class_name ShapecastTower extends Tower
@export var shapecast : ShapeCast3D
@export var particlesystem : GPUParticles3D
@export var status_stats : StatusStats
@export var shapecast: ShapeCast3D
@export var particlesystem: GPUParticles3D
@export var status_stats: StatusStats
func _process(delta: float) -> void:
@ -14,19 +13,19 @@ func _process(delta: float) -> void:
particlesystem.emitting = false
func shoot():
for index in shapecast.get_collision_count():
var target = shapecast.get_collider(index) as CharacterBody3D
func shoot() -> void:
for index: int in shapecast.get_collision_count():
var target: CharacterBody3D = shapecast.get_collider(index) as CharacterBody3D
hit(target)
func aim():
func aim() -> void:
yaw_model.look_at(targeted_enemy.global_position)
pitch_model.look_at(targeted_enemy.global_position)
pitch_model.rotation.x = 0.0
func hit(target):
func hit(target: CharacterBody3D) -> void:
if is_instance_valid(target) and target.alive:
target.damage(damage)
if Data.preferences.display_tower_damage_indicators:
@ -37,12 +36,12 @@ func hit(target):
func build_status_object() -> StatusEffect:
var status = StatusEffect.new()
var status: StatusEffect = StatusEffect.new()
status.stats = status_stats
return status
@rpc("reliable")
func networked_hit(target_node_path):
var target = get_tree().root.get_node(target_node_path)
func networked_hit(target_node_path: String) -> void:
var target: CharacterBody3D = get_tree().root.get_node(target_node_path) as CharacterBody3D
hit(target)

View File

@ -1,10 +1,9 @@
extends HitscanTower
class_name StatusApplyingTower
class_name StatusApplyingTower extends HitscanTower
@export var status_stats : StatusStats
@export var status_stats: StatusStats
func shoot():
func shoot() -> void:
super.shoot()
if targeted_enemy and is_instance_valid(targeted_enemy) and targeted_enemy.alive:
targeted_enemy.damage(damage)
@ -12,11 +11,11 @@ func shoot():
func build_status_object() -> StatusEffect:
var status = StatusEffect.new()
var status: StatusEffect = StatusEffect.new()
status.stats = status_stats
return status
@rpc("reliable")
func networked_shoot():
func networked_shoot() -> void:
super.networked_shoot()

View File

@ -1,21 +1,20 @@
extends Node3D
class_name Tower
class_name Tower extends Node3D
@export var stats : CardText
@export var animator : AnimationPlayer
@export var pitch_model : MeshInstance3D
@export var yaw_model : MeshInstance3D
@export var range_indicator : CSGSphere3D
@export var audio_player : AudioStreamPlayer3D
@export var stats: CardText
@export var animator: AnimationPlayer
@export var pitch_model: MeshInstance3D
@export var yaw_model: MeshInstance3D
@export var range_indicator: CSGSphere3D
@export var audio_player: AudioStreamPlayer3D
var owner_id : int
var damage_particle_scene = preload("res://Scenes/damage_particle.tscn")
var base_name
var targeted_enemy
var time_since_firing := 0.0
var time_between_shots := 0.0
var damage := 0.0
var target_range := 0.0
var owner_id: int
var damage_particle_scene: PackedScene = preload("res://Scenes/damage_particle.tscn")
var base_name: String
var targeted_enemy: EnemyController
var time_since_firing: float = 0.0
var time_between_shots: float = 0.0
var damage: float = 0.0
var target_range: float = 0.0
func _ready() -> void:
@ -25,7 +24,7 @@ func _ready() -> void:
range_indicator.radius = target_range
func preview_range(value):
func preview_range(value: bool) -> void:
range_indicator.set_visible(value)
@ -57,19 +56,19 @@ func _physics_process(_delta: float) -> void:
shoot()
func aim():
func aim() -> void:
yaw_model.look_at(targeted_enemy.global_position)
pitch_model.look_at(targeted_enemy.global_position)
pitch_model.rotation.x = 0.0
func acquire_target():
var most_progressed_enemy = null
for enemy in get_tree().get_nodes_in_group("Enemies"):
func acquire_target() -> void:
var most_progressed_enemy: EnemyController = null
for enemy: EnemyController in get_tree().get_nodes_in_group("Enemies"):
if global_position.distance_to(enemy.global_position) > target_range:
continue
var em_1 = enemy.movement_controller as EnemyMovement
var em_2 : EnemyMovement
var em_1: EnemyMovement = enemy.movement_controller as EnemyMovement
var em_2: EnemyMovement
if most_progressed_enemy != null:
em_2 = most_progressed_enemy.movement_controller as EnemyMovement
if (most_progressed_enemy == null or em_1.distance_remaining < em_2.distance_remaining) and enemy.stats.target_type & stats.target_type:
@ -79,26 +78,26 @@ func acquire_target():
networked_acquire_target.rpc(get_tree().root.get_path_to(most_progressed_enemy))
func shoot():
func shoot() -> void:
animator.play("shoot")
audio_player.play()
if is_multiplayer_authority():
networked_shoot.rpc()
func spawn_damage_indicator(pos):
func spawn_damage_indicator(pos: Vector3) -> void:
if damage > 0:
var marker = damage_particle_scene.instantiate()
var marker: Sprite3D = damage_particle_scene.instantiate()
get_tree().root.add_child(marker)
marker.set_number(damage)
marker.position = pos
@rpc("reliable")
func networked_shoot():
func networked_shoot() -> void:
shoot()
@rpc("reliable")
func networked_acquire_target(target_node_path):
func networked_acquire_target(target_node_path: String) -> void:
targeted_enemy = get_tree().root.get_node(target_node_path)

View File

@ -1,10 +1,9 @@
extends Weapon
class_name HitscanWeapon
class_name HitscanWeapon extends Weapon
@export var raycast : RayCast3D
@export var range_debug_indicator : CSGSphere3D
@export var raycast: RayCast3D
@export var range_debug_indicator: CSGSphere3D
var attack_range := 0.0
var attack_range: float = 0.0
func _ready() -> void:
@ -15,12 +14,12 @@ func _ready() -> void:
raycast.global_position = hero.camera.global_position
func shoot():
func shoot() -> void:
super.shoot()
if raycast.is_colliding():
var target = raycast.get_collider()
var target: CharacterBody3D = raycast.get_collider()
if target != null:
var target_hitbox = target.shape_owner_get_owner(raycast.get_collider_shape())
var target_hitbox: Hitbox = target.shape_owner_get_owner(raycast.get_collider_shape())
if target_hitbox is Hitbox:
hit(target, target_hitbox)
if Data.preferences.display_self_damage_indicators:
@ -28,14 +27,14 @@ func shoot():
networked_hit.rpc(get_tree().root.get_path_to(target), get_tree().root.get_path_to(target_hitbox))
func hit(_target, target_hitbox : Hitbox):
func hit(_target: CharacterBody3D, target_hitbox: Hitbox) -> void:
target_hitbox.damage(damage)
@rpc("reliable")
func networked_hit(target_path : String, target_hitbox_path : String):
var target = get_tree().root.get_node(target_path)
var target_hitbox = get_tree().root.get_node(target_hitbox_path) as Hitbox
func networked_hit(target_path: String, target_hitbox_path: String) -> void:
var target: CharacterBody3D = get_tree().root.get_node(target_path)
var target_hitbox: Hitbox = get_tree().root.get_node(target_hitbox_path) as Hitbox
hit(target, target_hitbox)
if Data.preferences.display_party_damage_indicators:
spawn_damage_indicator(target.sprite.global_position)

View File

@ -1,25 +1,24 @@
extends Weapon
class_name ProjectileWeapon
class_name ProjectileWeapon extends Weapon
@export var projectile_scene : PackedScene
@export var projectile_scene: PackedScene
var force := 20.0
var projectile_id := 0
var force: float = 20.0
var projectile_id: int = 0
func shoot():
func shoot() -> void:
super.shoot()
networked_spawn_projectile.rpc(multiplayer.get_unique_id(), -global_transform.basis.z)
@rpc("reliable")
func networked_shoot():
func networked_shoot() -> void:
super.networked_shoot()
@rpc("reliable", "call_local")
func networked_spawn_projectile(peer_id, direction):
var projectile = projectile_scene.instantiate() as Projectile
func networked_spawn_projectile(peer_id: int, direction: Vector3) -> void:
var projectile: Projectile = projectile_scene.instantiate() as Projectile
projectile.position = global_position
projectile.damage = damage
projectile.direction = direction

View File

@ -1,12 +1,11 @@
extends Weapon
class_name ShapecastWeapon
class_name ShapecastWeapon extends Weapon
@export var shapecast : ShapeCast3D
@export var range_debug_indicator : CSGSphere3D
@export var status_stats : StatusStats
@export var particles : GPUParticles3D
@export var shapecast: ShapeCast3D
@export var range_debug_indicator: CSGSphere3D
@export var status_stats: StatusStats
@export var particles: GPUParticles3D
var attack_range := 0.0
var attack_range: float = 0.0
func _ready() -> void:
@ -22,12 +21,12 @@ func _process(delta: float) -> void:
particles.emitting = trigger_held
func shoot():
func shoot() -> void:
super.shoot()
for index in shapecast.get_collision_count():
var target = shapecast.get_collider(index)
for index: int in shapecast.get_collision_count():
var target: CharacterBody3D = shapecast.get_collider(index)
if target:
var target_hitbox = target.shape_owner_get_owner(shapecast.get_collider_shape(index))
var target_hitbox: Hitbox = target.shape_owner_get_owner(shapecast.get_collider_shape(index))
if target_hitbox is Hitbox:
hit(target, target_hitbox)
if Data.preferences.display_self_damage_indicators:
@ -36,20 +35,20 @@ func shoot():
func build_status_object() -> StatusEffect:
var status = StatusEffect.new()
var status: StatusEffect = StatusEffect.new()
status.stats = status_stats
return status
func hit(target, target_hitbox : Hitbox):
func hit(target: CharacterBody3D, target_hitbox: Hitbox) -> void:
target_hitbox.damage(damage)
target.status_manager.add_effect(build_status_object())
@rpc("reliable")
func networked_hit(target_path : String, target_hitbox_path : String):
var target = get_tree().root.get_node(target_path)
var target_hitbox = get_tree().root.get_node(target_hitbox_path) as Hitbox
func networked_hit(target_path: String, target_hitbox_path: String) -> void:
var target: CharacterBody3D = get_tree().root.get_node(target_path) as CharacterBody3D
var target_hitbox: Hitbox = get_tree().root.get_node(target_hitbox_path) as Hitbox
hit(target, target_hitbox)
if Data.preferences.display_party_damage_indicators:
spawn_damage_indicator(target.sprite.global_position)

View File

@ -1,15 +1,14 @@
extends HitscanWeapon
class_name StatusApplyingWeapon
class_name StatusApplyingWeapon extends HitscanWeapon
@export var status_stats : StatusStats
@export var status_stats: StatusStats
func hit(target, target_hitbox : Hitbox):
func hit(target: CharacterBody3D, target_hitbox: Hitbox) -> void:
super.hit(target, target_hitbox)
target.status_manager.add_effect(build_status_object())
func build_status_object() -> StatusEffect:
var status = StatusEffect.new()
var status: StatusEffect = StatusEffect.new()
status.stats = status_stats
return status

View File

@ -1,27 +1,26 @@
extends Node3D
class_name Weapon
class_name Weapon extends Node3D
signal energy_changed(energy)
signal energy_changed(energy: int)
@export var stats : CardText
@export var animator : AnimationPlayer
@export var audio_player : AudioStreamPlayer3D
@export var recharge_timer : Timer
@export var stats: CardText
@export var animator: AnimationPlayer
@export var audio_player: AudioStreamPlayer3D
@export var recharge_timer: Timer
var damage_particle_scene = preload("res://Scenes/damage_particle.tscn")
var hero : Hero
var trigger_held := false
var second_trigger_held := false
var time_since_firing := 0.0
var time_between_shots := 0.0
var damage := 0.0
var max_energy := 100.0
var current_energy := 100.0
var energy_cost := 1.0
var recharging := false
var recharge_speed := 0.0
var recharge_acceleration = 2.0
var recharge_max_speed = 25.0
var damage_particle_scene: PackedScene = preload("res://Scenes/damage_particle.tscn")
var hero: Hero
var trigger_held: bool = false
var second_trigger_held: bool = false
var time_since_firing: float = 0.0
var time_between_shots: float = 0.0
var damage: float = 0.0
var max_energy: float = 100.0
var current_energy: float = 100.0
var energy_cost: float = 1.0
var recharging: bool = false
var recharge_speed: float = 0.0
var recharge_acceleration: float = 2.0
var recharge_max_speed: float = 25.0
func _ready() -> void:
@ -30,7 +29,7 @@ func _ready() -> void:
energy_cost = stats.get_attribute("Energy")
func set_hero(value):
func set_hero(value: Hero) -> void:
hero = value
@ -56,33 +55,33 @@ func _physics_process(_delta: float) -> void:
networked_shoot.rpc()
func hold_trigger():
func hold_trigger() -> void:
trigger_held = true
func release_trigger():
func release_trigger() -> void:
if trigger_held:
recharge_timer.start()
trigger_held = false
func hold_second_trigger():
func hold_second_trigger() -> void:
second_trigger_held = true
func release_second_trigger():
func release_second_trigger() -> void:
second_trigger_held = false
func spawn_damage_indicator(pos):
func spawn_damage_indicator(pos: Vector3) -> void:
if damage > 0:
var marker = damage_particle_scene.instantiate()
var marker: Node3D = damage_particle_scene.instantiate()
get_tree().root.add_child(marker)
marker.set_number(damage)
marker.position = pos
func shoot():
func shoot() -> void:
animator.play("shoot")
audio_player.play()
recharging = false
@ -91,7 +90,7 @@ func shoot():
@rpc
func networked_shoot():
func networked_shoot() -> void:
animator.play("shoot")
audio_player.play()

View File

@ -1,9 +1,8 @@
extends PanelContainer
class_name AlertPopup
class_name AlertPopup extends PanelContainer
signal completed
signal completed()
func set_popup(prompt_text, dismiss_text):
func set_popup(prompt_text: String, dismiss_text: String) -> void:
$VBoxContainer/Label.text = prompt_text
$VBoxContainer/MarginContainerButton.text = dismiss_text

View File

@ -1,4 +1,4 @@
extends VBoxContainer
class_name AudioOptions extends VBoxContainer
@export var master_input: SpinBox
@export var master_slider: HSlider

View File

@ -1,34 +1,33 @@
extends Node2D
class_name CardInHand
class_name CardInHand extends Node2D
var stats : Card
@export var rarity_sprite : Sprite2D
@export var title_text : Label
@export var description : RichTextLabel
@export var target_label : Label
var stats: Card
@export var rarity_sprite: Sprite2D
@export var title_text: Label
@export var description: RichTextLabel
@export var target_label: Label
func set_card(value):
func set_card(value: Card) -> void:
stats = value
title_text.text = stats.display_name
target_label.text = str(Data.TargetType.keys()[stats.tower_stats.target_type])
rarity_sprite.region_rect = Rect2(64 * stats.rarity, 0, 64, 64)
func process_card_text(card_text : CardText) -> String:
var processed_string = card_text.text
for stat in card_text.attributes:
func process_card_text(card_text: CardText) -> String:
var processed_string: String = card_text.text
for stat: StatAttribute in card_text.attributes:
processed_string = processed_string.replace(stat.key, str(stat.value))
processed_string = processed_string.replace("/", "[color=red]")
processed_string = processed_string.replace("\\", "[color=black]")
return processed_string
func view_weapon():
func view_weapon() -> void:
description.text = process_card_text(stats.weapon_stats)
target_label.text = "Both"
func view_tower():
func view_tower() -> void:
description.text = process_card_text(stats.tower_stats)
target_label.text = str(Data.TargetType.keys()[stats.tower_stats.target_type])

View File

@ -1,34 +1,34 @@
extends StaticBody3D
class_name CardPrinter
class_name CardPrinter extends StaticBody3D
@export var cards : Array[CardInHand]
@export var item_card_scene : PackedScene
var card_available = false
@export var button_collider : CollisionShape3D
@export var button_box : Node3D
@export var choice_colliders : Array[CollisionShape3D]
@export var cards: Array[CardInHand]
@export var item_card_scene: PackedScene
@export var button_collider: CollisionShape3D
@export var button_box: Node3D
@export var choice_colliders: Array[CollisionShape3D]
var card_available: bool = false
func randomize_cards():
var weight_total = 0
for rarity in Data.Rarity:
func randomize_cards() -> void:
var weight_total: int = 0
for rarity: String in Data.Rarity:
weight_total += Data.rarity_weights[rarity]
var generated_rarity = randi_range(0, weight_total)
var decided_rarity := 0
var generated_rarity: int = randi_range(0, weight_total)
var decided_rarity: int = 0
for rarity in Data.Rarity:
for rarity: String in Data.Rarity:
weight_total -= Data.rarity_weights[rarity]
if generated_rarity >= weight_total:
decided_rarity = Data.Rarity[rarity]
break
var card_array = []
for x in Data.cards:
var card_array: Array = []
for x: Card in Data.cards:
if x.rarity == decided_rarity:
card_array.append(x)
var card
for x in cards:
var card: Card
for x: CardInHand in cards:
if card_array.size() > 0:
card = card_array.pick_random()
card_array.erase(card)
@ -36,18 +36,18 @@ func randomize_cards():
#TODO: in reality this should just show the icon and then hovering over it lets you see either side at the players own discretion
x.view_tower()
$Node3D.set_visible(true)
for x in choice_colliders:
for x: CollisionShape3D in choice_colliders:
x.disabled = false
card_available = true
func retrieve_card(i):
func retrieve_card(i: int) -> void:
$Node3D.set_visible(false)
for x in choice_colliders:
for x: CollisionShape3D in choice_colliders:
x.disabled = true
if card_available:
var card = cards[i].stats
var item = item_card_scene.instantiate() as ItemCard
var card: Card = cards[i].stats
var item: ItemCard = item_card_scene.instantiate() as ItemCard
item.card = card
item.position = Vector3(1.683, 0, 0)
add_child(item)
@ -56,7 +56,7 @@ func retrieve_card(i):
$AudioStreamPlayer3D.play()
func _on_static_body_3d_button_interacted(_value) -> void:
func _on_static_body_3d_button_interacted(_value: int) -> void:
button_collider.disabled = true
button_box.position = Vector3(0,0,-0.2)
$AudioStreamPlayer3D.play()

View File

@ -1,20 +1,19 @@
extends Control
class_name Chatbox
class_name Chatbox extends Control
signal opened
signal closed
@export var input_line : LineEdit
@export var textbox : RichTextLabel
@export var text_panel : PanelContainer
@export var fade_timer : Timer
@export var input_line: LineEdit
@export var textbox: RichTextLabel
@export var text_panel: PanelContainer
@export var fade_timer: Timer
var text_selected := false
var username := "default"
var color = Color.TOMATO
var fading = true
var time_to_fade = 2.0
var time_since_started_fading = 2.0
var text_selected: bool = false
var username: String = "default"
var color: Color = Color.TOMATO
var fading: bool = true
var time_to_fade: float = 2.0
var time_since_started_fading:float = 2.0
func _process(delta: float) -> void:
@ -58,12 +57,12 @@ func _input(event: InputEvent) -> void:
fade_timer.start()
func change_username(old_name, new_name):
func change_username(old_name: String, new_name: String) -> void:
append_message("SERVER", Color.TOMATO, old_name + " has changed their display name to " + new_name)
@rpc("reliable","call_local","any_peer")
func append_message(user, user_color, content):
func append_message(user: String, user_color: Color, content: String) -> void:
textbox.append_text("[[color=" + user_color.to_html() + "]" + user + "[color=white]] " + content + "\n")
fading = false
fade_timer.start()

View File

@ -1,9 +1,8 @@
extends PanelContainer
class_name ConfirmationPopup
class_name ConfirmationPopup extends PanelContainer
signal completed(outcome)
signal completed(outcome: bool)
func set_popup(prompt_text, confirm_text, cancel_text):
func set_popup(prompt_text: String, confirm_text: String, cancel_text: String) -> void:
$VBoxContainer/Label.text = prompt_text
$VBoxContainer/HBoxContainer/Confirm.text = confirm_text
$VBoxContainer/HBoxContainer/Cancel.text = cancel_text

View File

@ -1,18 +1,18 @@
extends Sprite3D
class_name DamageParticle extends Sprite3D
@onready var label: Label = $SubViewport/Label
var time_alive := 0.0
var movement_speed := 1.0
var movement_vector : Vector3
var time_alive: float = 0.0
var movement_speed: float = 1.0
var movement_vector: Vector3
func _ready():
var theta = deg_to_rad(40)
var z = randf_range(cos(theta), 1)
var phi = randf_range(0, 2 * PI)
var vector = Vector3(sqrt(1 - pow(z, 2)) * cos(phi), z, sqrt(1 - pow(z, 2)) * sin(phi))
func _ready() -> void:
var theta: float = deg_to_rad(40)
var z: float = randf_range(cos(theta), 1)
var phi: float = randf_range(0, 2 * PI)
var vector: Vector3 = Vector3(sqrt(1 - pow(z, 2)) * cos(phi), z, sqrt(1 - pow(z, 2)) * sin(phi))
movement_vector = vector.normalized()
func set_number(num):
func set_number(num: int) -> void:
label.text = str(num)

View File

@ -9,14 +9,15 @@ var audio: PlayerAudioSettings
var preferences: PlayerPreferences
var player_profile: PlayerProfile
var player_keymap: PlayerKeymap
var player_controller_keymap: PlayerKeymap = preload("res://Resources/Keymaps/controller.tres")
var save_stats: SaveStats
var wall_cost := 1
var printer_cost := 15
var wall_cost: int = 1
var printer_cost: int = 15
enum TargetType {UNDEFINED = 0, LAND = 1, AIR = 2, BOTH = 3}
enum EnemyType {UNDEFINED = 0, LAND = 1, AIR = 2}
enum Rarity {COMMON = 0, UNCOMMON = 1, RARE = 2, EPIC = 3, LEGENDARY = 4}
var rarity_weights = {
var rarity_weights: Dictionary = {
"COMMON" = 50,
"UNCOMMON" = 30,
"RARE" = 10,
@ -33,32 +34,33 @@ func _ready() -> void:
preferences = PlayerPreferences.load_profile_from_disk()
player_keymap = PlayerKeymap.load_profile_from_disk()
player_keymap.apply()
player_controller_keymap.append_input_map()
save_stats = SaveStats.load_profile_from_disk()
characters.append(preload("res://PCs/Red/red.tres"))
characters.append(preload("res://PCs/Mechanic/red.tres"))
#characters.append(preload("res://PCs/Green/green.tres"))
characters.append(preload("res://PCs/Blue/blue.tres"))
characters.append(preload("res://PCs/Mage/blue.tres"))
#Common
cards.append(preload("res://PCs/Universal/ClassCards/Assault/card_assault.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/BombLauncher/card_bomb_launcher.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/Gatling/card_gatling.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/RocketLauncher/card_rocket_launcher.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/Assault/card_assault.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/BombLauncher/card_bomb_launcher.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/Gatling/card_gatling.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/RocketLauncher/card_rocket_launcher.tres"))
#Uncommon
cards.append(preload("res://PCs/Universal/ClassCards/Sniper/card_sniper.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/Blowdart/card_blowdart.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/Refrigerator/card_refrigerator.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/GlueLauncher/card_glue_launcher.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/Sniper/card_sniper.tres"))
cards.append(preload("res://PCs/Entomologist/ClassCards/Blowdart/card_blowdart.tres"))
cards.append(preload("res://PCs/Mage/ClassCards/Refrigerator/card_refrigerator.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/GlueLauncher/card_glue_launcher.tres"))
#Rare
cards.append(preload("res://PCs/Universal/ClassCards/Flamethrower/card_flamethrower.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/Flamethrower/card_flamethrower.tres"))
#cards.append(preload("res://PCs/Universal/ClassCards/DamageEnhancer/card_damage_enhancer.tres"))
#cards.append(preload("res://PCs/Universal/ClassCards/SpeedEnhancer/card_speed_enhancer.tres"))
#Epic
cards.append(preload("res://PCs/Universal/ClassCards/Icicle/card_icicle.tres"))
cards.append(preload("res://PCs/Universal/ClassCards/Fireball/card_fireball.tres"))
cards.append(preload("res://PCs/Mage/ClassCards/Icicle/card_icicle.tres"))
cards.append(preload("res://PCs/Mage/ClassCards/Fireball/card_fireball.tres"))
#cards.append(preload("res://PCs/Universal/ClassCards/GammaLaser/card_gamma_laser.tres"))
#Legendary
cards.append(preload("res://PCs/Universal/ClassCards/Reactor/card_reactor.tres"))
cards.append(preload("res://PCs/Mechanic/ClassCards/Reactor/card_reactor.tres"))
#cards.append(preload("res://PCs/Universal/ClassCards/Lightning/card_lightning.tres"))
enemies.append(preload("res://Worlds/GreenPlanet/Enemies/dog.tres"))

View File

@ -1,32 +1,31 @@
extends Node3D
class_name EditTool
class_name EditTool extends Node3D
@export var hero : Hero
@export var inventory : Inventory
@export var ray : RayCast3D
@export var wall_preview : TowerBase
@export var progress_bar : TextureProgressBar
@export var hero: Hero
@export var inventory: Inventory
@export var ray: RayCast3D
@export var wall_preview: TowerBase
@export var progress_bar: TextureProgressBar
var enabled := true
var point_id := -1
var obstacle_last_point := -1
var valid_point := false
var is_looking_at_tower_base := false
var tower_preview
var last_tower_base
var last_collider
var last_card
var ray_collider
var ray_point
var enabled: bool = true
var point_id: int = -1
var obstacle_last_point: int = -1
var valid_point: bool = false
var is_looking_at_tower_base: bool = false
var tower_preview: Tower
var last_tower_base: TowerBase
var last_collider: Object
var last_card: Card
var ray_collider: Object
var ray_point: Vector3
var interact_key_held := false
var interacted_once := false
var interact_held_time := 0.0
var interact_hold_time := 0.4
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.GREEN
var c: Color = Color.GREEN
c.a = 0.8
wall_preview.set_color(c)
wall_preview.set_float(0.0)
@ -36,7 +35,6 @@ func _ready() -> void:
func _process(delta: float) -> void:
if !enabled:
ray_collider = null
ray_point = null
wall_preview.set_visible(false)
if is_instance_valid(last_collider):
Game.level.a_star_graph_3d.tower_base_ids[last_collider.point_id].set_float(1.0)
@ -99,13 +97,13 @@ func _process(delta: float) -> void:
if !Game.level.a_star_graph_3d.point_is_build_location(point_id) or hero.currency < Data.wall_cost:
wall_preview.set_visible(false)
else:
var point_position = Game.level.a_star_graph_3d.astar.get_point_position(point_id)
var point_position: Vector3 = Game.level.a_star_graph_3d.astar.get_point_position(point_id)
wall_preview.global_position = point_position
wall_preview.global_rotation = Vector3.ZERO
if obstacle_last_point != point_id:
obstacle_last_point = point_id
if Game.level.a_star_graph_3d.test_path_if_point_toggled(point_id):
var c = Color.GREEN
var c: Color = Color.GREEN
c.a = 0.8
wall_preview.set_color(c)
wall_preview.set_float(0.0)
@ -116,7 +114,6 @@ func _process(delta: float) -> void:
valid_point = false
else:
ray_collider = null
ray_point = null
is_looking_at_tower_base = false
delete_tower_preview()
wall_preview.set_visible(false)
@ -124,10 +121,10 @@ func _process(delta: float) -> void:
wall_preview.set_visible(false)
func spawn_tower_preview():
func spawn_tower_preview() -> void:
delete_tower_preview()
last_tower_base = ray_collider
var card = inventory.contents.keys()[hero.inventory_selected_index]
var card: Card = inventory.contents.keys()[hero.inventory_selected_index]
last_card = card
tower_preview = card.turret_scene.instantiate() as Tower
tower_preview.stats = card.tower_stats
@ -136,7 +133,7 @@ func spawn_tower_preview():
ray_collider.add_child(tower_preview)
func delete_tower_preview():
func delete_tower_preview() -> void:
last_tower_base = null
last_card = null
if is_instance_valid(tower_preview):
@ -144,35 +141,35 @@ func delete_tower_preview():
tower_preview = null
func interact():
func interact() -> void:
if ray_collider is TowerBase:
var tower_base = ray_collider as TowerBase
var tower_base: TowerBase = ray_collider as TowerBase
put_card_in_tower_base(tower_base)
func build_wall():
func build_wall() -> void:
if point_id >= 0 and valid_point and hero.currency >= Data.wall_cost:
hero.currency -= Data.wall_cost
Game.level.a_star_graph_3d.toggle_point(point_id, multiplayer.get_unique_id())
wall_preview.set_visible(false)
func refund_wall(wall: TowerBase):
func refund_wall(wall: TowerBase) -> void:
last_collider = null
if wall.has_card:
wall.remove_card()
Game.level.a_star_graph_3d.remove_wall(wall)
func put_card_in_tower_base(tower_base: TowerBase):
func put_card_in_tower_base(tower_base: TowerBase) -> void:
if tower_base.has_card:
tower_base.remove_card()
else:
var card = inventory.remove_at(hero.inventory_selected_index)
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())
func set_progress_percent(value: float):
func set_progress_percent(value: float) -> void:
progress_bar.value = progress_bar.max_value * value

View File

@ -1,22 +1,21 @@
extends Sprite3D
class_name EightDirectionSprite3D
class_name EightDirectionSprite3D extends Sprite3D
func _process(_delta: float) -> void:
var cam = get_viewport().get_camera_3d()
var cam: Camera3D = get_viewport().get_camera_3d()
if !cam:
return
var tile_size = texture.region.size.x
var tile_size: int = texture.region.size.x
#stupid algorithm for dummy game developers
var camera_look_dir_3D = cam.global_position.direction_to(global_position).normalized()
var a = Vector2(global_transform.basis.z.x, global_transform.basis.z.z).normalized()
var b = Vector2(camera_look_dir_3D.x, camera_look_dir_3D.z).normalized()
var dot = a.x * b.x + a.y * b.y
var det = a.x * b.y - a.y * b.x
var final = rad_to_deg(atan2(det, dot)) + 180
var camera_look_dir_3D: Vector3 = cam.global_position.direction_to(global_position).normalized()
var a: Vector2 = Vector2(global_transform.basis.z.x, global_transform.basis.z.z).normalized()
var b: Vector2 = Vector2(camera_look_dir_3D.x, camera_look_dir_3D.z).normalized()
var dot: float = a.x * b.x + a.y * b.y
var det: float = a.x * b.y - a.y * b.x
var final: float = rad_to_deg(atan2(det, dot)) + 180
var t = texture.region
var t: Rect2 = texture.region
if final > 337.5 or final < 22.5:
t = Rect2(tile_size * 4, t.position.y, tile_size, tile_size)
elif final > 22.5 and final < 67.5:

View File

@ -1,6 +1,6 @@
extends Node3D
class_name EnemyGoal extends Node3D
@export var audio_player : AudioStreamPlayer3D
@export var audio_player: AudioStreamPlayer3D
func _on_area_3d_body_entered(body: Node3D) -> void:

View File

@ -1,25 +1,23 @@
extends Node3D
class_name EnemySpawner
class_name EnemySpawner extends Node3D
@export var own_id : int = 0
@export var path : VisualizedPath
@export var type : Data.EnemyType
@export var dest : Node3D
@export var enemy_path : Node
signal enemy_spawned()
var signal_for_after_enemy_died
var signal_for_after_enemy_reached_goal
signal signal_for_when_enemy_spawns
@export var land_enemy_scene: PackedScene
@export var air_enemy_scene: PackedScene
@export var own_id: int = 0
@export var path: VisualizedPath
@export var type: Data.EnemyType
@export var dest: Node3D
@export var enemy_path: Node
var current_wave
var enemy_spawn_timers = {}
var enemies_spawned = {}
var enemies_to_spawn := 0
var done_spawning = true
var enemy_id = 0
@export var land_enemy_scene : PackedScene
@export var air_enemy_scene : PackedScene
var enemy_died_callback: Callable
var enemy_reached_goal_callback: Callable
var current_wave: Dictionary = {}
var enemy_spawn_timers: Dictionary = {}
var enemies_spawned: Dictionary = {}
var enemies_to_spawn: int = 0
var done_spawning: bool = true
var enemy_id: int = 0
func _process(delta: float) -> void:
@ -27,11 +25,11 @@ func _process(delta: float) -> void:
done_spawning = true
return
for x in enemy_spawn_timers:
for x: Enemy in enemy_spawn_timers:
if enemies_spawned[x] == current_wave[x]:
continue
var enemy_stats = x
var enemy_stats: Enemy = x
enemy_spawn_timers[x] += delta
if enemy_spawn_timers[x] >= enemy_stats.spawn_cooldown:
@ -39,54 +37,54 @@ func _process(delta: float) -> void:
if type == Data.EnemyType.LAND:
networked_spawn_land_enemy.rpc(var_to_str(enemy_stats), own_id, enemy_id)
if type == Data.EnemyType.AIR:
var radius = 10.0
var random_dir = Vector3(randf_range(-1, 1), randf_range(-1, 1), randf_range(-1, 1))
var random_pos = randf_range(0, radius) * random_dir.normalized()
var radius: float = 10.0
var random_dir: Vector3 = Vector3(randf_range(-1, 1), randf_range(-1, 1), randf_range(-1, 1))
var random_pos: Vector3 = randf_range(0, radius) * random_dir.normalized()
networked_spawn_air_enemy.rpc(var_to_str(enemy_stats), random_pos, own_id, enemy_id)
enemy_spawn_timers[x] -= enemy_stats.spawn_cooldown
signal_for_when_enemy_spawns.emit()
enemy_spawned.emit()
enemy_id += 1
enemies_spawned[x] += 1
enemies_to_spawn -= 1
@rpc("reliable", "call_local")
func networked_spawn_land_enemy(enemy_stats, id1, id2):
var enemy = land_enemy_scene.instantiate() as EnemyController
func networked_spawn_land_enemy(enemy_stats: String, id1: int, id2: int) -> void:
var enemy: EnemyController = land_enemy_scene.instantiate() as EnemyController
enemy.name = str(id1) + str(id2)
enemy.stats = str_to_var(enemy_stats)
enemy.died.connect(signal_for_after_enemy_died)
enemy.reached_goal.connect(signal_for_after_enemy_reached_goal)
enemy.died.connect(enemy_died_callback)
enemy.reached_goal.connect(enemy_reached_goal_callback)
enemy.movement_controller.path = path.curve
enemy.position = global_position
enemy_path.add_child(enemy)
@rpc("reliable", "call_local")
func networked_spawn_air_enemy(enemy_stats, pos, id1, id2):
var enemy = air_enemy_scene.instantiate() as EnemyController
func networked_spawn_air_enemy(enemy_stats: String, pos: Vector3, id1: int, id2: int) -> void:
var enemy: EnemyController = air_enemy_scene.instantiate() as EnemyController
enemy.name = str(id1) + str(id2)
enemy.position = pos + global_position
enemy.stats = str_to_var(enemy_stats)
enemy.died.connect(signal_for_after_enemy_died)
enemy.reached_goal.connect(signal_for_after_enemy_reached_goal)
enemy.died.connect(enemy_died_callback)
enemy.reached_goal.connect(enemy_reached_goal_callback)
enemy.movement_controller.goal = dest
enemy_path.add_child(enemy)
func spawn_wave(value):
var relevant_enemies = {}
var wave = {}
for index in value:
func spawn_wave(value: Dictionary) -> void:
var relevant_enemies: Dictionary = {}
var wave: Dictionary = {}
for index: int in value:
wave[Data.enemies[index]] = value[index]
for x in wave:
for x: Enemy in wave:
if x.target_type == type:
relevant_enemies[x] = wave[x]
current_wave = relevant_enemies
enemies_to_spawn = 0
enemy_spawn_timers = {}
for x in current_wave:
for x: Enemy in current_wave:
enemies_to_spawn += current_wave[x]
enemy_spawn_timers[x] = 0.0
enemies_spawned[x] = 0

View File

@ -1,16 +1,17 @@
extends RayCast3D
class_name FloatAndSpin extends RayCast3D
@export_range(0.0, 3.0) var float_height := 1.5
@export_range(0.0, 2.0) var bounce_dist := 0.5
@export_range(0.0, 2.0) var bounce_speed := 0.4
@export_range(0.0, 4.0) var spin_speed := 0.5
@export_range(0.0, 3.0) var float_height: float = 1.5
@export_range(0.0, 2.0) var bounce_dist: float = 0.5
@export_range(0.0, 2.0) var bounce_speed: float = 0.4
@export_range(0.0, 4.0) var spin_speed: float = 0.5
@export var curve: Curve
var start_height = 0.0
var dest_height = 0.0
var t = 0.0
var start_height: float = 0.0
var dest_height: float = 0.0
var t: float = 0.0
func _ready():
func _ready() -> void:
start_height = position.y
#raycast downwards and position the item at a set height above the ground that the raycast
@ -27,7 +28,8 @@ func _ready():
start_height = get_collision_point().y + (1 * float_height) - (bounce_dist / 2.0)
dest_height = start_height + (bounce_dist / 2.0)
func _process(delta):
func _process(delta: float) -> void:
t += bounce_speed * delta
position.y = start_height + (dest_height - start_height) * curve.sample(t)
if t >= 1.0:

View File

@ -1,34 +1,35 @@
extends Node
signal wave_started(wave_number)
signal wave_finished(wave_number)
signal base_took_damage(remaining_health)
signal wave_started(wave_number: int)
signal wave_finished(wave_number: int)
signal base_took_damage(remaining_health: int)
signal game_started
signal game_restarted
signal lost_game
signal won_game
var level_scene = load("res://Worlds/GreenPlanet/Levels/first_level.tscn")
var player_scene = load("res://PCs/hero.tscn")
var main_menu_scene_path = "res://Scenes/Menus/main_menu.tscn"
var multiplayer_lobby_scene_path = "res://Scenes/Menus/multiplayer_lobby.tscn"
var singleplayer_lobby_scene_path = "res://Scenes/Menus/singleplayer_lobby.tscn"
var won_game_scene = load("res://Scenes/Menus/won_game_screen.tscn")
var lose_game_scene = load("res://Scenes/Menus/lost_game_screen.tscn")
var connected_players_nodes = {}
var game_active := false
var level : Level
var enemies := 0
var objective_health := 120
var wave := 0
var endless_mode := false
var upcoming_wave
var pot : float
var UILayer : CanvasLayer
var chatbox : Chatbox
var wave_limit := 20
var starting_cash := 16
var shop_chance := 0.0
var level_scene: PackedScene = load("res://Worlds/GreenPlanet/Levels/first_level.tscn")
var player_scene: PackedScene = load("res://PCs/hero.tscn")
var main_menu_scene_path: String = "res://Scenes/Menus/main_menu.tscn"
var multiplayer_lobby_scene_path: String = "res://Scenes/Menus/multiplayer_lobby.tscn"
var singleplayer_lobby_scene_path: String = "res://Scenes/Menus/singleplayer_lobby.tscn"
var won_game_scene: PackedScene = load("res://Scenes/Menus/won_game_screen.tscn")
var lose_game_scene: PackedScene = load("res://Scenes/Menus/lost_game_screen.tscn")
var connected_players_nodes: Dictionary = {}
var game_active: bool = false
var level: Level
var enemies: int = 0
var objective_health: int = 120
var wave: int = 0
var endless_mode: bool = false
var upcoming_wave: Dictionary
var pot: float
var UILayer: CanvasLayer
var chatbox: Chatbox
var wave_limit: int = 20
var starting_cash: int = 16
var shop_chance: float = 0.0
var stats: RoundStats = RoundStats.new()
func _ready() -> void:
@ -37,11 +38,11 @@ func _ready() -> void:
get_tree().root.add_child.call_deferred(UILayer)
func parse_command(text : String, peer_id : int):
func parse_command(text: String, peer_id: int) -> void:
if text.substr(1, 4) == "give":
var gift_name = text.substr(6) as String
var gift = Data.cards[0]
for x in Data.cards:
var gift_name: String = text.substr(6) as String
var gift: Card = Data.cards[0]
for x: Card in Data.cards:
if x.display_name == gift_name:
gift = x
connected_players_nodes[peer_id].inventory.add(gift)
@ -52,7 +53,7 @@ func parse_command(text : String, peer_id : int):
elif text.substr(1, 11) == "random_maze":
level.a_star_graph_3d.build_random_maze(50)
elif text.substr(1, 13) == "random_towers":
level.a_star_graph_3d.place_random_towers(level.a_star_graph_3d.tower_bases.size() / 3.0)
level.a_star_graph_3d.place_random_towers(floori(level.a_star_graph_3d.tower_bases.size() / 3.0))
elif text.substr(1, 11) == "set_endless":
if is_multiplayer_authority():
networked_set_endless.rpc(true)
@ -68,7 +69,7 @@ func parse_command(text : String, peer_id : int):
elif text.substr(1, 10) == "spawn_shop":
level.shop.randomize_cards()
elif text.substr(1, 7) == "prosper":
for id in connected_players_nodes:
for id: int in connected_players_nodes:
connected_players_nodes[id].currency += 50
elif text.substr(1, 8) == "set_wave":
if is_multiplayer_authority():
@ -82,29 +83,29 @@ func parse_command(text : String, peer_id : int):
@rpc("reliable", "call_local")
func networked_set_wave(wave_number):
func networked_set_wave(wave_number: int) -> void:
chatbox.append_message("SERVER", Color.TOMATO, "Set to wave " + str(wave_number))
for player in connected_players_nodes:
for player: int in connected_players_nodes:
connected_players_nodes[player].hud.set_wave_count(wave_number)
wave = wave_number
set_upcoming_wave()
func spawn_level():
func spawn_level() -> void:
level = level_scene.instantiate() as Level
for x in level.enemy_spawns:
for x: EnemySpawner in level.enemy_spawns:
#x.path = level.a_star_graph_3d.visualized_path
x.signal_for_after_enemy_died = enemy_died
x.signal_for_after_enemy_reached_goal = damage_goal
x.signal_for_when_enemy_spawns.connect(increase_enemy_count)
x.enemy_died_callback = enemy_died
x.enemy_reached_goal_callback = damage_goal
x.enemy_spawned.connect(increase_enemy_count)
add_child(level)
func spawn_players(player_array, player_profiles, chatbox_open_signal, chatbox_closed_signal):
var p_i = 0
func spawn_players(player_array: Array, player_profiles: Dictionary, chatbox_open_signal: Signal, chatbox_closed_signal: Signal) -> void:
var p_i: int = 0
player_array.sort()
for peer_id in player_array:
var player = player_scene.instantiate() as Hero
for peer_id: int in player_array:
var player: Hero = player_scene.instantiate() as Hero
player.name = str(peer_id)
player.player_name_tag.text = player_profiles[peer_id].display_name
player.position = level.player_spawns[p_i].global_position
@ -125,41 +126,41 @@ func spawn_players(player_array, player_profiles, chatbox_open_signal, chatbox_c
start_game()
func ready_player(_value):
for key in connected_players_nodes:
func ready_player(_value: int) -> void:
for key: int in connected_players_nodes:
if connected_players_nodes[key].ready_state == false:
return
spawn_enemy_wave()
func spawn_enemy_wave():
func spawn_enemy_wave() -> void:
level.shop.close()
wave += 1
level.a_star_graph_3d.find_path()
level.a_star_graph_3d.visualized_path.disable_visualization()
level.a_star_graph_3d.disable_all_tower_frames()
for spawn in level.enemy_spawns:
for spawn: EnemySpawner in level.enemy_spawns:
spawn.spawn_wave(upcoming_wave)
wave_started.emit(wave)
func set_upcoming_wave():
func set_upcoming_wave() -> void:
if is_multiplayer_authority():
var spawn_power = WaveManager.calculate_spawn_power(wave + 1, connected_players_nodes.size())
var new_wave = WaveManager.generate_wave(spawn_power, level.enemy_pool)
networked_set_upcoming_wave.rpc(new_wave, 6 + floori(spawn_power / 70))
var spawn_power: int = WaveManager.calculate_spawn_power(wave + 1, connected_players_nodes.size())
var new_wave: Dictionary = WaveManager.generate_wave(spawn_power, level.enemy_pool)
networked_set_upcoming_wave.rpc(new_wave, 6 + floori(spawn_power / 70.0))
@rpc("reliable", "call_local")
func networked_set_upcoming_wave(wave_dict, coins):
func networked_set_upcoming_wave(wave_dict: Dictionary, coins: int) -> void:
upcoming_wave = wave_dict
pot = coins
for key in connected_players_nodes:
for key: int in connected_players_nodes:
connected_players_nodes[key].hud.set_upcoming_wave(upcoming_wave)
@rpc("reliable", "call_local")
func networked_set_endless(value):
func networked_set_endless(value: bool) -> void:
endless_mode = value
if endless_mode:
chatbox.append_message("SERVER", Color.TOMATO, "Endless mode enabled!")
@ -167,15 +168,15 @@ func networked_set_endless(value):
chatbox.append_message("SERVER", Color.TOMATO, "Endless mode disabled!")
func increase_enemy_count():
func increase_enemy_count() -> void:
enemies += 1
func enemy_died(enemy):
func enemy_died(enemy: Enemy) -> void:
enemies -= 1
for key in connected_players_nodes:
for key: int in connected_players_nodes:
connected_players_nodes[key].hud.enemy_count_down(enemy)
for x in level.enemy_spawns:
for x: EnemySpawner in level.enemy_spawns:
if !x.done_spawning:
return
if enemies == 0:
@ -184,9 +185,10 @@ func enemy_died(enemy):
win_game()
func damage_goal(enemy, penalty):
func damage_goal(enemy: Enemy, penalty: int) -> void:
enemies -= 1
for key in connected_players_nodes:
stats.add_enemy_undefeated(wave, enemy)
for key: int in connected_players_nodes:
connected_players_nodes[key].hud.enemy_count_down(enemy)
objective_health -= penalty
base_took_damage.emit(objective_health)
@ -198,8 +200,8 @@ func damage_goal(enemy, penalty):
win_game()
func end_wave():
for peer_id in connected_players_nodes:
func end_wave() -> void:
for peer_id: int in connected_players_nodes:
connected_players_nodes[peer_id].currency += ceili(pot / connected_players_nodes.size())
connected_players_nodes[peer_id].ready_state = false
level.a_star_graph_3d.visualized_path.enable_visualization()
@ -215,18 +217,18 @@ func end_wave():
@rpc("reliable", "call_local")
func networked_spawn_shop():
func networked_spawn_shop() -> void:
level.shop.randomize_cards()
chatbox.append_message("SERVER", Color.TOMATO, "A shopkeeper has arrived!")
func remove_player(peer_id):
func remove_player(peer_id: int) -> void:
if connected_players_nodes.has(peer_id):
connected_players_nodes[peer_id].queue_free()
connected_players_nodes.erase(peer_id)
func start_game():
func start_game() -> void:
game_active = true
enemies = 0
objective_health = 120
@ -237,70 +239,71 @@ func start_game():
level.a_star_graph_3d.enable_non_path_tower_frames()
level.a_star_graph_3d.find_path()
set_upcoming_wave()
for peer_id in connected_players_nodes:
connected_players_nodes[peer_id].currency = starting_cash / connected_players_nodes.size()
for peer_id: int in connected_players_nodes:
connected_players_nodes[peer_id].currency = roundi(float(starting_cash) / float(connected_players_nodes.size()))
game_started.emit()
func restart_game():
func restart_game() -> void:
#implement game reloading system
for peer_id in connected_players_nodes:
for peer_id: int in connected_players_nodes:
connected_players_nodes[peer_id].queue_free()
connected_players_nodes.clear()
level.queue_free()
enemies = 0
objective_health = 120
wave = 0
stats = RoundStats.new()
spawn_level()
game_restarted.emit()
pass
func lose_game():
func lose_game() -> void:
if game_active == false:
return
game_active = false
Data.save_stats.add_game_outcome(false)
Data.save_stats.save_profile_to_disk()
var menu = lose_game_scene.instantiate()
var menu: Control = lose_game_scene.instantiate()
UILayer.add_child(menu)
lost_game.emit()
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
for peer_id in connected_players_nodes:
for peer_id: int in connected_players_nodes:
connected_players_nodes[peer_id].pause()
func win_game():
func win_game() -> void:
if game_active == false:
return
game_active = false
Data.save_stats.add_game_outcome(true)
Data.save_stats.save_profile_to_disk()
var menu = won_game_scene.instantiate()
var menu: Control = won_game_scene.instantiate()
UILayer.add_child(menu)
won_game.emit()
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
for peer_id in connected_players_nodes:
for peer_id: int in connected_players_nodes:
connected_players_nodes[peer_id].pause()
func quit_to_desktop():
func quit_to_desktop() -> void:
multiplayer.multiplayer_peer.close()
multiplayer.multiplayer_peer = null
get_tree().quit()
func scene_switch_main_menu():
for node in get_children():
func scene_switch_main_menu() -> void:
for node: Node in get_children():
node.queue_free()
multiplayer.multiplayer_peer.close()
multiplayer.multiplayer_peer = null
get_tree().change_scene_to_file(main_menu_scene_path)
func scene_switch_to_multiplayer_lobby():
func scene_switch_to_multiplayer_lobby() -> void:
get_tree().change_scene_to_file(multiplayer_lobby_scene_path)
func scene_switch_to_singleplayer_lobby():
func scene_switch_to_singleplayer_lobby() -> void:
get_tree().change_scene_to_file(singleplayer_lobby_scene_path)

View File

@ -1,16 +1,15 @@
extends VBoxContainer
class_name GameplayOptionsMenu
class_name GameplayOptionsMenu extends VBoxContainer
@export var look_sens_slider : HSlider
@export var look_sens_input : SpinBox
@export var toggle_sprint_checkbox : CheckButton
@export var invert_lookY : CheckButton
@export var invert_lookX : CheckButton
@export var fixed_minimap : CheckButton
@export var tower_damage : Button
@export var self_damage : Button
@export var party_damage : Button
@export var status_damage : Button
@export var look_sens_slider: HSlider
@export var look_sens_input: SpinBox
@export var toggle_sprint_checkbox: CheckButton
@export var invert_lookY: CheckButton
@export var invert_lookX: CheckButton
@export var fixed_minimap: CheckButton
@export var tower_damage: Button
@export var self_damage: Button
@export var party_damage: Button
@export var status_damage: Button
func _ready() -> void:

View File

@ -1,21 +1,20 @@
extends VBoxContainer
class_name GraphicsOptionsMenu
class_name GraphicsOptionsMenu extends VBoxContainer
@export var fov_input : SpinBox
@export var fov_slider : HSlider
@export var vsync_dropdown : OptionButton
@export var aa_dropdown : OptionButton
@export var window_dropdown : OptionButton
@export var fov_input: SpinBox
@export var fov_slider: HSlider
@export var vsync_dropdown: OptionButton
@export var aa_dropdown: OptionButton
@export var window_dropdown: OptionButton
func _ready():
func _ready() -> void:
fov_input.value = Data.graphics.hfov
fov_slider.value = Data.graphics.hfov
vsync_dropdown.selected = Data.graphics.vsync_mode
aa_dropdown.selected = Data.graphics.aa_mode
func save():
func save() -> void:
Data.graphics.hfov = fov_slider.value
Data.graphics.vsync_mode = vsync_dropdown.selected
Data.graphics.aa_mode = aa_dropdown.selected

View File

@ -1,22 +1,21 @@
extends Node
class_name Health
class_name Health extends Node
signal health_depleted
signal health_changed(health)
signal health_changed(health: int)
@export var damage_particle_scene : PackedScene
@export var damage_particle_scene: PackedScene
@export var max_health: int = 10
@export var max_health := 10
var current_health
var current_health: int
func take_damage(damage):
func take_damage(damage: int) -> void:
current_health -= damage
health_changed.emit(current_health)
if current_health <= 0:
health_depleted.emit()
func heal_damage(healing):
func heal_damage(healing: int) -> void:
current_health += healing
if current_health > max_health:
current_health = max_health

View File

@ -1,24 +1,24 @@
extends TextureProgressBar
class_name HealthBar extends TextureProgressBar
@export var health_bar_gradient: Gradient
@onready var prev_bar = $PreviousHealthBar
@onready var prev_bar: TextureProgressBar = $PreviousHealthBar
func setup(health: float):
func setup(health: float) -> void:
max_value = health
value = health
prev_bar.max_value = health
prev_bar.value = health
func on_health_changed(health: float):
func on_health_changed(health: float) -> void:
set_visible(true)
var health_went_down = true if health < value else false
var health_went_down: bool = true if health < value else false
value = health
tint_progress = health_bar_gradient.sample(value / max_value)
if health_went_down:
var tween = create_tween()
var tween: Tween = create_tween()
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_QUINT)
tween.tween_interval(0.3)

View File

@ -1,8 +1,7 @@
extends CollisionShape3D
class_name Hitbox
class_name Hitbox extends CollisionShape3D
signal took_damage(amount)
signal took_damage(amount: float)
func damage(amount):
func damage(amount: float) -> void:
took_damage.emit(amount)

View File

@ -1,11 +1,11 @@
extends StaticBody3D
class_name InteractButton
class_name InteractButton extends StaticBody3D
signal button_interacted(value)
signal button_interacted(value: int)
@export var button_press_value := 0
@export var press_cost := 0
@export var hover_text := "Press [Interact]"
@export var button_press_value: int = 0
@export var press_cost: int = 0
@export var hover_text: String = "Press [Interact]"
func press():
func press() -> void:
button_interacted.emit(button_press_value)

View File

@ -1,22 +1,21 @@
extends Node
class_name Inventory
class_name Inventory extends Node
signal item_added(item)
signal item_removed(item)
signal item_added(item: Item)
signal item_removed(item: Item)
@export var max_size := 0
var contents = {}
var size : int :
@export var max_size: int = 0
var contents: Dictionary = {}
var size: int :
get:
var x = 0
for key in contents:
var x: int = 0
for key: Item in contents:
x += contents[key]
return x
set(_value):
return
func add(item : Item) -> bool:
func add(item: Item) -> bool:
if item != null and max_size == 0 or size < max_size:
if contents.has(item):
contents[item] += 1
@ -28,8 +27,8 @@ func add(item : Item) -> bool:
return false
func remove_at(index : int) -> Item:
var item = contents.keys()[index]
func remove_at(index: int) -> Item:
var item: Item = contents.keys()[index]
contents[item] -= 1
if contents[item] == 0:
contents.erase(item)
@ -39,8 +38,8 @@ func remove_at(index : int) -> Item:
@rpc("reliable", "any_peer")
func networked_add(value):
var item = Data.cards[value]
func networked_add(value: int) -> void:
var item: Item = Data.cards[value]
if contents.has(item):
contents[item] += 1
else:
@ -49,8 +48,8 @@ func networked_add(value):
@rpc("reliable", "any_peer")
func networked_remove_at(value):
var item = contents.keys[value]
func networked_remove_at(value: int) -> void:
var item: Item = contents.keys[value]
contents[item] -= 1
if contents[item] == 0:
contents.erase(item)

View File

@ -1,5 +1,4 @@
extends StaticBody3D
class_name ItemCard
class_name ItemCard extends StaticBody3D
@export var card: Card
@ -13,7 +12,7 @@ func pick_up() -> Card:
@rpc
func networked_pick_up():
func networked_pick_up() -> void:
$CollisionShape3D.call_deferred("set_disabled", true)
$model/CSGSphere3D.set_visible(false)
$AudioStreamPlayer3D.play()

View File

@ -1 +1 @@
extends StaticBody3D
class_name ItemContainer extends StaticBody3D

97
Scripts/key_icon_map.gd Normal file
View File

@ -0,0 +1,97 @@
class_name KeyIconMap
static var keys: Dictionary = {
"48" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/0_Key_Light.png",
"49" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/1_Key_Light.png",
"50" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/2_Key_Light.png",
"51" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/3_Key_Light.png",
"52" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/4_Key_Light.png",
"53" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/5_Key_Light.png",
"54" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/6_Key_Light.png",
"55" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/7_Key_Light.png",
"56" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/8_Key_Light.png",
"57" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/9_Key_Light.png",
"65" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/A_Key_Light.png",
"66" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/B_Key_Light.png",
"67" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/C_Key_Light.png",
"68" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/D_Key_Light.png",
"69" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/E_Key_Light.png",
"70" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F_Key_Light.png",
"71" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/G_Key_Light.png",
"72" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/H_Key_Light.png",
"73" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/I_Key_Light.png",
"74" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/J_Key_Light.png",
"75" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/K_Key_Light.png",
"76" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/L_Key_Light.png",
"77" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/M_Key_Light.png",
"78" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/N_Key_Light.png",
"79" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/O_Key_Light.png",
"80" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/P_Key_Light.png",
"81" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Q_Key_Light.png",
"82" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/R_Key_Light.png",
"83" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/S_Key_Light.png",
"84" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/T_Key_Light.png",
"85" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/U_Key_Light.png",
"86" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/V_Key_Light.png",
"87" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/W_Key_Light.png",
"88" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/X_Key_Light.png",
"89" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Y_Key_Light.png",
"90" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Z_Key_Light.png",
"4194328" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Alt_Key_Light.png",
"4194322" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Arrow_Down_Key_Light.png",
"4194319" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Arrow_Left_Key_Light.png",
"4194321" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Arrow_Right_Key_Light.png",
"4194320" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Arrow_Up_Key_Light.png",
"42" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Asterisk_Key_Light.png",
"4194433" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Asterisk_Key_Light.png",
"4194308" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Backspace_Alt_Key_Light.png",
"91" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Bracket_Left_Key_Light.png",
"93" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Bracket_Right_Key_Light.png",
"4194329" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Caps_Lock_Key_Light.png",
"4194327" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Command_Key_Light.png",
"4194326" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Ctrl_Key_Light.png",
"4194312" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Del_Key_Light.png",
"4194318" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/End_Key_Light.png",
"4194309" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Enter_Alt_Key_Light.png",
"4194305" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Esc_Key_Light.png",
"4194332" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F1_Key_Light.png",
"4194333" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F2_Key_Light.png",
"4194334" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F3_Key_Light.png",
"4194335" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F4_Key_Light.png",
"4194336" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F5_Key_Light.png",
"4194337" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F6_Key_Light.png",
"4194338" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F7_Key_Light.png",
"4194339" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F8_Key_Light.png",
"4194340" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F9_Key_Light.png",
"4194341" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F10_Key_Light.png",
"4194342" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F11_Key_Light.png",
"4194343" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/F12_Key_Light.png",
"4194317" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Home_Key_Light.png",
"4194311" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Insert_Key_Light.png",
"60" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Mark_Left_Key_Light.png",
"62" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Mark_Right_Key_Light.png",
"45" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Minus_Key_Light.png",
"4194435" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Minus_Key_Light.png",
"4194330" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Num_Lock_Key_Light.png",
"4194324" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Page_Down_Key_Light.png",
"4194323" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Page_Up_Key_Light.png",
"43" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Plus_Key_Light.png",
"4194437" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Plus_Key_Light.png",
"4194314" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Print_Screen_Key_Light.png",
"63" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Question_Key_Light.png",
"34" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Quote_Key_Light.png",
"59" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Semicolon_Key_Light.png",
"4194325" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Shift_Key_Light.png",
"47" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Slash_Key_Light.png",
"4194434" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Slash_Key_Light.png",
"32" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Space_Key_Light.png",
"4194306" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Tab_Key_Light.png",
"126" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Tilda_Key_Light.png",
}
static var mouse_buttons: Dictionary = {
"1" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Mouse_Left_Key_Light.png",
"3" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Mouse_Middle_Key_Light.png",
"2" = "res://XeluController&KeyPrompts/Keyboard & Mouse/Light/Mouse_Right_Key_Light.png",
}

View File

@ -1,64 +1,67 @@
extends VBoxContainer
class_name KeybindsOptionsMenu
var keybind_popup = load("res://Scenes/UI/keybind_popup.tscn")
var keybind_boxes = []
var keybind_buttons = {}
var key_event
var selected_button
var selected_button_button
var listening_for_key := false
var keybind_entry_scene: PackedScene = load("res://Scenes/UI/keybind_entry.tscn")
var keybind_popup: PackedScene = load("res://Scenes/UI/keybind_popup.tscn")
var keybind_boxes: Array[KeybindEntry] = []
var key_event: InputEvent
var selected_entry: KeybindEntry
var listening_for_key: bool = false
func _ready() -> void:
for index in Data.keymaps.size():
var map = Data.keymaps[index]
var button = Button.new()
for index: int in Data.keymaps.size():
var map: PlayerKeymap = Data.keymaps[index]
var button: Button = Button.new()
button.text = map.title
button.pressed.connect(set_keymap.bind(index))
$HBoxContainer.add_child(button)
load_keybind_labels()
func set_keymap(keymap_index):
func set_keymap(keymap_index: int) -> void:
Data.player_keymap = Data.keymaps[keymap_index]
Data.player_keymap.apply()
load_keybind_labels()
func load_keybind_labels():
for box in keybind_boxes:
func load_keybind_labels() -> void:
for box: KeybindEntry in keybind_boxes:
box.queue_free()
keybind_boxes.clear()
for action in InputMap.get_actions():
for action: StringName in InputMap.get_actions():
if !action.begins_with("ui_"):
var box = HBoxContainer.new()
var alabel = Label.new()
var elabel = Button.new()
alabel.text = action
var entry: KeybindEntry = keybind_entry_scene.instantiate() as KeybindEntry
entry.set_action_name(action)
if InputMap.action_get_events(action).size() > 0:
elabel.text = InputMap.action_get_events(action)[0].as_text()
elabel.size_flags_horizontal += Control.SIZE_EXPAND
alabel.size_flags_horizontal += Control.SIZE_EXPAND
alabel.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
alabel.size_flags_stretch_ratio = 2.0
#elabel.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
box.add_child(alabel)
box.add_child(elabel)
elabel.pressed.connect(_on_keybind_button_pressed.bind(elabel))
keybind_buttons[elabel] = action
$ScrollContainer/VBoxContainer.add_child(box)
keybind_boxes.append(box)
entry.set_primary_bind(InputMap.action_get_events(action)[0])
if InputMap.action_get_events(action).size() > 1:
entry.set_secondary_bind(InputMap.action_get_events(action)[1])
keybind_boxes.append(entry)
entry.primary_bind_pressed.connect(_on_primary_keybind_button_pressed.bind(entry))
entry.secondary_bind_pressed.connect(_on_secondary_keybind_button_pressed.bind(entry))
$ScrollContainer/VBoxContainer.add_child(entry)
func _on_keybind_button_pressed(value: Button) -> void:
selected_button = keybind_buttons[value]
selected_button_button = value
var popup = keybind_popup.instantiate()
popup.event_detected.connect(change_key)
func _on_primary_keybind_button_pressed(keybind_entry: KeybindEntry) -> void:
selected_entry = keybind_entry
var popup: Control = keybind_popup.instantiate()
popup.event_detected.connect(change_primary_key)
Game.UILayer.add_child(popup)
func change_key(event: InputEvent):
Data.player_keymap.replace_action_event(selected_button, event)
selected_button_button.text = event.as_text()
func _on_secondary_keybind_button_pressed(keybind_entry: KeybindEntry) -> void:
selected_entry = keybind_entry
var popup: Control = keybind_popup.instantiate()
popup.event_detected.connect(change_secondary_key)
Game.UILayer.add_child(popup)
func change_primary_key(event: InputEvent) -> void:
Data.player_keymap.set_primary_action_event(selected_entry.action_string, event)
selected_entry.set_primary_bind(event)
func change_secondary_key(event: InputEvent) -> void:
Data.player_keymap.set_secondary_action_event(selected_entry.action_string, event)
selected_entry.set_secondary_bind(event)

View File

@ -1,5 +1,4 @@
extends Area3D
class_name KillBox
class_name KillBox extends Area3D
@export var level: Level

View File

@ -1,5 +1,4 @@
extends GridMap
class_name Level
class_name Level extends GridMap
@export var enemy_pool: Array[Enemy]
@export var player_spawns: Array[Node3D]
@ -13,25 +12,25 @@ class_name Level
@export var obstacle_scenes: Array[PackedScene]
func generate_obstacles():
var obstacle_count = randi_range(0, 5)
for index in obstacle_count:
var x = randi_range(0, a_star_graph_3d.grid_size.x - 1)
var y = randi_range(0, a_star_graph_3d.grid_size.y - 1)
var point_id = int(x * a_star_graph_3d.grid_size.y + y)
var chosen_obstacle = randi_range(0, obstacle_scenes.size() - 1)
var obstacle = obstacle_scenes[chosen_obstacle].instantiate() as GridMap
var orientations = [0, 90, 180, 270]
var chosen_orientation = orientations.pick_random()
func generate_obstacles() -> void:
var obstacle_count: int = randi_range(0, 5)
for index: int in obstacle_count:
var x: int = randi_range(0, a_star_graph_3d.grid_size.x - 1)
var y: int = randi_range(0, a_star_graph_3d.grid_size.y - 1)
var point_id: int = int(x * a_star_graph_3d.grid_size.y + y)
var chosen_obstacle: int = randi_range(0, obstacle_scenes.size() - 1)
var obstacle: GridMap = obstacle_scenes[chosen_obstacle].instantiate() as GridMap
var orientations: Array[int] = [0, 90, 180, 270]
var chosen_orientation: int = orientations.pick_random()
obstacle.position = a_star_graph_3d.astar.get_point_position(point_id)
obstacle.set_rotation_degrees(Vector3(0, chosen_orientation, 0))
add_child(obstacle)
for cell in obstacle.get_used_cells():
var cell_pos = obstacle.to_global(obstacle.map_to_local(cell))
var map_coord = Vector3i(round(cell_pos.x), 0, round(cell_pos.z))
for cell: Vector3i in obstacle.get_used_cells():
var cell_pos: Vector3 = obstacle.to_global(obstacle.map_to_local(cell))
var map_coord: Vector3i = Vector3i(round(cell_pos.x), 0, round(cell_pos.z))
#print("cell_pos: " + str(cell_pos) + "cell.z" + str(cell_pos.z) + ", map_coord: " + str(map_coord))
var closest_point = a_star_graph_3d.astar.get_closest_point(cell_pos, true)
var closest_point_pos = a_star_graph_3d.astar.get_point_position(closest_point)
var closest_point: int = a_star_graph_3d.astar.get_closest_point(cell_pos, true)
var closest_point_pos: Vector3 = a_star_graph_3d.astar.get_point_position(closest_point)
if closest_point_pos.distance_to(Vector3(cell_pos.x, closest_point_pos.y, cell_pos.z)) <= 0.5:
a_star_graph_3d.astar.set_point_disabled(closest_point)
if get_cell_item(map_coord) == 1:

View File

@ -1,10 +1,10 @@
extends Control
class_name LivesBarSegment
var lives_left := 6
var lives_left: int = 6
func take_life(value : int):
for x in value:
func take_life(value: int) -> void:
for x: int in value:
lives_left -= 1
if lives_left == 5:
$AnimationPlayer.play("lose1")

View File

@ -1,10 +1,10 @@
extends TextureRect
@export var segments : Array[LivesBarSegment]
var lives := 120.0
@export var segments: Array[LivesBarSegment]
var lives: float = 120.0
func take_life():
var segment_to_animate = ceil(lives / 6.0) - 1
func take_life() -> void:
var segment_to_animate: int = ceil(lives / 6.0) - 1
lives -= 1
segments[segment_to_animate].take_life(1)

View File

@ -1,15 +1,15 @@
extends Panel
class_name LoadoutEditor
class_name LoadoutEditor extends Panel
signal character_selected(character: int)
signal character_selected(character)
func _ready() -> void:
for i in Data.characters.size():
var button = Button.new()
for i: int in Data.characters.size():
var button: Button = Button.new()
button.text = Data.characters[i].hero_name
button.pressed.connect(set_character.bind(i))
$HBoxContainer.add_child(button)
func set_character(i: int):
func set_character(i: int) -> void:
character_selected.emit(i)

View File

@ -1,14 +1,22 @@
extends Control
class_name LostGameScreen extends Control
@export var box: PackedScene
func _ready() -> void:
var wins = float(Data.save_stats.twenty_game_history.count(true))
var games = float(Data.save_stats.twenty_game_history.size())
var winrate = int((wins / games) * 100.0)
var wins: float = float(Data.save_stats.twenty_game_history.count(true))
var games: float = float(Data.save_stats.twenty_game_history.size())
var winrate: int = int((wins / games) * 100.0)
$Label2.text = "Your 20-game winrate is now: " + str(winrate) + "%!"
$Label3.text = "Total games: " + str(Data.save_stats.wins + Data.save_stats.losses)
$Label4.text = "Total wins: " + str(Data.save_stats.wins)
$Label5.text = "Total losses: " + str(Data.save_stats.losses)
for wave_key: int in Game.stats.enemies_undefeated:
var spawned_box: EnemyBox = box.instantiate() as EnemyBox
$VBoxContainer.add_child(spawned_box)
spawned_box.set_wave(wave_key)
for enemy_key: Enemy in Game.stats.enemies_undefeated[wave_key]:
spawned_box.add_enemy_tag(enemy_key, Game.stats.enemies_undefeated[wave_key][enemy_key])
func _on_quit_button_pressed() -> void:

View File

@ -1,10 +1,11 @@
extends Control
class_name MainMenu extends Control
var confirmation_popup_scene = preload("res://Scenes/Menus/confirmation_popup.tscn")
var text_input_popup_scene = preload("res://Scenes/Menus/text_input_popup.tscn")
var multiplayer_lobby_scene_path = "res://Scenes/multiplayer_lobby.tscn"
var options_menu_scene = preload("res://Scenes/Menus/options_menu.tscn")
@export var bg_level : Level
@export var bg_level: Level
var confirmation_popup_scene: PackedScene = preload("res://Scenes/Menus/confirmation_popup.tscn")
var text_input_popup_scene: PackedScene = preload("res://Scenes/Menus/text_input_popup.tscn")
var multiplayer_lobby_scene_path: String = "res://Scenes/multiplayer_lobby.tscn"
var options_menu_scene: PackedScene = preload("res://Scenes/Menus/options_menu.tscn")
func _ready() -> void:
@ -15,42 +16,43 @@ func _ready() -> void:
bg_level.a_star_graph_3d.place_random_towers(20)
bg_level.a_star_graph_3d.disable_all_tower_frames()
Game.level = bg_level
var new_wave = WaveManager.generate_wave(400, bg_level.enemy_pool)
for spawn in bg_level.enemy_spawns:
spawn.signal_for_after_enemy_died = enemy_died
spawn.signal_for_after_enemy_reached_goal = damage_goal
spawn.signal_for_when_enemy_spawns.connect(increase_enemy_count)
var new_wave: Dictionary = WaveManager.generate_wave(400, bg_level.enemy_pool)
for spawn: EnemySpawner in bg_level.enemy_spawns:
spawn.enemy_died_callback = enemy_died
spawn.enemy_reached_goal_callback = damage_goal
spawn.enemy_spawned.connect(increase_enemy_count)
spawn.spawn_wave(new_wave)
#these exist purely to make the enemies that spawn on the main menu happy
func enemy_died(_some_arg):
func enemy_died(_some_arg: Enemy) -> void:
pass
func damage_goal(_some_arg1, _some_arg2):
func damage_goal(_some_arg1: int, _some_arg2: int) -> void:
pass
func increase_enemy_count():
func increase_enemy_count() -> void:
pass
func _on_display_name_edit_pressed() -> void:
var popup = text_input_popup_scene.instantiate() as TextInputPopup
var popup: TextInputPopup = text_input_popup_scene.instantiate() as TextInputPopup
popup.set_popup(Data.player_profile.display_name, "Display Name", "Confirm")
popup.completed.connect(change_profile_display_name)
add_child(popup)
func change_profile_display_name(display_name):
func change_profile_display_name(display_name: String) -> void:
$ProfileEditor/VBoxContainer/HBoxContainer/DisplayName.text = display_name
Data.player_profile.set_display_name(display_name)
func _on_quit_button_pressed() -> void:
var popup = confirmation_popup_scene.instantiate() as ConfirmationPopup
var popup: ConfirmationPopup = confirmation_popup_scene.instantiate() as ConfirmationPopup
popup.set_popup("Are you sure you want to quit?", "Yes", "No")
popup.completed.connect(quit_game)
add_child(popup)
func quit_game(confirmation):
func quit_game(confirmation: bool) -> void:
if confirmation:
get_tree().quit()
@ -60,7 +62,7 @@ func _on_play_button_pressed() -> void:
func _on_options_button_pressed() -> void:
var menu = options_menu_scene.instantiate()
var menu: OptionsMenu = options_menu_scene.instantiate()
add_child(menu)

View File

@ -1,8 +1,8 @@
extends Camera3D
class_name MinimapCamera3D
@export var anchor : Node3D
#@export var face_north : bool
@export var anchor: Node3D
#@export var face_north: bool
func _process(_delta: float) -> void:
global_position = anchor.global_position + (Vector3.UP * 100)

View File

@ -1,24 +1,23 @@
extends Control
class_name MultiplayerLobby
class_name MultiplayerLobby extends Control
signal player_connected(peer_id, player_profile)
signal player_disconnected(peer_id)
signal player_connected(peer_id: int, player_profile: PlayerProfile)
signal player_disconnected(peer_id: int)
signal disconnected_from_server
const SERVER_PORT := 58008
const MAX_PLAYERS := 4
const SERVER_PORT: int = 58008
const MAX_PLAYERS: int = 4
var enet_peer = ENetMultiplayerPeer.new()
@export var server_form: ServerForm
@export var scoreboard: Scoreboard
@export var loadout_editor: HeroSelector
@export var chatbox: Chatbox
@export var server_form : ServerForm
@export var scoreboard : Scoreboard
@export var loadout_editor : HeroSelector
@export var chatbox : Chatbox
var alert_popup_scene = preload("res://Scenes/Menus/alert_popup.tscn")
var connected_players_profiles = {}
var enet_peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
var alert_popup_scene: PackedScene = preload("res://Scenes/Menus/alert_popup.tscn")
var connected_players_profiles: Dictionary = {}
func _ready():
func _ready() -> void:
multiplayer.peer_connected.connect(_on_player_connected)
multiplayer.peer_disconnected.connect(_on_player_disconnected)
multiplayer.connected_to_server.connect(_on_connection_succeeded)
@ -26,29 +25,29 @@ func _ready():
multiplayer.server_disconnected.connect(_on_server_disconnected)
func _on_player_connected(peer_id):
func _on_player_connected(peer_id: int) -> void:
add_player.rpc_id(peer_id, Data.player_profile.to_dict())
func _on_player_disconnected(peer_id):
func _on_player_disconnected(peer_id: int) -> void:
if chatbox:
chatbox.append_message("SERVER", Color.TOMATO, connected_players_profiles[peer_id].display_name + " has disconnected!")
connected_players_profiles.erase(peer_id)
player_disconnected.emit(peer_id)
func _on_connection_succeeded():
func _on_connection_succeeded() -> void:
setup_game(multiplayer.get_unique_id())
func _on_connection_failed():
func _on_connection_failed() -> void:
multiplayer.multiplayer_peer = null
var popup = alert_popup_scene.instantiate() as AlertPopup
var popup: AlertPopup = alert_popup_scene.instantiate() as AlertPopup
popup.set_popup("Unable to connect to server", "OK")
add_child(popup)
func _on_server_disconnected():
func _on_server_disconnected() -> void:
multiplayer.multiplayer_peer = null
disconnected_from_server.emit()
@ -59,7 +58,7 @@ func create_server() -> void:
setup_game(1)
func setup_game(peer_id):
func setup_game(peer_id: int) -> void:
player_disconnected.connect(Game.remove_player)
Game.spawn_level()
scoreboard.all_players_ready.connect(start_game)
@ -74,7 +73,7 @@ func setup_game(peer_id):
player_connected.emit(peer_id, Data.player_profile)
func setup_the_ui():
func setup_the_ui() -> void:
scoreboard.unready_all_players()
scoreboard.set_visible(true)
loadout_editor.set_visible(true)
@ -83,39 +82,39 @@ func setup_the_ui():
func connect_to_server() -> void:
var ip = server_form.get_server_ip() if server_form.get_server_ip() else "localhost"
var port = server_form.get_server_port() if server_form.get_server_port() else str(SERVER_PORT)
var ip: String = server_form.get_server_ip() if server_form.get_server_ip() else "localhost"
var port: String = server_form.get_server_port() if server_form.get_server_port() else str(SERVER_PORT)
enet_peer.create_client(ip, int(port))
multiplayer.multiplayer_peer = enet_peer
func ready_player():
var peer_id = multiplayer.get_unique_id()
func ready_player() -> void:
var peer_id: int = multiplayer.get_unique_id()
networked_ready_player.rpc(peer_id)
func start_game():
func start_game() -> void:
enet_peer.refuse_new_connections = true
Game.spawn_players(connected_players_profiles.keys(), connected_players_profiles, chatbox.opened, chatbox.closed)
scoreboard.set_visible(false)
loadout_editor.set_visible(false)
func edit_player_profile(_argument):
var profile_dict = Data.player_profile.to_dict()
func edit_player_profile(_argument: PlayerProfile) -> void:
var profile_dict: Dictionary = Data.player_profile.to_dict()
networked_edit_player_profile.rpc(multiplayer.get_unique_id(), profile_dict)
@rpc("any_peer", "reliable", "call_local")
func networked_edit_player_profile(peer_id, new_profile_dict):
func networked_edit_player_profile(peer_id: int, new_profile_dict: Dictionary) -> void:
connected_players_profiles[peer_id].set_display_name(new_profile_dict["display_name"])
connected_players_profiles[peer_id].set_preferred_class(new_profile_dict["preferred_class"])
@rpc("any_peer","reliable")
func add_player(new_player_profile_dict):
var new_player_peer_id = multiplayer.get_remote_sender_id()
var new_player_profile = PlayerProfile.from_dict(new_player_profile_dict)
func add_player(new_player_profile_dict: Dictionary) -> void:
var new_player_peer_id: int = multiplayer.get_remote_sender_id()
var new_player_profile: PlayerProfile = PlayerProfile.from_dict(new_player_profile_dict)
if chatbox:
chatbox.append_message("SERVER", Color.TOMATO, new_player_profile.display_name + " has connected!")
connected_players_profiles[new_player_peer_id] = new_player_profile
@ -123,7 +122,7 @@ func add_player(new_player_profile_dict):
@rpc("any_peer", "reliable", "call_local")
func networked_ready_player(peer_id):
func networked_ready_player(peer_id: int) -> void:
scoreboard.set_player_ready_state(peer_id, true)

View File

@ -1,6 +1,6 @@
extends Camera3D
class_name OnTopCamera extends Camera3D
@export var clone_camera : Node3D
@export var clone_camera: Node3D
func _process(_delta: float) -> void:
global_position = clone_camera.global_position

View File

@ -1,9 +1,8 @@
extends Control
class_name OptionsMenu
class_name OptionsMenu extends Control
@export var gameplay : GameplayOptionsMenu
@export var graphics : GraphicsOptionsMenu
@export var keybinds : KeybindsOptionsMenu
@export var gameplay: GameplayOptionsMenu
@export var graphics: GraphicsOptionsMenu
@export var keybinds: KeybindsOptionsMenu
func _on_cancel_pressed() -> void:
@ -19,4 +18,5 @@ func _on_confirm_pressed() -> void:
Data.audio.save_profile_to_disk()
Data.preferences.save_profile_to_disk()
Data.player_keymap.save_profile_to_disk()
Data.player_controller_keymap.append_input_map()
queue_free()

View File

@ -1,16 +1,17 @@
extends PathFollow3D
class_name PathVisualThing extends PathFollow3D
@export var speed: float = 0.5
@export var world_model: Node3D
@export var minimap_model: Node3D
@export var speed = 0.5
@export var world_model : Node3D
@export var minimap_model : Node3D
func _process(delta: float) -> void:
progress += speed * delta
func set_world_visible(value: bool):
func set_world_visible(value: bool) -> void:
world_model.set_visible(value)
func set_minimap_visible(value: bool):
func set_minimap_visible(value: bool) -> void:
minimap_model.set_visible(value)

View File

@ -1,10 +1,10 @@
extends Control
class_name PauseMenu
class_name PauseMenu extends Control
signal closed
signal closed()
var options_menu_scene: PackedScene = preload("res://Scenes/Menus/options_menu.tscn")
var confirmation_popup_scene: PackedScene = preload("res://Scenes/Menus/confirmation_popup.tscn")
var options_menu_scene = preload("res://Scenes/Menus/options_menu.tscn")
var confirmation_popup_scene = preload("res://Scenes/Menus/confirmation_popup.tscn")
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("Pause"):
@ -18,30 +18,30 @@ func _on_resume_pressed() -> void:
func _on_options_pressed() -> void:
var menu = options_menu_scene.instantiate()
var menu: OptionsMenu = options_menu_scene.instantiate()
add_child(menu)
func _on_quit_to_main_menu_pressed() -> void:
var popup = confirmation_popup_scene.instantiate() as ConfirmationPopup
var popup: ConfirmationPopup = confirmation_popup_scene.instantiate() as ConfirmationPopup
popup.set_popup("Are you sure you want to quit and return to main menu?", "Yes", "No")
popup.completed.connect(return_to_menu)
add_child(popup)
func return_to_menu(confirmation):
func return_to_menu(confirmation: bool) -> void:
if confirmation:
Game.scene_switch_main_menu()
func _on_quit_to_desktop_pressed() -> void:
var popup = confirmation_popup_scene.instantiate() as ConfirmationPopup
var popup: ConfirmationPopup = confirmation_popup_scene.instantiate() as ConfirmationPopup
popup.set_popup("Are you sure you want to quit?", "Yes", "No")
popup.completed.connect(quit_game)
add_child(popup)
func quit_game(confirmation):
func quit_game(confirmation: bool) -> void:
if confirmation:
Game.quit_to_desktop()

View File

@ -1,4 +1,4 @@
extends PanelContainer
class_name PickupNotification extends PanelContainer
@export var fade_out_time: float
@export var style: StyleBoxFlat
@ -9,8 +9,8 @@ extends PanelContainer
@export var epic_background: Color
@export var legendary_background: Color
var fade_time = 0.0
var fading = false
var fade_time: float = 0.0
var fading: bool = false
func _ready() -> void:

15
Scripts/round_stats.gd Normal file
View File

@ -0,0 +1,15 @@
class_name RoundStats extends RefCounted
var enemies_undefeated: Dictionary
func add_enemy_undefeated(wave_num: int, enemy: Enemy) -> void:
if enemies_undefeated.has(wave_num):
var wave_dict: Dictionary = enemies_undefeated[wave_num] as Dictionary
if wave_dict.has(enemy):
wave_dict[enemy] += 1
else:
wave_dict[enemy] = 1
else:
enemies_undefeated[wave_num] = {}
enemies_undefeated[wave_num][enemy] = 1

View File

@ -1,10 +1,10 @@
extends PanelContainer
class_name Scoreboard
class_name Scoreboard extends PanelContainer
signal all_players_ready
signal all_players_ready()
var entry_scene: PackedScene = preload("res://Scenes/UI/scoreboard_entry.tscn")
var entries: Dictionary = {}
var entry_scene = preload("res://Scenes/UI/scoreboard_entry.tscn")
var entries = {}
func _ready() -> void:
$VBoxContainer/DummyEntry1.queue_free()
@ -12,26 +12,26 @@ func _ready() -> void:
$VBoxContainer/DummyEntry3.queue_free()
func get_player_entry(peer_id) -> ScoreboardEntry:
func get_player_entry(peer_id: int) -> ScoreboardEntry:
return entries[peer_id]
func set_player_ready_state(peer_id: int, state: bool):
func set_player_ready_state(peer_id: int, state: bool) -> void:
entries[peer_id].set_ready_state(state)
for id in entries:
for id: int in entries:
if !entries[id].get_ready_state():
return
all_players_ready.emit()
unready_all_players()
func unready_all_players():
for peer_id in entries:
func unready_all_players() -> void:
for peer_id: int in entries:
entries[peer_id].set_ready_state(false)
func add_player(peer_id: int, player_profile: PlayerProfile):
var entry = entry_scene.instantiate() as ScoreboardEntry
func add_player(peer_id: int, player_profile: PlayerProfile) -> void:
var entry: ScoreboardEntry = entry_scene.instantiate() as ScoreboardEntry
entry.name = str(peer_id)
entry.set_display_name("", player_profile.get_display_name())
entry.set_character(0, player_profile.get_preferred_class())
@ -41,6 +41,6 @@ func add_player(peer_id: int, player_profile: PlayerProfile):
$VBoxContainer.add_child(entry)
func remove_player(peer_id: int):
func remove_player(peer_id: int) -> void:
entries[peer_id].queue_free()
entries.erase(peer_id)

View File

@ -1,24 +1,23 @@
extends HBoxContainer
class_name ScoreboardEntry
class_name ScoreboardEntry extends HBoxContainer
var display_name: String
var character: int
var ready_state: bool
func set_display_name(_old_name: String, new_name: String):
func set_display_name(_old_name: String, new_name: String) -> void:
display_name = new_name
$DisplayName.text = new_name
func get_display_name() -> String:
return display_name
func set_character(_old_class: int, new_class: int):
func set_character(_old_class: int, new_class: int) -> void:
character = new_class
$CharacterName.text = Data.characters[new_class].hero_name
func get_character() -> int:
return character
func set_ready_state(state: bool):
func set_ready_state(state: bool) -> void:
ready_state = state
if state:
$TextureRect.texture.region = Rect2(32, 0, 32, 32)

View File

@ -1,5 +1,4 @@
extends PanelContainer
class_name ServerForm
class_name ServerForm extends PanelContainer
signal connect_button_pressed
signal host_button_pressed

View File

@ -1,12 +1,12 @@
extends Node3D
class_name ShopStand
class_name ShopStand extends Node3D
@export var cards : Array[CardInHand]
@export var choice_colliders : Array[CollisionShape3D]
@export var choice_buttons : Array[InteractButton]
@export var choice_sprites : Array[Sprite3D]
@export var item_card_scene : PackedScene
var price_dict = {
@export var cards: Array[CardInHand]
@export var choice_colliders: Array[CollisionShape3D]
@export var choice_buttons: Array[InteractButton]
@export var choice_sprites: Array[Sprite3D]
@export var item_card_scene: PackedScene
var price_dict: Dictionary = {
Data.Rarity.UNCOMMON : 30,
Data.Rarity.RARE : 50,
Data.Rarity.EPIC : 75,
@ -14,18 +14,18 @@ var price_dict = {
}
func close():
for x in choice_colliders:
func close() -> void:
for x: CollisionShape3D in choice_colliders:
x.disabled = true
for x in choice_sprites:
for x: Sprite3D in choice_sprites:
x.set_visible(false)
func randomize_cards():
var cheap_cards = []
var medium_cards = []
var pricey_cards = []
for card in Data.cards:
func randomize_cards() -> void:
var cheap_cards: Array[Card] = []
var medium_cards: Array[Card] = []
var pricey_cards: Array[Card] = []
for card: Card in Data.cards:
if card.rarity == Data.Rarity.UNCOMMON or card.rarity == Data.Rarity.RARE:
cheap_cards.append(card)
if card.rarity == Data.Rarity.RARE or card.rarity == Data.Rarity.EPIC:
@ -33,36 +33,36 @@ func randomize_cards():
if card.rarity == Data.Rarity.EPIC or card.rarity == Data.Rarity.LEGENDARY:
pricey_cards.append(card)
for x in 3:
var chosen_card = cheap_cards.pick_random()
for x: int in 3:
var chosen_card: Card = cheap_cards.pick_random()
cards[x].set_card(chosen_card)
cards[x].view_tower()
choice_buttons[x].press_cost = price_dict[chosen_card.rarity]
choice_buttons[x].hover_text = "Spend $" + str(choice_buttons[x].press_cost) + " to acquire " + chosen_card.display_name + "?"
for x in 2:
var chosen_card = medium_cards.pick_random()
for x: int in 2:
var chosen_card: Card = medium_cards.pick_random()
cards[x+3].set_card(chosen_card)
cards[x+3].view_tower()
choice_buttons[x+3].press_cost = price_dict[chosen_card.rarity]
choice_buttons[x+3].hover_text = "Spend $" + str(choice_buttons[x+3].press_cost) + " to acquire " + chosen_card.display_name + "?"
for x in 1:
var chosen_card = pricey_cards.pick_random()
for x: int in 1:
var chosen_card: Card = pricey_cards.pick_random()
cards[x+5].set_card(chosen_card)
cards[x+5].view_tower()
choice_buttons[x+5].press_cost = price_dict[chosen_card.rarity]
choice_buttons[x+5].hover_text = "Spend $" + str(choice_buttons[x+5].press_cost) + " to acquire " + chosen_card.display_name + "?"
for x in choice_colliders:
for x: CollisionShape3D in choice_colliders:
x.set_deferred("disabled", false)
for x in choice_sprites:
for x: Sprite3D in choice_sprites:
x.set_visible(true)
func retrieve_card(i):
func retrieve_card(i: int) -> void:
#close()
choice_colliders[i].disabled = true
choice_sprites[i].set_visible(false)
var card = cards[i].stats
var item = item_card_scene.instantiate() as ItemCard
var card: Card = cards[i].stats
var item: ItemCard = item_card_scene.instantiate() as ItemCard
item.card = card
item.position = Vector3(2.128, 0, 0)
add_child(item)

View File

@ -1,20 +1,21 @@
extends Control
class_name SinglePlayerLobby extends Control
@export var scoreboard : Scoreboard
@export var loadout_editor : HeroSelector
@export var chatbox : Chatbox
var connected_players_profiles = {}
@export var scoreboard: Scoreboard
@export var loadout_editor: HeroSelector
@export var chatbox: Chatbox
var connected_players_profiles: Dictionary = {}
var enet_peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
func _ready() -> void:
var enet_peer = ENetMultiplayerPeer.new()
enet_peer.create_server(58008, 1)
multiplayer.multiplayer_peer = enet_peer
enet_peer.refuse_new_connections = true
setup_game()
func setup_game():
func setup_game() -> void:
Game.spawn_level()
scoreboard.add_player(1, Data.player_profile)
scoreboard.all_players_ready.connect(start_game)
@ -24,21 +25,16 @@ func setup_game():
chatbox.username = Data.player_profile.display_name
Data.player_profile.display_name_changed.connect(chatbox.change_username)
loadout_editor.hero_selected.connect(Data.player_profile.set_preferred_class)
loadout_editor.hero_selected.connect(edit_player_profile)
connected_players_profiles[1] = Data.player_profile
func edit_player_profile(_argument):
var profile_dict = Data.player_profile.to_dict()
func start_game():
func start_game() -> void:
Game.spawn_players(connected_players_profiles.keys(), connected_players_profiles, chatbox.opened, chatbox.closed)
scoreboard.set_visible(false)
loadout_editor.set_visible(false)
func setup_the_ui():
func setup_the_ui() -> void:
scoreboard.unready_all_players()
scoreboard.set_visible(true)
loadout_editor.set_visible(true)

View File

@ -1,5 +1,5 @@
extends EnemyController
class_name Dummy
class_name Dummy extends EnemyController
func _on_health_health_depleted() -> void:
$Dog/Health.max_health = stats.health

View File

@ -1,9 +1,9 @@
extends PanelContainer
class_name TextInputPopup
class_name TextInputPopup extends PanelContainer
signal completed(outcome)
signal completed(outcome: bool)
func set_popup(prompt_text, placeholder_text, confirm_text):
func set_popup(prompt_text: String, placeholder_text: String, confirm_text: String) -> void:
$VBoxContainer/LineEdit.text = prompt_text
$VBoxContainer/LineEdit.placeholder_text = placeholder_text
$VBoxContainer/Button.text = confirm_text

View File

@ -1,79 +1,78 @@
extends StaticBody3D
class_name TowerBase
class_name TowerBase extends StaticBody3D
@export var inventory : Inventory
@export var block : Node3D
@export var collider : CollisionShape3D
@export var minimap_icon : Sprite3D
@export var north_icon : Sprite3D
@export var south_icon : Sprite3D
@export var east_icon : Sprite3D
@export var west_icon : Sprite3D
@export var north_mesh : CSGBox3D
@export var south_mesh : CSGBox3D
@export var east_mesh : CSGBox3D
@export var west_mesh : CSGBox3D
@export var north_collider : CollisionShape3D
@export var south_collider : CollisionShape3D
@export var east_collider : CollisionShape3D
@export var west_collider : CollisionShape3D
@export var inventory: Inventory
@export var block: Node3D
@export var collider: CollisionShape3D
@export var minimap_icon: Sprite3D
@export var north_icon: Sprite3D
@export var south_icon: Sprite3D
@export var east_icon: Sprite3D
@export var west_icon: Sprite3D
@export var north_mesh: CSGBox3D
@export var south_mesh: CSGBox3D
@export var east_mesh: CSGBox3D
@export var west_mesh: CSGBox3D
@export var north_collider: CollisionShape3D
@export var south_collider: CollisionShape3D
@export var east_collider: CollisionShape3D
@export var west_collider: CollisionShape3D
var owner_id : int
var point_id : int
var tower = null
var has_card : bool :
var owner_id: int
var point_id: int
var tower: Tower = null
var has_card: bool :
set(_value):
return
get:
return inventory.size != 0
func set_color(color: Color):
func set_color(color: Color) -> void:
$MeshInstance3D.set_instance_shader_parameter("Color", color)
func set_float(value: float):
func set_float(value: float) -> void:
$MeshInstance3D.set_instance_shader_parameter("Float", value)
func add_card(card: Card, caller_id: int) -> bool:
var result = inventory.add(card)
var result: bool = inventory.add(card)
if result:
networked_spawn_tower.rpc(caller_id)
return result
func remove_card():
func remove_card() -> void:
Game.connected_players_nodes[tower.owner_id].add_card(inventory.remove_at(0))
networked_remove_tower.rpc()
func toggle_collision():
func toggle_collision() -> void:
collider.disabled = !collider.disabled
func set_north_wall(value: bool):
func set_north_wall(value: bool) -> void:
north_mesh.set_visible(value)
north_collider.disabled = !value
func set_south_wall(value : bool):
func set_south_wall(value: bool) -> void:
south_mesh.set_visible(value)
south_collider.disabled = !value
func set_east_wall(value : bool):
func set_east_wall(value: bool) -> void:
east_mesh.set_visible(value)
east_collider.disabled = !value
func set_west_wall(value : bool):
func set_west_wall(value: bool) -> void:
west_mesh.set_visible(value)
west_collider.disabled = !value
@rpc("reliable", "call_local", "any_peer")
func networked_spawn_tower(caller_id : int):
func networked_spawn_tower(caller_id: int) -> void:
tower = inventory.contents.keys()[0].turret_scene.instantiate() as Tower
tower.stats = inventory.contents.keys()[0].tower_stats
tower.name = "tower"
@ -89,7 +88,7 @@ func networked_spawn_tower(caller_id : int):
@rpc("reliable", "call_local", "any_peer")
func networked_remove_tower():
func networked_remove_tower() -> void:
tower.queue_free()
tower = null
minimap_icon.modulate = Color.GREEN

View File

@ -1,27 +1,27 @@
extends Path3D
class_name VisualizedPath
class_name VisualizedPath extends Path3D
var visual_scene: PackedScene = preload("res://Scenes/path_visual_thing.tscn")
var length: float = 0.0
var visualizer_points: Array = []
var visual_scene = preload("res://Scenes/path_visual_thing.tscn")
var length := 0.0
var visualizer_points = []
func spawn_visualizer_points() -> void:
var new_length = curve.get_baked_length()
for x in floori(new_length) - visualizer_points.size():
var point = visual_scene.instantiate()
var new_length: float = curve.get_baked_length()
for x: int in floori(new_length) - visualizer_points.size():
var point: PathFollow3D = visual_scene.instantiate()
visualizer_points.append(point)
add_child(point)
length = new_length
#print(str(int(length)) + " / " + str(visualizer_points.size()) + ", diff: " + str(visualizer_points.size() - length))
for x in visualizer_points.size():
for x: int in visualizer_points.size():
visualizer_points[x].progress_ratio = float(x) / visualizer_points.size()
func disable_visualization():
for x in visualizer_points:
func disable_visualization() -> void:
for x: PathFollow3D in visualizer_points:
x.set_world_visible(false)
func enable_visualization():
for x in visualizer_points:
func enable_visualization() -> void:
for x: PathFollow3D in visualizer_points:
x.set_world_visible(true)

View File

@ -1,21 +1,21 @@
extends Node
func calculate_spawn_power(wave_number : int, number_of_players : int) -> int:
func calculate_spawn_power(wave_number: int, number_of_players: int) -> int:
return 20 + (50 * number_of_players) + (30 * wave_number)
func generate_wave(spawn_power : int, spawn_pool : Array[Enemy]) -> Dictionary:
var wave = {}
func generate_wave(spawn_power: int, spawn_pool: Array[Enemy]) -> Dictionary:
var wave: Dictionary = {}
#var sp_used = 0
var enemy_types = randi_range(1, 5)
var enemy_choices = spawn_pool.duplicate()
var sp_allotment = floori(spawn_power / enemy_types)
for x in enemy_types:
var choice = enemy_choices.pick_random()
var enemy_types: int = randi_range(1, 5)
var enemy_choices: Array[Enemy] = spawn_pool.duplicate()
var sp_allotment: int = floori(float(spawn_power) / float(enemy_types))
for x: int in enemy_types:
var choice: Enemy = enemy_choices.pick_random()
enemy_choices.erase(choice)
if sp_allotment / choice.spawn_power > 0:
wave[Data.enemies.find(choice)] = sp_allotment / choice.spawn_power
if floori(float(sp_allotment) / float(choice.spawn_power)) > 0:
wave[Data.enemies.find(choice)] = floori(float(sp_allotment) / float(choice.spawn_power))
#sp_used += wave[Data.enemies.find(choice)] * choice.spawn_power
#print("Generated wave with spawn power: " + str(sp_used) + "/" + str(spawn_power))
return wave

View File

@ -1,14 +1,22 @@
extends Control
class_name WonGameScreen extends Control
@export var box: PackedScene
func _ready() -> void:
var wins = float(Data.save_stats.twenty_game_history.count(true))
var games = float(Data.save_stats.twenty_game_history.size())
var winrate = int((wins / games) * 100.0)
var wins: int = Data.save_stats.twenty_game_history.count(true)
var games: int = Data.save_stats.twenty_game_history.size()
var winrate: int = int((float(wins) / float(games)) * 100.0)
$Label2.text = "Your 20-game winrate is now: " + str(winrate) + "%!"
$Label3.text = "Total games: " + str(Data.save_stats.wins + Data.save_stats.losses)
$Label4.text = "Total wins: " + str(Data.save_stats.wins)
$Label5.text = "Total losses: " + str(Data.save_stats.losses)
for wave_key: int in Game.stats.enemies_undefeated:
var spawned_box: EnemyBox = box.instantiate() as EnemyBox
$VBoxContainer.add_child(spawned_box)
spawned_box.set_wave(wave_key)
for enemy_key: Enemy in Game.stats.enemies_undefeated[wave_key]:
spawned_box.add_enemy_tag(enemy_key, Game.stats.enemies_undefeated[wave_key][enemy_key])
func _on_quit_button_pressed() -> void: