massive work towards godot 4

This commit is contained in:
2023-02-01 04:43:50 -05:00
parent 42259a89ed
commit 5dac6ced93
484 changed files with 5935 additions and 5084 deletions

271
scripts/Console.gd Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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()

View 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()

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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)

View 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
View 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
View 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