Files
Decked-Out-Defense/PCs/hero.gd

592 lines
19 KiB
GDScript

class_name Hero
extends CharacterBody3D
signal ready_state_changed(state: bool)
@export var hero_class: HeroClass
@export var camera: Camera3D
@export var gun_camera: Camera3D
@export var left_hand_sprite: Sprite3D
@export var left_hand: Node3D
@export var right_hand: Node3D
#@export var right_hand_animator: AnimationPlayer
@export var edit_tool: PathEditTool
@export var gauntlet_sprite: Sprite3D
@export var sprite: EightDirectionSprite3D
#@export var hand_sprite: Sprite2D
@export var interaction_raycast: RayCast3D
@export var draw_pile: Inventory
@export var hand: Inventory
@export var discard_pile: Inventory
@export var gauntlet_cards: Array[CardInHand]
@export var pause_menu_scene: PackedScene
@export var hud: HUD
@export var movement: PlayerMovement
@export var sprint_zoom_speed: float = 0.2
@export var player_name_tag: Label
@export var weapon_swap_timer: Timer
@export var card3d_scene: PackedScene
@export var card_select_scene: PackedScene
@export_subgroup("Audio")
@export var ears: AudioListener3D
@export var place_card_audio: AudioStreamPlayer
@export var swap_card_audio: AudioStreamPlayer
@export var ready_audio: AudioStreamPlayer
@export var unready_audio: AudioStreamPlayer
@export var fullpower_audio: AudioStreamPlayer
@export var zeropower_audio: AudioStreamPlayer
@export var swap_off_audio: AudioStreamPlayer
@export var swap_on_audio: AudioStreamPlayer
var building_mode: bool = true
var selection_boxes: Array[CardSelectionBox] = []
var unique_cards: Array[Card] = []
var hand_card_scene: PackedScene = preload("res://Scenes/UI/card_hand.tscn")
var card_sprites: Array[CardInHand]
var game_manager: GameManager
var hovering_item: InteractButton = null
var weapons_spawn_count: int = 0 #Used to prevent node name collisions for multiplayer
var hand_selected_index: int = 0
var equipped_weapon: int = 0
var weapons: Array[Weapon] = [null, null]
var cards: Array[Card] = [null, null]
var weapons_active: bool = false
var paused: bool = false
var editing_mode: bool = true
var profile: PlayerProfile
var ready_state: bool = false :
set(value):
ready_state = value
ready_state_changed.emit(value)
var currency: int = 0 :
set(value):
currency = value
hud.set_currency_count(value)
get:
return currency
var energy: int = 0 :
set(value):
energy = value
hud.set_energy_amount(value)
get:
return energy
var selected_card: Card :
set(_value):
pass
get():
return unique_cards[hand_selected_index]
func set_zoom_factor(value: float) -> void:
movement.zoom_factor = value
func _ready() -> void:
if is_multiplayer_authority():
#right_hand_animator.play("weapon_sway")
#right_hand_animator.speed_scale = 0
ears.make_current()
camera.make_current()
sprite.queue_free()
hand.max_size = 5
#hand_sprite.texture = hero_class.hand_texture
player_name_tag.queue_free()
for card: Card in hero_class.deck:
draw_pile.add(card)
else:
camera.set_visible(false)
gun_camera.set_visible(false)
hud.set_visible(false)
if weapons[equipped_weapon] != null:
weapons[equipped_weapon].set_raycast_origin(camera)
sprite.texture.atlas = hero_class.texture
check_left_hand_valid()
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _physics_process(_delta: float) -> void:
if !is_multiplayer_authority() or paused:
return
#if movement.input_vector == Vector2.ZERO:
#right_hand_animator.speed_scale = 0
#elif movement.sprinting:
#right_hand_animator.speed_scale = 1
#else:
#right_hand_animator.speed_scale = 0.6
func _process(delta: float) -> void:
if !is_multiplayer_authority() or paused:
return
if !movement.sprinting:
movement.zoom_factor += sprint_zoom_speed * 2.0 * delta
if movement.zoom_factor > 1.0:
movement.zoom_factor = 1.0
if editing_mode:
if interaction_raycast.is_colliding() and interaction_raycast.get_collider() is InteractButton:
hud.set_hover_text(interaction_raycast.get_collider().hover_text)
if !hovering_item or hovering_item != interaction_raycast.get_collider():
if hovering_item:
hovering_item.disable_hover_effect()
hovering_item = interaction_raycast.get_collider()
hovering_item.enable_hover_effect()
else:
hud.unset_hover_text()
if hovering_item:
hovering_item.disable_hover_effect()
hovering_item = null
if Input.is_action_just_pressed("Interact"):
edit_tool.interact()
if interaction_raycast.get_collider() is InteractButton:
var button: InteractButton = interaction_raycast.get_collider() as InteractButton
button.press(self)
if interaction_raycast.get_collider() is ItemCard:
add_card(interaction_raycast.get_collider().pick_up())
if building_mode:
if Input.is_action_just_pressed("Primary Fire"):
edit_tool.interact_key_held = true
if Input.is_action_just_released("Primary Fire"):
edit_tool.interact_key_held = false
if Input.is_action_just_pressed("Swap Weapons"):
edit_tool.interact_key_held = false
building_mode = false
$FirstPersonViewport/Head2/LeftHand.visible = true
$HUD/selection_boxes.visible = true
$HUD/PlaceIcon.visible = true
$HUD/SwapIcon.visible = true
else:
if Input.is_action_just_pressed("Primary Fire"):
equip_weapon(0)
if Input.is_action_just_pressed("Secondary Fire"):
equip_weapon(1)
if Input.is_action_just_pressed("Select Next Card") and hand.size > 1:
increment_selected()
swap_card_audio.play()
if Input.is_action_just_pressed("Select Previous Card") and hand.size > 1:
decrement_selected()
swap_card_audio.play()
if Input.is_action_just_pressed("Select 1st Card"):
if unique_cards.size() >= 1:
hand_selected_index = 0
swap_card_audio.play()
update_selected_box()
if Input.is_action_just_pressed("Select 2nd Card"):
if unique_cards.size() >= 2:
hand_selected_index = 1
swap_card_audio.play()
update_selected_box()
if Input.is_action_just_pressed("Select 3rd Card"):
if unique_cards.size() >= 3:
hand_selected_index = 2
swap_card_audio.play()
update_selected_box()
if Input.is_action_just_pressed("Select 4th Card"):
if unique_cards.size() >= 4:
hand_selected_index = 3
swap_card_audio.play()
update_selected_box()
if Input.is_action_just_pressed("Select 5th Card"):
if unique_cards.size() >= 5:
hand_selected_index = 4
swap_card_audio.play()
update_selected_box()
if Input.is_action_just_pressed("Swap Weapons"):
building_mode = true
$FirstPersonViewport/Head2/LeftHand.visible = false
$HUD/selection_boxes.visible = false
$HUD/PlaceIcon.visible = false
$HUD/SwapIcon.visible = false
if weapons[equipped_weapon] != null:
weapons[equipped_weapon].release_trigger()
weapons[equipped_weapon].release_second_trigger()
else:
if weapons[equipped_weapon] and weapons_active:
if Input.is_action_just_pressed("Primary Fire"):
weapons[equipped_weapon].hold_trigger()
if Input.is_action_just_released("Primary Fire"):
weapons[equipped_weapon].release_trigger()
if Input.is_action_pressed("Secondary Fire"):
weapons[equipped_weapon].hold_second_trigger()
if Input.is_action_just_released("Secondary Fire"):
weapons[equipped_weapon].release_second_trigger()
if Input.is_action_pressed("Primary Fire"):
movement.can_sprint = false
if Input.is_action_pressed("Secondary Fire"):
movement.can_sprint = false
if Input.is_action_just_pressed("Equip Primary Weapon"):
if equipped_weapon == 1 and weapons[0]:
swap_weapons()
if Input.is_action_just_pressed("Equip Secondary Weapon"):
if equipped_weapon == 0 and weapons[1]:
swap_weapons()
if Input.is_action_just_pressed("Swap Weapons"):
if weapons[0] and weapons[1]:
swap_weapons()
if movement.sprinting:
movement.zoom_factor -= sprint_zoom_speed * delta
if movement.zoom_factor <= 1.0 - movement.sprint_zoom_factor:
movement.zoom_factor = 1.0 - movement.sprint_zoom_factor
camera.fov = Data.graphics.hfov * (1.0 / movement.zoom_factor)
if Input.is_action_just_pressed("View Map"):
hud.maximise_minimap()
#Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
if Input.is_action_just_released("View Map"):
hud.minimize_minimap()
#Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
check_left_hand_valid()
func increment_selected() -> void:
hand_selected_index += 1
if hand_selected_index >= unique_cards.size():
hand_selected_index = 0
update_selected_box()
func decrement_selected() -> void:
if unique_cards.size() == 0:
hand_selected_index = 0
return
hand_selected_index -= 1
if hand_selected_index < 0:
hand_selected_index = unique_cards.size() - 1
update_selected_box()
func _unhandled_input(event: InputEvent) -> void:
if !is_multiplayer_authority() or paused:
return
if editing_mode and event.is_action_pressed("Ready"):
if ready_state:
unready_self()
else:
ready_self()
if event.is_action_pressed("Pause"):
var menu: PauseMenu = pause_menu_scene.instantiate() as PauseMenu
pause()
menu.game_manager = game_manager
menu.quit_to_desktop_pressed.connect(game_manager.quit_to_desktop)
menu.quit_to_main_menu_pressed.connect(game_manager.scene_switch_main_menu)
menu.closed.connect(unpause)
hud.add_child(menu)
func ready_self() -> void:
edit_tool.interact_key_held = false
if !ready_state:
ready_state = true
hud.place_icon.set_visible(false)
hud.swap_icon.set_visible(false)
hud.shrink_wave_start_label()
ready_audio.play()
networked_set_ready_state.rpc(ready_state)
func unready_self() -> void:
if ready_state:
ready_state = false
hud.grow_wave_start_label()
unready_audio.play()
networked_set_ready_state(ready_state)
func add_card(new_card: Card) -> void:
hand.append(new_card)
hud.pickup(new_card)
place_card_audio.play()
func unpause() -> void:
paused = false
movement.paused = false
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func pause() -> void:
paused = true
movement.paused = true
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
func enter_editing_mode(value: int) -> void:
gauntlet_sprite.visible = true
weapons_active = false
hud.set_wave_count(value + 1)
hud.set_energy_visible(false)
hud.grow_wave_start_label()
$HUD/selection_boxes.visible = true
$HUD/EnergyLabel.visible = true
$HUD/weapon_duration.visible = true
$HUD/weapon_duration2.visible = true
editing_mode = true
edit_tool.enabled = true
left_hand.visible = true
if weapons[equipped_weapon]:
weapons[equipped_weapon].release_trigger()
weapons[equipped_weapon].visible = false
func exit_editing_mode(value: int) -> void:
gauntlet_sprite.visible = false
$HUD/selection_boxes.visible = false
$HUD/EnergyLabel.visible = false
$HUD/weapon_duration.visible = false
$HUD/weapon_duration2.visible = false
weapons_active = false
hud.set_wave_count(value)
var offhand_weapon: Weapon = weapons[0] if equipped_weapon == 1 else weapons[1]
if offhand_weapon:
offhand_weapon.current_energy = offhand_weapon.max_energy
if (!weapons[equipped_weapon] and offhand_weapon) or (weapons[0] and equipped_weapon == 1):
swap_weapons()
if weapons[equipped_weapon]:
hud.set_energy_visible(true)
weapons[equipped_weapon].current_energy = weapons[equipped_weapon].max_energy
#this had to be commented out coz the new energy bar thinks "energy changed" is "energy used"
#weapons[equipped_weapon].energy_changed.emit(weapons[equipped_weapon].current_energy)
edit_tool.enabled = false
edit_tool.delete_tower_preview()
left_hand.visible = false
hud.unset_hover_text()
editing_mode = false
weapon_swap_timer.start()
func check_left_hand_valid() -> void:
if !editing_mode:
return
if hand.size == 0:
left_hand_sprite.visible = false
else:
left_hand_sprite.visible = true
update_selected_box()
func check_removal() -> void:
var index: int = -1
for card: Card in unique_cards:
if !hand.contents.has(card):
index = unique_cards.find(card)
if index >= 0:
unique_cards.remove_at(index)
selection_boxes[index].queue_free()
selection_boxes.remove_at(index)
for i: int in selection_boxes.size():
var card: Card = unique_cards[i]
selection_boxes[i].set_card(card)
selection_boxes[i].set_key(i)
if hand_selected_index == index:
decrement_selected()
update_selected_box()
func iterate_duration() -> void:
for slot: int in weapons.size():
if weapons[slot] == null:
continue
weapons[slot].duration -= 1
if slot == 0:
hud.primary_duration.text = "primary weapon rounds left = " + str(weapons[slot].duration)
elif slot == 1:
hud.secondary_duration.text = "secondary weapon rounds left = " + str(weapons[slot].duration)
if weapons[slot].duration <= 0:
unequip_weapon(slot)
func draw_to_hand_size() -> void:
while hand.size < hand.max_size:
if draw_pile.size == 0 and discard_pile.size == 0:
return
if draw_pile.size > 0:
var card: Card = draw_pile.remove_at(0)
hand.add(card)
var display: Card3D = card3d_scene.instantiate()
display.set_card(card)
display.position = Vector3(0.01 * hand.size, 0.0, -0.001 * hand.size)
display.rotation_degrees = Vector3(0.0, 0.0, -10.0 * hand.size)
$FirstPersonViewport/Head2/LeftHand/Cards.add_child(display)
#var tween: Tween = create_tween()
#tween.set_ease(Tween.EASE_OUT)
#tween.set_trans(Tween.TRANS_CUBIC)
#tween.tween_property(display, "position", Vector2(200.0 * hand.size, 80.0), 0.5)
else:
for x: int in discard_pile.size:
draw_pile.add(discard_pile.remove_at(0))
draw_pile.shuffle()
unique_cards = []
selection_boxes = []
for card: Card in hand.contents:
if !unique_cards.has(card):
unique_cards.append(card)
for i: int in $HUD/selection_boxes.get_child_count():
$HUD/selection_boxes.get_child(i).queue_free()
for i: int in unique_cards.size():
var card: Card = unique_cards[i]
var box: CardSelectionBox = card_select_scene.instantiate()
box.set_card(card)
box.set_key(i)
selection_boxes.append(box)
$HUD/selection_boxes.add_child(box)
hand_selected_index = 0
update_selected_box()
func update_selected_box() -> void:
for box: CardSelectionBox in selection_boxes:
box.deselect()
selection_boxes[hand_selected_index].select()
func equip_weapon(slot: int = 0) -> void:
var energy_cost: int = int(hand.item_at(hand_selected_index).rarity) + 1
energy_cost *= 2
if energy < energy_cost:
return
if weapons[slot] != null:
unequip_weapon(slot)
if hand.size > 0:
energy -= energy_cost
place_card_audio.play()
cards[slot] = hand.remove_at(hand.contents.find(selected_card))
#card_sprites[hand_selected_index].queue_free()
#card_sprites.remove_at(hand_selected_index)
discard_pile.add(cards[slot])
#TODO: Alternate thing to do with the hand i guess
#if !inventory.contents.has(cards[slot]):
#decrement_selected()
weapons[slot] = cards[slot].weapon_scene.instantiate()
weapons[slot].name = str(weapons_spawn_count)
weapons[slot].duration = cards[slot].duration
networked_equip_weapon.rpc(Data.cards.find(cards[slot]), 0, weapons_spawn_count)
weapons_spawn_count += 1
weapons[slot].set_multiplayer_authority(multiplayer.get_unique_id())
gauntlet_cards[slot].set_card(cards[slot])
if slot == 0:
hud.primary_duration.text = "primary weapon rounds left = " + str(weapons[slot].duration)
elif slot == 1:
hud.secondary_duration.text = "secondary weapon rounds left = " + str(weapons[slot].duration)
if slot == 0:
hud.place_icon.visible = false
else:
hud.swap_icon.visible = false
gauntlet_cards[slot].view_weapon()
gauntlet_cards[slot].visible = true
weapons[slot].set_hero(self)
weapons[slot].visible = false
right_hand.add_child(weapons[slot])
check_removal()
check_left_hand_valid()
if slot == 0:
weapons[slot].energy_spent.connect(hud.new_energy_bar.use_energy)
weapons[slot].energy_recharged.connect(hud.new_energy_bar.gain_energy)
hud.new_energy_bar.max_energy = weapons[slot].max_energy
if weapons[slot].stats.energy_type == Data.EnergyType.CONTINUOUS:
hud.new_energy_bar.enable_progress_bar()
if weapons[slot].stats.energy_type == Data.EnergyType.DISCRETE:
hud.new_energy_bar.create_discrete_icons(weapons[slot].max_energy)
else:
weapons[slot].energy_recharged.connect(hud.new_energy_bar.gain_secondary_energy)
hud.new_energy_bar.secondary_max_energy = weapons[slot].max_energy
hud.new_energy_bar.secondary_energy = weapons[slot].current_energy
func stow_weapon(slot: int = 0) -> void:
weapons[slot].release_trigger()
weapons[slot].release_second_trigger()
weapons[slot].visible = false
weapons[slot].energy_spent.disconnect(hud.new_energy_bar.use_energy)
weapons[slot].energy_recharged.disconnect(hud.new_energy_bar.gain_energy)
weapons[slot].energy_recharged.connect(hud.new_energy_bar.gain_secondary_energy)
hud.new_energy_bar.secondary_max_energy = weapons[slot].max_energy
hud.new_energy_bar.secondary_energy = weapons[slot].current_energy
func show_weapon(slot: int = 0) -> void:
weapons[slot].release_trigger()
weapons[slot].release_second_trigger()
weapons[slot].energy_recharged.disconnect(hud.new_energy_bar.gain_secondary_energy)
weapons[slot].energy_spent.connect(hud.new_energy_bar.use_energy)
weapons[slot].energy_recharged.connect(hud.new_energy_bar.gain_energy)
hud.set_weapon_energy(weapons[slot].current_energy, weapons[slot].stats.energy_type)
hud.new_energy_bar.max_energy = weapons[slot].max_energy
if weapons[slot].stats.energy_type == Data.EnergyType.CONTINUOUS:
hud.new_energy_bar.enable_progress_bar()
if weapons[slot].stats.energy_type == Data.EnergyType.DISCRETE:
hud.new_energy_bar.create_discrete_icons(weapons[slot].max_energy)
hud.new_energy_bar.use_energy(weapons[slot].max_energy - weapons[slot].current_energy, weapons[slot].stats.energy_type)
var offhand: int = 0 if equipped_weapon == 1 else 1
if !weapons[offhand]:
hud.new_energy_bar.disable_secondary_energy()
func swap_weapons() -> void:
if !weapons[0] and !weapons[1]:
return
weapons_active = false
swap_off_audio.play()
hud.audio_guard = true
if weapons[equipped_weapon]:
stow_weapon(equipped_weapon)
equipped_weapon = 0 if equipped_weapon == 1 else 1
show_weapon(equipped_weapon)
weapon_swap_timer.start()
func _on_timer_timeout() -> void:
weapons_active = true
if weapons[equipped_weapon]:
swap_on_audio.play()
weapons[equipped_weapon].visible = true
func unequip_weapon(slot: int = 0) -> void:
networked_unequip_weapon.rpc(slot)
gauntlet_cards[slot].visible = false
if slot == 0:
hud.place_icon.visible = true
hud.new_energy_bar.blank()
else:
hud.swap_icon.visible = true
hud.new_energy_bar.disable_secondary_energy()
weapons[slot].queue_free()
weapons[slot] = null
cards[slot] = null
place_card_audio.play()
check_left_hand_valid()
#MULTIPLAYER NETWORKED FUNCTIONS
@rpc("reliable")
func networked_set_ready_state(state: bool) -> void:
ready_state = state
@rpc("reliable")
func networked_swap_weapon() -> void:
swap_weapons()
@rpc("reliable")
func networked_equip_weapon(card_index: int, slot: int, id: int) -> void:
var new_card: Card = Data.cards[card_index]
var new_weapon: Weapon = new_card.weapon_scene.instantiate()
new_weapon.set_multiplayer_authority(multiplayer.get_remote_sender_id())
new_weapon.name = str(id)
new_weapon.set_hero(self)
right_hand.add_child(new_weapon)
cards[slot] = new_card
weapons[slot] = new_weapon
@rpc("reliable")
func networked_unequip_weapon(slot: int) -> void:
weapons[slot].queue_free()
weapons[slot] = null
cards[slot] = null