###################### ### Jessist Script ### ###################### # This script is part of Jessist # Jessist is licensed under GNU GPLv3 # # This script manages basically all important and shared functions and variables # used throughout Jessist. # It currently contains: # - a logger, # - scene switcher with fade transition, # - music player, # - crash function, # - dialog manager # NOTE: This code is pretty much imported from documentation with a few modifications « Bullshit # Link: https://docs.godotengine.org/en/stable/tutorials/scripting/singletons_autoload.html « Bullshit extends Node var currentDialog = null var dialogBalloon = ResourceLoader.load("res://Dialog/dialog/dialog.tscn").instance() var currentScene = null var loadingScene = ResourceLoader.load("res://Scenes/LoadingScene.tscn").instance() var transitionScene = ResourceLoader.load("res://Scenes/Transition.tscn").instance() var countersScene = ResourceLoader.load("res://Scenes/Modules/Counters.tscn").instance() var crashScene = ResourceLoader.load("res://Scenes/CrashHandler.tscn").instance() var debugConsoleScene = ResourceLoader.load("res://Scenes/Modules/DebugConsole.tscn").instance() var transitionState = 0 var music = AudioStreamPlayer.new() var sound = AudioStreamPlayer.new() export (bool) var debuggingMode = OS.is_debug_build() export (bool) var enableVerbosity = true export (bool) var enableVelocityMessages = true export (bool) var enableFunctionCalls = true export (bool) var enableCounters = false export (bool) var logger = true export (bool) var loggerInfo = true export (bool) var loggerWarn = true export (bool) var loggerError = true export (bool) var gamePaused = false export (float, -60, -5) var musicVolumeDefault = -5 export (float, -60, -5) var musicVolumePaused = -15 export (float, -60, -5) var musicVolumeLoad = -40 export (float) var musicVolume = 0 export (String, "Rocket") var musicPlaying = "Rocket" export (AudioStreamOGGVorbis) var musicStream = null export (String) var soundPlaying = null export (AudioStreamOGGVorbis) var soundStream = null export (bool) var soundAllow = true export (bool) var musicAllow = true export (bool) var allowCheats = true export (bool) var crashed = false var thread = null var threadMusic = null var threadMusicPlay = null var threadSound = null var threadSoundPlay = null var transitionThread = null var logSchema = "[%logtype%] [%script% | %function%] %message%" var sessionLog = Array() enum logTypes {CALL,ERRO,WARN,INFO,VERB,VEPO} func _ready(): if debuggingMode: logInfo("GameController","_ready","Developer Mode is activated. If this should be a production build, DISABLE debuggingMode IN GameController.gd NOW.") else: pass #enableVerbosity = false #enableVelocityMessages = false #enableFunctionCalls = false #enableCounters = false if not enableVerbosity: enableVelocityMessages = false enableFunctionCalls = false if not logger: loggerInfo = false loggerWarn = false loggerError = false currentScene = get_tree().get_root().get_child(get_tree().get_root().get_child_count() - 1) logInfo("GameController","_ready","Initialization done") func _process(_delta): if Input.is_action_just_pressed("debug_console") and debuggingMode: get_tree().get_root().add_child(debugConsoleScene) func switchToMainScreen(loadGame): logInfo("GameController","switchToMainScreen","Request for scene switch to MainScreen accepted") logInfo("GameController","switchScene","GCSC Waiting for all threads to finish execution") if loadGame: call_deferred("_switchScene_deferred", "res://Scenes/MainScreen.tscn", false) else: call_deferred("_switchScene_deferred", "res://Scenes/MainScreen.tscn", false) func switchScene(path): logInfo("GameController","switchScene","Request for scene switch accepted") gamePaused = true logInfo("GameController","switchScene","Waiting for all threads to finish execution") call_deferred("_switchScene_deferred", path, false) func _switchScene_deferred(path, isMainScreen): logInfo("GameController","_switchScene_deferred","Threads finished execution") _transition_start() while true: yield(get_tree().create_timer(0.01), "timeout") if transitionState == 1: continue else: break logInfo("GameController","_switchScene_deferred","Removing scenes") for child in get_tree().get_root().get_children(): if child.name == "gameController" or child.name == "sp" or child.name == "gd" or child.name == "scene_manager" or child.name == "Transition" or child.name == music.name or child.name == "CrashHandler": continue logInfo("GameController","_switchScene_deferred","Removing child " + child.name) get_tree().get_root().remove_child(child) if currentScene != null: logInfo("GameController","_switchScene_deferred","Freeing currentScene") currentScene.free() logInfo("GameController","_switchScene_deferred","Displaying loading scene") get_tree().get_root().add_child(loadingScene) get_tree().set_current_scene(loadingScene) transitionState = 2 while true: yield(get_tree().create_timer(0.01), "timeout") if transitionState == 3: continue else: break while true: yield(get_tree().create_timer(0.01), "timeout") if transitionState == 2: continue else: break var waitnum = 0 if isMainScreen: waitnum = 8.25 else: waitnum = 1.25 logInfo("GameController","_switchScene_deferred","Waiting " + str(waitnum) + "s") yield(get_tree().create_timer(waitnum),"timeout") logInfo("GameController","_switchScene_deferred","Starting thread") thread = Thread.new() thread.start(self, "_switchScene_thread_start", path) func _switchScene_thread_start(path): logInfo("GameController","_switchScene_thread_start","Loading and instancing scene") var loader = ResourceLoader.load_interactive(path) while true: if loader.poll() == ERR_FILE_EOF: currentScene = loader.get_resource().instance() break call_deferred("_switchScene_thread_end") func _switchScene_thread_end(): _transition_start() while true: yield(get_tree().create_timer(0.01), "timeout") if transitionState == 1: continue else: break logInfo("GameController","_switchScene_thread_end","Displaying scene " + currentScene.name) get_tree().get_root().add_child(currentScene) get_tree().set_current_scene(currentScene) if enableCounters: logInfo("GameController","_switchScene_thread_end","Adding counters") get_tree().get_root().add_child(countersScene) logInfo("GameController","_switchScene_thread_end","Removing loading scene") for child in get_tree().get_root().get_children(): if child.name == "LoadingScene": get_tree().get_root().remove_child(child) transitionState = 2 gamePaused = false while true: yield(get_tree().create_timer(0.01), "timeout") if transitionState == 3: continue else: break logInfo("GameController","_switchScene_thread_end","Execution done") func transitionSwitch(): logInfo("GameController","transitionSwitch","Call to transitionSwitch() detected. Please remove that line from your script.") func _transition_start(): changeVolume("volumePaused") logInfo("GameController","_transition_start","Adding TransitionScene") get_tree().get_root().add_child(transitionScene) var transition = get_node("/root/Transition") logInfo("GameController","_transition_start","Starting FADEIN transition") transitionState = 1 transition.startTransition(transition.transitionStates.FADEIN) yield(get_tree().create_timer(0.5), "timeout") logInfo("GameController","_transition_start","FADEIN transition done") transitionState = 3 transitionThread = Thread.new() transitionThread.start(self,"_transition_start_thread",transition) func _transition_start_thread(transition): logInfo("GameController","_transition_start","Waiting for FADEOUT allowance") while true: yield(get_tree().create_timer(0.01), "timeout") if transitionState == 2: break else: continue logInfo("GameController","_transition_start","Starting FADEOUT transition") transition.startTransition(transition.transitionStates.FADEOUT) yield(get_tree().create_timer(0.5), "timeout") logInfo("GameController","_transition_start","FADEOUT transition done") changeVolume("volumeDefault") _transition_end() func _transition_end(): for child in get_tree().get_root().get_children(): if child.name == "Transition": logInfo("GameController","_transition_end","Removing TransitionScene") get_tree().get_root().remove_child(child) transitionState = 0 func _logger(logtype,script,function,message): if logger: if logtype == logTypes.CALL: logtype = "CALL" elif logtype == logTypes.ERRO: logtype = "ERRO" elif logtype == logTypes.INFO: logtype = "INFO" elif logtype == logTypes.WARN: logtype = "WARN" elif logtype == logTypes.VERB: logtype = "VERB" elif logtype == logTypes.VEPO: logtype = "VEPO" print(logSchema.replace("%logtype%",logtype).replace("%script%",script).replace("%function%",function).replace("%message%",message)) sessionLog.append(logSchema.replace("%logtype%",logtype).replace("%script%",script).replace("%function%",function).replace("%message%",message)) func logCall(script,function,args): if not enableFunctionCalls: return if function == "_ready": _logger(logTypes.CALL,script,function,"Starting initialization of script " + script) return args = str(args) if args == "" or args == null or args == "Null": _logger(logTypes.CALL,script,function,"Function was called") else: _logger(logTypes.CALL,script,function,"Function was called with arguments " + args) func logInfo(script,function,message): if not loggerInfo: return _logger(logTypes.INFO,script,function,message) func logWarn(script,function,message): if not loggerWarn: return _logger(logTypes.WARN,script,function,message) func logError(script,function,message): if not loggerError: return _logger(logTypes.ERRO,script,function,message) func logVerbose(script,function,message): if not enableVerbosity: return _logger(logTypes.VERB,script,function,message) func logVelocity(script,function,messageVelocityPosition): if not enableVelocityMessages: return var message = null if typeof(messageVelocityPosition) == typeof(Vector2(0,0)): message = "VELO/POS » X: " + str(messageVelocityPosition.x) + " | Y: " + str(messageVelocityPosition.y) else: message = str(messageVelocityPosition) _logger(logTypes.VEPO,script,function,message) func loadSound(effect): if not soundAllow: return if effect == null or effect == "": logInfo("GameController","loadSound","Argument is null") soundPlaying = effect logInfo("GameController","loadSound","Loading sound " + soundPlaying) soundStream = load("res://Sounds/" + soundPlaying + ".ogg") sound.stream = soundStream sound.volume_db = 0 get_tree().get_root().add_child(sound) func playSound(delay): if not soundAllow: return if soundStream == null: logInfo("GameController","playSound","Sound stream is not loaded") return threadSoundPlay = Thread.new() threadSoundPlay.start(self, "_playSound_thread",delay) func _playSound_thread(delay): yield(get_tree().create_timer(delay), "timeout") for child in get_tree().get_root().get_children(): if child.name == sound.name: logInfo("GameController","playSound","Starting playback") child.play(0) func stopSound(wildcardOrSound): for child in get_tree().get_root().get_children(): if typeof(wildcardOrSound) == typeof(true): if wildcardOrSound: if child.name == sound.name: logInfo("GameController","stopSound","Stopping playback of every sound") get_tree().get_root().remove_child(child) else: logInfo("GameController","stopSound","Wildcard is disabled") else: if child.name == sound.name and sound.stream.resource_path == "res://Sounds/" + sound + ".ogg": logInfo("GameController","stopSound","Stopping playback of sound " + sound) get_tree().get_root().remove_child(child) func loadMusic(song): if not musicAllow: return if song == null or song == "": logInfo("GameController","loadMusic","Argument is null") stopMusic() musicPlaying = song logInfo("GameController","loadMusic","Loading music " + musicPlaying) musicStream = load("res://Sounds/Music/" + musicPlaying + ".ogg") music.stream = musicStream music.volume_db = musicVolumeLoad musicVolume = musicVolumeLoad get_tree().get_root().add_child(music) func playMusic(delay): if not musicAllow: return if musicStream == null: logInfo("GameController","playMusic","Music stream is not loaded") return threadMusicPlay = Thread.new() threadMusicPlay.start(self,"_playMusic_thread",delay) func _playMusic_thread(delay): if not delay == null: yield(get_tree().create_timer(delay), "timeout") for child in get_tree().get_root().get_children(): if child.name == music.name: logInfo("GameController","playMusic","Starting playback") child.play(0) func stopMusic(): for child in get_tree().get_root().get_children(): if child.name == music.name: logInfo("GameController","stopMusic","Stopping playback") get_tree().get_root().remove_child(child) func pauseMusic(): for child in get_tree().get_root().get_children(): if child.name == music.name: if child.playing: logInfo("GameController","pauseMusic","Pausing playback") child.playing = false func continueMusic(): for child in get_tree().get_root().get_children(): if child.name == music.name: if not child.playing: logInfo("GameController","continueMusic","Continuing playback") child.playing = true func changeVolume(valueOrSetValue): logInfo("GameController","changeVolume","Changing volume") if typeof(valueOrSetValue) == typeof(""): if valueOrSetValue == "volumeDefault": threadMusic = Thread.new() threadMusic.start(self, "_changeVolume_thread", musicVolumeDefault) elif valueOrSetValue == "volumePaused": threadMusic = Thread.new() threadMusic.start(self, "_changeVolume_thread", musicVolumePaused) else: logInfo("GameController","changeVolume","Invalid SetValue. Please use volumeDefault, volumePaused or a custom number") return elif typeof(valueOrSetValue) == typeof(float(0)): threadMusic = Thread.new() threadMusic.start(self, "_changeVolume_thread", valueOrSetValue) else: logInfo("GameController","changeVolume","Invalid argument type. Please use a volumeDefault, volumePaused or a custom number") return func _changeVolume_thread(volume): var musicplayer = null for child in get_tree().get_root().get_children(): if child.name == music.name: musicplayer = child if musicplayer == null: logInfo("GameController","changeVolume","Music player not found") return while true: if volume == musicplayer.volume_db: break elif volume >= musicplayer.volume_db: musicplayer.volume_db += 1 elif volume <= musicplayer.volume_db: musicplayer.volume_db -= 1 logInfo("GameController","changeVolume","Volume: " + str(musicplayer.volume_db)) musicVolume = musicplayer.volume_db yield(get_tree().create_timer(0.05), "timeout") func isMusicPlaying(): for child in get_tree().get_root().get_children(): if child.name == music.name: return child.playing func crashJessist(script,function,debugInfo): if crashed: return crashed = true logInfo("GameController","crashJessist","Pausing game") gamePaused = true logInfo("GameController","crashJessist","Loading CrashHandler scene") crashScene.debuggingInformation = [script,function,debugInfo] get_tree().get_root().add_child(crashScene) get_tree().set_current_scene(crashScene) logInfo("GameController","crashJessist","Waiting for all threads to finish execution") call_deferred("_crashJessist_deferred") func _crashJessist_deferred(): logInfo("GameController","_crashJessist_deferred","Killing scenes") for child in get_tree().get_root().get_children(): if child.name == "gameController" or child.name == "sp" or child.name == "gd" or child.name == "scene_manager" or child.name == "Transition" or child.name == music.name or child.name == "CrashHandler": continue logInfo("GameController","_crashJessist_deferred","Removing child " + child.name) get_tree().get_root().remove_child(child) if currentScene != null: currentScene.free() func getFullLog(): logInfo("GameController","getFullLog","Collecting full log file") var sessionLogTmp = sessionLog sessionLogTmp.append("LOGSESSIONEND") var logfile = str(sessionLogTmp) logfile = logfile.replace("[LOGSESSIONSTART, ","") logfile = logfile.replace(", LOGSESSIONEND]","") logfile = logfile.replace(", ","\n") logInfo("GameController","getFullLog","Collected full log file") return logfile func getLog(lines): logInfo("GameController","getFullLog","Collecting last " + str(lines) + " lines of the log file") var sessionLogTmp = Array() sessionLogTmp.append("LOGSESSIONSTART") sessionLogTmp.append_array(sessionLog.slice(sessionLog.size() - lines, sessionLog.size())) sessionLogTmp.append("LOGSESSIONEND") var logfile = str(sessionLogTmp) logfile = logfile.replace("[LOGSESSIONSTART, ","") logfile = logfile.replace(", LOGSESSIONEND]","") logfile = logfile.replace(", ","\n") logInfo("GameController","getFullLog","Collected " + str(lines)) return logfile func dialog(diag,entrypoint): logInfo("GameController","dialog","Dialog request aknowledged") var res = null if diag == "Timeleton": res = preload("res://Dialog/Timeleton.tres") elif diag == "GameEnd": res = preload("res://Dialog/GameEnd.tres") else: logError("GameController","dialogStart","Can't start dialog, invalid dialog specified") return logInfo("GameController","dialog","Displaying dialog") _showDiag(entrypoint, res) func _showDiag(title: String, resource: DialogueResource) -> void: var dialogue = yield(DialogueManager.get_next_dialogue_line(title, resource), "completed") if dialogue != null: var balloon = dialogBalloon balloon.dialogue = dialogue add_child(balloon) # Dialogue might have response options so we have to wait and see # what the player chose. "actioned" is emitted and passes the "next_id" # once the player has made their choice. _showDiag(yield(balloon, "actioned"), resource)