mirror of
				https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
				synced 2025-11-04 08:35:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			491 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			GDScript
		
	
	
	
	
	
			
		
		
	
	
			491 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 = null
 | 
						|
var time_tween = null
 | 
						|
 | 
						|
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:
 | 
						|
	if score_tween != null:
 | 
						|
		score_tween.kill()
 | 
						|
	if time_tween != null:
 | 
						|
		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(".", ""))
 |