extends Node signal orbit_updated signal stats_updated signal crew_updated # Declare member variables here. Examples: # var a = 2 # var b = "text" const debug = true var current_scene = null var difficulty = null var difficulties = { "Easy": 0, "Medium": 1, "Hard": 2, } var difficulty_data = { 0: { "planet": "res://assets/moon.png", "starting_altitude": 60000, "starting_crew": 5, "starting_drag": 75, "drag_function": funcref(self, "moon_drag"), "rescue_altitude": 10000, "maximum_crew": 15, "minimum_altitude": 1000, }, 1: { "planet": "res://assets/planet.png", "starting_altitude": 600000, "starting_crew": 4, "starting_drag": 100, "drag_function": funcref(self, "planet_drag"), "rescue_altitude": 100000, "maximum_crew": 10, "minimum_altitude": 30000, }, 2: { "planet": "res://assets/blackhole.png", "starting_altitude": 200000001000000, "starting_crew": 3, "starting_drag": 125, "drag_function": funcref(self, "blackhole_drag"), "rescue_altitude": 200000000100000, "maximum_crew": 6, "minimum_altitude": 200000000000000, } } var current_depth = 0 const OptionsPerLevel = 3 const TreeDepth = 5 const EncounterTypes = [ "ArtificialSatellite", "NaturalSatellite", #"Comet", #"Debris", ##"Gases", #"Mystery", #"Alien", "Ship", #"Station", #"LocationSpecific", # Eg., Moon, Planet, Blackhole... ] const EncounterData = { # "a": { # "tooltip": "", # "situations": { # 0: { # "title": "a x", # "picture": null, # "text": "asdfs", # "choices": { # 0: { # "title": "x", # "tooltip": "aa", # "then": "aa", # "results": { # # starting from last, if chance >= index between 0-100 # 0: { # "title": "a", # "text": "a", # "stat_changes": Dictionary(), # }, # } # } # } # } # } # } "RescueOperation": { "tooltip": "A ship is stranded here, and they need your help", "situations": { 0: { "title": "The Diligent's Rescue", "picture": null, "text": "", "choices": { 0: { "title": "Prioritise the warp crystal", "tooltip": "", "then": "You shove past the haggard looking crew of the " + \ "Diligent, ignoring their arched eyebrows and sideways " + \ "glances as you hurry to the Engineering section. \n\n" + \ "The [rainbow freq=0.5 sat=2 val=200]Warp Crystal[/rainbow] " + \ "is already packed in an open carrying case. It looks like a " + \ "good one, and should last a few jumps.\n\nYou grab the case " + \ "and make haste back to the Wellspring before the Diligent " + \ "sinks further into the gravity well", "results": { 0: { "title": "Gaining supplies, losing morale", "text": "", "stat_changes": { "supplies": 500, }, "crew_changes": { "morale": -50, } } } }, 1: { "title": "Prioritise the crew of the Diligent", "then": "You rush to get all the members of the Diligent's crew " + \ "abord before the ships sink deeper into the gravity well. Your mates " + \ "just finish getting that last stretcher on board before the a beeping klaxon " + \ "starts to signal that the two ships are about to be torn away from each other.", "tooltip": "", "results": { 0: { "title": "Gaining crew", "text": "", "stat_changes": { "extra_crew": 5, }, } } }, 2: { "title": "Try to repair the Diligent", "tooltip": "", "then": "Your crew works tirelessly hand-in-hand with" + \ " the Diligent's trying to make their ship fully spaceworthy " + \ "again.", "results": { 0: { "title": "Lose altitude", "text": "", "orbit_changes": { "altitude": -1000, "escape_dv": 100, } } } } } } } }, "ArtificialSatellite" : { "tooltip": "", "situations": { 0: { "title": "Abandoned observation satellite", "picture": null, "text": "During the coast phase of your descent, your ship is " + \ "passing near a derelict satellite. A visual inspection shows " + \ "scorch marks and loose panel on the side", "choices": { 0: { "title": "Download data", "tooltip": "", "then": "Your wireless systems initialize a mesh connection " + \ "with the object and the data begins to stream back to your ship", "results": { 0: { "title": "Losing DeltaV", "text": "The data seems to decodes itself and a malicious program " + \ "begins to run on your ship systems. It manages to fire some of the " + \ "thrusters before you can lock it down.", "stat_changes": { "deltav": -100, }, }, 50: { "title": "Gaining DeltaV", "text": "After decoding the data, it seems to be a detailed chart of " + \ "the local gravity well. This should help you fine tune the course " + \ "towards the [b]Diligent[/b]", "stat_changes": { "deltav": 100, }, }, 90: { "title": "Nothing", "text": "The data appears to be hopelessly corrupt, and you cannot glean anything from it", }, }, }, 1: { "title": "Salvage the probe", "tooltip": "", "then": "Your crew attempts to haul the probe abord using a magnetic cable", "results": { 0: { "title": "Nothing", "text": "The materials making up the probe are so corroded that they " + \ "are unusable and only fit for melting down", "stat_changes": Dictionary(), }, 25: { "title": "Gaining Supplies", "text": "Despite evidence that somebody had tried to repair - or tamper - " + \ "with the satellite, the material composition of it yields many useful " + \ "components", "stat_changes": { "supplies": 100, }, }, 90: { "title": "An event occuring", "text": "During the cable connection, the line gets caught. " + \ "A crew member heads on EVA to try and fix it." + \ "As they near the satellite, it explodes! Their space suit is shredded and they die instantly.", "stat_changes": { "extra_crew": -1, } }, 95: { "title": "An event occuring", "text": "During the cable connection, the line gets caught." + \ "A crew member heads on EVA to try and fix it." + \ "Nearing the satellite, they see a blinking light just under the loose panel. Fearing a bomb, they cut the cable and come back to the ship", } } }, 2: { "title": "Do nothing", "tooltip": "", "then": "You drift silently past the satellite on way down to the Diligent", "results": { 0: { "title": "Nothing happening", "text": "The satellite's collision avoidance system seems to kick in and it adjusts it's orbit away from your ship", } } } } }, }, }, "NaturalSatellite" : { "tooltip": "", "situations": { 0: { "title": "Unexpected object", "picture": null, "text": "The proximity sensor alarms blare suddenly, there's a rock on a collision course!", "choices": { 0: { "title": "Evade", "then": "You fire the thrusters, quickly moving yourself away from the source of danger", "tooltip": "", "results": { 0: { "title": "Losing DeltaV", "text": "The sudden unplanned maneauver eats into your fuel reservers", "stat_changes": { "deltav": -100, } } } }, 1: { "title": "Brace for impact", "then": "You slam the red alert button and your crew pile into their crash seats, gritting their teeth for what is to come", "tooltip": "", "results": { 0: { "title": "Losing Crew and Health", "text": "The object pierces through your hull at hundreds of meters per second, tearing flesh and steel alike. Bulkheads clamp down and sirens wail. After a few seconds, the situation stabilises and you look around, noting that not everyone made it.", "stat_changes": { "extra_crew": -1, } }, 50: { "title": "Losing health", "text": "The object pierces through your hull at hundreds of meters per second, tearing through all manners of ships systems. Chaos reigns as emergency repair systems kick in", "stat_changes": { "health": -250, } }, } }, } } } }, "Comet" : { "tooltip": "", "situations": { 0: { "title": "Extra-solar fly-by", "picture": null, "text": "A large comet blazes through the system, passing nearby. It leaves sparkling trails of ice and gases in it's wake", "choices": { 0: { "title": "Observer the comet", "then": "You direct the majority of the sensors on your ship to observe the comet, and the crew crams in the observation deck to catch glimpses of the fly-by", "results": { }, }, }, }, }, }, "Debris" : { }, #"Gases" : {}, "Mystery" : {}, "Alien" : {}, "Ship" : { "tooltip": "", "situations": { 0: { "title": "Another ship", "picture": null, "text": "There's the quiet remanents of a ship floating through space. " + \ "The hull seems largely intact, but the lights are off.", "choices": { 0: { "title": "Send a boarding party", "then": "You send over a skiff with some of your crew", "tooltip": "", "results": { 0: { "title": "Gain DeltaV", "text": "Nobody is home, but the fuel reserves are almost full", "stat_changes": { "deltav": 100, } }, 25: { "title": "Gain crew", "text": "The away team finds cryo-stasis pods running on battery power", "stat_changes": { "extra_crew": 1 } }, 50: { "title": "Nothing", "text": "The ship is empty of people and supplies. There is a nice diamond ring though", }, 80: { "title": "Event", "text": "An explosion rips through the ship as the boarding skiff docks with it. All hands are lost", "stat_changes": { "extra_crew": -2, } }, 90: { "title": "Event", "text": "The hulk is piled full of dessicated corpses dressed in white and gold vestments, bearing aquiline sigils. Disturbing the grave seems to rub your crew the wrong way.", "crew_changes": { "morale": -25, } } } }, 2: { "title": "Do nothing", "tooltip": "", "then": "You drift silently past the ship on way down to the Diligent", "results": { 0: { "title": "Nothing happening", "text": "The crew looks on through sensors and portholes at the diminishing spec that may have once been a refuge in the void to some souls, now quiet.", } } } }, } } }, "Station" : {}, "LocationSpecific" : {}, } var rng = null var encounters = { # 0: [ # { # "type": EncounterTypeString, # "instance": EncounterNode, # "selected": Boolean (false), # "visited": Boolean (false), # }, ... # ], ... } var current_state = 0 var states = { 0: "Choose Difficulty", 1: "Generate Map", 2: "Intro", 3: "Set Resources and Generate Crew", 4: "Choose flight-path In", 5: "Encounters", 6: "Going Deeper", 7: "Choose flight-path Out", 8: "Encounters 2", 9: "End Game", } const default_ship_stats = { "health": 1000, "deltav": 1000, "supplies": 500, "crew": [], "next_crew_id": 2, "target_position": Vector2(0, 0), "starting_position": Vector2(0, 0), } var ship_stats = {} const default_orbit_stats = { "altitude": 0, "drag": 0, "record_low": 0, "escape_dv": 0, } var orbit_stats = {} # Called when the node enters the scene tree for the first time. func _ready(): self.rng = RandomNumberGenerator.new() self.rng.randomize() func reset_to_new(): var d = difficulty self.reset() self.initialize(d) self.current_state = 4 goto_scene("res://src/ui/ChooseFlightIn.tscn") func reset_to_main_menu(): goto_scene("res://src/ui/MainMenu.tscn") self.reset() func reset(): # @TODO: do we need to free the encounter or crew instances? I don't think so, # since they are part of the tree that's freed when the scene is changed... ship_stats = Dictionary() orbit_stats = Dictionary() # orbit stats: probably not necessary self.current_state = 0 self.encounters = {} self.current_depth = 0 self.difficulty = null var bg = get_tree().get_root().get_node("Background") if bg: bg.free() var end = get_tree().get_root().find_node("End") if end: end.free() func initialize(d): self.difficulty = d for k in default_ship_stats.keys(): ship_stats[k] = default_ship_stats[k] ship_stats['crew'] = Array() for k in default_orbit_stats.keys(): orbit_stats[k] = default_orbit_stats[k] # Generate a map var i = 0 while i < self.TreeDepth: var n = 0 self.encounters[i] = [] while n < self.OptionsPerLevel: var type = self.EncounterTypes[self.rng.randi_range(0, len(self.EncounterTypes)-1)] var encounter = { "type": type, "instance": null, "visited": false, "selected": false, "locked": false, } self.encounters[i].append(encounter) n += 1 i += 1 self.encounters[i] = [] self.encounters[i].append({ "type": "RescueOperation", "instance": null, "visited": false, "selected": true, "locked": true, }) for level in encounters.keys(): print("Encounter level " + str(level)) for e in self.encounters[level]: print("\tOption: " + e.type) # Set the orbit stats self.orbit_stats["altitude"] = get_difficulty_data("starting_altitude") self.orbit_stats["drag"] = get_difficulty_data("starting_drag") self.orbit_stats["record_low"] = get_difficulty_data("starting_altitude") self.generate_crew() get_tree().get_root().call_deferred("add_child", ResourceLoader.load("res://src/ui/Background.tscn").instance()) func get_difficulty_data(key): return self.difficulty_data[self.difficulty][key] func generate_crew(): self.ship_stats["crew"].append({ "name": "Wellspring's Captain", "may_be_sacrified": false, "picture": null, "personality": "paragon", "position": null, "morale": null, "tooltip": "This is you", "upkeep": 10, "id": 1, }) var x = 0 while x < self.get_difficulty_data("starting_crew"): self.add_random_crew_member() x += 1 func add_random_crew_member(): self.ship_stats["crew"].append({ "name": "Xxx", "may_be_sacrified": true, "picture": null, "position": null, "upkeep": 10, "morale": 100, "tooltip": null, "personality": null, "id": self.ship_stats['next_crew_id'], }) self.ship_stats['next_crew_id'] += 1 func generate_encounter_instance(data, level = null, index = null): var instance = null if index == null: index = 0 var source_data = self.EncounterData[data[index]["type"]] var situation = self.rng.randi_range(0, len(source_data["situations"])-1) instance = ResourceLoader.load("res://src/ui/Encounter.tscn").instance() instance.initialize(source_data["situations"][situation]) if level != null and index != null: self.encounters[level][index]["instance"] = instance return instance func goto_scene(scene, current = null, free = true): call_deferred("_deferred_goto_scene", scene, current, free) func _deferred_goto_scene(scene, current = null, free = true): get_tree().get_root().print_tree_pretty() if current: if free: current.free() else: current.set_visible(false) elif self.current_scene: if free: self.current_scene.free() else: self.current_scene.set_visible(false) var next = ResourceLoader.load(scene).instance() get_tree().get_root().add_child(next) get_tree().set_current_scene(next) self.current_scene = next func start_introduction(): self.current_state = 2 self.goto_scene("res://src/ui/Intro.tscn") func end_introduction(): self.current_state = 4 self.goto_scene("res://src/ui/ChooseFlightIn.tscn") func start_encounters(picks): var x = 0 while x < len(self.encounters): self.encounters[x][picks[x]]["selected"] = true self.encounters[x][picks[x]]["locked"] = true x += 1 if self.current_state < 5: self.current_state = 5 self.goto_scene("res://src/ui/Encounters.tscn") if self.current_state > 5: self.current_state = 8 self.goto_scene("res://src/ui/Encounters.tscn", null, false) func choose_flightpath_out(): GameState.current_state = 7 #get_tree().get_root().print_tree_pretty() self.ship_stats['starting_position'] = get_tree().get_root().get_node("Encounters/Map/Ship").get_global_position() self.encounters.erase(GameState.current_depth) GameState.current_depth -= 1 self.goto_scene("res://src/ui/ChooseFlightIn.tscn", null, false) func update_stats(d): for k in d.keys(): if k == "extra_crew": var max_crew = get_difficulty_data("maximum_crew") var crew_to_add = d[k] var x = 0 var modif = false if crew_to_add > 0: if d[k] + len(ship_stats['crew']) > max_crew: crew_to_add = max_crew - len(ship_stats['crew']) while x < crew_to_add: self.add_random_crew_member() modif = true x += 1 elif crew_to_add < 0: print("Needing to lose crew") while crew_to_add < 0 and len(ship_stats['crew']) > 0: ship_stats['crew'].pop_back() print("Lost crew") modif = true crew_to_add += 1 self.update_crew({"morale": -5}) if len(ship_stats['crew']) == 0: self.end(false, "Everybody died") if modif: emit_signal("crew_updated") continue if d[k] == null: continue if d[k] is Vector2: ship_stats[k] = d[k] else: print("Stat change for " + k) print("\tOld: " + str(ship_stats[k])) print("\tNew: " + str(ship_stats[k] + d[k])) ship_stats[k] += d[k] if ship_stats['deltav'] <= 0: self.end(false, "Ran out of fuel") if ship_stats['health'] <= 0: self.end(false, "Your ship fell apart") if ship_stats['supplies'] <= 0: self.end(false, "You ran out of supplies") if ship_stats['supplies'] > 1000: ship_stats['supplies'] = 1000; if ship_stats['deltav'] > 1000: ship_stats['deltav'] = 1000 if ship_stats['health'] > 1000: ship_stats['health'] = 1000 emit_signal("stats_updated") func get_supply_upkeep(): var upkeep = 0 var x = 0 while x < len(ship_stats['crew']): upkeep += ship_stats['crew'][x]['upkeep'] #if ship_stats['crew'][x]['morale'] != null: # upkeep += ship_stats['crew'][x]['upkeep'] * x += 1 return upkeep func update_orbit(d): for k in d.keys(): if k == "altitude": var old = orbit_stats[k] if (orbit_stats[k] + d[k]) < orbit_stats[k]: orbit_stats["record_low"] = orbit_stats[k] + d[k] if d[k] is Vector2: orbit_stats[k] = d[k] else: print("Orbit change for " + k) print("\tOld: " + str(orbit_stats[k])) print("\tNew: " + str(orbit_stats[k] + d[k])) orbit_stats[k] += d[k] emit_signal("orbit_updated") func update_crew(d): var c = len(ship_stats['crew'])-1 while c >= 0: for k in d.keys(): if ship_stats['crew'][c][k] != null: ship_stats['crew'][c][k] += d[k] if ship_stats['crew'][c][k] <= 0: print("Crew #" + str(c) + " has taken a walk on the wrong side of the hull due to low " + k) ship_stats['crew'].remove(c) c -= 1 emit_signal("crew_updated") func end(win_or_fail, reason): # Load the dialog print("ending: " + str(win_or_fail) + " " + reason) var e = ResourceLoader.load("res://src/ui/End.tscn").instance() e.initialize(win_or_fail, reason) self.add_child(e) e.popup_centered() self.current_state = 9 # Called every frame. 'delta' is the elapsed time since the previous frame. #func _process(delta): # pass