mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-21 15:08:12 +00:00

* Some state machine functions to make code tidier in the future * Added a function to Global to check if we're playtesting, for convenience * Only allow noclip w/o debug in leveltesting, toggling added, kept jump key to exit
489 lines
14 KiB
GDScript
489 lines
14 KiB
GDScript
extends Node
|
|
|
|
var level_theme := "Overworld":
|
|
set(value):
|
|
level_theme = value
|
|
level_theme_changed.emit()
|
|
var theme_time := "Day":
|
|
set(value):
|
|
theme_time = value
|
|
level_time_changed.emit()
|
|
|
|
signal level_theme_changed
|
|
signal level_time_changed
|
|
|
|
const BASE64_CHARSET := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
|
|
const VERSION_CHECK_URL := "https://raw.githubusercontent.com/JHDev2006/smb1r-version/refs/heads/main/version.txt"
|
|
|
|
var entity_gravity := 10.0
|
|
var entity_max_fall_speed := 280
|
|
|
|
var level_editor: LevelEditor = null
|
|
var current_level: Level = null
|
|
|
|
var second_quest := false
|
|
var extra_worlds_win := false
|
|
const lang_codes := ["en", "fr", "es", "de", "it", "pt", "pl", "tr", "ru", "jp", "fil", "id", "ga"]
|
|
|
|
var config_path : String = get_config_path()
|
|
|
|
var rom_path := ""
|
|
var rom_assets_exist := false
|
|
var ROM_POINTER_PATH = config_path.path_join("rom_pointer.smb")
|
|
var ROM_PATH = config_path.path_join("baserom.nes")
|
|
var ROM_ASSETS_PATH = config_path.path_join("resource_packs/BaseAssets")
|
|
const ROM_PACK_NAME := "BaseAssets"
|
|
const ROM_ASSETS_VERSION := 1
|
|
|
|
var server_version := -1
|
|
var current_version := -1
|
|
var version_number := ""
|
|
|
|
const LEVEL_THEMES := {
|
|
"SMB1": SMB1_LEVEL_THEMES,
|
|
"SMBLL": SMB1_LEVEL_THEMES,
|
|
"SMBANN": SMB1_LEVEL_THEMES,
|
|
"SMBS": SMBS_LEVEL_THEMES
|
|
}
|
|
|
|
const SMB1_LEVEL_THEMES := ["Overworld", "Desert", "Snow", "Jungle", "Desert", "Snow", "Jungle", "Overworld", "Space", "Autumn", "Pipeland", "Skyland", "Volcano"]
|
|
const SMBS_LEVEL_THEMES := ["Overworld", "Garden", "Beach", "Mountain", "Garden", "Beach", "Mountain", "Overworld", "Autumn", "Pipeland", "Skyland", "Volcano", "Fuck"]
|
|
|
|
const FORCE_NIGHT_THEMES := ["Space"]
|
|
const FORCE_DAY_THEMES := []
|
|
|
|
signal text_shadow_changed
|
|
|
|
@onready var player_ghost: PlayerGhost = $PlayerGhost
|
|
|
|
var debugged_in := true
|
|
|
|
var score_tween = create_tween()
|
|
var time_tween = create_tween()
|
|
|
|
var total_deaths := 0
|
|
|
|
var score := 0:
|
|
set(value):
|
|
if disco_mode == true:
|
|
if value > score:
|
|
var diff = value - score
|
|
score = score + (diff * 1)
|
|
else:
|
|
score = value
|
|
else:
|
|
score = value
|
|
var coins := 0:
|
|
set(value):
|
|
coins = value
|
|
if coins >= 100:#
|
|
if Settings.file.difficulty.inf_lives == 0 and (Global.current_game_mode != Global.GameMode.CHALLENGE and Global.current_campaign != "SMBANN"):
|
|
lives += floor(coins / 100.0)
|
|
AudioManager.play_sfx("1_up", get_viewport().get_camera_2d().get_screen_center_position())
|
|
coins = coins % 100
|
|
var time := 300
|
|
var lives := 3
|
|
var world_num := 1
|
|
|
|
var level_num := 1
|
|
var disco_mode := false
|
|
|
|
enum Room{MAIN_ROOM, BONUS_ROOM, COIN_HEAVEN, PIPE_CUTSCENE, TITLE_SCREEN}
|
|
|
|
const room_strings := ["MainRoom", "BonusRoom", "CoinHeaven", "PipeCutscene", "TitleScreen"]
|
|
|
|
var current_room: Room = Room.MAIN_ROOM
|
|
|
|
signal transition_finished
|
|
var transitioning_scene := false
|
|
var awaiting_transition := false
|
|
|
|
signal level_complete_begin
|
|
signal score_tally_finished
|
|
|
|
var achievements := "0000000000000000000000000000"
|
|
|
|
const LSS_GAME_ID := 5
|
|
|
|
enum AchievementID{
|
|
SMB1_CLEAR, SMBLL_CLEAR, SMBS_CLEAR, SMBANN_CLEAR,
|
|
SMB1_CHALLENGE, SMBLL_CHALLENGE, SMBS_CHALLENGE,
|
|
SMB1_BOO, SMBLL_BOO, SMBS_BOO,
|
|
SMB1_GOLD_BOO, SMBLL_GOLD_BOO, SMBS_GOLD_BOO,
|
|
SMB1_BRONZE, SMBLL_BRONZE, SMBS_BRONZE,
|
|
SMB1_SILVER, SMBLL_SILVER, SMBS_SILVER,
|
|
SMB1_GOLD, SMBLL_GOLD, SMBS_GOLD,
|
|
SMB1_RUN, SMBLL_RUN, SMBS_RUN,
|
|
ANN_PRANK, SMBLL_WORLD9,
|
|
COMPLETIONIST
|
|
}
|
|
|
|
const HIDDEN_ACHIEVEMENTS := [AchievementID.COMPLETIONIST]
|
|
|
|
var can_time_tick := true:
|
|
set(value):
|
|
can_time_tick = value
|
|
if value == false:
|
|
pass
|
|
|
|
var player_power_states := "0000"
|
|
|
|
var connected_players := 1
|
|
|
|
const CAMPAIGNS := ["SMB1", "SMBLL", "SMBS", "SMBANN"]
|
|
|
|
var player_characters := [0, 0, 0, 0]:
|
|
set(value):
|
|
player_characters = value
|
|
player_characters_changed.emit()
|
|
signal player_characters_changed
|
|
|
|
signal disco_level_continued
|
|
|
|
signal frame_rule
|
|
|
|
var hard_mode := false
|
|
|
|
var current_campaign := "SMB1"
|
|
|
|
var death_load := false
|
|
|
|
var tallying_score := false
|
|
|
|
var in_title_screen := false
|
|
|
|
var game_paused := false
|
|
var can_pause := true
|
|
|
|
var fade_transition := true
|
|
|
|
enum GameMode{NONE, CAMPAIGN, BOO_RACE, CHALLENGE, MARATHON, MARATHON_PRACTICE, LEVEL_EDITOR, CUSTOM_LEVEL, DISCO}
|
|
|
|
const game_mode_strings := ["Default", "Campaign", "BooRace", "Challenge", "Marathon", "MarathonPractice", "LevelEditor", "CustomLevel", "Disco"]
|
|
|
|
var current_game_mode: GameMode = GameMode.NONE
|
|
|
|
var high_score := 0
|
|
var game_beaten := false
|
|
|
|
signal p_switch_toggle
|
|
var p_switch_active := false
|
|
var p_switch_timer := 0.0
|
|
var p_switch_timer_paused := false
|
|
|
|
var debug_mode := false
|
|
|
|
func _ready() -> void:
|
|
current_version = get_version_number()
|
|
get_server_version()
|
|
if OS.is_debug_build():
|
|
debug_mode = false
|
|
setup_config_dirs()
|
|
check_for_rom()
|
|
|
|
func setup_config_dirs() -> void:
|
|
var dirs = [
|
|
"custom_characters",
|
|
"custom_levels",
|
|
"logs",
|
|
"marathon_recordings",
|
|
"resource_packs",
|
|
"saves",
|
|
"screenshots"
|
|
]
|
|
|
|
for d in dirs:
|
|
var full_path = Global.config_path.path_join(d)
|
|
if not DirAccess.dir_exists_absolute(full_path):
|
|
DirAccess.make_dir_recursive_absolute(full_path)
|
|
|
|
func get_config_path() -> String:
|
|
var exe_path := OS.get_executable_path()
|
|
var exe_dir := exe_path.get_base_dir()
|
|
var portable_flag := exe_dir.path_join("portable.txt")
|
|
|
|
# Test that exe dir is writeable, if not fallback to user://
|
|
if FileAccess.file_exists(portable_flag):
|
|
var test_file = exe_dir.path_join("test.txt")
|
|
var f = FileAccess.open(test_file, FileAccess.WRITE)
|
|
if f:
|
|
f.close()
|
|
var dir = DirAccess.open(exe_dir)
|
|
if dir:
|
|
dir.remove(test_file.get_file())
|
|
var local_dir = exe_dir.path_join("config")
|
|
if not DirAccess.dir_exists_absolute(local_dir):
|
|
DirAccess.make_dir_recursive_absolute(local_dir)
|
|
return local_dir
|
|
else:
|
|
push_warning("Portable flag found but exe directory is not writeable. Falling back to user://")
|
|
return "user://"
|
|
|
|
func check_for_rom() -> void:
|
|
rom_path = ""
|
|
rom_assets_exist = false
|
|
if FileAccess.file_exists(Global.ROM_PATH) == false:
|
|
return
|
|
var path = Global.ROM_PATH
|
|
if FileAccess.file_exists(path):
|
|
if ROMVerifier.is_valid_rom(path):
|
|
rom_path = path
|
|
if DirAccess.dir_exists_absolute(ROM_ASSETS_PATH):
|
|
var pack_json: String = FileAccess.get_file_as_string(ROM_ASSETS_PATH + "/pack_info.json")
|
|
var pack_dict: Dictionary = JSON.parse_string(pack_json)
|
|
if pack_dict.get("version", -1) == ROM_ASSETS_VERSION:
|
|
rom_assets_exist = true
|
|
else:
|
|
ResourceGenerator.updating = true
|
|
OS.move_to_trash(ROM_ASSETS_PATH)
|
|
|
|
func _process(delta: float) -> void:
|
|
if Input.is_action_just_pressed("debug_reload"):
|
|
ResourceSetter.cache.clear()
|
|
ResourceSetterNew.cache.clear()
|
|
ResourceGetter.cache.clear()
|
|
AudioManager.current_level_theme = ""
|
|
level_theme_changed.emit()
|
|
log_comment("Reloaded resource packs!")
|
|
|
|
if Input.is_action_just_pressed("toggle_fps_count"):
|
|
%FPSCount.visible = !%FPSCount.visible
|
|
%FPSCount.text = str(int(Engine.get_frames_per_second())) + " FPS"
|
|
|
|
handle_p_switch(delta)
|
|
if Input.is_key_label_pressed(KEY_F11) and debug_mode == false and OS.is_debug_build():
|
|
AudioManager.play_global_sfx("switch")
|
|
debug_mode = true
|
|
log_comment("Debug Mode enabled! some bugs may occur!")
|
|
|
|
if Input.is_action_just_pressed("ui_screenshot"):
|
|
take_screenshot()
|
|
|
|
func take_screenshot() -> void:
|
|
var img: Image = get_viewport().get_texture().get_image()
|
|
var filename = Global.config_path.path_join("screenshots/screenshot_" + str(int(Time.get_unix_time_from_system())) + ".png")
|
|
var err = img.save_png(filename)
|
|
if !err:
|
|
log_comment("Screenshot Saved!")
|
|
else:
|
|
log_error(error_string(err))
|
|
|
|
func handle_p_switch(delta: float) -> void:
|
|
if p_switch_active and get_tree().paused == false:
|
|
if p_switch_timer_paused == false:
|
|
p_switch_timer -= delta
|
|
if p_switch_timer <= 0:
|
|
p_switch_active = false
|
|
p_switch_toggle.emit()
|
|
AudioManager.stop_music_override(AudioManager.MUSIC_OVERRIDES.PSWITCH)
|
|
|
|
func get_build_time() -> void:
|
|
print(int(Time.get_unix_time_from_system()))
|
|
|
|
func get_version_number() -> int:
|
|
var number = (FileAccess.open("res://version.txt", FileAccess.READ).get_as_text())
|
|
version_number = str(number)
|
|
return int(number)
|
|
|
|
func player_action_pressed(action := "", player_id := 0) -> bool:
|
|
return Input.is_action_pressed(action + "_" + str(player_id))
|
|
|
|
func player_action_just_pressed(action := "", player_id := 0) -> bool:
|
|
return Input.is_action_just_pressed(action + "_" + str(player_id))
|
|
|
|
func player_action_just_released(action := "", player_id := 0) -> bool:
|
|
return Input.is_action_just_released(action + "_" + str(player_id))
|
|
|
|
func tally_time() -> void:
|
|
if tallying_score:
|
|
return
|
|
$ScoreTally.play()
|
|
tallying_score = true
|
|
var target_score = score + (time * 50)
|
|
score_tween = create_tween()
|
|
time_tween = create_tween()
|
|
var duration = float(time) / 120
|
|
|
|
score_tween.tween_property(self, "score", target_score, duration)
|
|
time_tween.tween_property(self, "time", 0, duration)
|
|
await score_tween.finished
|
|
tallying_score = false
|
|
$ScoreTally.stop()
|
|
$ScoreTallyEnd.play()
|
|
score_tally_finished.emit()
|
|
|
|
func cancel_score_tally() -> void:
|
|
score_tween.kill()
|
|
time_tween.kill()
|
|
tallying_score = false
|
|
$ScoreTally.stop()
|
|
|
|
func activate_p_switch() -> void:
|
|
if p_switch_active == false:
|
|
p_switch_toggle.emit()
|
|
AudioManager.set_music_override(AudioManager.MUSIC_OVERRIDES.PSWITCH, 99, false)
|
|
p_switch_timer = 10
|
|
p_switch_active = true
|
|
|
|
func reset_values() -> void:
|
|
PlayerGhost.idx = 0
|
|
Checkpoint.passed_checkpoints.clear()
|
|
Checkpoint.sublevel_id = 0
|
|
Global.total_deaths = 0
|
|
Door.unlocked_doors = []
|
|
Checkpoint.unlocked_doors = []
|
|
KeyItem.total_collected = 0
|
|
Checkpoint.keys_collected = 0
|
|
Level.start_level_path = Level.get_scene_string(Global.world_num, Global.level_num)
|
|
LevelPersistance.reset_states()
|
|
Level.first_load = true
|
|
Level.can_set_time = true
|
|
Level.in_vine_level = false
|
|
Level.vine_return_level = ""
|
|
Level.vine_warp_level = ""
|
|
p_switch_active = false
|
|
p_switch_timer = 0.0
|
|
|
|
func clear_saved_values() -> void:
|
|
coins = 0
|
|
score = 0
|
|
lives = 3
|
|
player_power_states = "0000"
|
|
|
|
func transition_to_scene(scene_path := "") -> void:
|
|
Global.fade_transition = bool(Settings.file.visuals.transition_animation)
|
|
if transitioning_scene:
|
|
return
|
|
transitioning_scene = true
|
|
if fade_transition:
|
|
$Transition/AnimationPlayer.play("FadeIn")
|
|
await $Transition/AnimationPlayer.animation_finished
|
|
await get_tree().create_timer(0.1, true).timeout
|
|
else:
|
|
%TransitionBlock.modulate.a = 1
|
|
$Transition.show()
|
|
await get_tree().create_timer(0.1, true).timeout
|
|
get_tree().change_scene_to_file(scene_path)
|
|
await get_tree().scene_changed
|
|
await get_tree().create_timer(0.15, true).timeout
|
|
if fade_transition:
|
|
$Transition/AnimationPlayer.play_backwards("FadeIn")
|
|
else:
|
|
$Transition/AnimationPlayer.play("RESET")
|
|
$Transition.hide()
|
|
transitioning_scene = false
|
|
transition_finished.emit()
|
|
|
|
|
|
|
|
func do_fake_transition(duration := 0.2) -> void:
|
|
if fade_transition:
|
|
$Transition/AnimationPlayer.play("FadeIn")
|
|
await $Transition/AnimationPlayer.animation_finished
|
|
await get_tree().create_timer(duration, false).timeout
|
|
$Transition/AnimationPlayer.play_backwards("FadeIn")
|
|
else:
|
|
%TransitionBlock.modulate.a = 1
|
|
$Transition.show()
|
|
await get_tree().create_timer(duration + 0.05, false).timeout
|
|
$Transition.hide()
|
|
|
|
func freeze_screen() -> void:
|
|
if Settings.file.video.visuals == 1:
|
|
return
|
|
$Transition.show()
|
|
$Transition/Freeze.show()
|
|
$Transition/Freeze.texture = ImageTexture.create_from_image(get_viewport().get_texture().get_image())
|
|
|
|
func close_freeze() -> void:
|
|
$Transition/Freeze.hide()
|
|
$Transition.hide()
|
|
|
|
var recording_dir = config_path.path_join("marathon_recordings")
|
|
|
|
func update_game_status() -> void:
|
|
var lives_str := str(Global.lives)
|
|
if Settings.file.difficulty.inf_lives == 1:
|
|
lives_str = "∞"
|
|
var string := "Coins = " + str(Global.coins) + " Lives = " + lives_str
|
|
|
|
func open_marathon_results() -> void:
|
|
get_node("GameHUD/MarathonResults").open()
|
|
|
|
func open_disco_results() -> void:
|
|
get_node("GameHUD/DiscoResults").open()
|
|
|
|
func on_score_sfx_finished() -> void:
|
|
if tallying_score:
|
|
$ScoreTally.play()
|
|
|
|
func get_server_version() -> void:
|
|
var http = HTTPRequest.new()
|
|
add_child(http)
|
|
http.request_completed.connect(version_got)
|
|
http.request(VERSION_CHECK_URL, [], HTTPClient.METHOD_GET)
|
|
|
|
func version_got(_result, response_code, _headers, body) -> void:
|
|
if response_code == 200:
|
|
server_version = int(body.get_string_from_utf8())
|
|
else:
|
|
server_version = -2
|
|
|
|
func log_error(msg := "") -> void:
|
|
var error_message = $CanvasLayer/VBoxContainer/ErrorMessage.duplicate()
|
|
error_message.text = "Error - " + msg
|
|
error_message.visible = true
|
|
$CanvasLayer/VBoxContainer.add_child(error_message)
|
|
await get_tree().create_timer(10, false).timeout
|
|
error_message.queue_free()
|
|
|
|
func log_warning(msg := "") -> void:
|
|
var error_message = $CanvasLayer/VBoxContainer/Warning.duplicate()
|
|
error_message.text = "Warning - " + msg
|
|
error_message.visible = true
|
|
$CanvasLayer/VBoxContainer.add_child(error_message)
|
|
await get_tree().create_timer(10, false).timeout
|
|
error_message.queue_free()
|
|
|
|
func log_comment(msg := "") -> void:
|
|
var error_message = $CanvasLayer/VBoxContainer/Comment.duplicate()
|
|
error_message.text = msg
|
|
error_message.visible = true
|
|
$CanvasLayer/VBoxContainer.add_child(error_message)
|
|
await get_tree().create_timer(2, false).timeout
|
|
error_message.queue_free()
|
|
|
|
func level_editor_is_playtesting() -> bool:
|
|
if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
|
|
if Global.level_editor.current_state == LevelEditor.EditorState.PLAYTESTING:
|
|
return true
|
|
return false
|
|
|
|
func unlock_achievement(achievement_id := AchievementID.SMB1_CLEAR) -> void:
|
|
achievements[achievement_id] = "1"
|
|
if achievement_id != AchievementID.COMPLETIONIST:
|
|
check_completionist_achievement()
|
|
SaveManager.write_achievements()
|
|
|
|
func check_completionist_achievement() -> void:
|
|
if achievements.count("0") == 1:
|
|
unlock_achievement(AchievementID.COMPLETIONIST)
|
|
|
|
const FONT = preload("res://Assets/Sprites/UI/Font.fnt")
|
|
|
|
func sanitize_string(string := "") -> String:
|
|
string = string.to_upper()
|
|
for i in string.length():
|
|
if FONT.has_char(string.unicode_at(i)) == false and string[i] != "\n":
|
|
string = string.replace(string[i], " ")
|
|
return string
|
|
|
|
func get_base_asset_version() -> int:
|
|
var json = JSON.parse_string(FileAccess.open("user://BaseAssets/pack_info.json", FileAccess.READ).get_as_text())
|
|
var version = json.version
|
|
return get_version_num_int(version)
|
|
|
|
func get_version_num_int(ver_num := "0.0.0") -> int:
|
|
return int(ver_num.replace(".", ""))
|