massive work towards godot 4
This commit is contained in:
271
scripts/Console.gd
Normal file
271
scripts/Console.gd
Normal file
@ -0,0 +1,271 @@
|
||||
extends Control
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
|
||||
|
||||
|
||||
const CHANGE_TIME = 0.0125
|
||||
const ACTION_TIME = 0.25
|
||||
var actionTimer
|
||||
|
||||
var changeChar
|
||||
var queuedAction
|
||||
var charCount = 0
|
||||
var visableChars = 0
|
||||
|
||||
var tempValue = ""
|
||||
|
||||
const MAIN_MENU = ['Next Level', 'Upgrades', 'Main Menu']
|
||||
|
||||
|
||||
const ALL_EQUIPMENT = {
|
||||
#"pistol" : 4,
|
||||
#"smg" : 8
|
||||
}
|
||||
|
||||
const BASE_UNLOCK = {
|
||||
#"stealth" : 1000,
|
||||
"jump" : 1
|
||||
}
|
||||
|
||||
func _ready():
|
||||
actionTimer = Timer.new()
|
||||
actionTimer.connect("timeout",Callable(self,"RunQueuedAction"))
|
||||
add_child(actionTimer)
|
||||
$Display.text = $Display.text + "\nGood job Unit " + String(SaveManager.get_run()) + "!"
|
||||
addLine("\nAwaiting input...")
|
||||
changeChar = CHANGE_TIME
|
||||
$Display.visible_characters = 18
|
||||
visableChars = 18
|
||||
updateCharCount()
|
||||
|
||||
GenerateInputs(MAIN_MENU)
|
||||
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func GenerateInputs(options):
|
||||
for child in $Buttons.get_children():
|
||||
child.queue_free()
|
||||
for option in options:
|
||||
var button = Button.new()
|
||||
button.text = " [" + option + "] "
|
||||
button.connect("button_down",Callable(self,"ButtonInput").bind(option))
|
||||
$Buttons.add_child(button)
|
||||
|
||||
func ButtonInput(input):
|
||||
if input == "Main Menu":
|
||||
addLine("gis exit\nExiting environment...")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Next Level":
|
||||
addLine("gis run unit " + String(SaveManager.get_run()))
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Upgrades":
|
||||
addLine("gis config unit " + String(SaveManager.get_run()))
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Back":
|
||||
addLine("X")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Equipment":
|
||||
addLine("2")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Abilities":
|
||||
addLine("1")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input.to_lower() in SaveManager.get_equipment():
|
||||
addLine("gis access equipment " + input.to_lower())
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input.to_lower() in SaveManager.get_actions():
|
||||
addLine("gis access upgrade " + input.to_lower())
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Equip":
|
||||
addLine("1")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Upgrade":
|
||||
addLine("1")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Unequip":
|
||||
addLine("1")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input == "Buy Equipment":
|
||||
addLine("3")
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
elif input.to_lower() in ALL_EQUIPMENT:
|
||||
addLine("gis equipment purchase " + input.to_lower())
|
||||
if !queuedAction:
|
||||
queuedAction = input
|
||||
else:
|
||||
addLine("Error 404! Command `button:" + input + "` not found!")
|
||||
|
||||
func capFirst(inputVal):
|
||||
return inputVal.capitalize()[0] + inputVal.substr(1, len(inputVal))
|
||||
|
||||
func RunQueuedAction():
|
||||
if queuedAction == "Main Menu":
|
||||
get_tree().change_scene_to_file("res://Nodes/Title.tscn")
|
||||
elif queuedAction == "Next Level":
|
||||
get_tree().change_scene_to_file("res://Nodes/Game.tscn")
|
||||
elif queuedAction == "Upgrades":
|
||||
clearConsole()
|
||||
addLine("Upgrade Chips: " + String(SaveManager.get_upgrade_points()) + "\n\n")
|
||||
addLine("Select upgrade category:")
|
||||
addLine("1. Abilities")
|
||||
addLine("2. Equipment")
|
||||
addLine("3. Buy Equipment")
|
||||
addLine("\nX. Back")
|
||||
GenerateInputs(['Abilities', 'Equipment', 'Buy Equipment', 'Back'])
|
||||
elif queuedAction == "Buy Equipment":
|
||||
clearConsole()
|
||||
addLine("Upgrade Chips: " + String(SaveManager.get_upgrade_points()) + "\n\n")
|
||||
addLine("Equipment:")
|
||||
var i = 1
|
||||
var tempInputs = []
|
||||
for equipment in ALL_EQUIPMENT:
|
||||
if !(equipment in SaveManager.get_equipment()):
|
||||
tempInputs.append(capFirst(equipment))
|
||||
addLine(String(i) + ". " + capFirst(equipment) + " (COST " + String(ALL_EQUIPMENT[equipment]) + ")")
|
||||
i += 1
|
||||
GenerateInputs(tempInputs + ['Upgrades'])
|
||||
elif queuedAction == "Back":
|
||||
GenerateInputs(MAIN_MENU)
|
||||
clearConsole()
|
||||
elif queuedAction == "Equipment":
|
||||
clearConsole()
|
||||
addLine("Upgrade Chips: " + String(SaveManager.get_upgrade_points()) + "\n\n")
|
||||
addLine("Equipment:")
|
||||
var i = 1
|
||||
var tempInputs = []
|
||||
for equip in SaveManager.get_equipment():
|
||||
var suffix = ""
|
||||
if equip == SaveManager.get_equiped():
|
||||
suffix = " (EQUIPED)"
|
||||
addLine(String(i) + ". " + equip.capitalize()[0] + equip.substr(1, len(equip)) + suffix)
|
||||
tempInputs.append(equip.capitalize()[0] + equip.substr(1, len(equip)))
|
||||
i += 1
|
||||
addLine('\nX. Back')
|
||||
|
||||
GenerateInputs(tempInputs + ["Upgrades"])
|
||||
elif queuedAction == "Abilities":
|
||||
clearConsole()
|
||||
addLine("Upgrade Chips: " + String(SaveManager.get_upgrade_points()) + "\n\n")
|
||||
addLine("Abilities:")
|
||||
var i = 1
|
||||
var tempInputs = []
|
||||
for action in SaveManager.get_actions():
|
||||
addLine(String(i) + ". " + action.capitalize()[0] + action.substr(1, len(action)))
|
||||
tempInputs.append(action.capitalize()[0] + action.substr(1, len(action)))
|
||||
i += 1
|
||||
addLine('\nX. Back')
|
||||
|
||||
GenerateInputs(tempInputs + ["Upgrades"])
|
||||
elif queuedAction.to_lower() in SaveManager.get_equipment():
|
||||
clearConsole()
|
||||
addLine("Equipment: " + queuedAction)
|
||||
addLine("")
|
||||
var tempInputs = []
|
||||
if(queuedAction.to_lower() == SaveManager.get_equiped()):
|
||||
tempInputs.append("Unequip")
|
||||
addLine("1. Unequip")
|
||||
else:
|
||||
tempInputs.append("Equip")
|
||||
addLine("1. Equip")
|
||||
addLine("\nX. Back")
|
||||
tempValue = queuedAction.to_lower()
|
||||
GenerateInputs(tempInputs + ["Equipment"])
|
||||
elif queuedAction.to_lower() in SaveManager.get_actions():
|
||||
clearConsole()
|
||||
addLine("Upgrade Chips: " + String(SaveManager.get_upgrade_points()) + "\n\n")
|
||||
addLine("Ability: " + queuedAction)
|
||||
addLine("Level: " + String(SaveManager.get_action_value(queuedAction.to_lower())))
|
||||
addLine("")
|
||||
var pointsToUpgrade = 1 * int(SaveManager.get_action_value(queuedAction.to_lower()))
|
||||
if queuedAction.to_lower() in BASE_UNLOCK:
|
||||
pointsToUpgrade += BASE_UNLOCK[queuedAction.to_lower()]
|
||||
var tempInputs = []
|
||||
tempInputs.append("Upgrade")
|
||||
addLine("1. Upgrade (" + String(pointsToUpgrade) + " Points)")
|
||||
addLine("\nX. Back")
|
||||
tempValue = queuedAction.to_lower()
|
||||
GenerateInputs(tempInputs + ["Abilities"])
|
||||
elif queuedAction == "Equip":
|
||||
SaveManager.set_equiped(tempValue)
|
||||
addLine("\nEquiped: " + tempValue.capitalize()[0] + tempValue.substr(1, len(tempValue)))
|
||||
queuedAction = "Equipment"
|
||||
actionTimer.stop()
|
||||
return
|
||||
elif queuedAction == "Upgrade":
|
||||
var UPGRADE_COST = 1 * int(SaveManager.get_action_value(tempValue.to_lower()))
|
||||
if tempValue.to_lower() in BASE_UNLOCK:
|
||||
UPGRADE_COST += BASE_UNLOCK[tempValue.to_lower()]
|
||||
if (SaveManager.get_upgrade_points() >= UPGRADE_COST):
|
||||
SaveManager.change_upgrade_points(-1 * UPGRADE_COST)
|
||||
SaveManager.set_action_value(tempValue, SaveManager.get_action_value(tempValue) + 1)
|
||||
addLine("\nUpgraded: " + tempValue.capitalize()[0] + tempValue.substr(1, len(tempValue)))
|
||||
else:
|
||||
addLine("\nNot enough upgrade chips!")
|
||||
queuedAction = tempValue
|
||||
actionTimer.stop()
|
||||
return
|
||||
elif queuedAction == "Unequip":
|
||||
SaveManager.set_equiped("none")
|
||||
addLine("\nUnequiped: " + tempValue.capitalize()[0] + tempValue.substr(1, len(tempValue)))
|
||||
queuedAction = "Equipment"
|
||||
actionTimer.stop()
|
||||
return
|
||||
elif queuedAction.to_lower() in ALL_EQUIPMENT:
|
||||
var cost = ALL_EQUIPMENT[queuedAction.to_lower()]
|
||||
if (SaveManager.get_upgrade_points() >= cost):
|
||||
SaveManager.change_upgrade_points(-1 * cost)
|
||||
addLine("Purchased: " + queuedAction)
|
||||
SaveManager.unlock_equipment(queuedAction.to_lower())
|
||||
else:
|
||||
addLine("\nNot enough upgrade chips!")
|
||||
queuedAction = "Buy Equipment"
|
||||
return
|
||||
else:
|
||||
addLine("Error 404! Command `action:" + queuedAction + "` not found!")
|
||||
queuedAction = null
|
||||
addLine("\nAwaiting input...")
|
||||
actionTimer.stop()
|
||||
|
||||
func _process(delta):
|
||||
if(visableChars < charCount):
|
||||
if(changeChar <= 0):
|
||||
visableChars += 4
|
||||
$Display.visible_characters = visableChars
|
||||
changeChar = CHANGE_TIME
|
||||
else:
|
||||
changeChar -= delta
|
||||
else:
|
||||
changeChar = CHANGE_TIME
|
||||
if queuedAction && actionTimer.is_stopped():
|
||||
actionTimer.start(ACTION_TIME)
|
||||
|
||||
func addLine(line):
|
||||
$Display.text = $Display.text + "\n" + line
|
||||
updateCharCount()
|
||||
|
||||
func clearConsole():
|
||||
$Display.visible_characters = 0
|
||||
$Display.text = ""
|
||||
visableChars = 0
|
||||
updateCharCount()
|
||||
|
||||
func updateCharCount():
|
||||
charCount = $Display.get_total_character_count()
|
14
scripts/Exit.gd
Normal file
14
scripts/Exit.gd
Normal file
@ -0,0 +1,14 @@
|
||||
extends Node2D
|
||||
|
||||
|
||||
func _ready():
|
||||
$Area2D.connect("body_entered",Callable(self,"on_collide"))
|
||||
|
||||
|
||||
func on_collide(body):
|
||||
if body.has_method("victoryCondition"):
|
||||
MusicPlayer.stop()
|
||||
MusicPlayer.stream = load("res://Music/DOS-88/Smooth Sailing.ogg")
|
||||
MusicPlayer.volume_db = 0
|
||||
MusicPlayer.play()
|
||||
body.victoryCondition()
|
51
scripts/RunLabel.gd
Normal file
51
scripts/RunLabel.gd
Normal file
@ -0,0 +1,51 @@
|
||||
extends Label
|
||||
|
||||
#Hide all charafcters checked start
|
||||
func _ready():
|
||||
text = "Authorization Granted: Unit " + String($"/root/SaveManager".get_run())
|
||||
show_text(2)
|
||||
visible_characters = 0
|
||||
|
||||
|
||||
var timePassed = 0 #Current amount of time spend displaying te
|
||||
const CHECK_LENGTH = 0.05 #Interval to check for updates
|
||||
var timeNeeded = 0 #Time that it takes to display the text
|
||||
var timer #Timer object
|
||||
var fadeTimer #Timer object
|
||||
|
||||
func show_text(seconds):
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!timer):
|
||||
timer = Timer.new()
|
||||
add_child(timer)
|
||||
timer.connect("timeout",Callable(self,"on_timeout"))
|
||||
timer.start(CHECK_LENGTH)
|
||||
|
||||
func fade_text(seconds):
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!fadeTimer):
|
||||
fadeTimer = Timer.new()
|
||||
add_child(fadeTimer)
|
||||
fadeTimer.connect("timeout",Callable(self,"on_fade_timeout"))
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
|
||||
func on_fade_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
modulate.a = 1 - (timePassed/timeNeeded)
|
||||
if(timePassed >= timeNeeded):
|
||||
fadeTimer.queue_free()
|
||||
else:
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
pass
|
||||
|
||||
func on_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
visible_characters = (timePassed/timeNeeded) * get_total_character_count()
|
||||
if(timePassed >= timeNeeded):
|
||||
timer.queue_free()
|
||||
fade_text(2)
|
||||
else:
|
||||
timer.start(CHECK_LENGTH)
|
||||
pass
|
53
scripts/TypeLabel.gd
Normal file
53
scripts/TypeLabel.gd
Normal file
@ -0,0 +1,53 @@
|
||||
extends Label
|
||||
|
||||
@export var time_to_show = 4.0
|
||||
@export var fade_after_show = true
|
||||
#Hide all charafcters checked start
|
||||
func _ready():
|
||||
show_text(time_to_show)
|
||||
visible_characters = 0
|
||||
|
||||
|
||||
var timePassed = 0 #Current amount of time spend displaying te
|
||||
const CHECK_LENGTH = 0.05 #Interval to check for updates
|
||||
var timeNeeded = 0 #Time that it takes to display the text
|
||||
var timer #Timer object
|
||||
var fadeTimer #Timer object
|
||||
|
||||
func show_text(seconds):
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!timer):
|
||||
timer = Timer.new()
|
||||
add_child(timer)
|
||||
timer.connect("timeout",Callable(self,"on_timeout"))
|
||||
timer.start(CHECK_LENGTH)
|
||||
|
||||
func fade_text(seconds):
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!fadeTimer):
|
||||
fadeTimer = Timer.new()
|
||||
add_child(fadeTimer)
|
||||
fadeTimer.connect("timeout",Callable(self,"on_fade_timeout"))
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
|
||||
func on_fade_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
modulate.a = 1 - (timePassed/timeNeeded)
|
||||
if(timePassed >= timeNeeded):
|
||||
fadeTimer.queue_free()
|
||||
else:
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
pass
|
||||
|
||||
func on_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
visible_characters = (timePassed/timeNeeded) * get_total_character_count()
|
||||
if(timePassed >= timeNeeded):
|
||||
timer.queue_free()
|
||||
if(fade_after_show):
|
||||
fade_text(2)
|
||||
else:
|
||||
timer.start(CHECK_LENGTH)
|
||||
pass
|
49
scripts/baddie.gd
Normal file
49
scripts/baddie.gd
Normal file
@ -0,0 +1,49 @@
|
||||
extends Node2D
|
||||
|
||||
@export
|
||||
var HP: int = 8
|
||||
|
||||
@export
|
||||
var color_str: String = "ffff00"
|
||||
|
||||
func _ready():
|
||||
var tile_map: TileMap = get_node("%tile_map")
|
||||
var tile_pos = tile_map.local_to_map(Vector2i(int(position.x), int(position.y)))
|
||||
if(tile_map.get_cell_source_id(0, tile_pos) != -1):
|
||||
push_error("Enemy placed at tile in use, freeing!")
|
||||
queue_free()
|
||||
|
||||
func take_damage(dmg):
|
||||
playAudio("Bomb_Drop.wav")
|
||||
modulate = Color(255,0,0)
|
||||
$CharacterBody2D/PointLight2D.color = Color(255,0,0)
|
||||
HP -= dmg
|
||||
reset_color()
|
||||
|
||||
|
||||
var color_timer
|
||||
func reset_color():
|
||||
if !color_timer:
|
||||
color_timer = Timer.new()
|
||||
add_child(color_timer)
|
||||
color_timer.connect("timeout",Callable(self,"color_timeout"))
|
||||
color_timer.start(0.125)
|
||||
|
||||
func color_timeout():
|
||||
var color = Color.from_string(color_str, Color.WHITE)
|
||||
modulate = color
|
||||
$CharacterBody2D/PointLight2D.color = Color(color)
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if(HP <= 0):
|
||||
queue_free()
|
||||
|
||||
|
||||
var audioPlayer
|
||||
func playAudio(track):
|
||||
if !audioPlayer:
|
||||
audioPlayer = AudioStreamPlayer.new()
|
||||
get_parent().add_child(audioPlayer)
|
||||
audioPlayer.stream = load("res://assets/sound/%s" % track)
|
||||
audioPlayer.volume_db = -30
|
||||
audioPlayer.play()
|
100
scripts/basic_enemy.gd
Normal file
100
scripts/basic_enemy.gd
Normal file
@ -0,0 +1,100 @@
|
||||
extends CharacterBody2D
|
||||
|
||||
const UP = Vector2(0, -1)
|
||||
const BASE_GRAVITY = 20
|
||||
|
||||
@export var active_distance = 32
|
||||
@export var angry_distance = 100
|
||||
|
||||
@export var speed = 25
|
||||
|
||||
@export var attack_speed = 1
|
||||
|
||||
var angry = false
|
||||
|
||||
var knockback = 0
|
||||
var player
|
||||
|
||||
const UPDATE_ANGRY_TIME = 0.25
|
||||
|
||||
var motion = Vector2(0, 0)
|
||||
var TIMER
|
||||
|
||||
func _ready():
|
||||
$AnimatedSprite2D.play("default")
|
||||
$Area2D.connect("body_entered",Callable(self,"collision_method"))
|
||||
var alarmRoot = get_parent().get_parent()
|
||||
if alarmRoot.has_node("BaddieAlarm"):
|
||||
for node in alarmRoot.get_children():
|
||||
if node.name == "BaddieAlarm":
|
||||
node.timeout.connect(self.update_angry)
|
||||
TIMER = node
|
||||
break
|
||||
else:
|
||||
var node := Timer.new()
|
||||
node.name = "BaddieAlarm"
|
||||
node.timeout.connect(self.update_angry)
|
||||
alarmRoot.add_child.call_deferred(node)
|
||||
node.start.call_deferred(UPDATE_ANGRY_TIME)
|
||||
TIMER = node
|
||||
|
||||
func collision_method(body):
|
||||
if body.has_method("deal_damage"):
|
||||
body.deal_damage()
|
||||
knockback += 100
|
||||
|
||||
func take_damage(dmg):
|
||||
knockback += 25 * dmg
|
||||
get_parent().take_damage(dmg)
|
||||
|
||||
func update_angry():
|
||||
if angry && global_position.distance_to(player.global_position) > angry_distance:
|
||||
angry = false
|
||||
elif global_position.distance_to(player.global_position) < active_distance:
|
||||
angry = true
|
||||
if(TIMER.wait_time <= 0):
|
||||
TIMER.start(UPDATE_ANGRY_TIME)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
#Implement the force of gravity!
|
||||
motion.y += BASE_GRAVITY
|
||||
|
||||
if is_on_floor():
|
||||
motion.y = 0
|
||||
|
||||
if knockback > 0:
|
||||
motion.y -= knockback/2
|
||||
if(player.global_position.x > global_position.x):
|
||||
motion.x -= knockback
|
||||
else:
|
||||
motion.x += knockback
|
||||
knockback -= 30
|
||||
else:
|
||||
if !player:
|
||||
player = get_node("/root/World3D/Player")
|
||||
else:
|
||||
|
||||
|
||||
if angry:
|
||||
angry = true
|
||||
if($AnimatedSprite2D.animation != "run"):
|
||||
$AnimatedSprite2D.play("run")
|
||||
if player.global_position.distance_to(global_position) > 24:
|
||||
if(player.global_position.x > global_position.x):
|
||||
motion.x += speed
|
||||
$AnimatedSprite2D.flip_h = false
|
||||
$Area2D.rotation = 0
|
||||
else:
|
||||
motion.x -= speed
|
||||
$AnimatedSprite2D.flip_h = true
|
||||
$Area2D.rotation = PI
|
||||
else:
|
||||
knockback += 60
|
||||
else:
|
||||
$AnimatedSprite2D.play("default")
|
||||
|
||||
set_velocity(motion)
|
||||
set_up_direction(UP)
|
||||
move_and_slide()
|
||||
motion = velocity
|
31
scripts/bullet.gd
Normal file
31
scripts/bullet.gd
Normal file
@ -0,0 +1,31 @@
|
||||
class_name Projectile
|
||||
extends Area2D
|
||||
|
||||
@export
|
||||
var damage: int = 1
|
||||
|
||||
@export
|
||||
var speed: float = 500
|
||||
|
||||
@export
|
||||
var lifetime: float = 5
|
||||
|
||||
func _ready():
|
||||
self.body_entered.connect(self._on_body_entered)
|
||||
|
||||
var timer: Timer = Timer.new()
|
||||
self.add_child(timer)
|
||||
timer.timeout.connect(func():
|
||||
self.queue_free()
|
||||
)
|
||||
timer.start(lifetime)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
var direction = Vector2.from_angle(rotation)
|
||||
|
||||
self.position += (speed*delta) * direction
|
||||
|
||||
func _on_body_entered(body: Node2D) -> void:
|
||||
if body.has_method("take_damage"):
|
||||
body.take_damage(self.damage)
|
||||
self.queue_free()
|
12
scripts/destroy_after_animation.gd
Normal file
12
scripts/destroy_after_animation.gd
Normal file
@ -0,0 +1,12 @@
|
||||
extends AnimatedSprite2D
|
||||
|
||||
func _ready():
|
||||
play("spawn")
|
||||
connect("animation_finished",Callable(self,"on_animation_finished"))
|
||||
|
||||
|
||||
func on_animation_finished():
|
||||
if(animation == "spawn"):
|
||||
play("destroy")
|
||||
else:
|
||||
get_parent().queue_free()
|
49
scripts/equipment/equipment.gd
Normal file
49
scripts/equipment/equipment.gd
Normal file
@ -0,0 +1,49 @@
|
||||
class_name Equipment
|
||||
extends Node2D
|
||||
|
||||
signal sheath(bool)
|
||||
|
||||
@export
|
||||
var auto_z_index: bool = true
|
||||
|
||||
@export
|
||||
var auto_flip: bool = true
|
||||
|
||||
var _sheathed: bool = true
|
||||
|
||||
var _original_z_index: int
|
||||
|
||||
func init_equipment() -> void:
|
||||
self._original_z_index = self.z_index
|
||||
self._update_z_index()
|
||||
|
||||
func is_sheathed() -> bool:
|
||||
return self._sheathed
|
||||
|
||||
func toggle_sheath() -> void:
|
||||
self._sheathed = !self._sheathed
|
||||
|
||||
self._update_z_index()
|
||||
|
||||
self.sheath.emit(self._sheathed)
|
||||
|
||||
func _update_z_index() -> void:
|
||||
if self.auto_z_index:
|
||||
if self._sheathed:
|
||||
self.z_index = _original_z_index - 100
|
||||
else:
|
||||
self.z_index = _original_z_index
|
||||
|
||||
func is_facing_left() -> bool:
|
||||
return get_global_mouse_position().x < global_position.x
|
||||
|
||||
func process_equipment(_delta: float) -> void:
|
||||
self._update_z_index()
|
||||
|
||||
if auto_flip:
|
||||
if self.is_facing_left():
|
||||
self.scale.x = -1
|
||||
else:
|
||||
self.scale.x = 1
|
||||
else:
|
||||
self.scale.x = 1
|
77
scripts/equipment/pistol.gd
Normal file
77
scripts/equipment/pistol.gd
Normal file
@ -0,0 +1,77 @@
|
||||
class_name EquipmentGun
|
||||
extends Equipment
|
||||
|
||||
@export
|
||||
var bullet: PackedScene
|
||||
|
||||
@export
|
||||
var left_arm: Line2D
|
||||
|
||||
@export
|
||||
var right_arm: Line2D
|
||||
|
||||
@export
|
||||
var origin: Node2D
|
||||
|
||||
@export
|
||||
var bullet_spawning_point: Node2D
|
||||
|
||||
@export
|
||||
var pistol_handle: Node2D
|
||||
|
||||
@export
|
||||
var sprite: Sprite2D
|
||||
|
||||
@export
|
||||
var sheath_point: Node2D
|
||||
|
||||
@onready
|
||||
var _original_sprite_pos: Vector2 = sprite.position
|
||||
|
||||
@onready
|
||||
var _original_sprite_rotation: float = sprite.rotation
|
||||
|
||||
func _ready() -> void:
|
||||
self.init_equipment()
|
||||
|
||||
self.sheath.connect(self._on_sheath)
|
||||
self._on_sheath(self.is_sheathed())
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
self.process_equipment(delta)
|
||||
|
||||
if self.is_sheathed():
|
||||
return
|
||||
|
||||
self.origin.look_at(self.get_global_mouse_position())
|
||||
|
||||
self.right_arm.clear_points()
|
||||
self.right_arm.add_point(Vector2(2.5, 0))
|
||||
self.right_arm.add_point(to_local(self.pistol_handle.global_position))
|
||||
self.left_arm.clear_points()
|
||||
self.left_arm.add_point(Vector2(-2.5, 0))
|
||||
self.left_arm.add_point(to_local(self.pistol_handle.global_position))
|
||||
|
||||
self.sprite.flip_v = self.is_facing_left()
|
||||
|
||||
if Input.is_action_just_pressed("attack"):
|
||||
var projectile: Node2D = self.bullet.instantiate()
|
||||
self.get_parent().get_parent().add_child(projectile)
|
||||
projectile.global_position = self.bullet_spawning_point.global_position
|
||||
projectile.rotation = origin.rotation
|
||||
|
||||
func _on_sheath(sheathed: bool):
|
||||
self.auto_flip = sheathed
|
||||
|
||||
if sheathed:
|
||||
self.origin.rotation = 0
|
||||
self.sprite.position = self.sheath_point.position
|
||||
self.sprite.rotation = self.sheath_point.rotation
|
||||
|
||||
self.right_arm.clear_points()
|
||||
self.left_arm.clear_points()
|
||||
else:
|
||||
self.sprite.position = self._original_sprite_pos
|
||||
self.sprite.rotation = self._original_sprite_rotation
|
||||
|
||||
|
33
scripts/equipment/saber.gd
Normal file
33
scripts/equipment/saber.gd
Normal file
@ -0,0 +1,33 @@
|
||||
class_name EquipmentSaber
|
||||
extends Equipment
|
||||
|
||||
@export
|
||||
var animation_player: AnimationPlayer
|
||||
|
||||
@export
|
||||
var area: Area2D
|
||||
|
||||
@export
|
||||
var damage: int = 1
|
||||
|
||||
func _ready() -> void:
|
||||
self.init_equipment()
|
||||
|
||||
self.area.body_entered.connect(self._on_body_entered)
|
||||
self._update_z_index()
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
self.process_equipment(delta)
|
||||
|
||||
if self.is_sheathed():
|
||||
if self.animation_player.current_animation != "sheathed":
|
||||
self.animation_player.play("sheathed")
|
||||
else:
|
||||
if not self.animation_player.current_animation in ["attack", "idle"]:
|
||||
self.animation_player.play("idle")
|
||||
if Input.is_action_just_pressed("attack"):
|
||||
self.animation_player.play("attack")
|
||||
|
||||
func _on_body_entered(body: Node2D) -> void:
|
||||
if body.has_method("take_damage"):
|
||||
body.take_damage(self.damage)
|
17
scripts/game.gd
Normal file
17
scripts/game.gd
Normal file
@ -0,0 +1,17 @@
|
||||
extends Camera2D
|
||||
|
||||
var speed = 2
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var camera_move_dir = Vector2(0,0)
|
||||
if(Input.is_action_pressed("right")):
|
||||
camera_move_dir += Vector2(speed,0)
|
||||
if(Input.is_action_pressed("left")):
|
||||
camera_move_dir -= Vector2(speed,0)
|
||||
|
||||
if(Input.is_action_pressed("up")):
|
||||
camera_move_dir -= Vector2(0,speed)
|
||||
if(Input.is_action_pressed("down")):
|
||||
camera_move_dir += Vector2(0,speed)
|
||||
|
||||
global_translate(camera_move_dir)
|
67
scripts/manage_intro.gd
Normal file
67
scripts/manage_intro.gd
Normal file
@ -0,0 +1,67 @@
|
||||
extends Label
|
||||
|
||||
@export
|
||||
var title_screen: PackedScene
|
||||
|
||||
#Hide all charafcters checked start
|
||||
func _ready():
|
||||
show_text(2)
|
||||
visible_characters = 0
|
||||
|
||||
|
||||
var timePassed = 0 #Current amount of time spend displaying te
|
||||
const CHECK_LENGTH = 0.05 #Interval to check for updates
|
||||
var timeNeeded = 0 #Time that it takes to display the text
|
||||
var timer #Timer object
|
||||
var fadeTimer #Timer object
|
||||
|
||||
func show_text(seconds):
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!timer):
|
||||
timer = Timer.new()
|
||||
add_child(timer)
|
||||
timer.connect("timeout",Callable(self,"on_timeout"))
|
||||
timer.start(CHECK_LENGTH)
|
||||
|
||||
func fade_text(seconds):
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!fadeTimer):
|
||||
fadeTimer = Timer.new()
|
||||
add_child(fadeTimer)
|
||||
fadeTimer.connect("timeout",Callable(self,"on_fade_timeout"))
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
|
||||
func on_fade_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
modulate.a = 1 - (timePassed/timeNeeded)
|
||||
if(timePassed >= timeNeeded):
|
||||
fadeTimer.stop()
|
||||
checkIfDone()
|
||||
else:
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
pass
|
||||
|
||||
var done = false
|
||||
func checkIfDone():
|
||||
if(done):
|
||||
fadeTimer.queue_free()
|
||||
timer.queue_free()
|
||||
get_tree().change_scene_to_packed(title_screen)
|
||||
else:
|
||||
visible_characters = 0
|
||||
modulate.a = 1
|
||||
text = "Welcome Unit " + str(SaveManager.get_run() + 1) + "."
|
||||
done = true
|
||||
show_text(3)
|
||||
|
||||
func on_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
visible_characters = (timePassed/timeNeeded) * get_total_character_count()
|
||||
if(timePassed >= timeNeeded):
|
||||
timer.stop()
|
||||
fade_text(2)
|
||||
else:
|
||||
timer.start(CHECK_LENGTH)
|
||||
pass
|
310
scripts/map_generation.gd
Normal file
310
scripts/map_generation.gd
Normal file
@ -0,0 +1,310 @@
|
||||
extends Node
|
||||
|
||||
@export var mapSize = 128
|
||||
var playerSpawn = Vector2()
|
||||
|
||||
@export
|
||||
var player_scene: PackedScene
|
||||
|
||||
@onready
|
||||
var tile_map: TileMap = $tile_map
|
||||
|
||||
@export
|
||||
var light: PackedScene
|
||||
|
||||
@export
|
||||
var pickup: PackedScene
|
||||
|
||||
@export
|
||||
var basic_enemy: PackedScene
|
||||
|
||||
@export
|
||||
var exit: PackedScene
|
||||
|
||||
@export
|
||||
var music: AudioStream
|
||||
|
||||
const PATH_SIZE = 2
|
||||
|
||||
func _ready():
|
||||
|
||||
MusicPlayer.stop()
|
||||
MusicPlayer.stream = music
|
||||
MusicPlayer.volume_db = 0
|
||||
MusicPlayer.play()
|
||||
|
||||
|
||||
UpdateProgress("Loading generation libraries...")
|
||||
randomize()
|
||||
|
||||
func UpdateProgress(message):
|
||||
print(message)
|
||||
$LoadingScreen.get_child(2).text = message
|
||||
|
||||
func setTile(x,y, value):
|
||||
var tileValue = -1
|
||||
if(value == "block"):
|
||||
tileValue = 0
|
||||
elif(value == "safe_block"):
|
||||
tileValue = 2
|
||||
elif(value == "player"):
|
||||
playerSpawn = Vector2(x,y)
|
||||
elif(value == "ladder"):
|
||||
tileValue = 1
|
||||
elif(value == "light"):
|
||||
create_object(x,y, light)
|
||||
elif(value == "coin"):
|
||||
create_object(x,y, pickup)
|
||||
elif(value == "enemy"):
|
||||
create_object(x,y, basic_enemy)
|
||||
elif(value == "exit"):
|
||||
create_object(x,y, exit)
|
||||
tile_map.set_cell(tileValue, Vector2i(x, y))
|
||||
|
||||
func create_object(x: int, y: int, object_scene: PackedScene) -> void:
|
||||
var obj = object_scene.instantiate()
|
||||
self.add_child(obj)
|
||||
var pos = tile_map.map_to_local(Vector2i(x,y))
|
||||
obj.position = Vector2(pos.x + 8, pos.y + 8)
|
||||
|
||||
func generateStructure(x,y, structure):
|
||||
var symbolDictionary = {
|
||||
"x" : "safe_block",
|
||||
"p" : "player",
|
||||
"l" : "ladder",
|
||||
"c" : "coin",
|
||||
"e" : "enemy",
|
||||
"#" : "exit",
|
||||
"?": "light"
|
||||
}
|
||||
var largestX = 0
|
||||
var largestY = structure.size()
|
||||
for structY in range(0, structure.size()):
|
||||
for structX in range(0, structure[structY].size()):
|
||||
if structX > largestX:
|
||||
largestX = structX
|
||||
var symbol = structure[structY][structX]
|
||||
setTile(x + structX, y + structY, symbolDictionary.get(symbol))
|
||||
var rect = Rect2(Vector2(x-1,y-1),Vector2(largestX+1,largestY+1))
|
||||
return rect
|
||||
|
||||
|
||||
func fillMap(value="block"):
|
||||
for x in range(0, mapSize):
|
||||
for y in range(0, mapSize):
|
||||
setTile(x,y,value)
|
||||
|
||||
func spawnPlayer():
|
||||
var tempVector = Vector2(playerSpawn.x * tile_map.cell_size.x, playerSpawn.y * tile_map.cell_size.y)
|
||||
var player = player_scene.instantiate()
|
||||
add_child(player)
|
||||
player.position = tempVector
|
||||
var welcome = load("res://Nodes/PlayerGreetings.tscn").instantiate()
|
||||
add_child(welcome)
|
||||
welcome.position = Vector2(tempVector.x - 16, tempVector.y - 16)
|
||||
tile_map.set_cell(-1, Vector2i(playerSpawn.x, playerSpawn.y))
|
||||
$LoadingScreen.hideSelf()
|
||||
|
||||
var rooms = Array()
|
||||
func createConnections():
|
||||
var graph = AStar3D.new()
|
||||
var point_id = 0
|
||||
for x in range(mapSize):
|
||||
for y in range(mapSize):
|
||||
if tile_map.get_cell(x,y) == 0:
|
||||
graph.add_point(point_id, Vector3(x,y,0))
|
||||
|
||||
if x > 0 && tile_map.get_cell(x - 1, y) == 0:
|
||||
var left_point = graph.get_closest_point(Vector3(x - 1, y, 0))
|
||||
graph.connect_points(point_id, left_point)
|
||||
|
||||
if y > 0 && tile_map.get_cell(x, y - 1) == 0:
|
||||
var above_point = graph.get_closest_point(Vector3(x, y - 1, 0))
|
||||
graph.connect_points(point_id, above_point)
|
||||
|
||||
point_id += 1
|
||||
|
||||
var room_graph = AStar3D.new()
|
||||
point_id = 0
|
||||
for room in rooms:
|
||||
var room_center = room.position + room.size / 2
|
||||
room_graph.add_point(point_id, Vector3(room_center.x, room_center.y, 0))
|
||||
point_id += 1
|
||||
|
||||
while !is_everything_connected(room_graph):
|
||||
add_random_connection(graph, room_graph)
|
||||
|
||||
func is_everything_connected(graph):
|
||||
var points = graph.get_points()
|
||||
var start = points.pop_back()
|
||||
for point in points:
|
||||
var path = graph.get_point_path(start, point)
|
||||
if !path:
|
||||
return false
|
||||
return true
|
||||
|
||||
func add_random_connection(stone_graph, room_graph):
|
||||
|
||||
var start_room_id = get_least_connected_point(room_graph)
|
||||
var end_room_id = get_nearest_unconnected_point(room_graph, start_room_id)
|
||||
|
||||
var start_position = pick_random_door_location(rooms[start_room_id])
|
||||
var end_position = pick_random_door_location(rooms[end_room_id])
|
||||
|
||||
var closet_start_point = stone_graph.get_closest_point(start_position)
|
||||
var closet_end_point = stone_graph.get_closest_point(end_position)
|
||||
|
||||
var path = stone_graph.get_point_path(closet_start_point, closet_end_point)
|
||||
|
||||
for pos in path:
|
||||
for i in range(PATH_SIZE):
|
||||
if(tile_map.get_cell(pos.x+i, pos.y+i) == 0):
|
||||
setTile(pos.x+i, pos.y+i, "-1")
|
||||
if(tile_map.get_cell(pos.x+i, pos.y-i) == 0):
|
||||
setTile(pos.x+i, pos.y-i, "-1")
|
||||
if(tile_map.get_cell(pos.x-i, pos.y+i) == 0):
|
||||
setTile(pos.x-i, pos.y+i, "-1")
|
||||
if(tile_map.get_cell(pos.x-i, pos.y-i) == 0):
|
||||
setTile(pos.x-i, pos.y-i, "-1")
|
||||
if tile_map.get_cell(pos.x, pos.y - 2) == -1:
|
||||
if tile_map.get_cell(pos.x, pos.y - 1) == -1:
|
||||
if tile_map.get_cell(pos.x, pos.y) == -1:
|
||||
if !isNextToCell(pos.x, pos.y, 1):
|
||||
setTile(pos.x, pos.y, "ladder")
|
||||
#elif(randf_range(0,1) > 0.666):
|
||||
# setTile(pos.x, pos.y, "light")
|
||||
|
||||
elif tile_map.get_cell(pos.x, pos.y + 2) == -1:
|
||||
if tile_map.get_cell(pos.x, pos.y + 1) == -1:
|
||||
if tile_map.get_cell(pos.x, pos.y) == -1:
|
||||
if !isNextToCell(pos.x, pos.y, 1):
|
||||
setTile(pos.x, pos.y, "ladder")
|
||||
|
||||
room_graph.connect_points(start_room_id, end_room_id)
|
||||
|
||||
func isNextToCell(x, y, tileId):
|
||||
return tile_map.get_cell(x-1, y) == tileId or tile_map.get_cell(x+1, y) == tileId or tile_map.get_cell(x, y-1) == tileId or tile_map.get_cell(x, y+1) == tileId
|
||||
|
||||
func get_least_connected_point(graph):
|
||||
var point_ids = graph.get_points()
|
||||
|
||||
var least
|
||||
var tied_for_least
|
||||
|
||||
for point in point_ids:
|
||||
var count = graph.get_point_connections(point).size()
|
||||
if !least or count < least:
|
||||
least = count
|
||||
tied_for_least = [point]
|
||||
elif count == least:
|
||||
tied_for_least.append(point)
|
||||
|
||||
return tied_for_least[randi() % tied_for_least.size()]
|
||||
|
||||
func get_nearest_unconnected_point(graph, target_point):
|
||||
var target_position = graph.get_point_position(target_point)
|
||||
var point_ids = graph.get_points()
|
||||
|
||||
var nearest
|
||||
var tied_for_nearest = []
|
||||
|
||||
for point in point_ids:
|
||||
if point == target_point:
|
||||
continue
|
||||
|
||||
var path = graph.get_point_path(point, target_point)
|
||||
if path:
|
||||
continue
|
||||
|
||||
var dist = (graph.get_point_position(point) - target_position).length()
|
||||
if !nearest || dist < nearest:
|
||||
nearest = dist
|
||||
tied_for_nearest = [point]
|
||||
elif dist == nearest:
|
||||
tied_for_nearest.append(point)
|
||||
return tied_for_nearest[randi() % tied_for_nearest.size()]
|
||||
|
||||
func pick_random_door_location(room):
|
||||
var options = []
|
||||
|
||||
for x in range(room.position.x + 1, room.end.x - 2):
|
||||
if tile_map.get_cell(x, room.position.y) == -1:
|
||||
options.append(Vector3(x, room.position.y, 0))
|
||||
if tile_map.get_cell(x, room.end.y) == -1:
|
||||
options.append(Vector3(x, room.end.y - 1, 0))
|
||||
|
||||
for y in range(room.position.y + 1, room.end.y - 2):
|
||||
if tile_map.get_cell(room.position.x, y) == -1:
|
||||
options.append(Vector3(room.position.x, y, 0))
|
||||
if tile_map.get_cell(room.end.x - 1, y) == -1:
|
||||
options.append(Vector3(room.end.x - 1, y, 0))
|
||||
|
||||
|
||||
return options[randi() % options.size()]
|
||||
|
||||
func defaultGenerator(padding = 16):
|
||||
|
||||
UpdateProgress("Running default generator with map size " + str(mapSize) + "x" + str(mapSize))
|
||||
fillMap()
|
||||
|
||||
|
||||
var randomStructures = [
|
||||
[
|
||||
['x','x','x','x','x','x','x','x','x','x','x','x'],
|
||||
[' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '],
|
||||
[' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '],
|
||||
[' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '],
|
||||
['x','x',' ',' ','x',' ',' ','x',' ',' ','x','x'],
|
||||
['x',' ',' ',' ','x',' ',' ','x',' ',' ',' ','x'],
|
||||
['x',' ',' ',' ','x',' ','e','x',' ','e',' ','x'],
|
||||
['x','x','x','x','x','x','x','x','x','x','x','x']
|
||||
],
|
||||
[
|
||||
['x','x','x','x','x','x','x','x','x','x','x','x'],
|
||||
[' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '],
|
||||
[' ',' ',' ',' ','x','l',' ','x',' ',' ',' ',' '],
|
||||
[' ','e',' ',' ','x',' ',' ','x',' ',' ',' ',' '],
|
||||
['x','x','x','x','x','l',' ','x','x','x','x','x'],
|
||||
['x',' ',' ',' ','x',' ',' ','x',' ',' ',' ','x'],
|
||||
['x','c',' ',' ',' ',' ','e',' ',' ',' ','c','x'],
|
||||
['x','x','x','x','x','x','x','x','x','x','x','x']
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
for i in range(randf_range(mapSize/32.0, mapSize/8.0)):
|
||||
rooms.append(generateStructure(randf_range(padding, mapSize - padding),randf_range(padding, mapSize - padding), randomStructures[randf_range(0, randomStructures.size())]))
|
||||
|
||||
|
||||
#Create spawn point
|
||||
UpdateProgress("Creating client connection port...")
|
||||
var spawnStructure = [
|
||||
['x','x','x','x','x','x','x','x','x'],
|
||||
['x',' ','?',' ',' ',' ','?',' ','x'],
|
||||
['x',' ',' ',' ',' ',' ',' ',' ',' '],
|
||||
['x',' ','p',' ',' ',' ',' ',' ',' '],
|
||||
['x','x','x','x','x','x','x','x','x']]
|
||||
rooms.append(generateStructure(randf_range(padding, mapSize/3.0),randf_range(padding, mapSize/3.0), spawnStructure))
|
||||
|
||||
var exitStructure = [
|
||||
['x','x','x','x','x','x','x'],
|
||||
['x',' ',' ',' ',' ',' ','x'],
|
||||
['x',' ',' ',' ',' ',' ','x'],
|
||||
[' ',' ',' ','#',' ',' ',' '],
|
||||
[' ',' ','x','x','x',' ',' '],
|
||||
[' ',' ','x','x','x',' ',' ']]
|
||||
|
||||
rooms.append(generateStructure(randf_range(padding, mapSize - padding),randf_range(padding, mapSize - padding*3), exitStructure))
|
||||
|
||||
createConnections()
|
||||
|
||||
tile_map.set_cell(playerSpawn.x, playerSpawn.y, 0)
|
||||
|
||||
|
||||
UpdateProgress("Removing all possible escapes...")
|
||||
for x in range(0, mapSize):
|
||||
for y in range(0, mapSize):
|
||||
if x < padding or y < padding or x >= mapSize - padding or y >= mapSize - padding:
|
||||
setTile(x,y,"block")
|
||||
|
||||
spawnPlayer()
|
7
scripts/pickup.gd
Normal file
7
scripts/pickup.gd
Normal file
@ -0,0 +1,7 @@
|
||||
extends Node2D
|
||||
|
||||
func _ready():
|
||||
var tile_map = get_node("%tile_map") as TileMap
|
||||
var tile_pos = tile_map.local_to_map(position)
|
||||
if(tile_map.get_cell(0, Vector2i(tile_pos.x, tile_pos.y)) != 0):
|
||||
queue_free()
|
211
scripts/player.gd
Normal file
211
scripts/player.gd
Normal file
@ -0,0 +1,211 @@
|
||||
class_name Player
|
||||
extends CharacterBody2D
|
||||
|
||||
signal unequip()
|
||||
signal coin_update(int)
|
||||
|
||||
signal health_update(int)
|
||||
signal death()
|
||||
|
||||
|
||||
const BASE_MOVEMENT_SPEED := 10000
|
||||
const BASE_JUMP_HEIGHT := -250
|
||||
|
||||
|
||||
|
||||
@export
|
||||
var jump_platform: PackedScene
|
||||
|
||||
@export
|
||||
var animation_player: AnimationPlayer
|
||||
|
||||
@export
|
||||
var arms_sprite: Sprite2D
|
||||
|
||||
@export
|
||||
var damage_sound: AudioStream
|
||||
|
||||
@export
|
||||
var sword_sound: AudioStream
|
||||
|
||||
@export_category("Combat")
|
||||
@export
|
||||
var max_hp: int = 25
|
||||
|
||||
|
||||
@export_dir
|
||||
var equipment_dir: String
|
||||
|
||||
@export
|
||||
var equipment_node: Node2D
|
||||
|
||||
@export_category("Movement")
|
||||
@export
|
||||
var default_speed: float = 1
|
||||
|
||||
@export
|
||||
var default_jump_height: float = 1
|
||||
|
||||
|
||||
@onready
|
||||
var health: int = max_hp :
|
||||
set(value):
|
||||
value = clampi(value, 0, max_hp)
|
||||
|
||||
if value != health:
|
||||
health_update.emit(value)
|
||||
if value == 0:
|
||||
death.emit()
|
||||
health = value
|
||||
get:
|
||||
return health
|
||||
|
||||
@onready
|
||||
var default_gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
|
||||
|
||||
var coins: int = 0 :
|
||||
set(value):
|
||||
if value != coins:
|
||||
coin_update.emit(coins)
|
||||
coins = value
|
||||
get:
|
||||
return coins
|
||||
|
||||
var motion: Vector2 = Vector2.ZERO
|
||||
|
||||
var currently_equiped: String = "pistol"
|
||||
|
||||
var extra_jumps: int = 2
|
||||
|
||||
var current_jumps: int = 0
|
||||
|
||||
var jump_height: float = 0
|
||||
|
||||
func _ready() -> void:
|
||||
self.add_item("pistol")
|
||||
self.add_item("saber")
|
||||
|
||||
func deal_damage(dmg = 1) -> void:
|
||||
self._play_audio(damage_sound)
|
||||
self.health -= dmg
|
||||
|
||||
func switch_sheath() -> void:
|
||||
var item := get_currently_equiped_node()
|
||||
item.toggle_sheath()
|
||||
|
||||
|
||||
func _play_audio(track: AudioStream) -> void:
|
||||
var audio_player = get_node_or_null("AudioStreamPlayer")
|
||||
if !audio_player:
|
||||
audio_player = AudioStreamPlayer.new()
|
||||
audio_player.name = "AudioStreamPlayer"
|
||||
self.add_child(audio_player)
|
||||
audio_player.stream = track
|
||||
audio_player.volume_db = -30
|
||||
audio_player.play()
|
||||
|
||||
func pickup_coin(coin_value: int = 1) -> void:
|
||||
self.coins += coin_value
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var item = get_currently_equiped_node()
|
||||
arms_sprite.visible = (item == null || item.is_sheathed())
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
|
||||
self._combat_process(delta)
|
||||
self._gravity_process(delta)
|
||||
self._movement_process(delta)
|
||||
self._animation_process(delta)
|
||||
|
||||
self.set_velocity(self.motion)
|
||||
self.set_up_direction(Vector2.UP)
|
||||
self.move_and_slide()
|
||||
self.motion = self.velocity
|
||||
|
||||
func _combat_process(_delta: float) -> void:
|
||||
|
||||
for i in range(0, 2):
|
||||
if Input.is_action_just_pressed("equip_slot_%s" % [str(i+1)]):
|
||||
if self.equipment_node.get_child_count() > i:
|
||||
self.equip(self.equipment_node.get_child(i).name)
|
||||
|
||||
if Input.is_action_just_pressed("sheath"):
|
||||
self.switch_sheath()
|
||||
if Input.is_action_pressed("attack") and self.get_currently_equiped_node().is_sheathed():
|
||||
self.switch_sheath()
|
||||
|
||||
func _gravity_process(delta: float) -> void:
|
||||
self.motion.y += self.default_gravity * delta
|
||||
if self.is_on_floor():
|
||||
self.motion.y = 0
|
||||
|
||||
func _movement_process(delta: float) -> void:
|
||||
|
||||
# Horizontal movement
|
||||
if Input.is_action_pressed("move_right"):
|
||||
self.motion.x = (self.BASE_MOVEMENT_SPEED * delta) * self.default_speed
|
||||
elif Input.is_action_pressed("move_left"):
|
||||
self.motion.x = (-self.BASE_MOVEMENT_SPEED * delta) * self.default_speed
|
||||
else:
|
||||
self.motion.x = 0
|
||||
|
||||
# Handle jumps
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
if self.is_on_floor():
|
||||
|
||||
if Input.is_action_pressed("move_down"):
|
||||
pass # lmanley: todo reimplement platforms
|
||||
else:
|
||||
self.jump()
|
||||
self.current_jumps = self.extra_jumps
|
||||
|
||||
elif self.current_jumps > 0:
|
||||
self.jump()
|
||||
self.spawn_jump_platform()
|
||||
self.current_jumps -= 1
|
||||
|
||||
func jump() -> void:
|
||||
self.motion.y = self.BASE_JUMP_HEIGHT * self.default_jump_height
|
||||
|
||||
func spawn_jump_platform() -> void:
|
||||
self._play_audio(sword_sound)
|
||||
var platform = self.jump_platform.instantiate()
|
||||
self.get_parent().add_child(platform)
|
||||
platform.position = Vector2(self.position.x, self.position.y + 4)
|
||||
|
||||
func _animation_process(_delta: float) -> void:
|
||||
|
||||
if animation_player is PlayerAnimationPlayer:
|
||||
if get_global_mouse_position().x < global_position.x:
|
||||
self.animation_player.set_direction(Vector2.LEFT)
|
||||
else:
|
||||
self.animation_player.set_direction(Vector2.RIGHT)
|
||||
|
||||
if not self.is_on_floor():
|
||||
self.animation_player.safe_play("jump")
|
||||
elif abs(self.motion.x) > 0:
|
||||
self.animation_player.safe_play("walk")
|
||||
else:
|
||||
self.animation_player.safe_play("idle")
|
||||
|
||||
func get_currently_equiped_node() -> Equipment:
|
||||
return self.equipment_node.get_node_or_null(self.currently_equiped)
|
||||
|
||||
func equip(equipment_id: String) -> void:
|
||||
if equipment_id == self.currently_equiped:
|
||||
self.switch_sheath()
|
||||
else:
|
||||
var current = self.get_currently_equiped_node()
|
||||
if not current.is_sheathed():
|
||||
current.toggle_sheath()
|
||||
|
||||
currently_equiped = equipment_id
|
||||
current = self.get_currently_equiped_node()
|
||||
if current.is_sheathed():
|
||||
current.toggle_sheath()
|
||||
|
||||
func add_item(equiment_id: String) -> void:
|
||||
var item = load("%s/%s.tscn" % [equipment_dir, equiment_id]).instantiate()
|
||||
item.name = equiment_id
|
||||
equipment_node.add_child(item)
|
12
scripts/player_animation.gd
Normal file
12
scripts/player_animation.gd
Normal file
@ -0,0 +1,12 @@
|
||||
class_name PlayerAnimationPlayer
|
||||
extends AnimationPlayer
|
||||
|
||||
@export
|
||||
var sprite: Sprite2D
|
||||
|
||||
func set_direction(dir: Vector2) -> void:
|
||||
self.sprite.flip_h = dir == Vector2.LEFT
|
||||
|
||||
func safe_play(animation: String) -> void:
|
||||
if self.current_animation != animation:
|
||||
self.play(animation)
|
119
scripts/saving.gd
Normal file
119
scripts/saving.gd
Normal file
@ -0,0 +1,119 @@
|
||||
extends Node
|
||||
|
||||
const SAVE_PATH = "res://save_raw.yaml"
|
||||
const CONFIG_PATH = "res://config.cfg"
|
||||
|
||||
var _config_file = ConfigFile.new()
|
||||
|
||||
const RUN_PATH = "user://run.save"
|
||||
const SAVE_PROGRESS = "user://progress.save"
|
||||
|
||||
var _settings = {
|
||||
"audio": {
|
||||
"mute": "false"
|
||||
}
|
||||
}
|
||||
|
||||
var _game_progress = {
|
||||
"upgrade_points" : "0",
|
||||
"equipment" : ["saber"],
|
||||
"equiped" : "saber",
|
||||
"actions" :
|
||||
{
|
||||
"jump" : 1
|
||||
}
|
||||
}
|
||||
|
||||
func _ready():
|
||||
if !FileAccess.file_exists(SAVE_PROGRESS):
|
||||
save_settings()
|
||||
else:
|
||||
load_settings()
|
||||
|
||||
|
||||
func load_json(path):
|
||||
var file = FileAccess.open(path, FileAccess.READ)
|
||||
var tmp_text = file.get_as_text()
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(tmp_text)
|
||||
var data = test_json_conv.get_data()
|
||||
return data
|
||||
|
||||
func write_json(path, data):
|
||||
var file = FileAccess.open(path, FileAccess.WRITE)
|
||||
file.store_string(JSON.stringify(data))
|
||||
|
||||
func get_run():
|
||||
if(FileAccess.file_exists(RUN_PATH)):
|
||||
var _run_file = FileAccess.open(RUN_PATH, FileAccess.READ)
|
||||
var run_value = _run_file.get_64()
|
||||
return run_value
|
||||
else:
|
||||
return 0
|
||||
|
||||
func add_run():
|
||||
var currentRun = get_run()
|
||||
currentRun += 1
|
||||
var _run_file = FileAccess.open(RUN_PATH, FileAccess.WRITE)
|
||||
_run_file.store_64(currentRun)
|
||||
return currentRun
|
||||
|
||||
|
||||
func save_progress():
|
||||
write_json(SAVE_PROGRESS, _game_progress)
|
||||
|
||||
func get_upgrade_points():
|
||||
if "upgrade_points" in _game_progress:
|
||||
return int(_game_progress["upgrade_points"])
|
||||
else:
|
||||
return 0
|
||||
|
||||
func change_upgrade_points(pts):
|
||||
_game_progress["upgrade_points"] = int(_game_progress["upgrade_points"]) + pts
|
||||
|
||||
func get_equipment():
|
||||
return _game_progress['equipment']
|
||||
|
||||
func get_equiped():
|
||||
return _game_progress['equiped']
|
||||
|
||||
func set_equiped(equip):
|
||||
_game_progress['equiped'] = equip
|
||||
save_progress()
|
||||
|
||||
func unlock_equipment(equip):
|
||||
_game_progress['equipment'].append(equip)
|
||||
save_progress()
|
||||
|
||||
|
||||
func get_actions():
|
||||
var actions = []
|
||||
for action in _game_progress['actions']:
|
||||
actions.append(action)
|
||||
return actions
|
||||
|
||||
func get_action_value(action):
|
||||
return _game_progress['actions'][action]
|
||||
|
||||
func set_action_value(action, value):
|
||||
_game_progress['actions'][action] = value
|
||||
save_progress()
|
||||
|
||||
|
||||
func save_settings():
|
||||
for section in _settings.keys():
|
||||
for key in _settings[section]:
|
||||
_config_file.set_value(section, key, _settings[section][key])
|
||||
_config_file.save(CONFIG_PATH)
|
||||
|
||||
func load_settings():
|
||||
var error = _config_file.load(CONFIG_PATH)
|
||||
if error != OK:
|
||||
print("Failed to load config file. Error: %s" % error)
|
||||
return -1
|
||||
|
||||
for section in _settings.keys():
|
||||
for key in _settings[section]:
|
||||
var val = _config_file.get_value(section, key, null)
|
||||
_settings[section][key] = val
|
||||
|
65
scripts/title_screen.gd
Normal file
65
scripts/title_screen.gd
Normal file
@ -0,0 +1,65 @@
|
||||
extends Control
|
||||
|
||||
@export
|
||||
var music: AudioStream
|
||||
|
||||
@export
|
||||
var new_game_scene: PackedScene
|
||||
|
||||
var fade_to: PackedScene
|
||||
|
||||
func _ready():
|
||||
MusicPlayer.stop()
|
||||
MusicPlayer.stream = music
|
||||
MusicPlayer.volume_db = 0
|
||||
MusicPlayer.play()
|
||||
$Fader.modulate.a = 1
|
||||
$CreditsMenu.hide()
|
||||
|
||||
$"New Game".connect("button_down",Callable(self,"new_game"))
|
||||
$Credits.connect("button_down",Callable(self,"show_credits"))
|
||||
$Quit.connect("button_down",Callable(self,"on_quit_down"))
|
||||
|
||||
fade_out(3, 1, -1)
|
||||
|
||||
func new_game():
|
||||
SaveManager.add_run()
|
||||
fade_to = new_game_scene
|
||||
fade_out(3, -80)
|
||||
|
||||
func show_credits():
|
||||
$CreditsMenu.show()
|
||||
|
||||
func on_quit_down():
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
var timePassed = 0 #Current amount of time spend displaying te
|
||||
const CHECK_LENGTH = 0.05 #Interval to check for updates
|
||||
var timeNeeded = 0 #Time that it takes to display the text
|
||||
var fadeTimer #Timer object
|
||||
|
||||
var multiplier = 1
|
||||
var adder = 0
|
||||
func fade_out(seconds, multi = 1, add = 0):
|
||||
multiplier = multi
|
||||
adder = add
|
||||
timeNeeded = seconds
|
||||
timePassed = 0
|
||||
if(!fadeTimer):
|
||||
fadeTimer = Timer.new()
|
||||
add_child(fadeTimer)
|
||||
fadeTimer.connect("timeout",Callable(self,"on_fade_timeout"))
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
|
||||
func on_fade_timeout():
|
||||
timePassed += CHECK_LENGTH
|
||||
MusicPlayer.volume_db = multiplier * (timePassed/timeNeeded)
|
||||
$Fader.modulate.a = abs(timePassed/timeNeeded + adder)
|
||||
if(timePassed >= timeNeeded):
|
||||
fadeTimer.stop()
|
||||
if($Fader.modulate.a > 0.5):
|
||||
get_tree().change_scene_to_packed(fade_to)
|
||||
else:
|
||||
fadeTimer.start(CHECK_LENGTH)
|
||||
pass
|
Reference in New Issue
Block a user