commit 2b60269c1bd36029575524c9e8a3dc218ce91059 Author: Kienan Stewart Date: Sun Apr 30 20:23:43 2023 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26bd211 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*~ +*.import +*.aup3-wal diff --git a/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf b/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf new file mode 100644 index 0000000..e63b764 Binary files /dev/null and b/Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf differ diff --git a/Blah.gd b/Blah.gd new file mode 100644 index 0000000..d93ef92 --- /dev/null +++ b/Blah.gd @@ -0,0 +1,165 @@ +extends Node + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" +const camera_drag_threshold = 0.2 +var camera_drag_start = null + +# Called when the node enters the scene tree for the first time. +func _ready(): + # For non-game PRNG, eg. sounds + randomize() + + var c = get_tree().get_nodes_in_group("character")[0] + c.connect("character_movement", self, "_on_character_movement") + c.connect("storage_changed", self, "_on_character_storage") + get_node("UiLayer/PanelContainer/VBoxContainer/Capacity").set_text("Cargo %s" % c.capacity_str()) + var g = get_node("Game") + g.connect("dropoff_score_changed", self, "_on_dropoff_score_changed") + g.connect("game_ended", self, "_on_game_ended") + + var d = get_node("UiLayer/GameEndDialog") + d.find_node("Continue").connect("pressed", self, "_on_continue") + d.find_node("Restart").connect("pressed", self, "_on_restart") + d.find_node("New").connect("pressed", self, "_on_new") + d.find_node("Quit").connect("pressed", self, "_on_quit") + d.find_node("LevelCode").set_text(g.get_levelcode()) + +func _on_character_movement(value): + get_node("UiLayer/PanelContainer/VBoxContainer/Moved").set_text("Moved: %d" % value) + get_node("UiLayer/PanelContainer/VBoxContainer/Score").set_text("Total score: %d" % get_node("Game").get_score()) + +func _on_character_storage(value): + var c = get_tree().get_nodes_in_group("character")[0] + get_node("UiLayer/PanelContainer/VBoxContainer/Capacity").set_text("Cargo %s" % c.capacity_str()) + +func _on_dropoff_score_changed(value): + get_node("UiLayer/PanelContainer/VBoxContainer/Supplied").set_text("Supplied score: %d" % value[0]) + get_node("UiLayer/PanelContainer/VBoxContainer/Delivered").set_text("Delivered: %d" % value[1]) + get_node("UiLayer/PanelContainer/VBoxContainer/Score").set_text("Total score: %d" % get_node("Game").get_score()) + +func _on_game_ended(): + get_tree().paused = true + var g = get_node("Game") + var d = get_node("UiLayer/GameEndDialog") + var score_data = g.get_supplied() + d.find_node("Score").set_bbcode("[center]Score: %d[/center]" % g.get_score()) + d.find_node("Supplied").set_bbcode("%d / %d supplied\n%d points" % score_data.slice(0, 2)) + d.find_node("Moved").set_bbcode("%d moves" % g.get_moves()) + d.find_node("Delivered").set_bbcode("%d delivered" % score_data[3]) + var path = "" + for n in g.get_node("Character").path_history: + path += "%s -> " % n.node_name + if path.length() > 4: + path = path.substr(0, path.length()-4) + d.find_node("Path").set_bbcode("[center]Path[/center]\n%s" % path) + d.find_node("Continue").set_visible(score_data[0] < score_data[1]) + if !score_data[0] < score_data[1]: + get_node("UiAudio").set_stream(load("res://resources/untitled.wav")) + get_node("UiAudio").play() + d.find_node("LevelCode").set_text(g.get_levelcode()) + d.set_exclusive(true) + d.popup_centered() + +func _on_continue(): + get_node("UiLayer/GameEndDialog").set_visible(false) + get_tree().paused = false + +func _on_restart(): + get_node("Game").restart(get_node("Game").params) + get_node("Camera2D").set_zoom(Vector2(1,1)) + get_node("Camera2D").set_offset(Vector2(512, 300)) + self._on_continue() + + # Reset UI + _on_character_movement(0) + _on_character_storage(0) + _on_dropoff_score_changed([0, 0, 0]) + # From _ready + var c = get_tree().get_nodes_in_group("character")[0] + c.connect("character_movement", self, "_on_character_movement") + c.connect("storage_changed", self, "_on_character_storage") + get_node("UiLayer/PanelContainer/VBoxContainer/Capacity").set_text("Cargo %s" % c.capacity_str()) + var g = get_node("Game") + g.connect("dropoff_score_changed", self, "_on_dropoff_score_changed") + g.connect("game_ended", self, "_on_game_ended") + +func _on_new(): + # Show the level setting popup + get_node("UiLayer/GameEndDialog").set_visible(false) + get_node("UiLayer/NewLevelDialog").set_exclusive(true) + get_node("UiLayer/NewLevelDialog").popup_centered() + +func _on_quit(): + get_tree().quit() + +func _unhandled_input(event): + if event is InputEventKey and event.pressed and !event.echo: + # Quit on Escape press. + if event.scancode == KEY_ESCAPE: + var data = get_node("Game").get_supplied() + var ended = data[0] >= data[1] + if get_node("UiLayer/GameEndDialog").visible && !ended: + self._on_continue() + else: + self._on_game_ended() + if event is InputEventMouseButton and event.pressed: + var zoom = get_node("Camera2D").get_zoom() + if event.button_index == BUTTON_WHEEL_UP: + zoom -= Vector2(.1, .1) + get_node("Camera2D").set_zoom(zoom) + elif event.button_index == BUTTON_WHEEL_DOWN: + zoom += Vector2(.1, .1) + get_node("Camera2D").set_zoom(zoom) + if event.button_index == BUTTON_RIGHT: + self.camera_drag_start = get_viewport().get_mouse_position() + if event is InputEventMouseButton and event.button_index == BUTTON_RIGHT: + if !event.pressed and self.camera_drag_start != null: + self.camera_drag_start = null + +func _process(delta): + if self.camera_drag_start != null: + var pos = get_viewport().get_mouse_position() + var pos_delta = self.camera_drag_start - pos + get_node("Camera2D").set_offset( + get_node("Camera2D").get_offset() + pos_delta + ) + self.camera_drag_start = pos + +func _on_NewLevelDialog_start_pressed(params): + get_node("UiLayer/NewLevelDialog").set_visible(false) + get_node("Camera2D").set_zoom(Vector2(1,1)) + get_node("Camera2D").set_offset(Vector2(512, 300)) + get_node("Game").restart(params) + self._on_continue() + + # Reset UI + _on_character_movement(0) + _on_character_storage(0) + _on_dropoff_score_changed([0, 0, 0]) + # From _ready + var c = get_tree().get_nodes_in_group("character")[0] + c.connect("character_movement", self, "_on_character_movement") + c.connect("storage_changed", self, "_on_character_storage") + get_node("UiLayer/PanelContainer/VBoxContainer/Capacity").set_text("Cargo %s" % c.capacity_str()) + var g = get_node("Game") + g.connect("dropoff_score_changed", self, "_on_dropoff_score_changed") + g.connect("game_ended", self, "_on_game_ended") + + +func _on_Hide_toggled(button_pressed): + get_node("UiLayer/PanelContainer/VBoxContainer").set_visible(!button_pressed) + var size = get_node("UiLayer/PanelContainer").get_size() + if button_pressed: + size.y = 50 + get_node("UiLayer/PanelContainer").set_size(size) + else: + size.y = 600 + get_node("UiLayer/PanelContainer").set_size(size) + + +func _on_ResetCamera_pressed(): + get_node("Camera2D").set_offset(Vector2(512, 300)) + get_node("Camera2D").set_zoom(Vector2(1, 1)) diff --git a/Blah.tscn b/Blah.tscn new file mode 100644 index 0000000..956b8a9 --- /dev/null +++ b/Blah.tscn @@ -0,0 +1,130 @@ +[gd_scene load_steps=7 format=2] + +[ext_resource path="res://Game.tscn" type="PackedScene" id=1] +[ext_resource path="res://Blah.gd" type="Script" id=2] +[ext_resource path="res://GameEnd.tscn" type="PackedScene" id=3] +[ext_resource path="res://resources/UI Theme.tres" type="Theme" id=4] +[ext_resource path="res://resources/NewLevel.tscn" type="PackedScene" id=5] +[ext_resource path="res://resources/Background.tscn" type="PackedScene" id=6] + +[node name="Deliver" type="Node"] +pause_mode = 2 +script = ExtResource( 2 ) + +[node name="Game" parent="." instance=ExtResource( 1 )] +pause_mode = 1 + +[node name="UiAudio" type="AudioStreamPlayer" parent="."] +pause_mode = 2 + +[node name="Camera2D" type="Camera2D" parent="."] +offset = Vector2( 512, 300 ) +current = true + +[node name="BgLayer" type="CanvasLayer" parent="."] +layer = -1 + +[node name="Background" parent="BgLayer" instance=ExtResource( 6 )] + +[node name="UiLayer" type="CanvasLayer" parent="."] + +[node name="PanelContainer" type="Panel" parent="UiLayer"] +margin_left = 808.0 +margin_right = 1023.0 +margin_bottom = 597.0 + +[node name="Hide" type="CheckButton" parent="UiLayer/PanelContainer"] +margin_left = 7.0 +margin_top = 7.0 +margin_right = 147.0 +margin_bottom = 47.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +text = "Minimize" + +[node name="VBoxContainer" type="VBoxContainer" parent="UiLayer/PanelContainer"] +margin_left = 7.0 +margin_top = 50.0 +margin_right = 208.0 +margin_bottom = 590.0 + +[node name="Delivered" type="Label" parent="UiLayer/PanelContainer/VBoxContainer"] +modulate = Color( 0.576471, 1, 0.572549, 1 ) +margin_right = 201.0 +margin_bottom = 15.0 +theme = ExtResource( 4 ) +text = "Delivered: 0" + +[node name="Supplied" type="Label" parent="UiLayer/PanelContainer/VBoxContainer"] +modulate = Color( 0.576471, 1, 0.572549, 1 ) +margin_top = 19.0 +margin_right = 201.0 +margin_bottom = 34.0 +theme = ExtResource( 4 ) +text = "Supplied score: 0" + +[node name="Moved" type="Label" parent="UiLayer/PanelContainer/VBoxContainer"] +modulate = Color( 1, 0.545098, 0.545098, 1 ) +margin_top = 38.0 +margin_right = 201.0 +margin_bottom = 53.0 +theme = ExtResource( 4 ) +text = "Moved: 0" + +[node name="Score" type="Label" parent="UiLayer/PanelContainer/VBoxContainer"] +margin_top = 57.0 +margin_right = 201.0 +margin_bottom = 72.0 +theme = ExtResource( 4 ) +text = "Total score: 0" + +[node name="HSeparator" type="HSeparator" parent="UiLayer/PanelContainer/VBoxContainer"] +margin_top = 76.0 +margin_right = 201.0 +margin_bottom = 80.0 + +[node name="Capacity" type="Label" parent="UiLayer/PanelContainer/VBoxContainer"] +margin_top = 84.0 +margin_right = 201.0 +margin_bottom = 99.0 +theme = ExtResource( 4 ) +text = "Cargo: 0 / 10" + +[node name="HSeparator2" type="HSeparator" parent="UiLayer/PanelContainer/VBoxContainer"] +margin_top = 103.0 +margin_right = 201.0 +margin_bottom = 107.0 + +[node name="Label" type="Label" parent="UiLayer/PanelContainer/VBoxContainer"] +margin_top = 111.0 +margin_right = 201.0 +margin_bottom = 486.0 +theme = ExtResource( 4 ) +text = " +Pick up cargo from uparrrow, and deliver to downarrow. + +Paths have a cost to use them, try to minimize your movement cost to maximize your score. + +Deliver cargo to all destinations to end game. + +Move: double click on selected node +Move node: click and hold to drag +Hold right-click and drag to pan around. +Pan View: right-click + drag +Zoom: scroll wheel +Menu: Escape" +autowrap = true + +[node name="ResetCamera" type="Button" parent="UiLayer/PanelContainer/VBoxContainer"] +margin_top = 490.0 +margin_right = 201.0 +margin_bottom = 510.0 +text = "Reset Camera" + +[node name="GameEndDialog" parent="UiLayer" instance=ExtResource( 3 )] + +[node name="NewLevelDialog" parent="UiLayer" instance=ExtResource( 5 )] + +[connection signal="toggled" from="UiLayer/PanelContainer/Hide" to="." method="_on_Hide_toggled"] +[connection signal="pressed" from="UiLayer/PanelContainer/VBoxContainer/ResetCamera" to="." method="_on_ResetCamera_pressed"] +[connection signal="start_pressed" from="UiLayer/NewLevelDialog" to="." method="_on_NewLevelDialog_start_pressed"] diff --git a/Character.gd b/Character.gd new file mode 100644 index 0000000..93c2eb6 --- /dev/null +++ b/Character.gd @@ -0,0 +1,121 @@ +extends Node2D + +signal character_movement +signal arrived_at +signal storage_changed + +var location = null +var offset = Vector2(0, 16) +var destination = null +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +var target = null +var links = {} + +var capacity = 10 +var stored = 0 +var path_history = [] +var movement_cost = 0 + +func capacity_str(): + if is_inf(self.capacity): + return "%d / ∞" % self.stored + return "%d / %d" % [self.stored, self.capacity] + +func set_location(n, teleport = false): + assert(n != null) + self.path_history.append(n) + if teleport: + self.position = n.get_position() + self.offset + else: + self.destination = n.get_position() + self.offset + if self.location != null: + self.movement_cost += self.links[n].weight + emit_signal("character_movement", self.movement_cost) + get_node("Audio").play() + self.location = n + self.clear_links() + self.clear_target() + self.target = null; + # Highlight links connected to this one that are traversable by the player + for link in get_tree().get_nodes_in_group("links"): + if link.start == n or link.end == n: + link.get_node("Line").set_default_color(Color("98f9ac")) + var target = link.start + if link.start == n: + target = link.end + self.links[target] = link + else: + link.get_node("Line").set_default_color(Color("98a8f9")) + # print("Links: ", self.links) + + +func clear_links(): + for link in self.links: + self.links[self.target].get_node("Line").set_default_color(Color("98f9ac")) + self.links[self.target].get_node("Label").remove_color_override("default_color") + self.links[self.target].get_node("Label").set_scale(Vector2(1, 1)) + self.links = {} + +func clear_target(): + if self.target != null && self.target in self.links: + self.links[self.target].get_node("Line").set_default_color(Color("98f9ac")) + self.links[self.target].get_node("Label").remove_color_override("default_color") + self.links[self.target].get_node("Label").set_scale(Vector2(1, 1)) + self.target = null + +func set_target(node): + self.clear_target() + self.target = node + self.links[self.target].get_node("Line").set_default_color(Color("0fff2c")) + self.links[self.target].get_node("Label").add_color_override("default_color", Color("ff00e0")) + self.links[self.target].get_node("Label").set_scale(Vector2(2, 2)) + var audio = get_tree().get_current_scene().find_node("UiAudio") + if audio: + audio.set_stream(load("res://resources/Tap.wav")) + audio.play() + +func can_move(to): + return self.destination == null && self.links.has(to) + +func pickup(amount): + self.stored += amount + emit_signal("storage_changed", self.stored) + self._on_storage_changed(self.stored) + +func dropoff(amount): + self.stored -= amount + emit_signal("storage_changed", self.stored) + self._on_storage_changed(self.stored) + +func _on_storage_changed(value): + var ratio = float(self.stored) / float(self.capacity) + get_node("Box3").set_visible(ratio >= 0.75) + get_node("Box2").set_visible(ratio >= 0.50) + get_node("Box").set_visible(ratio > 0) + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + if destination != null: + var p = self.get_position().move_toward(self.destination, delta * 500) + self.set_position(p) + if p.distance_to(self.destination) < 5: + self.set_position(self.destination) + self.destination = null + get_node("Audio").stop() + emit_signal("arrived_at", self.location) + if destination == null and location != null: + var p = get_global_mouse_position() + var distance = null + var closest = null + for node in location.peers: + if !is_instance_valid(node): + continue + var d = node.get_position().distance_to(p) + if distance == null or d < distance: + distance = d + closest = node + if self.target != closest: + self.set_target(closest) diff --git a/Character.tscn b/Character.tscn new file mode 100644 index 0000000..1c4dc7f --- /dev/null +++ b/Character.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://resources/character.png" type="Texture" id=1] +[ext_resource path="res://Character.gd" type="Script" id=2] +[ext_resource path="res://resources/box.png" type="Texture" id=3] +[ext_resource path="res://resources/Ratchet.wav" type="AudioStream" id=4] + +[node name="Character" type="Node2D"] +script = ExtResource( 2 ) + +[node name="Sprite" type="Sprite" parent="."] +texture = ExtResource( 1 ) + +[node name="Box" type="Sprite" parent="."] +visible = false +position = Vector2( 15, 4 ) +scale = Vector2( 0.5, 0.5 ) +texture = ExtResource( 3 ) + +[node name="Box2" type="Sprite" parent="."] +visible = false +position = Vector2( 18, -2 ) +scale = Vector2( 0.5, 0.5 ) +texture = ExtResource( 3 ) + +[node name="Box3" type="Sprite" parent="."] +visible = false +position = Vector2( 15, -9 ) +scale = Vector2( 0.5, 0.5 ) +z_index = -1 +texture = ExtResource( 3 ) + +[node name="Audio" type="AudioStreamPlayer" parent="."] +stream = ExtResource( 4 ) diff --git a/DetailFont.tres b/DetailFont.tres new file mode 100644 index 0000000..6ce62d0 --- /dev/null +++ b/DetailFont.tres @@ -0,0 +1,11 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[sub_resource type="DynamicFontData" id=1] +hinting = 1 +font_path = "res://Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf" + +[resource] +size = 18 +outline_size = 1 +outline_color = Color( 0.262745, 0.227451, 0.227451, 1 ) +font_data = SubResource( 1 ) diff --git a/DetailFontTheme.tres b/DetailFontTheme.tres new file mode 100644 index 0000000..f1fa978 --- /dev/null +++ b/DetailFontTheme.tres @@ -0,0 +1,6 @@ +[gd_resource type="Theme" load_steps=2 format=2] + +[ext_resource path="res://DetailFont.tres" type="DynamicFont" id=1] + +[resource] +default_font = ExtResource( 1 ) diff --git a/DropOff.gd b/DropOff.gd new file mode 100644 index 0000000..100c942 --- /dev/null +++ b/DropOff.gd @@ -0,0 +1,57 @@ +extends "res://Node.gd" + +var full_sounds = [ + preload("res://resources/Coins1.wav"), + preload("res://resources/Coins2.wav"), + preload("res://resources/Thanks.wav"), + preload("res://resources/YoureTheBest.wav"), +] +var dropoff_sounds = [ + preload("res://resources/Items.wav"), + preload("res://resources/Thunk.wav"), + preload("res://resources/Scribble.wav"), + preload("res://resources/Paper2.wav"), +] + +func _init(): + self.capacity = 1 + self.value = 1 + self.texture_resource = "res://resources/dropoff.png" + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +# Called when the node enters the scene tree for the first time. +func _ready(): + self.add_to_group("dropoff") + +func receive(amount): + if amount <= 0: + return + self.stored += amount + self.update_help(true) + +func update_help(audio = false): + get_node("Help").set_text("{} / {}\n{}".format([self.stored, self.capacity, self.value], "{}")) + if self.stored < self.capacity: + get_node("Help").set_tooltip("Drop off {} more to satistify delivery requirements.\nWhen satisfied {} will be added to your score".format([self.capacity - self.stored, self.value], "{}")) + else: + get_node("Help").set_tooltip("Fully supplied") + if self.stored >= self.capacity: + get_node("Sprite").set_modulate(Color("00ea81")) + get_node("Help").set_self_modulate(Color("00ea81")) + if audio: + get_node("Audio").set_stream( + self.full_sounds[randi() % self.full_sounds.size()] + ) + get_node("Audio").play() + else: + if audio: + get_node("Audio").set_stream( + self.dropoff_sounds[randi() % self.dropoff_sounds.size()] + ) + get_node("Audio").play() +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/DropOff.tscn b/DropOff.tscn new file mode 100644 index 0000000..28c3d8a --- /dev/null +++ b/DropOff.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Node.tscn" type="PackedScene" id=1] +[ext_resource path="res://DropOff.gd" type="Script" id=2] + +[node name="DropOff" instance=ExtResource( 1 )] +script = ExtResource( 2 ) + +[node name="Sprite" parent="." index="0"] +texture = null diff --git a/Empty.gd b/Empty.gd new file mode 100644 index 0000000..0ec0845 --- /dev/null +++ b/Empty.gd @@ -0,0 +1,18 @@ +extends "res://Node.gd" + +func _init(): + self.texture_resource = "res://resources/empty.png" +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + get_node("Help").set_tooltip("Empty spaces neither take nor give cargo") + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/Empty.tscn b/Empty.tscn new file mode 100644 index 0000000..6452944 --- /dev/null +++ b/Empty.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Node.tscn" type="PackedScene" id=1] +[ext_resource path="res://Empty.gd" type="Script" id=2] + +[node name="Empty" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/Game.gd b/Game.gd new file mode 100644 index 0000000..aaee9e7 --- /dev/null +++ b/Game.gd @@ -0,0 +1,387 @@ +extends Node2D + +signal dropoff_score_changed +signal game_ended +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +const Dropoff = preload("DropOff.tscn") +const Pickup = preload("Pickup.tscn") +const Start = preload("Start.tscn") +const Empty = preload("Empty.tscn") +const Link = preload("Link.tscn") +const Character = preload("Character.tscn") + +# Configuration parameters +const default_params = { + 'seed': 'ld53', + 'node_count': 12, + 'cargo_availability': 2.0, + 'pickup_count_range': Vector2(1, 2), + 'empty_node_chance': 15, + 'dropoff_value_range': Vector2(1, 3), + 'dropoff_capacity_range': Vector2(1, 3), + 'link_cost_range': Vector2(1, 2), +} + +static func easy_params(): + var p = default_params.duplicate() + p.cargo_availability = INF; + p.pickup_count_range = Vector2(1, 1) + p.node_count = 6 + p.dropoff_capacity_range = Vector2(1, 2) + p.link_cost_range = Vector2(1, 1) + return p + +static func medium_params(): + var p = default_params.duplicate() + return p + +static func hard_params(): + var p = default_params.duplicate() + p.pickup_count_range = Vector2(1, 3) + p.cargo_availability = 1.0 + p.node_count = 24 + p.dropoff_capacity_range = Vector2(1, 5) + p.link_cost_range = Vector2(1, 3) + return p + +var params = null +var random = RandomNumberGenerator.new() + +func get_levelcode(): + return Marshalls.variant_to_base64(self.params) + +static func parse_levelcode(code): + var p = Marshalls.base64_to_variant(code) + # Make sure we have the keys present in the default params + # Extraneous keys are ignored + if p != null and !p.has_all(default_params.keys()): + return null + return p + +func restart(new_params = null): + if new_params: + self.params = new_params + for n in self.get_children(): + n.free() + self._init(self.params['seed']) + self.params = new_params + self._ready() + +func _init(random_seed: String = "ld53"): + self.random = RandomNumberGenerator.new() + print("Seed: %s" % random_seed) + self.random.set_seed(hash(random_seed)) + +func random_position(): + var bottom = self.random.randi_range(0, 1) + var right = self.random.randi_range(0, 1) + var x_range = Vector2( + 32 + (right * 512), + 1024 + ((right - 1) * 512) + ) + var y_range = Vector2( + 32 + (bottom * 300), + 600 + ((bottom - 1) * 300) + ) + return Vector2( + self.random.randi_range(x_range.x, x_range.y), + self.random.randi_range(y_range.x, y_range.y) + ) + +func indexed_position(index): + # Positions are on a grid + var row_count = 3 + var col_count = 4 + if self.params.node_count == 24: + col_count = 6 + row_count = 4 + if self.params.node_count == 36: + col_count = 6 + row_count = 6 + var row = index % row_count + var col = index / row_count + var position = Vector2( + (1024 / col_count) * col, + (600 / row_count) * row + ) + var jitter_value = 64 + var jitter = Vector2( + self.random.randi_range(-jitter_value, jitter_value), + self.random.randi_range(-jitter_value, jitter_value) + ) + return position + Vector2(64, 64) + jitter + +func distance_to_closest_node(position, node): + var closest = 65000 + for n in get_tree().get_nodes_in_group("nodes"): + if n == node: + continue + var distance = n.get_position().distance_to(position) + if distance < closest: + closest = distance + return closest + +func link_nodes(n1, n2): + assert(n1 != null) + assert(n2 != null) + var n = Link.instance() + n.set_ends(n1, n2) + n1.peers.append(n2) + n2.peers.append(n1) + n1.remove_from_group("unlinked") + n2.remove_from_group("unlinked") + add_child(n) + # print("Linked ", n1, " to ", n2) + # print("\tN1 peers: ", n1.peers) + # print("\tN2 peers: ", n2.peers) + return n + +func reconstruct_path(cameFrom, current): + var total_path = [] + while cameFrom.has(current): + current = cameFrom[current] + total_path.push_front(current) + return total_path + +func find_path(start, destination): + var openSet = [start] + var from = {} + var gScore = {} + var fScore = {} + fScore[start] = 1 + while openSet.size() > 0: + print(openSet) + var current = null + for n in openSet: + if !fScore.has(n): + fScore[n] = INF + if current == null: + current = n + else: + if fScore[n] < fScore[current]: + current = n + if current == destination: + return reconstruct_path(from, current) + openSet.remove(openSet.find(current)) + + for n in current.peers: + if !gScore.has(current): + gScore[current] = INF + var tentative_score = gScore[current] + 1 + if gScore.has(n) && tentative_score < gScore[n]: + from[n] = current + fScore[n] = tentative_score + 100 + gScore[n] = tentative_score + if openSet.find(n) == -1: + openSet.append(n) + return null + +func get_reachable_nodes(start): + var nodes_in_starting_graph = [start] + start.peers + var nodes_to_check = start.peers + var nodes_checked = [start] + while nodes_to_check.size() > 0: + var checking_node = nodes_to_check.pop_front() + #print("Checking: ", checking_node) + #print("\tPeers", checking_node.peers) + if nodes_checked.find(checking_node) != -1: + continue + for nx in checking_node.peers: + if nodes_checked.find(nx) == -1: + nodes_to_check.append(nx) + if nodes_in_starting_graph.find(checking_node) == -1: + nodes_in_starting_graph.append(checking_node) + nodes_checked.append(checking_node) + return nodes_in_starting_graph + +# Called when the node enters the scene tree for the first time. +func _ready(): + if self.params == null: + print("Resetting params") + self.params = easy_params() + var nodes = 0 + var n = null + # Add start + n = Start.instance() + n.set_position(Vector2(512 - 32, 300-32)) + n.add_to_group("unlinked") + n.name_from_index(nodes) + self.add_child(n) + var start = n + nodes += 1 + + # Add pickup(s) + var count = self.random.randi_range(self.params.pickup_count_range.x, self.params.pickup_count_range.y) + while count > 0: + n = Pickup.instance() + n.add_to_group("unlinked") + n.name_from_index(nodes) + self.add_child(n) + count -= 1 + nodes += 1 + + # Add other node(s) + var total_to_dropoff = 0 + while nodes < self.params.node_count + 1: + if self.random.randi_range(0, 99) < self.params.empty_node_chance: + n = Empty.instance() + else: + n = Dropoff.instance() + n.capacity = self.random.randi_range(self.params.dropoff_capacity_range.x, self.params.dropoff_capacity_range.y) + n.value = self.random.randi_range(self.params.dropoff_value_range.x, self.params.dropoff_value_range.y) + total_to_dropoff += n.capacity + n.add_to_group("unlinked") + n.name_from_index(nodes) + self.add_child(n) + print("Added node: ", n) + nodes += 1 + + # Distribute available cargo between dropoff points randomly when finite + # amount available. + if !is_inf(self.params.cargo_availability): + var cargo_available = total_to_dropoff * self.params.cargo_availability + for cargo_node in get_tree().get_nodes_in_group("pickup"): + var cargo_count = self.random.randi_range(1, cargo_available) + cargo_available -= cargo_count + cargo_node.set_stored(cargo_count) + if cargo_available > 0: + get_tree().get_nodes_in_group("pickup")[-1].add_stored(cargo_available) + + # Each node should have at least one link + var unlinked_nodes = get_tree().get_nodes_in_group("unlinked") + while unlinked_nodes.size() > 0: + var source = unlinked_nodes.pop_front() + var targets = get_tree().get_nodes_in_group("nodes") + var target = targets[self.random.randi_range(0, targets.size()-1)] + while target == source: + target = targets[self.random.randi_range(0, targets.size()-1)] + var link = link_nodes(source, target) + link.set_weight(self.random.randi_range( + self.params.link_cost_range.x, + self.params.link_cost_range.y + )) + + unlinked_nodes = get_tree().get_nodes_in_group("unlinked") + + # For each node, make sure we can reach the start node, merging + # any disjointed graphs + var nodes_in_starting_graph = get_reachable_nodes(start) + + print("Starting graph nodes: ", nodes_in_starting_graph) + for node in get_tree().get_nodes_in_group("nodes"): + if nodes_in_starting_graph.find(node) == -1: + print(node, " can't be reached from start") + var target = nodes_in_starting_graph[self.random.randi_range(0, nodes_in_starting_graph.size()-1)] + link_nodes(node, target) + nodes_in_starting_graph = get_reachable_nodes(start) + + # Set new node positions + # @TODO: Better (?) layout algorithm, eg. https://en.wikipedia.org/wiki/Graph_drawing + var x_range = Vector2(32, 1024-32) + var y_range = Vector2(32, 600-32) + var distance_threshold = 32 + var idx = 0 + for node in get_tree().get_nodes_in_group("nodes"): + if node.is_in_group("start"): + continue + var position = self.indexed_position(idx) + var tries = 0 + var closest = distance_to_closest_node(position, node) + # While the position is within a distance of another node, rechoose + while closest <= distance_threshold: + if closest == 0: + closest = 65000 + for n2 in get_tree().get_nodes_in_group("nodes"): + if n2 == node: + continue + var distance = n2.get_position().distance_to(position) + if distance < closest: + closest = distance + # print("Closest point to ", position, " ", closest) + tries += 1 + if tries % 10 == 0: + distance_threshold /= 2 + print("Reducing threshold for point ", node, " to ", distance_threshold) + position = self.random_position() + node.set_position(position) + # print("Placed node ", node, " after ", tries, " tries") + idx += 1 + + + + # Update link linepositions based on the node positions + for link in get_tree().get_nodes_in_group("links"): + link.redraw_line() + # @BUG It shouldn't be necessary to recalculate the peers + # For some reason, we lose the peer on the start node + if link.start == start: + start.peers.append(link.end) + if link.end == start: + start.peers.append(link.start) + + # Add player + n = Character.instance() + add_child(n) + n.add_to_group("character") + n.set_location(start, true) + n.connect("arrived_at", self, "on_character_arrival") + + +func on_character_arrival(node): + if node.is_in_group("dropoff"): + var max_delivery = node.capacity - node.stored + var max_avail = get_node("Character").stored + var delta = min(max_avail, max_delivery) + print("Dropoff %d to %s" % [delta, node]) + get_node("Character").dropoff(delta) + node.receive(delta) + # Recalculate dropoff score + var score = self.get_supplied() + var all_supplied = score[0] >= score[1] + emit_signal("dropoff_score_changed", [score[2], score[3]]) + if all_supplied: + emit_signal("game_ended") + elif node.is_in_group("pickup"): + var max_pickup = get_node("Character").capacity - get_node("Character").stored + var min_avail = node.stored + var delta = min(min_avail, max_pickup) + print("Pickup up %d from %s" % [delta, node]) + get_node("Character").pickup(delta) + node.drain(delta) + elif node.is_in_group("start"): + print("@TODO: Start") + +func get_moves(): + return get_node("Character").movement_cost + +func get_score(): + var data = get_supplied() + # Delivered + Supplied bonus - Movement + return data[2] + data[3] - get_moves() + +func get_supplied(): + # [nodes_done, nodes_total, earned_value, cargo_done, cargo_total] + var done = 0 + var dropoff_score = 0 + var cargo_done = 0 + var cargo_total = 0 + for n in get_tree().get_nodes_in_group("dropoff"): + cargo_total += n.capacity + cargo_done += n.stored + if n.stored >= n.capacity: + dropoff_score += n.value + done += 1 + return [ + done, + get_tree().get_nodes_in_group("dropoff").size(), + dropoff_score, + cargo_done, + cargo_total + ] + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/Game.tscn b/Game.tscn new file mode 100644 index 0000000..2994b5b --- /dev/null +++ b/Game.tscn @@ -0,0 +1,8 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://Game.gd" type="Script" id=1] + +[node name="Game" type="Node2D"] +script = ExtResource( 1 ) + +[connection signal="game_ended" from="." to="." method="_on_Game_game_ended"] diff --git a/GameEnd.tscn b/GameEnd.tscn new file mode 100644 index 0000000..0c798ad --- /dev/null +++ b/GameEnd.tscn @@ -0,0 +1,193 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://resources/building.png" type="Texture" id=1] +[ext_resource path="res://resources/moves.png" type="Texture" id=2] +[ext_resource path="res://DetailFontTheme.tres" type="Theme" id=3] +[ext_resource path="res://resources/UI Theme.tres" type="Theme" id=4] +[ext_resource path="res://resources/boxes.png" type="Texture" id=5] + +[node name="GameEndDialog" type="PopupDialog"] +margin_right = 497.0 +margin_bottom = 454.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_left = 9.0 +margin_top = 14.0 +margin_right = 487.0 +margin_bottom = 440.0 + +[node name="Score" type="RichTextLabel" parent="VBoxContainer"] +margin_right = 478.0 +margin_bottom = 18.0 +theme = ExtResource( 3 ) +bbcode_enabled = true +bbcode_text = "[center]Score: {}[/center]" +text = "Score: {}" +fit_content_height = true + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] +margin_top = 22.0 +margin_right = 478.0 +margin_bottom = 26.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 30.0 +margin_right = 478.0 +margin_bottom = 152.0 +alignment = 1 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"] +margin_right = 151.0 +margin_bottom = 122.0 +size_flags_horizontal = 3 + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/HBoxContainer/VBoxContainer"] +margin_left = 43.0 +margin_right = 107.0 +margin_bottom = 64.0 +size_flags_horizontal = 4 +size_flags_vertical = 0 +texture = ExtResource( 1 ) + +[node name="Supplied" type="RichTextLabel" parent="VBoxContainer/HBoxContainer/VBoxContainer"] +margin_top = 68.0 +margin_right = 151.0 +margin_bottom = 122.0 +theme = ExtResource( 3 ) +bbcode_enabled = true +bbcode_text = "{} / {} supplied +{} points " +text = "{} / {} supplied +{} points " +fit_content_height = true + +[node name="VSeparator2" type="VSeparator" parent="VBoxContainer/HBoxContainer"] +margin_left = 155.0 +margin_right = 159.0 +margin_bottom = 122.0 + +[node name="VBoxContainer2" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"] +margin_left = 163.0 +margin_right = 314.0 +margin_bottom = 122.0 +size_flags_horizontal = 3 + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] +margin_left = 43.0 +margin_right = 107.0 +margin_bottom = 64.0 +size_flags_horizontal = 4 +texture = ExtResource( 2 ) + +[node name="Moved" type="RichTextLabel" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] +margin_top = 68.0 +margin_right = 151.0 +margin_bottom = 86.0 +theme = ExtResource( 3 ) +bbcode_enabled = true +bbcode_text = "{} moves" +text = "{} moves" +fit_content_height = true + +[node name="VSeparator" type="VSeparator" parent="VBoxContainer/HBoxContainer"] +margin_left = 318.0 +margin_right = 322.0 +margin_bottom = 122.0 + +[node name="VBoxContainer3" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"] +margin_left = 326.0 +margin_right = 478.0 +margin_bottom = 122.0 +size_flags_horizontal = 3 + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/HBoxContainer/VBoxContainer3"] +margin_left = 44.0 +margin_right = 108.0 +margin_bottom = 64.0 +size_flags_horizontal = 4 +texture = ExtResource( 5 ) + +[node name="Delivered" type="RichTextLabel" parent="VBoxContainer/HBoxContainer/VBoxContainer3"] +margin_top = 68.0 +margin_right = 152.0 +margin_bottom = 86.0 +theme = ExtResource( 3 ) +bbcode_enabled = true +bbcode_text = "{} moves" +text = "{} moves" +fit_content_height = true + +[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] +margin_top = 156.0 +margin_right = 478.0 +margin_bottom = 160.0 + +[node name="Path" type="RichTextLabel" parent="VBoxContainer"] +margin_top = 164.0 +margin_right = 478.0 +margin_bottom = 263.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme = ExtResource( 3 ) +bbcode_enabled = true +fit_content_height = true + +[node name="Label" type="Label" parent="VBoxContainer"] +margin_top = 267.0 +margin_right = 478.0 +margin_bottom = 282.0 +theme = ExtResource( 4 ) +text = "Level Code" +align = 1 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +margin_top = 286.0 +margin_right = 478.0 +margin_bottom = 290.0 + +[node name="LevelCode" type="TextEdit" parent="VBoxContainer"] +margin_top = 294.0 +margin_right = 478.0 +margin_bottom = 394.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme = ExtResource( 4 ) +readonly = true +wrap_enabled = true + +[node name="HSeparator4" type="HSeparator" parent="VBoxContainer"] +margin_top = 398.0 +margin_right = 478.0 +margin_bottom = 402.0 + +[node name="VBoxContainer3" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 406.0 +margin_right = 478.0 +margin_bottom = 426.0 + +[node name="Continue" type="Button" parent="VBoxContainer/VBoxContainer3"] +visible = false +margin_right = 12.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +text = "Continue" + +[node name="Restart" type="Button" parent="VBoxContainer/VBoxContainer3"] +margin_right = 156.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +text = "Restart" + +[node name="New" type="Button" parent="VBoxContainer/VBoxContainer3"] +margin_left = 160.0 +margin_right = 317.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +text = "New" + +[node name="Quit" type="Button" parent="VBoxContainer/VBoxContainer3"] +margin_left = 321.0 +margin_right = 478.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +text = "Quit" diff --git a/Link.gd b/Link.gd new file mode 100644 index 0000000..1ed9c13 --- /dev/null +++ b/Link.gd @@ -0,0 +1,47 @@ +extends Node2D + +var start = null +var end = null +var weight = 1 + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + add_to_group("links") + get_node("Label").set_text("%d" % self.weight) + get_node("Label").set_tooltip("Moving across this line costs {} energy".format([self.weight], "{}")) + +func set_weight(value): + assert(value > 0) + self.weight = value + get_node("Label").set_text("%d" % self.weight) + get_node("Label").set_tooltip("Moving across this line costs {} energy".format([self.weight], "{}")) + if self.weight >= 2: + get_node("Label").set_modulate(Color("d7e65b")) + if self.weight >= 3: + get_node("Label").set_modulate(Color("e22c2c")) + +func set_ends(a, b): + assert(a != null) + assert(b != null) + self.start = a + self.end = b + self.redraw_line() + +func redraw_line(): + get_node("Line").clear_points() + get_node("Label").set_position(Vector2( + abs(end.get_position().x + start.get_position().x) / 2, + abs(end.get_position().y + start.get_position().y) / 2 + )) + get_node("Line").add_point(self.start.get_position()) + get_node("Line").add_point(self.end.get_position()) + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/Link.tscn b/Link.tscn new file mode 100644 index 0000000..230dab1 --- /dev/null +++ b/Link.tscn @@ -0,0 +1,27 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://Link.gd" type="Script" id=1] +[ext_resource path="res://DetailFont.tres" type="DynamicFont" id=2] + +[sub_resource type="Theme" id=1] +default_font = ExtResource( 2 ) + +[node name="Link" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Line" type="Line2D" parent="."] +z_index = -1 +width = 6.0 +default_color = Color( 0.596078, 0.976471, 0.67451, 1 ) + +[node name="Label" type="Label" parent="."] +margin_left = -12.0 +margin_top = -12.0 +margin_right = 12.0 +margin_bottom = 12.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +theme = SubResource( 1 ) +text = "1" +align = 1 +valign = 1 diff --git a/Node.gd b/Node.gd new file mode 100644 index 0000000..3b5c88b --- /dev/null +++ b/Node.gd @@ -0,0 +1,93 @@ +extends Node2D + +var stored = 0 +var capacity = 0 +var texture_resource = "" +var value = 0 +var node_name = '' + +var peers = [] +const drag_threshold = 0.2 +var drag = false +var drag_hold = 0 + +func name_from_index(index): + var n = char(index % 26 + 65) + if index > 26: + n += "%d" % index / 26 + self.set_node_name(n) + +func set_node_name(value): + self.node_name = value + get_node("Label").set_text(self.node_name) + +func is_full(): + return self.capacity >= self.stored + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + add_to_group("nodes") + if self.texture_resource != "": + get_node("Sprite").set_texture(load(self.texture_resource)) + self.update_help() + +func update_help(): + get_node("Help").set_tooltip("") + get_node("Help").set_text("") + +func path_to(destination): + pass + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +func _process(delta): + if self.drag: + self.drag_hold += delta + +func update_position(pos): + self.set_position(pos) + for link in get_tree().get_nodes_in_group("links"): + if link.end == self or link.start == self: + link.redraw_line() + var c = get_tree().get_nodes_in_group("character")[0] + if is_instance_valid(c): + if c.location == self: + c.set_position(self.get_position() + c.offset) + +func _on_Help_gui_input(event): + if event is InputEventMouseMotion: + if self.drag and self.drag_hold > self.drag_threshold: + self.set_position(get_global_mouse_position()) + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT and event.is_doubleclick(): + if false: + print(self) + print("\tPeers: ", self.peers) + var links = [] + for link in get_tree().get_nodes_in_group("links"): + if link.start == self or link.end == self: + links.append(link) + print("\tLinks: ") + for link in links: + print("\t\t", link, " ", link.start, " <---> ", link.end) + + var c = get_tree().get_nodes_in_group("character")[0] + if c != null and c.can_move(self): + c.set_location(self) + if event.button_index == BUTTON_LEFT and !event.is_doubleclick(): + if event.pressed: + self.drag = true + else: + if self.drag: + self.drag = false + if self.drag_hold > self.drag_threshold: + self.update_position(get_global_mouse_position()) + self.drag_hold = 0 + diff --git a/Node.tscn b/Node.tscn new file mode 100644 index 0000000..8d13ca9 --- /dev/null +++ b/Node.tscn @@ -0,0 +1,41 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://Node.gd" type="Script" id=1] +[ext_resource path="res://resources/dropoff.png" type="Texture" id=2] +[ext_resource path="res://DetailFontTheme.tres" type="Theme" id=3] +[ext_resource path="res://DetailFont.tres" type="DynamicFont" id=4] + +[sub_resource type="Theme" id=1] +default_font = ExtResource( 4 ) + +[node name="Node" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Sprite" type="Sprite" parent="."] +texture = ExtResource( 2 ) + +[node name="Help" type="RichTextLabel" parent="."] +margin_left = -32.0 +margin_top = -32.0 +margin_right = 32.0 +margin_bottom = 32.0 +hint_tooltip = "Drop off X more here to fully satisfy the delivery requirements. +When satisfied, Y will be added to your score." +theme = SubResource( 1 ) +text = "0 / 0 +0" + +[node name="Label" type="Label" parent="."] +margin_left = -32.0 +margin_top = -32.0 +margin_right = 32.0 +margin_bottom = 32.0 +theme = ExtResource( 3 ) +text = "XX" +align = 2 +valign = 2 +uppercase = true + +[node name="Audio" type="AudioStreamPlayer" parent="."] + +[connection signal="gui_input" from="Help" to="." method="_on_Help_gui_input"] diff --git a/Node2D.gd b/Node2D.gd new file mode 100644 index 0000000..da6010b --- /dev/null +++ b/Node2D.gd @@ -0,0 +1,16 @@ +extends "res://Node.gd" + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/Pickup.gd b/Pickup.gd new file mode 100644 index 0000000..7cc105b --- /dev/null +++ b/Pickup.gd @@ -0,0 +1,60 @@ +extends "res://Node.gd" + +var empty_sounds = [ + preload("res://resources/NoMore.wav"), + preload("res://resources/ThatsAll.wav"), +] + +var load_sounds = [ + preload("res://resources/Thunk.wav"), +] + +func _init(): + self.texture_resource = "res://resources/pickup.png" + self.stored = INF + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + self.add_to_group("pickup") + +func stored_str(): + if is_inf(self.stored): + return "\u221E" + return "{}".format([self.stored], "{}") + +func add_stored(value): + self.stored += value + self.update_help() + +func set_stored(value): + self.stored = value + self.update_help() + +func drain(amount): + if amount <= 0: + return + self.stored -= amount + get_node("Audio").set_stream(self.load_sounds[randi() % self.load_sounds.size()]) + get_node("Audio").play() + self.update_help() + +func update_help(): + get_node("Help").set_tooltip("Go here to replenish your stock\nThere are {} items available here".format([stored_str()], "{}")) + get_node("Help").set_text("{}".format([stored_str()], "{}")) + if self.stored <= 0: + get_node("Sprite").set_modulate(Color("da0000")) + get_node("Help").set_self_modulate(Color("da0000")) + + var a = get_node("Audio") + a.set_stream(self.empty_sounds[randi() % self.empty_sounds.size()]) + a.play() + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/Pickup.tscn b/Pickup.tscn new file mode 100644 index 0000000..d030b89 --- /dev/null +++ b/Pickup.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Node.tscn" type="PackedScene" id=1] +[ext_resource path="res://Pickup.gd" type="Script" id=2] + +[node name="Pickup" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/Start.gd b/Start.gd new file mode 100644 index 0000000..af8929c --- /dev/null +++ b/Start.gd @@ -0,0 +1,17 @@ +extends "res://Node.gd" + +func _init(): + self.texture_resource = "res://resources/start.png" +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + self.add_to_group("start") + get_node("Help").set_tooltip("@TODO: Use an action here to end game early") + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/Start.tscn b/Start.tscn new file mode 100644 index 0000000..f8b9218 --- /dev/null +++ b/Start.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Node.tscn" type="PackedScene" id=1] +[ext_resource path="res://Start.gd" type="Script" id=2] + +[node name="Start" instance=ExtResource( 1 )] +script = ExtResource( 2 ) diff --git a/Super Bubble.ttf b/Super Bubble.ttf new file mode 100644 index 0000000..6d6d29f Binary files /dev/null and b/Super Bubble.ttf differ diff --git a/bg.xcf b/bg.xcf new file mode 100644 index 0000000..cf2670a Binary files /dev/null and b/bg.xcf differ diff --git a/bg_desert.png b/bg_desert.png new file mode 100644 index 0000000..c5be1e7 Binary files /dev/null and b/bg_desert.png differ diff --git a/bg_desert2.png b/bg_desert2.png new file mode 100644 index 0000000..ac61de4 Binary files /dev/null and b/bg_desert2.png differ diff --git a/default_env.tres b/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..c98fbb6 Binary files /dev/null and b/icon.png differ diff --git a/icons.xcf b/icons.xcf new file mode 100644 index 0000000..0a1547d Binary files /dev/null and b/icons.xcf differ diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..8c4d27f --- /dev/null +++ b/project.godot @@ -0,0 +1,29 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=4 + +[application] + +config/name="LD53: Delivery" +config/description="Pickup and deliver in a nearby area. Minimize your movement to maximize your score." +run/main_scene="res://Blah.tscn" +boot_splash/show_image=false +config/icon="res://resources/boxes.png" + +[gui] + +common/drop_mouse_on_gui_input_disabled=true + +[physics] + +common/enable_pause_aware_picking=true + +[rendering] + +environment/default_environment="res://default_env.tres" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..aaf551a --- /dev/null +++ b/readme.md @@ -0,0 +1,15 @@ +# LD53: Delivery + +Pickup and deliver things around an area, trying to minimize how far you travel. + +# Tools + + * Godot 3 + * GIMP + * Audacity + +# External Resources + + * Super Bubble font: https://www.dafont.com/super-bubble.font + * Bitstream Vera Sans Nerd: https://github.com/ryanoasis/nerd-fonts + * Satellite shots from google, remixed for background diff --git a/resources/Background.tscn b/resources/Background.tscn new file mode 100644 index 0000000..c42ecbb --- /dev/null +++ b/resources/Background.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://bg_desert2.png" type="Texture" id=1] + +[node name="Background" type="Node2D"] + +[node name="Base" type="Sprite" parent="."] +texture = ExtResource( 1 ) +centered = false diff --git a/resources/Coins1.wav b/resources/Coins1.wav new file mode 100644 index 0000000..b81b3cf Binary files /dev/null and b/resources/Coins1.wav differ diff --git a/resources/Coins2.wav b/resources/Coins2.wav new file mode 100644 index 0000000..10575fd Binary files /dev/null and b/resources/Coins2.wav differ diff --git a/resources/Comic Story.ttf b/resources/Comic Story.ttf new file mode 100644 index 0000000..abc42a6 Binary files /dev/null and b/resources/Comic Story.ttf differ diff --git a/resources/Items.wav b/resources/Items.wav new file mode 100644 index 0000000..e536255 Binary files /dev/null and b/resources/Items.wav differ diff --git a/resources/NewLevel.gd b/resources/NewLevel.gd new file mode 100644 index 0000000..5d8a749 --- /dev/null +++ b/resources/NewLevel.gd @@ -0,0 +1,85 @@ +extends Control + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +signal start_pressed + +# Called when the node enters the scene tree for the first time. +func _ready(): + #get_node(".").set_exclusive(true) + #get_node(".").popup_centered() + var Game = load("Game.gd") + get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/ParameterTweaker").from_params(Game.medium_params()) + + +func _on_difficulty_preset_pressed(button, value): + var Game = load("Game.gd") + var buttons = { + get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Easy"): funcref(Game, "easy_params"), + get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Medium"): funcref(Game, "medium_params"), + get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Hard"): funcref(Game, "hard_params"), + get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Custom"): null, + } + if value: + for b in buttons.keys(): + if b != button: + b.set_pressed(false) + if buttons[button] != null: + get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/ParameterTweaker").from_params(buttons[button].call_func()) + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + + +func _on_LevelCode_text_changed(): + var p = load("Game.gd").parse_levelcode(find_node("LevelCode").text) + if p == null: + find_node("Valid").set_text("Invalid level code") + find_node("Valid").add_color_override("font_color", Color("ff0000")) + find_node("Reset").set_disabled(true) + else: + find_node("Valid").set_text("Valid level code") + find_node("Valid").add_color_override("font_color", Color("00ff00")) + find_node("Reset").set_disabled(false) + get_node("VBoxContainer/TabContainer/Import Level/ParameterTweaker").from_params(p) + +func _on_Reset_pressed(): + var p = load("Game.gd").parse_levelcode(find_node("LevelCode").text) + get_node("VBoxContainer/TabContainer/Import/ParameterTweaker").from_params(p) + + +func _on_Custom_toggled(button_pressed): + _on_difficulty_preset_pressed(get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Custom"), button_pressed) + + +func _on_Hard_toggled(button_pressed): + _on_difficulty_preset_pressed(get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Hard"), button_pressed) + + +func _on_Medium_toggled(button_pressed): + _on_difficulty_preset_pressed(get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Medium"), button_pressed) + + +func _on_Easy_toggled(button_pressed): + _on_difficulty_preset_pressed(get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Easy"), button_pressed) + + +func _on_ParameterTweaker_reset(params): + find_node("GeneratedLevelCode").set_text(Marshalls.variant_to_base64(params)) + + +func _on_ParameterTweaker_changed(params): + find_node("GeneratedLevelCode").set_text(Marshalls.variant_to_base64(params)) + var custom = get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Custom") + custom.set_pressed(true) + + + +func _on_Start_pressed(): + var params = get_node("VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/ParameterTweaker").to_params() + if get_node("VBoxContainer/TabContainer/Import Level").is_visible(): + params = get_node("VBoxContainer/TabContainer/Import Level/ParameterTweaker").to_params() + emit_signal("start_pressed", params) diff --git a/resources/NewLevel.tscn b/resources/NewLevel.tscn new file mode 100644 index 0000000..f21d38b --- /dev/null +++ b/resources/NewLevel.tscn @@ -0,0 +1,192 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://resources/UI Theme.tres" type="Theme" id=1] +[ext_resource path="res://resources/NewLevel.gd" type="Script" id=2] +[ext_resource path="res://resources/ParameterTweaker.tscn" type="PackedScene" id=3] + +[node name="PopupPanel" type="PopupPanel"] +margin_right = 538.0 +margin_bottom = 426.0 +theme = ExtResource( 1 ) +script = ExtResource( 2 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_left = 4.0 +margin_top = 4.0 +margin_right = 534.0 +margin_bottom = 422.0 +theme = ExtResource( 1 ) + +[node name="TabContainer" type="TabContainer" parent="VBoxContainer"] +margin_right = 530.0 +margin_bottom = 380.0 +grow_horizontal = 2 +grow_vertical = 2 +rect_min_size = Vector2( 0, 380 ) +theme = ExtResource( 1 ) +tab_align = 0 + +[node name="Select Difficulty" type="Tabs" parent="VBoxContainer/TabContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 33.0 +margin_right = -4.0 +margin_bottom = -4.0 +theme = ExtResource( 1 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Select Difficulty"] +margin_right = 522.0 +margin_bottom = 340.0 +theme = ExtResource( 1 ) + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer"] +margin_right = 522.0 +margin_bottom = 21.0 +theme = ExtResource( 1 ) + +[node name="Easy" type="Button" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer"] +margin_right = 127.0 +margin_bottom = 21.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +toggle_mode = true +text = "Short" + +[node name="Medium" type="Button" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer"] +margin_left = 131.0 +margin_right = 259.0 +margin_bottom = 21.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +toggle_mode = true +pressed = true +text = "Medium" + +[node name="Hard" type="Button" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer"] +margin_left = 263.0 +margin_right = 390.0 +margin_bottom = 21.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +toggle_mode = true +text = "Long" + +[node name="Custom" type="Button" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer"] +margin_left = 394.0 +margin_right = 522.0 +margin_bottom = 21.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +toggle_mode = true +text = "Custom" + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer"] +margin_top = 25.0 +margin_right = 522.0 +margin_bottom = 29.0 +theme = ExtResource( 1 ) + +[node name="ParameterTweaker" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer" instance=ExtResource( 3 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 33.0 +margin_right = 522.0 +margin_bottom = 233.0 +rect_min_size = Vector2( 200, 200 ) + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer"] +margin_top = 237.0 +margin_right = 522.0 +margin_bottom = 241.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer"] +margin_top = 245.0 +margin_right = 522.0 +margin_bottom = 260.0 +theme = ExtResource( 1 ) +text = "Level Code - Copy to share with others" +align = 1 + +[node name="GeneratedLevelCode" type="TextEdit" parent="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer"] +margin_top = 264.0 +margin_right = 522.0 +margin_bottom = 344.0 +rect_min_size = Vector2( 0, 80 ) +theme = ExtResource( 1 ) +readonly = true +wrap_enabled = true + +[node name="Import Level" type="Tabs" parent="VBoxContainer/TabContainer"] +visible = false +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 33.0 +margin_right = -4.0 +margin_bottom = -4.0 +theme = ExtResource( 1 ) + +[node name="LevelCode" type="TextEdit" parent="VBoxContainer/TabContainer/Import Level"] +margin_left = 2.0 +margin_top = 20.0 +margin_right = 518.0 +margin_bottom = 112.0 +hint_tooltip = "Enter the level code" +theme = ExtResource( 1 ) +wrap_enabled = true + +[node name="Valid" type="Label" parent="VBoxContainer/TabContainer/Import Level"] +margin_left = 13.0 +margin_top = 123.0 +margin_right = 55.0 +margin_bottom = 138.0 +theme = ExtResource( 1 ) +text = "Valid level code" + +[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Import Level"] +margin_left = 7.0 +margin_top = -3.0 +margin_right = 516.0 +margin_bottom = 12.0 +theme = ExtResource( 1 ) +text = "Level Code" +align = 1 + +[node name="Reset" type="Button" parent="VBoxContainer/TabContainer/Import Level"] +margin_left = 135.0 +margin_top = 121.0 +margin_right = 294.0 +margin_bottom = 142.0 +theme = ExtResource( 1 ) +text = "Reset from level code" + +[node name="ParameterTweaker" parent="VBoxContainer/TabContainer/Import Level" instance=ExtResource( 3 )] +margin_left = 9.0 +margin_top = 149.0 +margin_right = 421.0 +margin_bottom = -6.0 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +margin_top = 384.0 +margin_right = 530.0 +margin_bottom = 388.0 +theme = ExtResource( 1 ) + +[node name="Start" type="Button" parent="VBoxContainer"] +margin_top = 392.0 +margin_right = 530.0 +margin_bottom = 413.0 +theme = ExtResource( 1 ) +text = "Start" + +[connection signal="toggled" from="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Easy" to="." method="_on_Easy_toggled"] +[connection signal="toggled" from="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Medium" to="." method="_on_Medium_toggled"] +[connection signal="toggled" from="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Hard" to="." method="_on_Hard_toggled"] +[connection signal="toggled" from="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/HBoxContainer/Custom" to="." method="_on_Custom_toggled"] +[connection signal="changed" from="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/ParameterTweaker" to="." method="_on_ParameterTweaker_changed"] +[connection signal="reset" from="VBoxContainer/TabContainer/Select Difficulty/VBoxContainer/ParameterTweaker" to="." method="_on_ParameterTweaker_reset"] +[connection signal="text_changed" from="VBoxContainer/TabContainer/Import Level/LevelCode" to="." method="_on_LevelCode_text_changed"] +[connection signal="pressed" from="VBoxContainer/TabContainer/Import Level/Reset" to="." method="_on_Reset_pressed"] +[connection signal="pressed" from="VBoxContainer/Start" to="." method="_on_Start_pressed"] diff --git a/resources/NoMore.wav b/resources/NoMore.wav new file mode 100644 index 0000000..d66dcb7 Binary files /dev/null and b/resources/NoMore.wav differ diff --git a/resources/Paper2.wav b/resources/Paper2.wav new file mode 100644 index 0000000..9780803 Binary files /dev/null and b/resources/Paper2.wav differ diff --git a/resources/ParameterTweaker.gd b/resources/ParameterTweaker.gd new file mode 100644 index 0000000..4f11adc --- /dev/null +++ b/resources/ParameterTweaker.gd @@ -0,0 +1,116 @@ +extends Control + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +signal changed +signal reset +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + +func to_params(): + var params = { + 'seed': find_node("Seed").get_text(), + 'node_count': find_node("LocationCount").get_value(), + 'cargo_availability': find_node("CargoAvailability").get_value(), + 'pickup_count_range': Vector2(1, find_node("PickupCount").get_value()), + 'empty_node_chance': find_node("EmptyNodeChance").get_value(), + 'dropoff_value_range': Vector2(1, find_node("DropoffValue").get_value()), + 'dropoff_capacity_range': Vector2(1, find_node("DropoffCapacity").get_value()), + 'link_cost_range': Vector2(1, find_node("LinkWeight").get_value()), + } + if find_node("Infinite").is_pressed(): + params.cargo_availability = INF + return params + +func from_params(params): + self.set_block_signals(true) + find_node("Seed").set_text(params.seed) + find_node("LocationCount").set_value(params.node_count) + get_node("VBoxContainer/HBoxContainer2/Value").set_text("%d" % params.node_count) + if is_inf(params.cargo_availability): + get_node("VBoxContainer/HBoxContainer3/CargoAvailability").set_editable(false) + get_node("VBoxContainer/HBoxContainer3/Value").set_text("INF") + get_node("VBoxContainer/HBoxContainer3/Infinite").set_pressed(true) + else: + get_node("VBoxContainer/HBoxContainer3/CargoAvailability").set_editable(true) + get_node("VBoxContainer/HBoxContainer3/CargoAvailability").set_value(params.cargo_availability) + get_node("VBoxContainer/HBoxContainer3/Value").set_text("%2.1f" % params.cargo_availability) + get_node("VBoxContainer/HBoxContainer3/Infinite").set_pressed(false) + get_node("VBoxContainer/HBoxContainer4/PickupCount").set_value(params.pickup_count_range.y) + get_node("VBoxContainer/HBoxContainer4/Value").set_text("%d" % params.pickup_count_range.y) + get_node("VBoxContainer/HBoxContainer5/EmptyNodeChance").set_value(params.empty_node_chance) + get_node("VBoxContainer/HBoxContainer5/Value").set_text("%d" % params.empty_node_chance) + get_node("VBoxContainer/HBoxContainer6/DropoffValue").set_value(params.dropoff_value_range.y) + get_node("VBoxContainer/HBoxContainer6/Value").set_text("%d" % params.dropoff_value_range.y) + get_node("VBoxContainer/HBoxContainer7/DropoffCapacity").set_value(params.dropoff_capacity_range.y) + get_node("VBoxContainer/HBoxContainer7/Value").set_text("%d" % params.dropoff_capacity_range.y) + get_node("VBoxContainer/HBoxContainer8/LinkWeight").set_value(params.link_cost_range.y) + get_node("VBoxContainer/HBoxContainer8/Value").set_text("%d" % params.link_cost_range.y) + self.set_block_signals(false) + emit_signal("reset", self.to_params()) + +func _on_RandomizeSeed_pressed(): + # 33 - 126 + var character_count = randi() % 29 + 4 + var new_seed = "" + while character_count > 0: + new_seed += char(randi() % 94 + 33) + character_count -= 1 + find_node("Seed").set_text(new_seed) + emit_signal("changed", self.to_params()) + + +func _on_LocationCount_value_changed(value): + get_node("VBoxContainer/HBoxContainer2/Value").set_text("%d" % value) + emit_signal("changed", self.to_params()) + + +func _on_CargoAvailability_value_changed(value): + get_node("VBoxContainer/HBoxContainer3/Value").set_text("%2.1f" % value) + emit_signal("changed", self.to_params()) + + +func _on_CheckBox_toggled(button_pressed): + if button_pressed: + get_node("VBoxContainer/HBoxContainer3/Value").set_text("INF") + get_node("VBoxContainer/HBoxContainer3/CargoAvailability").set_editable(false) + else: + get_node("VBoxContainer/HBoxContainer3/Value").set_text("%2.1f" % + get_node("VBoxContainer/HBoxContainer3/CargoAvailability").get_value() + ) + get_node("VBoxContainer/HBoxContainer3/CargoAvailability").set_editable(true) + emit_signal("changed", self.to_params()) + + +func _on_PickupCount_value_changed(value): + get_node("VBoxContainer/HBoxContainer4/Value").set_text("%d" % value) + emit_signal("changed", self.to_params()) + + +func _on_EmptyNodeChance_value_changed(value): + get_node("VBoxContainer/HBoxContainer5/Value").set_text("%d" % value) + emit_signal("changed", self.to_params()) + + +func _on_DropoffValue_value_changed(value): + get_node("VBoxContainer/HBoxContainer6/Value").set_text("%d" % value) + emit_signal("changed", self.to_params()) + + +func _on_DropoffCapacity_value_changed(value): + get_node("VBoxContainer/HBoxContainer7/Value").set_text("%d" % value) + emit_signal("changed", self.to_params()) + + +func _on_LinkWeight_value_changed(value): + get_node("VBoxContainer/HBoxContainer8/Value").set_text("%d" % value) + emit_signal("changed", self.to_params()) diff --git a/resources/ParameterTweaker.tscn b/resources/ParameterTweaker.tscn new file mode 100644 index 0000000..53cc6d6 --- /dev/null +++ b/resources/ParameterTweaker.tscn @@ -0,0 +1,269 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://resources/UI Theme.tres" type="Theme" id=1] +[ext_resource path="res://resources/ParameterTweaker.gd" type="Script" id=2] + +[node name="ParameterTweaker" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +theme = ExtResource( 1 ) +script = ExtResource( 2 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_right = 375.0 +margin_bottom = 52.0 +theme = ExtResource( 1 ) + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] +margin_right = 375.0 +margin_bottom = 16.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer2"] +margin_right = 98.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "Location count" + +[node name="LocationCount" type="HSlider" parent="VBoxContainer/HBoxContainer2"] +margin_left = 102.0 +margin_right = 364.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +min_value = 6.0 +max_value = 64.0 +value = 6.0 +rounded = true + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer2"] +margin_left = 368.0 +margin_right = 375.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "6" + +[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 20.0 +margin_right = 375.0 +margin_bottom = 44.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer3"] +margin_top = 4.0 +margin_right = 126.0 +margin_bottom = 19.0 +hint_tooltip = "How much cargo is available from pickup locations relative to the total number of requested cargo from dropoff locations." +mouse_filter = 1 +text = "Cargo Availability" + +[node name="CargoAvailability" type="HSlider" parent="VBoxContainer/HBoxContainer3"] +margin_left = 130.0 +margin_right = 262.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +min_value = 1.0 +max_value = 3.0 +step = 0.1 +value = 1.0 + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer3"] +margin_left = 266.0 +margin_top = 4.0 +margin_right = 287.0 +margin_bottom = 19.0 +text = "1.0" + +[node name="Infinite" type="CheckBox" parent="VBoxContainer/HBoxContainer3"] +margin_left = 291.0 +margin_right = 375.0 +margin_bottom = 24.0 +text = "Infinite" + +[node name="HBoxContainer4" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 48.0 +margin_right = 375.0 +margin_bottom = 64.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer4"] +margin_right = 147.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "Pickup Location Count" + +[node name="PickupCount" type="HSlider" parent="VBoxContainer/HBoxContainer4"] +margin_left = 151.0 +margin_right = 371.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +min_value = 1.0 +max_value = 3.0 +value = 1.0 +rounded = true +tick_count = 3 +ticks_on_borders = true + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer4"] +margin_left = 375.0 +margin_right = 375.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) + +[node name="HBoxContainer5" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 68.0 +margin_right = 375.0 +margin_bottom = 84.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer5"] +margin_right = 119.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "Empty Node Chance" + +[node name="EmptyNodeChance" type="HSlider" parent="VBoxContainer/HBoxContainer5"] +margin_left = 123.0 +margin_right = 357.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +max_value = 90.0 +value = 15.0 +rounded = true + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer5"] +margin_left = 361.0 +margin_right = 375.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "15" + +[node name="HBoxContainer6" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 88.0 +margin_right = 375.0 +margin_bottom = 104.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer6"] +margin_right = 147.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "Maximum Dropoff Value" + +[node name="DropoffValue" type="HSlider" parent="VBoxContainer/HBoxContainer6"] +margin_left = 151.0 +margin_right = 364.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +min_value = 1.0 +max_value = 10.0 +value = 3.0 +rounded = true + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer6"] +margin_left = 368.0 +margin_right = 375.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "3" + +[node name="HBoxContainer7" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 108.0 +margin_right = 375.0 +margin_bottom = 124.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer7"] +margin_right = 168.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "Maximum Dropoff Capacity" + +[node name="DropoffCapacity" type="HSlider" parent="VBoxContainer/HBoxContainer7"] +margin_left = 172.0 +margin_right = 364.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +min_value = 1.0 +max_value = 10.0 +value = 3.0 +rounded = true + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer7"] +margin_left = 368.0 +margin_right = 375.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "3" + +[node name="HBoxContainer8" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 128.0 +margin_right = 375.0 +margin_bottom = 144.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer8"] +margin_right = 133.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "Maximum Link Weight" + +[node name="LinkWeight" type="HSlider" parent="VBoxContainer/HBoxContainer8"] +margin_left = 137.0 +margin_right = 364.0 +margin_bottom = 16.0 +size_flags_horizontal = 3 +theme = ExtResource( 1 ) +min_value = 1.0 +max_value = 10.0 +value = 2.0 +rounded = true + +[node name="Value" type="Label" parent="VBoxContainer/HBoxContainer8"] +margin_left = 368.0 +margin_right = 375.0 +margin_bottom = 15.0 +theme = ExtResource( 1 ) +text = "2" + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 148.0 +margin_right = 375.0 +margin_bottom = 180.0 +theme = ExtResource( 1 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] +margin_top = 8.0 +margin_right = 28.0 +margin_bottom = 23.0 +theme = ExtResource( 1 ) +text = "Seed" + +[node name="Seed" type="TextEdit" parent="VBoxContainer/HBoxContainer"] +margin_left = 32.0 +margin_right = 296.0 +margin_bottom = 32.0 +rect_min_size = Vector2( 64, 32 ) +size_flags_horizontal = 3 +theme = ExtResource( 1 ) + +[node name="RandomizeSeed" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 300.0 +margin_right = 375.0 +margin_bottom = 32.0 +theme = ExtResource( 1 ) +text = "Randomize" + +[connection signal="value_changed" from="VBoxContainer/HBoxContainer2/LocationCount" to="." method="_on_LocationCount_value_changed"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer3/CargoAvailability" to="." method="_on_CargoAvailability_value_changed"] +[connection signal="toggled" from="VBoxContainer/HBoxContainer3/Infinite" to="." method="_on_CheckBox_toggled"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer4/PickupCount" to="." method="_on_PickupCount_value_changed"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer5/EmptyNodeChance" to="." method="_on_EmptyNodeChance_value_changed"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer6/DropoffValue" to="." method="_on_DropoffValue_value_changed"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer7/DropoffCapacity" to="." method="_on_DropoffCapacity_value_changed"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer8/LinkWeight" to="." method="_on_LinkWeight_value_changed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/RandomizeSeed" to="." method="_on_RandomizeSeed_pressed"] diff --git a/resources/Ratchet.wav b/resources/Ratchet.wav new file mode 100644 index 0000000..af8d1c5 Binary files /dev/null and b/resources/Ratchet.wav differ diff --git a/resources/Scribble.wav b/resources/Scribble.wav new file mode 100644 index 0000000..1791cfa Binary files /dev/null and b/resources/Scribble.wav differ diff --git a/resources/Tap.wav b/resources/Tap.wav new file mode 100644 index 0000000..1df4cc9 Binary files /dev/null and b/resources/Tap.wav differ diff --git a/resources/Thanks.wav b/resources/Thanks.wav new file mode 100644 index 0000000..c6aea8a Binary files /dev/null and b/resources/Thanks.wav differ diff --git a/resources/ThatsAll.wav b/resources/ThatsAll.wav new file mode 100644 index 0000000..57a3a03 Binary files /dev/null and b/resources/ThatsAll.wav differ diff --git a/resources/Thunk.wav b/resources/Thunk.wav new file mode 100644 index 0000000..387f8b0 Binary files /dev/null and b/resources/Thunk.wav differ diff --git a/resources/UI Theme.tres b/resources/UI Theme.tres new file mode 100644 index 0000000..c371fac --- /dev/null +++ b/resources/UI Theme.tres @@ -0,0 +1,10 @@ +[gd_resource type="Theme" load_steps=3 format=2] + +[ext_resource path="res://Bitstream Vera Sans Mono Bold Nerd Font Complete.ttf" type="DynamicFontData" id=1] + +[sub_resource type="DynamicFont" id=1] +size = 12 +font_data = ExtResource( 1 ) + +[resource] +default_font = SubResource( 1 ) diff --git a/resources/YoureTheBest.wav b/resources/YoureTheBest.wav new file mode 100644 index 0000000..93c5b76 Binary files /dev/null and b/resources/YoureTheBest.wav differ diff --git a/resources/box.png b/resources/box.png new file mode 100644 index 0000000..210c406 Binary files /dev/null and b/resources/box.png differ diff --git a/resources/boxes.png b/resources/boxes.png new file mode 100644 index 0000000..569162a Binary files /dev/null and b/resources/boxes.png differ diff --git a/resources/building.png b/resources/building.png new file mode 100644 index 0000000..faf57e1 Binary files /dev/null and b/resources/building.png differ diff --git a/resources/character.png b/resources/character.png new file mode 100644 index 0000000..930e93c Binary files /dev/null and b/resources/character.png differ diff --git a/resources/dropoff.png b/resources/dropoff.png new file mode 100644 index 0000000..f1df7dd Binary files /dev/null and b/resources/dropoff.png differ diff --git a/resources/empty.png b/resources/empty.png new file mode 100644 index 0000000..706f52b Binary files /dev/null and b/resources/empty.png differ diff --git a/resources/moves.png b/resources/moves.png new file mode 100644 index 0000000..b7a02b6 Binary files /dev/null and b/resources/moves.png differ diff --git a/resources/pickup.png b/resources/pickup.png new file mode 100644 index 0000000..9de2bc1 Binary files /dev/null and b/resources/pickup.png differ diff --git a/resources/start.png b/resources/start.png new file mode 100644 index 0000000..53bfe83 Binary files /dev/null and b/resources/start.png differ diff --git a/resources/untitled.wav b/resources/untitled.wav new file mode 100644 index 0000000..abc6037 Binary files /dev/null and b/resources/untitled.wav differ diff --git a/sounds.aup3 b/sounds.aup3 new file mode 100644 index 0000000..0924895 Binary files /dev/null and b/sounds.aup3 differ