way too many changes to list, oops. big rewrite.
This commit is contained in:
14
Scripts/Affectors/affector.gd
Normal file
14
Scripts/Affectors/affector.gd
Normal file
@ -0,0 +1,14 @@
|
||||
class_name Affector extends Node
|
||||
|
||||
var damage_particle_scene: PackedScene = preload("res://Scenes/damage_particle.tscn")
|
||||
|
||||
|
||||
func apply_effect(effect: Effect, targets: Array[EnemyController]) -> void:
|
||||
pass
|
||||
|
||||
|
||||
func spawn_damage_indicator(damage: int, pos: Vector3) -> void:
|
||||
var marker: Sprite3D = damage_particle_scene.instantiate()
|
||||
get_tree().root.add_child(marker)
|
||||
marker.set_number(damage)
|
||||
marker.position = pos
|
1
Scripts/Affectors/affector.gd.uid
Normal file
1
Scripts/Affectors/affector.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://5gl7yyrvjeow
|
13
Scripts/Affectors/area_affector.gd
Normal file
13
Scripts/Affectors/area_affector.gd
Normal file
@ -0,0 +1,13 @@
|
||||
class_name AreaAffector extends Affector
|
||||
|
||||
@export var shapecast: ShapeCast3D
|
||||
|
||||
|
||||
func apply_effect(effect: Effect, targets: Array[EnemyController]) -> void:
|
||||
for i: int in shapecast.get_collision_count():
|
||||
var enemy: EnemyController = shapecast.get_collider(i) as EnemyController
|
||||
#print(shapecast.get_collider(i))
|
||||
if targets.has(enemy):
|
||||
enemy.apply_effect(effect)
|
||||
if Data.preferences.display_tower_damage_indicators and effect.damage > 0:
|
||||
spawn_damage_indicator(effect.damage, enemy.sprite.global_position)
|
1
Scripts/Affectors/area_affector.gd.uid
Normal file
1
Scripts/Affectors/area_affector.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://duvfverjdqodj
|
8
Scripts/Affectors/direct_affect.gd
Normal file
8
Scripts/Affectors/direct_affect.gd
Normal file
@ -0,0 +1,8 @@
|
||||
class_name DirectAffect extends Affector
|
||||
|
||||
|
||||
func apply_effect(effect: Effect, targets: Array[EnemyController]) -> void:
|
||||
for enemy: EnemyController in targets:
|
||||
enemy.apply_effect(effect)
|
||||
if Data.preferences.display_tower_damage_indicators and effect.damage > 0:
|
||||
spawn_damage_indicator(effect.damage, enemy.sprite.global_position)
|
1
Scripts/Affectors/direct_affect.gd.uid
Normal file
1
Scripts/Affectors/direct_affect.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://8d0a4uc2i0ti
|
21
Scripts/Affectors/spawn_affect.gd
Normal file
21
Scripts/Affectors/spawn_affect.gd
Normal file
@ -0,0 +1,21 @@
|
||||
class_name SpawnAffect extends Affector
|
||||
|
||||
@export var spawn_scene: PackedScene
|
||||
@export var tower: Tower
|
||||
|
||||
var force: float = 150.0
|
||||
var projectile_id: int = 0
|
||||
|
||||
|
||||
func apply_effect(effect: Effect, targets: Array[EnemyController]) -> void:
|
||||
for target: EnemyController in targets:
|
||||
var projectile: Projectile = spawn_scene.instantiate() as Projectile
|
||||
if projectile is HomingProjectile:
|
||||
projectile.target = target
|
||||
projectile.position = tower.yaw_model.global_position
|
||||
projectile.effect = effect
|
||||
projectile.direction = -tower.yaw_model.global_transform.basis.z
|
||||
projectile.force = force
|
||||
projectile.name = tower.base_name + str(tower.owner_id) + str(projectile_id)
|
||||
get_tree().root.add_child(projectile)
|
||||
projectile_id += 1
|
1
Scripts/Affectors/spawn_affect.gd.uid
Normal file
1
Scripts/Affectors/spawn_affect.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ccu1u6nqkjxki
|
1
Scripts/EnemyAI/beelining_controller.gd.uid
Normal file
1
Scripts/EnemyAI/beelining_controller.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://d147vuqksqhis
|
@ -2,4 +2,5 @@ class_name EnemyMovement extends Node
|
||||
|
||||
@export var character: CharacterBody3D
|
||||
|
||||
var astar: AStarGraph3D
|
||||
var distance_remaining: float = 0.0
|
||||
|
1
Scripts/EnemyAI/enemy_movement.gd.uid
Normal file
1
Scripts/EnemyAI/enemy_movement.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cy0htr7710hnn
|
143
Scripts/EnemyAI/leaping_controller.gd
Normal file
143
Scripts/EnemyAI/leaping_controller.gd
Normal file
@ -0,0 +1,143 @@
|
||||
class_name LeapingController extends PathingController
|
||||
|
||||
@export var eastl: Label
|
||||
@export var westl: Label
|
||||
@export var northl: Label
|
||||
@export var southl: Label
|
||||
@export var easts: Sprite3D
|
||||
@export var wests: Sprite3D
|
||||
@export var norths: Sprite3D
|
||||
@export var souths: Sprite3D
|
||||
@export var box: CSGBox3D
|
||||
|
||||
var tolerance: float = 50.0
|
||||
var jumping: bool = false
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
tolerance = remap(character.health.current_health, 10, 50, character.health.max_health * 0.20, character.health.max_health)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if !path or jumping:
|
||||
return
|
||||
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: Transform3D = path.sample_baked_with_rotation(path_progress, true)
|
||||
character.global_position = sample.origin
|
||||
character.look_at(character.global_position + -sample.basis.z)
|
||||
var closest_point: int = astar.astar.get_closest_point(character.global_position, false)
|
||||
box.global_position = astar.astar.get_point_position(closest_point)
|
||||
var east: int = astar.get_east_point(closest_point)
|
||||
var west: int = astar.get_west_point(closest_point)
|
||||
var north: int = astar.get_north_point(closest_point)
|
||||
var south: int = astar.get_south_point(closest_point)
|
||||
#if east >= 0 and astar.astar.is_point_disabled(east):
|
||||
#eastl.text = "fuck no"
|
||||
#else:
|
||||
#eastl.text = "yeah"
|
||||
#if west >= 0 and astar.astar.is_point_disabled(west):
|
||||
#westl.text = "fuck no"
|
||||
#else:
|
||||
#westl.text = "yeah"
|
||||
#if north >= 0 and astar.astar.is_point_disabled(north):
|
||||
#northl.text = "fuck no"
|
||||
#else:
|
||||
#northl.text = "yeah"
|
||||
#if south >= 0 and astar.astar.is_point_disabled(south):
|
||||
#southl.text = "fuck no"
|
||||
#else:
|
||||
#southl.text = "yeah"
|
||||
norths.global_position = character.global_position + Vector3(-1.0, 1.0, 0.0)
|
||||
souths.global_position = character.global_position + Vector3(1.0, 1.0, 0.0)
|
||||
easts.global_position = character.global_position + Vector3(0.0, 1.0, -1.0)
|
||||
wests.global_position = character.global_position + Vector3(0.0, 1.0, 1.0)
|
||||
if east >= 0:
|
||||
if astar.astar.is_point_disabled(east):
|
||||
var further_point: int = astar.get_east_point(east)
|
||||
if further_point >= 0 and !astar.astar.is_point_disabled(further_point):
|
||||
var expected_offset: float = path.get_closest_offset(character.global_position + Vector3(0.0, 0.0, -4.0))
|
||||
var current_offset: float = path.get_closest_offset(character.global_position)
|
||||
var gain: float = expected_offset - current_offset
|
||||
if gain >= tolerance:
|
||||
distance_remaining -= gain
|
||||
path_progress += gain
|
||||
leap(Vector3(0.0, 0.0, -4.0))
|
||||
#eastl.text = str(gain)
|
||||
#easts.visible = true
|
||||
else:
|
||||
eastl.text = "cant"
|
||||
else:
|
||||
eastl.text = "clear"
|
||||
else:
|
||||
eastl.text = "invalid"
|
||||
if west >= 0:
|
||||
if astar.astar.is_point_disabled(west):
|
||||
var further_point: int = astar.get_west_point(west)
|
||||
if further_point >= 0 and !astar.astar.is_point_disabled(further_point):
|
||||
var expected_offset: float = path.get_closest_offset(character.global_position + Vector3(0.0, 0.0, 4.0))
|
||||
var current_offset: float = path.get_closest_offset(character.global_position)
|
||||
var gain: float = expected_offset - current_offset
|
||||
if gain >= tolerance:
|
||||
distance_remaining -= gain
|
||||
path_progress += gain
|
||||
leap(Vector3(0.0, 0.0, 4.0))
|
||||
#westl.text = str(gain)
|
||||
#wests.visible = true
|
||||
else:
|
||||
westl.text = "cant"
|
||||
else:
|
||||
westl.text = "clear"
|
||||
else:
|
||||
westl.text = "invalid"
|
||||
if north >= 0:
|
||||
if astar.astar.is_point_disabled(north):
|
||||
var further_point: int = astar.get_north_point(north)
|
||||
if further_point >= 0 and !astar.astar.is_point_disabled(further_point):
|
||||
var expected_offset: float = path.get_closest_offset(character.global_position + Vector3(-4.0, 0.0, 0.0))
|
||||
var current_offset: float = path.get_closest_offset(character.global_position)
|
||||
var gain: float = expected_offset - current_offset
|
||||
if gain >= tolerance:
|
||||
distance_remaining -= gain
|
||||
path_progress += gain
|
||||
leap(Vector3(-4.0, 0.0, 0.0))
|
||||
#northl.text = str(gain)
|
||||
#norths.visible = true
|
||||
else:
|
||||
northl.text = "cant"
|
||||
else:
|
||||
northl.text = "clear"
|
||||
else:
|
||||
northl.text = "invalid"
|
||||
if south >= 0:
|
||||
if astar.astar.is_point_disabled(south):
|
||||
var further_point: int = astar.get_south_point(south)
|
||||
if further_point >= 0 and !astar.astar.is_point_disabled(further_point):
|
||||
var expected_offset: float = path.get_closest_offset(character.global_position + Vector3(4.0, 0.0, 0.0))
|
||||
var current_offset: float = path.get_closest_offset(character.global_position)
|
||||
var gain: float = expected_offset - current_offset
|
||||
if gain >= tolerance:
|
||||
distance_remaining -= gain
|
||||
path_progress += gain
|
||||
leap(Vector3(4.0, 0.0, 0.0))
|
||||
#southl.text = str(gain)
|
||||
#souths.visible = true
|
||||
else:
|
||||
southl.text = "cant"
|
||||
else:
|
||||
southl.text = "clear"
|
||||
else:
|
||||
southl.text = "invalid"
|
||||
|
||||
|
||||
func finish_jump() -> void:
|
||||
jumping = false
|
||||
|
||||
|
||||
func leap(to_point: Vector3) -> void:
|
||||
jumping = true
|
||||
var tween: Tween = create_tween()
|
||||
tween.tween_property(character, "global_position", character.global_position + (to_point / 2.0) + Vector3.UP, 1.0)
|
||||
tween.tween_property(character, "global_position", character.global_position + to_point, 1.0)
|
||||
tween.tween_callback(finish_jump)
|
1
Scripts/EnemyAI/leaping_controller.gd.uid
Normal file
1
Scripts/EnemyAI/leaping_controller.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dqluvn05min37
|
@ -18,3 +18,4 @@ func _physics_process(delta: float) -> void:
|
||||
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)
|
||||
var closest_point: Vector3 = path.get_closest_point(character.global_position)
|
||||
|
1
Scripts/EnemyAI/pathing_controller.gd.uid
Normal file
1
Scripts/EnemyAI/pathing_controller.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://b62xnsbki8axa
|
@ -33,7 +33,7 @@ func explode() -> void:
|
||||
|
||||
|
||||
func hit(target: CharacterBody3D) -> void:
|
||||
target.damage(damage)
|
||||
target.apply_effect(effect)
|
||||
if owner_id == 0:
|
||||
if Data.preferences.display_tower_damage_indicators:
|
||||
spawn_damage_indicator(target.sprite.global_position)
|
||||
|
1
Scripts/Projectiles/explosive_projectile.gd.uid
Normal file
1
Scripts/Projectiles/explosive_projectile.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cubn2iabwg3
|
1
Scripts/Projectiles/homing_projectile.gd.uid
Normal file
1
Scripts/Projectiles/homing_projectile.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dwr38fukjqu7r
|
@ -9,6 +9,7 @@ var force: float = 2.0
|
||||
var damage: float = 0.0
|
||||
var lifetime: float = 10.0
|
||||
var time_alive: float = 0.0
|
||||
var effect: Effect
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@ -20,10 +21,10 @@ func _process(delta: float) -> void:
|
||||
|
||||
|
||||
func spawn_damage_indicator(pos: Vector3) -> void:
|
||||
if damage > 0:
|
||||
if effect.damage > 0:
|
||||
var marker: Node3D = damage_particle_scene.instantiate()
|
||||
get_tree().root.add_child(marker)
|
||||
marker.set_number(damage)
|
||||
marker.set_number(effect.damage)
|
||||
marker.position = pos
|
||||
|
||||
|
||||
|
1
Scripts/Projectiles/projectile.gd.uid
Normal file
1
Scripts/Projectiles/projectile.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bifvnevs5y4nj
|
1
Scripts/Projectiles/status_applying_projectile.gd.uid
Normal file
1
Scripts/Projectiles/status_applying_projectile.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ba2aqn82wo747
|
@ -1,6 +1,10 @@
|
||||
class_name Card extends Item
|
||||
|
||||
enum Faction {GENERIC = 0}
|
||||
enum Faction {
|
||||
GENERIC = 0,
|
||||
ENGINEER = 1,
|
||||
MAGE = 2,
|
||||
}
|
||||
|
||||
@export var rarity: Data.Rarity
|
||||
@export var faction: Faction
|
||||
|
1
Scripts/Resources/card.gd.uid
Normal file
1
Scripts/Resources/card.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://d40isem6w5d8
|
@ -1,6 +1,7 @@
|
||||
class_name CardText extends Resource
|
||||
|
||||
@export var target_type: Data.TargetType
|
||||
@export var energy_type: Data.EnergyType
|
||||
@export var attributes: Array[StatAttribute]
|
||||
@export_multiline var text: String
|
||||
|
||||
|
1
Scripts/Resources/card_text.gd.uid
Normal file
1
Scripts/Resources/card_text.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dg7gxxqfqxcmc
|
@ -10,3 +10,24 @@ class_name Enemy extends Resource
|
||||
@export var penalty: int = 10
|
||||
@export var movement_speed: float = 0.5
|
||||
@export var spawn_cooldown: float = 1.0
|
||||
|
||||
@export_group("Spawner Card")
|
||||
@export_subgroup("Common")
|
||||
@export var common_group: int = 1
|
||||
@export var common_cost: int = 1
|
||||
|
||||
@export_subgroup("Uncommon")
|
||||
@export var uncommon_group: int = 1
|
||||
@export var uncommon_cost: int = 1
|
||||
|
||||
@export_subgroup("Rare")
|
||||
@export var rare_group: int = 1
|
||||
@export var rare_cost: int = 1
|
||||
|
||||
@export_subgroup("Epic")
|
||||
@export var epic_group: int = 1
|
||||
@export var epic_cost: int = 1
|
||||
|
||||
@export_subgroup("Legendary")
|
||||
@export var legendary_group: int = 1
|
||||
@export var legendary_cost: int = 1
|
||||
|
1
Scripts/Resources/enemy.gd.uid
Normal file
1
Scripts/Resources/enemy.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cbwxa2a4hfcy4
|
@ -4,3 +4,5 @@ class_name HeroClass extends Resource
|
||||
@export var texture: Texture
|
||||
@export var hand_texture: Texture
|
||||
@export var deck: Array[Card]
|
||||
@export var faction: Card.Faction
|
||||
@export var podium: PackedScene
|
||||
|
1
Scripts/Resources/hero_class.gd.uid
Normal file
1
Scripts/Resources/hero_class.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dcwtg2gev3uia
|
1
Scripts/Resources/item.gd.uid
Normal file
1
Scripts/Resources/item.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://uomjb4sj4enc
|
1
Scripts/Resources/player_audio_settings.gd.uid
Normal file
1
Scripts/Resources/player_audio_settings.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ctwk3deywlswg
|
@ -9,7 +9,7 @@ const SAVE_PATH: String = "user://graphics_settings.tres"
|
||||
|
||||
|
||||
func apply_graphical_settings(viewport: Viewport) -> void:
|
||||
DisplayServer.window_set_vsync_mode(vsync_mode)
|
||||
#DisplayServer.window_set_vsync_mode(vsync_mode)
|
||||
match aa_mode:
|
||||
0:
|
||||
viewport.use_taa = false
|
||||
|
1
Scripts/Resources/player_graphics_settings.gd.uid
Normal file
1
Scripts/Resources/player_graphics_settings.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bte0pj6bwedb0
|
1
Scripts/Resources/player_keymap.gd.uid
Normal file
1
Scripts/Resources/player_keymap.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://vkthiwr3vq4g
|
1
Scripts/Resources/player_preferences.gd.uid
Normal file
1
Scripts/Resources/player_preferences.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c78bl6r5qlday
|
1
Scripts/Resources/player_profile.gd.uid
Normal file
1
Scripts/Resources/player_profile.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://b1s4nrql8i1sm
|
86
Scripts/Resources/save_data.gd
Normal file
86
Scripts/Resources/save_data.gd
Normal file
@ -0,0 +1,86 @@
|
||||
class_name SaveData extends RefCounted
|
||||
|
||||
const SAVE_PATH: String = "user://save1.txt"
|
||||
|
||||
#Game History
|
||||
var twenty_game_history: Array[bool] = []
|
||||
var wins: int = 0
|
||||
var losses: int = 0
|
||||
|
||||
#Engineer
|
||||
var engineer_cards_bought: int = 0
|
||||
|
||||
|
||||
#Unlocking the mage
|
||||
var mage_card_seen_in_shop: bool = false
|
||||
var mage_cards_bought: int = 0
|
||||
var mage_unlocked: bool = 0
|
||||
|
||||
|
||||
func add_game_outcome(outcome: bool) -> void:
|
||||
if outcome:
|
||||
wins += 1
|
||||
else:
|
||||
losses += 1
|
||||
twenty_game_history.push_back(outcome)
|
||||
if twenty_game_history.size() > 20:
|
||||
twenty_game_history.pop_front()
|
||||
|
||||
|
||||
func unlock_all_content() -> void:
|
||||
mage_unlocked = true
|
||||
|
||||
|
||||
func lock_all_content() -> void:
|
||||
mage_unlocked = false
|
||||
|
||||
|
||||
func bought_engineer_card() -> void:
|
||||
engineer_cards_bought += 1
|
||||
|
||||
|
||||
func saw_mage_card_in_shop() -> void:
|
||||
mage_card_seen_in_shop = true
|
||||
save_to_disc()
|
||||
|
||||
|
||||
func bought_mage_card() -> void:
|
||||
mage_cards_bought += 1
|
||||
if mage_cards_bought >= 10:
|
||||
mage_unlocked = true
|
||||
save_to_disc()
|
||||
|
||||
|
||||
func save_to_disc() -> void:
|
||||
var save_file: FileAccess = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
||||
var dict: Dictionary = {
|
||||
"wins" = wins,
|
||||
"losses" = losses,
|
||||
"twenty_game_history" = twenty_game_history,
|
||||
"engineer_cards_bought" = engineer_cards_bought,
|
||||
"mage_card_seen_in_shop" = mage_card_seen_in_shop,
|
||||
"mage_cards_bought" = mage_cards_bought,
|
||||
"mage_unlocked" = mage_unlocked,
|
||||
}
|
||||
var json_string: String = JSON.stringify(dict)
|
||||
save_file.store_line(json_string)
|
||||
|
||||
|
||||
static func load_profile_from_disk() -> SaveData:
|
||||
if FileAccess.file_exists(SAVE_PATH):
|
||||
var save_file: FileAccess = FileAccess.open(SAVE_PATH, FileAccess.READ)
|
||||
var json_string: String = save_file.get_line()
|
||||
var json: JSON = JSON.new()
|
||||
var parse_result: Error = json.parse(json_string)
|
||||
if parse_result == OK:
|
||||
var dict: Dictionary = json.data
|
||||
var stats: SaveData = SaveData.new()
|
||||
stats.wins = dict["wins"]
|
||||
stats.losses = dict["losses"]
|
||||
stats.twenty_game_history.append_array(dict["twenty_game_history"])
|
||||
stats.engineer_cards_bought = dict["engineer_cards_bought"]
|
||||
stats.mage_card_seen_in_shop = dict["mage_card_seen_in_shop"]
|
||||
stats.mage_cards_bought = dict["mage_cards_bought"]
|
||||
stats.mage_unlocked = dict["mage_unlocked"]
|
||||
return stats
|
||||
return SaveData.new()
|
1
Scripts/Resources/save_data.gd.uid
Normal file
1
Scripts/Resources/save_data.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://6tvi4ox481cp
|
@ -1,25 +0,0 @@
|
||||
class_name SaveStats extends Resource
|
||||
|
||||
const SAVE_PATH: String = "user://save_stats.tres"
|
||||
|
||||
@export var wins: int
|
||||
@export var losses: int
|
||||
@export var twenty_game_history: Array[bool]
|
||||
|
||||
|
||||
func add_game_outcome(outcome: bool) -> void:
|
||||
if outcome:
|
||||
wins += 1
|
||||
else:
|
||||
losses += 1
|
||||
twenty_game_history.push_back(outcome)
|
||||
if twenty_game_history.size() > 20:
|
||||
twenty_game_history.pop_front()
|
||||
|
||||
|
||||
func save_profile_to_disk() -> void:
|
||||
ResourceSaver.save(self, SAVE_PATH)
|
||||
static func load_profile_from_disk() -> SaveStats:
|
||||
if ResourceLoader.exists(SAVE_PATH):
|
||||
return ResourceLoader.load(SAVE_PATH)
|
||||
return SaveStats.new()
|
1
Scripts/Resources/stat_attribute.gd.uid
Normal file
1
Scripts/Resources/stat_attribute.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://yjb0uv6og430
|
1
Scripts/Resources/status_stats.gd.uid
Normal file
1
Scripts/Resources/status_stats.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bq6jp8bwub6je
|
@ -2,4 +2,4 @@ class_name StatusDoT extends StatusEffect
|
||||
|
||||
|
||||
func proc(affected: EnemyController, stacks: int, _existing_effects: Dictionary) -> void:
|
||||
affected.damage(stats.potency * stacks)
|
||||
affected.health.take_damage(int(stats.potency * stacks))
|
||||
|
1
Scripts/StatusEffects/status_dot.gd.uid
Normal file
1
Scripts/StatusEffects/status_dot.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c6eghujlaqhwi
|
@ -1,6 +1,6 @@
|
||||
class_name StatusEffect extends RefCounted
|
||||
class_name StatusEffect extends Resource
|
||||
|
||||
var stats: StatusStats
|
||||
@export var stats: StatusStats
|
||||
|
||||
var time_since_proc: float = 0.0
|
||||
var time_existed: float = 0.0
|
||||
|
1
Scripts/StatusEffects/status_effect.gd.uid
Normal file
1
Scripts/StatusEffects/status_effect.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://chy7bx8dlwgs0
|
1
Scripts/StatusEffects/status_slow.gd.uid
Normal file
1
Scripts/StatusEffects/status_slow.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bh74uangqekuk
|
@ -1,13 +0,0 @@
|
||||
class_name HitscanTower extends Tower
|
||||
|
||||
|
||||
func shoot() -> void:
|
||||
super.shoot()
|
||||
target_finder.get_target().damage(damage)
|
||||
if Data.preferences.display_tower_damage_indicators:
|
||||
spawn_damage_indicator(target_finder.get_target().sprite.global_position)
|
||||
|
||||
|
||||
@rpc("reliable")
|
||||
func networked_shoot() -> void:
|
||||
super.networked_shoot()
|
@ -1,30 +0,0 @@
|
||||
class_name ProjectileTower extends Tower
|
||||
|
||||
@export var projectile_scene: PackedScene
|
||||
|
||||
var force: float = 150.0
|
||||
var projectile_id: int = 0
|
||||
|
||||
|
||||
func shoot() -> void:
|
||||
if is_multiplayer_authority():
|
||||
networked_spawn_projectile.rpc(multiplayer.get_unique_id())
|
||||
|
||||
|
||||
@rpc("reliable")
|
||||
func networked_shoot() -> void:
|
||||
super.networked_shoot()
|
||||
shoot()
|
||||
|
||||
|
||||
@rpc("reliable", "call_local")
|
||||
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
|
||||
projectile.force = force
|
||||
projectile.name = base_name + str(peer_id) + str(projectile_id)
|
||||
get_tree().root.add_child(projectile)
|
||||
projectile_id += 1
|
||||
return projectile
|
@ -1,36 +0,0 @@
|
||||
class_name RangeAffectingTower extends StatusApplyingTower
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if !is_multiplayer_authority():
|
||||
return
|
||||
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: EnemyController in enemies_in_range:
|
||||
fire(enemy)
|
||||
|
||||
|
||||
func aim() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func fire(target: EnemyController) -> void:
|
||||
if is_instance_valid(target) and target.alive:
|
||||
target.damage(damage)
|
||||
target.status_manager.add_effect(build_status_object())
|
||||
if Data.preferences.display_tower_damage_indicators:
|
||||
spawn_damage_indicator(target.sprite.global_position)
|
||||
if is_multiplayer_authority():
|
||||
networked_fire.rpc(get_tree().root.get_path_to(target))
|
||||
|
||||
|
||||
@rpc("reliable")
|
||||
func networked_fire(target_node_path: String) -> void:
|
||||
var target: EnemyController = get_tree().root.get_node(target_node_path)
|
||||
fire(target)
|
@ -1,47 +0,0 @@
|
||||
class_name ShapecastTower extends Tower
|
||||
|
||||
@export var shapecast: ShapeCast3D
|
||||
@export var particlesystem: GPUParticles3D
|
||||
@export var status_stats: StatusStats
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
super._process(delta)
|
||||
if target_finder.get_target():
|
||||
particlesystem.emitting = true
|
||||
else:
|
||||
particlesystem.emitting = false
|
||||
|
||||
|
||||
func shoot() -> void:
|
||||
for index: int in shapecast.get_collision_count():
|
||||
var target: CharacterBody3D = shapecast.get_collider(index) as CharacterBody3D
|
||||
hit(target)
|
||||
|
||||
|
||||
func aim() -> void:
|
||||
yaw_model.look_at(target_finder.get_target().global_position)
|
||||
pitch_model.look_at(target_finder.get_target().global_position)
|
||||
pitch_model.rotation.x = 0.0
|
||||
|
||||
|
||||
func hit(target: CharacterBody3D) -> void:
|
||||
if is_instance_valid(target) and target.alive:
|
||||
target.damage(damage)
|
||||
if Data.preferences.display_tower_damage_indicators:
|
||||
spawn_damage_indicator(target.sprite.global_position)
|
||||
target.status_manager.add_effect(build_status_object())
|
||||
if is_multiplayer_authority():
|
||||
networked_hit.rpc(get_tree().root.get_path_to(target))
|
||||
|
||||
|
||||
func build_status_object() -> StatusEffect:
|
||||
var status: StatusEffect = StatusEffect.new()
|
||||
status.stats = status_stats
|
||||
return status
|
||||
|
||||
|
||||
@rpc("reliable")
|
||||
func networked_hit(target_node_path: String) -> void:
|
||||
var target: CharacterBody3D = get_tree().root.get_node(target_node_path) as CharacterBody3D
|
||||
hit(target)
|
@ -1,21 +0,0 @@
|
||||
class_name StatusApplyingTower extends HitscanTower
|
||||
|
||||
@export var status_stats: StatusStats
|
||||
|
||||
|
||||
func shoot() -> void:
|
||||
super.shoot()
|
||||
if target_finder.get_target():
|
||||
target_finder.get_target().damage(damage)
|
||||
target_finder.get_target().status_manager.add_effect(build_status_object())
|
||||
|
||||
|
||||
func build_status_object() -> StatusEffect:
|
||||
var status: StatusEffect = StatusEffect.new()
|
||||
status.stats = status_stats
|
||||
return status
|
||||
|
||||
|
||||
@rpc("reliable")
|
||||
func networked_shoot() -> void:
|
||||
super.networked_shoot()
|
@ -1,80 +0,0 @@
|
||||
class_name Tower extends Node3D
|
||||
|
||||
@export var stats: CardText
|
||||
@export var target_finder: TargetFinder
|
||||
@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: 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:
|
||||
time_between_shots = stats.get_attribute("Fire Delay")
|
||||
damage = stats.get_attribute("Damage")
|
||||
target_range = stats.get_attribute("Range")
|
||||
range_indicator.radius = target_range
|
||||
|
||||
|
||||
func preview_range(value: bool) -> void:
|
||||
range_indicator.set_visible(value)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if !is_multiplayer_authority():
|
||||
return
|
||||
if time_since_firing < time_between_shots:
|
||||
time_since_firing += delta
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if !is_multiplayer_authority():
|
||||
#only doing the graphical sort of stuff but not shoot logic
|
||||
if target_finder.get_target():
|
||||
aim()
|
||||
return
|
||||
if target_finder.get_target():
|
||||
aim()
|
||||
if time_since_firing >= time_between_shots:
|
||||
time_since_firing -= time_between_shots
|
||||
shoot()
|
||||
|
||||
|
||||
func aim() -> void:
|
||||
yaw_model.look_at(target_finder.get_target().global_position)
|
||||
pitch_model.look_at(target_finder.get_target().global_position)
|
||||
pitch_model.rotation.x = 0.0
|
||||
|
||||
|
||||
func shoot() -> void:
|
||||
animator.play("shoot")
|
||||
audio_player.play()
|
||||
if is_multiplayer_authority():
|
||||
networked_shoot.rpc()
|
||||
|
||||
|
||||
func spawn_damage_indicator(pos: Vector3) -> void:
|
||||
if damage > 0:
|
||||
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() -> void:
|
||||
shoot()
|
||||
|
||||
|
||||
#@rpc("reliable")
|
||||
#func networked_acquire_target(target_node_path: String) -> void:
|
||||
#targeted_enemy = get_tree().root.get_node(target_node_path)
|
@ -19,7 +19,7 @@ func shoot() -> void:
|
||||
if raycast.is_colliding():
|
||||
var target: CharacterBody3D = raycast.get_collider()
|
||||
if target != null:
|
||||
var target_hitbox: Hitbox = target.shape_owner_get_owner(raycast.get_collider_shape())
|
||||
var target_hitbox: CollisionShape3D = 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:
|
||||
|
1
Scripts/Weapons/hitscan_weapon.gd.uid
Normal file
1
Scripts/Weapons/hitscan_weapon.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bp3o5klntwmhd
|
@ -20,7 +20,9 @@ func networked_shoot() -> void:
|
||||
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
|
||||
var effect: Effect = Effect.new()
|
||||
effect.damage = damage
|
||||
projectile.effect = effect
|
||||
projectile.direction = direction
|
||||
projectile.force = force
|
||||
projectile.owner_id = peer_id
|
||||
|
1
Scripts/Weapons/projectile_weapon.gd.uid
Normal file
1
Scripts/Weapons/projectile_weapon.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://d2gdg2lcedfgg
|
1
Scripts/Weapons/shapecast_weapon.gd.uid
Normal file
1
Scripts/Weapons/shapecast_weapon.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://1l1qccgmp5ih
|
1
Scripts/Weapons/status_applying_weapon.gd.uid
Normal file
1
Scripts/Weapons/status_applying_weapon.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dqcjfcecqhuec
|
@ -1,6 +1,7 @@
|
||||
class_name Weapon extends Node3D
|
||||
|
||||
signal energy_changed(energy: int)
|
||||
signal energy_spent(energy: int, type: Data.EnergyType)
|
||||
signal energy_recharged(energy: int, type: Data.EnergyType)
|
||||
|
||||
@export var stats: CardText
|
||||
@export var animator: AnimationPlayer
|
||||
@ -13,7 +14,7 @@ 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 damage: int = 0
|
||||
var max_energy: float = 100.0
|
||||
var current_energy: float = 100.0
|
||||
var energy_cost: float = 1.0
|
||||
@ -21,12 +22,16 @@ var recharging: bool = false
|
||||
var recharge_speed: float = 0.0
|
||||
var recharge_acceleration: float = 2.0
|
||||
var recharge_max_speed: float = 25.0
|
||||
#var time_since_trigger: float = 0.0
|
||||
var prev_energy_int: int = 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
time_between_shots = stats.get_attribute("Fire Delay")
|
||||
damage = stats.get_attribute("Damage")
|
||||
energy_cost = stats.get_attribute("Energy")
|
||||
damage = int(stats.get_attribute("Damage"))
|
||||
#energy_cost = stats.get_attribute("Energy")
|
||||
max_energy = stats.get_attribute("Energy")
|
||||
current_energy = max_energy
|
||||
|
||||
|
||||
func set_hero(value: Hero) -> void:
|
||||
@ -41,22 +46,33 @@ func _process(delta: float) -> void:
|
||||
current_energy += recharge_speed * delta
|
||||
if current_energy >= max_energy:
|
||||
current_energy = max_energy
|
||||
energy_changed.emit(current_energy)
|
||||
recharging = false
|
||||
if stats.energy_type == Data.EnergyType.CONTINUOUS:
|
||||
energy_recharged.emit(recharge_speed * delta, stats.energy_type)
|
||||
if stats.energy_type == Data.EnergyType.DISCRETE and int(current_energy) > prev_energy_int:
|
||||
energy_recharged.emit(1, stats.energy_type)
|
||||
prev_energy_int = int(current_energy)
|
||||
#energy_changed.emit(current_energy)
|
||||
if time_since_firing < time_between_shots:
|
||||
time_since_firing += delta
|
||||
if trigger_held and stats.energy_type == Data.EnergyType.CONTINUOUS:
|
||||
current_energy -= delta
|
||||
energy_spent.emit(delta, stats.energy_type)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
func _physics_process(delta: float) -> void:
|
||||
if trigger_held and current_energy >= energy_cost and time_since_firing >= time_between_shots:
|
||||
if stats.energy_type == Data.EnergyType.DISCRETE:
|
||||
current_energy -= 1
|
||||
energy_spent.emit(1, stats.energy_type)
|
||||
time_since_firing -= time_between_shots
|
||||
current_energy -= energy_cost
|
||||
energy_changed.emit(current_energy)
|
||||
shoot()
|
||||
networked_shoot.rpc()
|
||||
|
||||
|
||||
func hold_trigger() -> void:
|
||||
trigger_held = true
|
||||
recharge_timer.stop()
|
||||
|
||||
|
||||
func release_trigger() -> void:
|
||||
|
1
Scripts/Weapons/weapon.gd.uid
Normal file
1
Scripts/Weapons/weapon.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://blh4s3v07ycwa
|
@ -6,10 +6,8 @@ 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 spawners: Array[EnemySpawner]
|
||||
@export var tower_path: Node
|
||||
var tower_base_scene: PackedScene = load("res://Scenes/TowerBase/tower_base.tscn")
|
||||
var tower_frame_scene: PackedScene = load("res://Scenes/tower_frame.tscn")
|
||||
@ -19,6 +17,11 @@ var tower_frames: Array = []
|
||||
var wall_id: int = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for spawner: EnemySpawner in spawners:
|
||||
spawner.astar = self
|
||||
|
||||
|
||||
func toggle_point(point_id: int, caller_id: int) -> void:
|
||||
networked_toggle_point.rpc(point_id, caller_id)
|
||||
|
||||
@ -210,15 +213,18 @@ func place_random_towers(tower_limit: int) -> void:
|
||||
|
||||
|
||||
func find_path() -> bool:
|
||||
var path: PackedVector3Array = astar.get_point_path(astar.get_point_count() - 2, astar.get_point_count() - 1)
|
||||
if !path.is_empty():
|
||||
var curve: Curve3D = Curve3D.new()
|
||||
for point: Vector3 in path:
|
||||
curve.add_point(point)
|
||||
spawner.path.curve = curve
|
||||
spawner.path.spawn_visualizer_points()
|
||||
return true
|
||||
return false
|
||||
for spawn: EnemySpawner in spawners:
|
||||
var path: PackedVector3Array = astar.get_point_path(spawn.astar_point_id, astar.get_point_count() - 1)
|
||||
if !path.is_empty():
|
||||
var curve: Curve3D = Curve3D.new()
|
||||
for point: Vector3 in path:
|
||||
curve.add_point(point)
|
||||
spawn.path.global_position = Vector3.ZERO
|
||||
spawn.path.curve = curve
|
||||
else:
|
||||
return false
|
||||
spawners[0].path.spawn_visualizer_points()
|
||||
return true
|
||||
|
||||
|
||||
func make_grid() -> void:
|
||||
@ -247,10 +253,12 @@ func make_grid() -> void:
|
||||
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: int in grid_size.y:
|
||||
astar.connect_points(int(astar.get_point_count() - 1), x)
|
||||
for spawn: EnemySpawner in spawners:
|
||||
non_build_locations.append(astar.get_point_count())
|
||||
spawn.astar_point_id = astar.get_point_count()
|
||||
astar.add_point(astar.get_point_count(), spawn.global_position)
|
||||
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: int in grid_size.y:
|
||||
|
1
Scripts/a_star_graph_3d.gd.uid
Normal file
1
Scripts/a_star_graph_3d.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://u404brdoaku
|
1
Scripts/alert_popup.gd.uid
Normal file
1
Scripts/alert_popup.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://4uwd40mavufi
|
1
Scripts/audio_options.gd.uid
Normal file
1
Scripts/audio_options.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c4ljvgrb81du6
|
1
Scripts/card_hand.gd.uid
Normal file
1
Scripts/card_hand.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://d6ejaumcenmg
|
1
Scripts/chatbox.gd.uid
Normal file
1
Scripts/chatbox.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dmdf7tbvc3bsg
|
1
Scripts/cinema_cam.gd.uid
Normal file
1
Scripts/cinema_cam.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://yk54owkf7pgj
|
1
Scripts/confirmation_popup.gd.uid
Normal file
1
Scripts/confirmation_popup.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bjt72v1wym5ie
|
16
Scripts/corpse.gd
Normal file
16
Scripts/corpse.gd
Normal file
@ -0,0 +1,16 @@
|
||||
class_name Corpse extends RigidBody3D
|
||||
|
||||
|
||||
func set_sprite(tex: Texture) -> void:
|
||||
$Sprite3D.texture = tex
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var tween: Tween = create_tween()
|
||||
tween.tween_interval(20.0)
|
||||
tween.tween_property($Sprite3D, "modulate", Color(1.0, 1.0, 1.0, 0.0), 4.0)
|
||||
tween.tween_callback(queue_free)
|
||||
|
||||
|
||||
func _on_body_entered(_body: Node) -> void:
|
||||
freeze = true
|
1
Scripts/corpse.gd.uid
Normal file
1
Scripts/corpse.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://mm665gsfr23a
|
1
Scripts/damage_particle.gd.uid
Normal file
1
Scripts/damage_particle.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://blt7umrgo3tfh
|
121
Scripts/data.gd
121
Scripts/data.gd
@ -4,16 +4,20 @@ var characters: Array[HeroClass]
|
||||
var cards: Array[Card]
|
||||
var enemies: Array[Enemy]
|
||||
var keymaps: Array[PlayerKeymap]
|
||||
var mods: Dictionary[String, String]
|
||||
var graphics: PlayerGraphicsSettings
|
||||
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 save_data: SaveData
|
||||
|
||||
const DEFAULT_SERVER_PORT: int = 58008
|
||||
|
||||
var wall_cost: int = 1
|
||||
var printer_cost: int = 15
|
||||
enum EnergyType {UNDEFINED = 0, DISCRETE = 1, CONTINUOUS = 2}
|
||||
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}
|
||||
@ -25,7 +29,80 @@ var rarity_weights: Dictionary = {
|
||||
"LEGENDARY" = 1
|
||||
}
|
||||
|
||||
|
||||
## Recursively searches a folder for any Card resources and loads them
|
||||
func load_cards(path: String) -> void:
|
||||
cards = []
|
||||
var dir: DirAccess = DirAccess.open(path)
|
||||
if dir:
|
||||
dir.list_dir_begin()
|
||||
var file_name: String = dir.get_next()
|
||||
while file_name != "":
|
||||
if dir.current_is_dir():
|
||||
load_cards(path + file_name)
|
||||
else:
|
||||
var card: Card = load(path + "/" + file_name)
|
||||
if card:
|
||||
cards.append(card)
|
||||
file_name = dir.get_next()
|
||||
|
||||
|
||||
func load_classes() -> void:
|
||||
characters = []
|
||||
var dir: DirAccess = DirAccess.open("res://Classes")
|
||||
if dir:
|
||||
dir.list_dir_begin()
|
||||
var folder_name: String = dir.get_next()
|
||||
while folder_name != "":
|
||||
if dir.current_is_dir():
|
||||
var dir2: DirAccess = DirAccess.open("res://Classes/" + folder_name)
|
||||
if dir2:
|
||||
dir2.list_dir_begin()
|
||||
var folder_name2: String = dir2.get_next()
|
||||
while folder_name2 != "":
|
||||
if folder_name2 == "class.tres":
|
||||
var hero_class: HeroClass = load("res://Classes/" + folder_name + "/" + folder_name2)
|
||||
characters.append(hero_class)
|
||||
folder_name2 = dir2.get_next()
|
||||
else:
|
||||
pass
|
||||
folder_name = dir.get_next()
|
||||
|
||||
|
||||
func load_mods(mod_list: Dictionary[String, bool]) -> void:
|
||||
for mod_name: String in mod_list:
|
||||
if mod_list[mod_name]:
|
||||
var success: bool = ProjectSettings.load_resource_pack(mods[mod_name])
|
||||
if success:
|
||||
print("Successfully loaded mod: " + mod_name + " at path: " + mods[mod_name])
|
||||
else:
|
||||
print("Failed to load mod: " + mod_name + " at path: " + mods[mod_name])
|
||||
load_classes()
|
||||
load_cards("res://Cards")
|
||||
|
||||
func _ready() -> void:
|
||||
var mod_dir: DirAccess = DirAccess.open("res://Mods")
|
||||
if mod_dir:
|
||||
mod_dir.list_dir_begin()
|
||||
var file_name: String = mod_dir.get_next()
|
||||
while file_name != "":
|
||||
if mod_dir.current_is_dir():
|
||||
var data_dir: DirAccess = DirAccess.open("res://Mods/" + file_name)
|
||||
if data_dir:
|
||||
data_dir.list_dir_begin()
|
||||
var data_name: String = data_dir.get_next()
|
||||
while data_name != "":
|
||||
if data_name.ends_with(".json"):
|
||||
var file: FileAccess = FileAccess.open("res://Mods/" + file_name + "/" + data_name, FileAccess.READ)
|
||||
var json_string: String = file.get_line()
|
||||
var json: JSON = JSON.new()
|
||||
var parse_result: Error = json.parse(json_string)
|
||||
if parse_result == OK:
|
||||
var dict: Dictionary = json.data
|
||||
mods[dict["display_name"]] = "res://Mods/" + file_name + "/" + dict["pck_path"]
|
||||
data_name = data_dir.get_next()
|
||||
file_name = mod_dir.get_next()
|
||||
|
||||
keymaps.append(preload("res://Resources/Keymaps/qwerty.tres"))
|
||||
keymaps.append(preload("res://Resources/Keymaps/azerty.tres"))
|
||||
keymaps.append(preload("res://Resources/Keymaps/dvorak.tres"))
|
||||
@ -41,37 +118,15 @@ func _ready() -> void:
|
||||
player_keymap = PlayerKeymap.load_profile_from_disk()
|
||||
player_keymap.apply()
|
||||
player_controller_keymap.append_input_map()
|
||||
save_stats = SaveStats.load_profile_from_disk()
|
||||
save_data = SaveData.load_profile_from_disk()
|
||||
|
||||
characters.append(preload("res://PCs/Mechanic/red.tres"))
|
||||
#characters.append(preload("res://PCs/Green/green.tres"))
|
||||
characters.append(preload("res://PCs/Mage/blue.tres"))
|
||||
load_classes()
|
||||
load_cards("res://Cards")
|
||||
|
||||
#Common
|
||||
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/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/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/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/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"))
|
||||
enemies.append(preload("res://Worlds/GreenPlanet/Enemies/dog_fast.tres"))
|
||||
enemies.append(preload("res://Worlds/GreenPlanet/Enemies/dog_heavy.tres"))
|
||||
enemies.append(preload("res://Worlds/GreenPlanet/Enemies/dog_boss.tres"))
|
||||
enemies.append(preload("res://Worlds/GreenPlanet/Enemies/airenemy.tres"))
|
||||
enemies.append(preload("res://Worlds/GreenPlanet/Enemies/airenemy2.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/dog.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/dog_fast.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/dog_heavy.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/dog_boss.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/airenemy.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/airenemy2.tres"))
|
||||
enemies.append(preload("res://Resources/Enemies/leapfrog.tres"))
|
||||
|
1
Scripts/data.gd.uid
Normal file
1
Scripts/data.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dod20lw3c8kqm
|
1
Scripts/edit_tool.gd.uid
Normal file
1
Scripts/edit_tool.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ckm02cx0ai624
|
5
Scripts/effect.gd
Normal file
5
Scripts/effect.gd
Normal file
@ -0,0 +1,5 @@
|
||||
class_name Effect extends Resource
|
||||
|
||||
|
||||
@export var damage: int = 0
|
||||
@export var status_effects: Array[StatusEffect] = []
|
1
Scripts/effect.gd.uid
Normal file
1
Scripts/effect.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://djp7tepdsda8w
|
1
Scripts/eight_direction_sprite.gd.uid
Normal file
1
Scripts/eight_direction_sprite.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://by8jxwui7chwl
|
5
Scripts/enemy_card.gd
Normal file
5
Scripts/enemy_card.gd
Normal file
@ -0,0 +1,5 @@
|
||||
class_name EnemyCard extends RefCounted
|
||||
|
||||
|
||||
var enemy: Enemy = null
|
||||
var rarity: Data.Rarity = Data.Rarity.COMMON
|
1
Scripts/enemy_card.gd.uid
Normal file
1
Scripts/enemy_card.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://brf6kradnuce8
|
1
Scripts/enemy_goal.gd.uid
Normal file
1
Scripts/enemy_goal.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cxwtuxytavfu5
|
@ -3,16 +3,20 @@ class_name EnemySpawner extends Node3D
|
||||
signal enemy_spawned()
|
||||
|
||||
@export var land_enemy_scene: PackedScene
|
||||
@export var leap_enemy_scene: PackedScene
|
||||
@export var air_enemy_scene: PackedScene
|
||||
@export var own_id: int = 0
|
||||
@export var path: VisualizedPath
|
||||
var astar: AStarGraph3D
|
||||
@export var own_id: int = 0
|
||||
@export var type: Data.EnemyType
|
||||
@export var dest: Node3D
|
||||
@export var enemy_path: Node
|
||||
|
||||
var astar_point_id: int = 0
|
||||
var enemy_died_callback: Callable
|
||||
var enemy_reached_goal_callback: Callable
|
||||
var current_wave: Dictionary = {}
|
||||
var current_wave: Array[EnemyCard]
|
||||
var enemy_types_to_spawn: Dictionary = {}
|
||||
var enemy_spawn_timers: Dictionary = {}
|
||||
var enemies_spawned: Dictionary = {}
|
||||
var enemies_to_spawn: int = 0
|
||||
@ -26,7 +30,7 @@ func _process(delta: float) -> void:
|
||||
return
|
||||
|
||||
for x: Enemy in enemy_spawn_timers:
|
||||
if enemies_spawned[x] == current_wave[x]:
|
||||
if enemies_spawned[x] == enemy_types_to_spawn[x]:
|
||||
continue
|
||||
|
||||
var enemy_stats: Enemy = x
|
||||
@ -35,12 +39,12 @@ func _process(delta: float) -> void:
|
||||
if enemy_spawn_timers[x] >= enemy_stats.spawn_cooldown:
|
||||
if is_multiplayer_authority():
|
||||
if type == Data.EnemyType.LAND:
|
||||
networked_spawn_land_enemy.rpc(var_to_str(enemy_stats), own_id, enemy_id)
|
||||
networked_spawn_land_enemy.rpc(Data.enemies.find(enemy_stats), own_id, enemy_id)
|
||||
if type == Data.EnemyType.AIR:
|
||||
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)
|
||||
networked_spawn_air_enemy.rpc(Data.enemies.find(enemy_stats), random_pos, own_id, enemy_id)
|
||||
|
||||
enemy_spawn_timers[x] -= enemy_stats.spawn_cooldown
|
||||
enemy_spawned.emit()
|
||||
@ -49,43 +53,64 @@ func _process(delta: float) -> void:
|
||||
enemies_to_spawn -= 1
|
||||
|
||||
|
||||
#TODO: not sure enemies need all this info over the network
|
||||
#TODO: generalize enemy scene selection, i.e. store the scenes in the enemy
|
||||
#card like towers do
|
||||
@rpc("reliable", "call_local")
|
||||
func networked_spawn_land_enemy(enemy_stats: String, id1: int, id2: int) -> void:
|
||||
var enemy: EnemyController = land_enemy_scene.instantiate() as EnemyController
|
||||
func networked_spawn_land_enemy(enemy_stats: int, id1: int, id2: int) -> void:
|
||||
var enemy: EnemyController
|
||||
if enemy_stats != 6:
|
||||
enemy = land_enemy_scene.instantiate() as EnemyController
|
||||
else:
|
||||
enemy = leap_enemy_scene.instantiate() as EnemyController
|
||||
enemy.name = str(id1) + str(id2)
|
||||
enemy.stats = str_to_var(enemy_stats)
|
||||
enemy.stats = Data.enemies[enemy_stats]
|
||||
enemy.died.connect(enemy_died_callback)
|
||||
enemy.reached_goal.connect(enemy_reached_goal_callback)
|
||||
enemy.movement_controller.path = path.curve
|
||||
enemy.movement_controller.astar = astar
|
||||
enemy.position = global_position
|
||||
enemy_path.add_child(enemy)
|
||||
|
||||
|
||||
@rpc("reliable", "call_local")
|
||||
func networked_spawn_air_enemy(enemy_stats: String, pos: Vector3, id1: int, id2: int) -> void:
|
||||
func networked_spawn_air_enemy(enemy_stats: int, 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.stats = Data.enemies[enemy_stats]
|
||||
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: Dictionary) -> void:
|
||||
var relevant_enemies: Dictionary = {}
|
||||
var wave: Dictionary = {}
|
||||
for index: int in value:
|
||||
wave[Data.enemies[index]] = value[index]
|
||||
for x: Enemy in wave:
|
||||
if x.target_type == type:
|
||||
relevant_enemies[x] = wave[x]
|
||||
current_wave = relevant_enemies
|
||||
func spawn_wave() -> void:
|
||||
enemies_to_spawn = 0
|
||||
enemy_spawn_timers = {}
|
||||
for x: Enemy in current_wave:
|
||||
enemies_to_spawn += current_wave[x]
|
||||
enemy_spawn_timers[x] = 0.0
|
||||
enemies_spawned[x] = 0
|
||||
for card: EnemyCard in current_wave:
|
||||
match(card.rarity):
|
||||
Data.Rarity.COMMON:
|
||||
enemy_types_to_spawn[card.enemy] += card.enemy.common_group
|
||||
enemies_to_spawn += card.enemy.common_group
|
||||
Data.Rarity.UNCOMMON:
|
||||
enemy_types_to_spawn[card.enemy] += card.enemy.uncommon_group
|
||||
enemies_to_spawn += card.enemy.uncommon_group
|
||||
Data.Rarity.RARE:
|
||||
enemy_types_to_spawn[card.enemy] += card.enemy.rare_group
|
||||
enemies_to_spawn += card.enemy.rare_group
|
||||
Data.Rarity.EPIC:
|
||||
enemy_types_to_spawn[card.enemy] += card.enemy.epic_group
|
||||
enemies_to_spawn += card.enemy.epic_group
|
||||
Data.Rarity.LEGENDARY:
|
||||
enemy_types_to_spawn[card.enemy] += card.enemy.legendary_group
|
||||
enemies_to_spawn += card.enemy.legendary_group
|
||||
enemy_spawn_timers[card.enemy] = 0.0
|
||||
enemies_spawned[card.enemy] = 0
|
||||
current_wave = []
|
||||
done_spawning = false
|
||||
|
||||
|
||||
func add_card(new_card: EnemyCard) -> void:
|
||||
current_wave.append(new_card)
|
||||
enemy_types_to_spawn[new_card.enemy] = 0
|
||||
|
1
Scripts/enemy_spawner.gd.uid
Normal file
1
Scripts/enemy_spawner.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dkuxg6ek5us4f
|
1
Scripts/float_and_spin.gd.uid
Normal file
1
Scripts/float_and_spin.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cl2mi4bnpatwk
|
@ -17,17 +17,16 @@ var singleplayer_lobby_scene_path: String = "res://Scenes/Menus/singleplayer_lob
|
||||
var game_end_scene: PackedScene = load("res://Scenes/Menus/GameEndScreen/game_end_screen.tscn")
|
||||
var connected_players_nodes: Dictionary = {}
|
||||
var game_active: bool = false
|
||||
var gamemode: GameMode = null
|
||||
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 starting_cash: int = 25
|
||||
var shop_chance: float = 0.0
|
||||
var stats: RoundStats
|
||||
var rng: FastNoiseLite
|
||||
@ -171,32 +170,41 @@ 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: EnemySpawner in level.enemy_spawns:
|
||||
spawn.spawn_wave(upcoming_wave)
|
||||
spawn.path.disable_visualization()
|
||||
spawn.spawn_wave()
|
||||
wave_started.emit(wave)
|
||||
|
||||
|
||||
func set_upcoming_wave() -> void:
|
||||
if is_multiplayer_authority():
|
||||
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))
|
||||
#var new_wave: Dictionary = WaveManager.generate_wave(spawn_power, level.enemy_pool)
|
||||
var new_wave: Wave = WaveManager.generate_wave(spawn_power, level.enemy_pool, level.enemy_spawns)
|
||||
temp_set_upcoming_wave(new_wave, floori(WaveManager.calculate_pot(wave + 1, connected_players_nodes.size()) / 20.0))
|
||||
#networked_set_upcoming_wave.rpc(new_wave, 6 + floori(spawn_power / 70.0))
|
||||
|
||||
|
||||
@rpc("reliable", "call_local")
|
||||
func networked_set_upcoming_wave(wave_dict: Dictionary, coins: int) -> void:
|
||||
upcoming_wave = wave_dict
|
||||
func temp_set_upcoming_wave(wave: Wave, coins: int) -> void:
|
||||
pot = coins
|
||||
for key: int in connected_players_nodes:
|
||||
connected_players_nodes[key].hud.set_upcoming_wave(upcoming_wave)
|
||||
connected_players_nodes[multiplayer.get_unique_id()].hud.show_wave_generation_anim(wave)
|
||||
connected_players_nodes[multiplayer.get_unique_id()].hud.set_upcoming_wave(wave.to_dict())
|
||||
|
||||
#TODO: You'll probably have to write a to_dict function for the new wave system
|
||||
#before any of this shit works in multiplayer
|
||||
#@rpc("reliable", "call_local")
|
||||
#func networked_set_upcoming_wave(wave_dict: Dictionary, coins: int) -> void:
|
||||
#upcoming_wave = wave_dict
|
||||
#pot = coins
|
||||
#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: bool) -> void:
|
||||
endless_mode = value
|
||||
if endless_mode:
|
||||
gamemode.endless = value
|
||||
if gamemode.endless:
|
||||
chatbox.append_message("SERVER", Color.TOMATO, "Endless mode enabled!")
|
||||
else:
|
||||
chatbox.append_message("SERVER", Color.TOMATO, "Endless mode disabled!")
|
||||
@ -215,7 +223,7 @@ func enemy_died(enemy: Enemy) -> void:
|
||||
return
|
||||
if enemies == 0:
|
||||
end_wave()
|
||||
if !endless_mode and wave >= wave_limit:
|
||||
if !gamemode.endless and wave >= wave_limit:
|
||||
end(true)
|
||||
|
||||
|
||||
@ -230,7 +238,7 @@ func damage_goal(enemy: Enemy, penalty: int) -> void:
|
||||
end(false)
|
||||
elif enemies == 0:
|
||||
end_wave()
|
||||
if !endless_mode and wave >= wave_limit:
|
||||
if !gamemode.endless and wave >= wave_limit:
|
||||
end(true)
|
||||
|
||||
|
||||
@ -238,7 +246,8 @@ 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].unready_self()
|
||||
level.a_star_graph_3d.visualized_path.enable_visualization()
|
||||
for spawn: EnemySpawner in level.enemy_spawns:
|
||||
spawn.path.enable_visualization()
|
||||
level.a_star_graph_3d.enable_non_path_tower_frames()
|
||||
if is_multiplayer_authority():
|
||||
if randf_in_range(23 * wave, 0.0, 1.0) <= shop_chance:
|
||||
@ -282,9 +291,9 @@ func setup() -> void:
|
||||
game_setup.emit()
|
||||
|
||||
|
||||
func start(rng_seed: int = randi()) -> void:
|
||||
func start() -> void:
|
||||
if is_multiplayer_authority():
|
||||
set_seed.rpc(rng_seed)
|
||||
set_seed.rpc(gamemode.rng_seed)
|
||||
else:
|
||||
await rng_seeded
|
||||
|
||||
@ -305,14 +314,15 @@ func start(rng_seed: int = randi()) -> void:
|
||||
game_active = true
|
||||
chatbox.append_message("SERVER", Color.TOMATO, "Started with seed: " + str(rng.seed))
|
||||
game_started.emit()
|
||||
#print("started game with seed: " + str(gamemode.rng_seed))
|
||||
|
||||
|
||||
func end(outcome: bool) -> void:
|
||||
if game_active == false:
|
||||
return
|
||||
game_active = false
|
||||
Data.save_stats.add_game_outcome(outcome)
|
||||
Data.save_stats.save_profile_to_disk()
|
||||
Data.save_data.add_game_outcome(outcome)
|
||||
Data.save_data.save_to_disc()
|
||||
var menu: GameEndScreen = game_end_scene.instantiate() as GameEndScreen
|
||||
match outcome:
|
||||
false:
|
||||
|
1
Scripts/game.gd.uid
Normal file
1
Scripts/game.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ocgd16bqo81s
|
7
Scripts/game_mode.gd
Normal file
7
Scripts/game_mode.gd
Normal file
@ -0,0 +1,7 @@
|
||||
class_name GameMode extends RefCounted
|
||||
|
||||
var multiplayer: bool = false
|
||||
var seeded: bool = false
|
||||
var rng_seed: int = 0
|
||||
var endless: bool = false
|
||||
var daily: bool = false
|
1
Scripts/game_mode.gd.uid
Normal file
1
Scripts/game_mode.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cbqxwt57eglct
|
1
Scripts/gameplay_options.gd.uid
Normal file
1
Scripts/gameplay_options.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dtrjph756oq1f
|
1
Scripts/graphics_options.gd.uid
Normal file
1
Scripts/graphics_options.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bpb5c5r1yi8um
|
@ -8,6 +8,7 @@ signal health_changed(health: int)
|
||||
|
||||
var current_health: int
|
||||
|
||||
|
||||
func take_damage(damage: int) -> void:
|
||||
current_health -= damage
|
||||
health_changed.emit(current_health)
|
||||
|
1
Scripts/health.gd.uid
Normal file
1
Scripts/health.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bamhci3kawuyt
|
1
Scripts/health_bar.gd.uid
Normal file
1
Scripts/health_bar.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bf06es50d0flv
|
@ -1,7 +1,7 @@
|
||||
class_name Hitbox extends CollisionShape3D
|
||||
|
||||
signal took_damage(amount: float)
|
||||
signal took_damage(amount: int)
|
||||
|
||||
|
||||
func damage(amount: float) -> void:
|
||||
func damage(amount: int) -> void:
|
||||
took_damage.emit(amount)
|
||||
|
1
Scripts/hitbox.gd.uid
Normal file
1
Scripts/hitbox.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cummt2be3r1gq
|
180
Scripts/hud.gd
180
Scripts/hud.gd
@ -1,180 +0,0 @@
|
||||
class_name HUD extends CanvasLayer
|
||||
|
||||
var last_lives_count: int = 120
|
||||
@export var player: Hero
|
||||
@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: RichTextLabel
|
||||
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: RichTextLabel
|
||||
@export var place_icon: TextureRect
|
||||
@export var swap_icon: TextureRect
|
||||
@export var place_text: RichTextLabel
|
||||
@export var swap_text: RichTextLabel
|
||||
|
||||
var audio_guard: bool = false
|
||||
|
||||
|
||||
func set_energy_visible(value: bool) -> void:
|
||||
weapon_energy_bar.set_visible(value)
|
||||
|
||||
|
||||
func set_offhand_energy_visible(value: bool) -> void:
|
||||
offhand_energy_bar.set_visible(value)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
fps_label.text = "FPS: " + str(Engine.get_frames_per_second())
|
||||
wave_start_label.text = parse_action_tag("[center]Press #Ready# to start wave")
|
||||
place_text.text = parse_action_tag("[center]#Equip In Gauntlet#")
|
||||
swap_text.text = parse_action_tag("[center]#Secondary Fire#")
|
||||
|
||||
|
||||
func grow_wave_start_label() -> void:
|
||||
tween_label(300.0)
|
||||
|
||||
|
||||
func shrink_wave_start_label() -> void:
|
||||
tween_label(0.0)
|
||||
|
||||
|
||||
func tween_label(x: float) -> void:
|
||||
var tween: Tween = create_tween()
|
||||
tween.set_ease(Tween.EASE_IN_OUT)
|
||||
tween.set_trans(Tween.TRANS_QUAD)
|
||||
if x > 0.0:
|
||||
tween.tween_callback(wave_start_label.set_visible.bind(true))
|
||||
tween.parallel().tween_property(wave_start_label, "offset_left", -x, 0.6)
|
||||
tween.parallel().tween_property(wave_start_label, "offset_right", x, 0.6)
|
||||
if x <= 0.0:
|
||||
tween.tween_callback(wave_start_label.set_visible.bind(false))
|
||||
|
||||
|
||||
func set_hover_text(text: String) -> void:
|
||||
hover_text.text = parse_action_tag(text)
|
||||
hover_text.set_visible(true)
|
||||
|
||||
|
||||
func unset_hover_text() -> void:
|
||||
hover_text.set_visible(false)
|
||||
|
||||
|
||||
func set_wave_count(value: int) -> void:
|
||||
wave_count.text = str(value)
|
||||
|
||||
|
||||
func set_lives_count(value: int) -> void:
|
||||
lives_count.text = str(value)
|
||||
for x: int in last_lives_count - value:
|
||||
$LivesBar.take_life()
|
||||
last_lives_count = value
|
||||
|
||||
|
||||
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: Dictionary) -> void:
|
||||
var frame_count: int = 0
|
||||
enemy_names = []
|
||||
var wave: Dictionary = {}
|
||||
for index: int in value:
|
||||
wave[Data.enemies[index]] = value[index]
|
||||
for x: int in enemy_sprites.size():
|
||||
enemy_sprites[x].set_visible(false)
|
||||
enemy_counts[x].set_visible(false)
|
||||
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])
|
||||
enemy_sprites[frame_count].set_visible(true)
|
||||
enemy_counts[frame_count].set_visible(true)
|
||||
frame_count += 1
|
||||
|
||||
|
||||
func set_currency_count(value: int) -> void:
|
||||
currency_count.text = str(value)
|
||||
|
||||
|
||||
func set_crosshair_visible(value: bool) -> void:
|
||||
crosshair.set_visible(value)
|
||||
|
||||
|
||||
func set_weapon_energy(value: int) -> void:
|
||||
weapon_energy_bar.value = value
|
||||
if player.editing_mode:
|
||||
audio_guard = true
|
||||
if value == 0 and !audio_guard:
|
||||
player.zeropower_audio.play()
|
||||
audio_guard = true
|
||||
if value == 100 and !audio_guard:
|
||||
player.fullpower_audio.play()
|
||||
audio_guard = true
|
||||
if value > 0 and value < 100:
|
||||
audio_guard = false
|
||||
|
||||
|
||||
func set_offhand_energy(value: int) -> void:
|
||||
offhand_energy_bar.value = value
|
||||
|
||||
|
||||
func maximise_minimap(anchor: Node3D) -> void:
|
||||
minimap_cam.anchor = anchor
|
||||
minimap.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
minimap.offset_bottom = -40
|
||||
minimap.offset_top = 40
|
||||
minimap.offset_left = 40
|
||||
minimap.offset_right = -40
|
||||
minimap_viewport.size = Vector2(1840, 1000)
|
||||
minimap_cam.size = 30
|
||||
minimap_outline.set_visible(false)
|
||||
currency_count.set_visible(false)
|
||||
|
||||
|
||||
func minimize_minimap(anchor: Node3D) -> void:
|
||||
minimap_cam.anchor = anchor
|
||||
minimap.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT)
|
||||
minimap.offset_right = -40
|
||||
minimap.offset_top = 40
|
||||
minimap.offset_left = -256
|
||||
minimap.offset_bottom = 256
|
||||
minimap_viewport.size = Vector2(256, 256)
|
||||
minimap_cam.size = 15
|
||||
minimap_outline.set_visible(true)
|
||||
currency_count.set_visible(true)
|
||||
|
||||
|
||||
func pickup(card: Card) -> void:
|
||||
var notif: PickupNotification = pickup_notif_scene.instantiate()
|
||||
notif.set_card(card)
|
||||
$VBoxContainer.add_child(notif)
|
||||
|
||||
|
||||
func parse_action_tag(text: String) -> String:
|
||||
var string_array: PackedStringArray = text.split("#")
|
||||
if string_array.size() > 1:
|
||||
var event: InputEvent = InputMap.action_get_events(string_array[1])[0]
|
||||
if event is InputEventKey:
|
||||
string_array[1] = "[img=top,50]%s[/img]" % KeyIconMap.keys[str(event.keycode)]
|
||||
if event is InputEventMouseButton:
|
||||
string_array[1] = "[img=top,50]%s[/img]" % KeyIconMap.mouse_buttons[str(event.button_index)]
|
||||
text = "".join(string_array)
|
||||
return text
|
@ -4,8 +4,16 @@ signal button_interacted(value: int, callback: Hero)
|
||||
|
||||
@export var button_press_value: int = 0
|
||||
@export var press_cost: int = 0
|
||||
@export var hover_text: String = "#Interact# to [do thing]"
|
||||
@export var hover_text: String = "[center]#Interact# to [do thing]"
|
||||
|
||||
|
||||
func press(callback_player: Hero) -> void:
|
||||
button_interacted.emit(button_press_value, callback_player)
|
||||
|
||||
|
||||
func enable_hover_effect() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func disable_hover_effect() -> void:
|
||||
pass
|
||||
|
1
Scripts/interact_button.gd.uid
Normal file
1
Scripts/interact_button.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dkfswql8ui0bt
|
1
Scripts/inventory.gd.uid
Normal file
1
Scripts/inventory.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://do24iuot0j7d7
|
1
Scripts/item_card.gd.uid
Normal file
1
Scripts/item_card.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://1l7xhsd5prk1
|
1
Scripts/item_container.gd.uid
Normal file
1
Scripts/item_container.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c0pqprebrhakh
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user