mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-22 15:38:14 +00:00
Merge remote-tracking branch 'upstream/main' into pulls/small-crouch-hitbox-fix
This commit is contained in:
@@ -65,11 +65,17 @@ func player_win_race() -> void:
|
||||
TimedBooBlock.can_tick = false
|
||||
|
||||
var cleared_boo: int = 0
|
||||
for boo_time in boo.time_needed:
|
||||
if SpeedrunHandler.timer < boo_time:
|
||||
cleared_boo += 1
|
||||
else:
|
||||
break
|
||||
|
||||
if boo_colour >= 4:
|
||||
cleared_boo = 5
|
||||
else:
|
||||
var idx := 0
|
||||
for boo_time in boo.time_needed:
|
||||
if SpeedrunHandler.timer < boo_time and idx < 4:
|
||||
cleared_boo += 1
|
||||
else:
|
||||
break
|
||||
idx += 1
|
||||
|
||||
if int(BooRaceHandler.cleared_boo_levels[level_id]) <= cleared_boo:
|
||||
BooRaceHandler.cleared_boo_levels[level_id] = str(cleared_boo)
|
||||
|
@@ -26,7 +26,7 @@ func get_resource(resource: Resource) -> Resource:
|
||||
|
||||
if original_resource is Texture:
|
||||
var new_resource = null
|
||||
if path.contains("user://"):
|
||||
if path.contains(Global.config_path):
|
||||
new_resource = ImageTexture.create_from_image(Image.load_from_file(path))
|
||||
else:
|
||||
new_resource = load(path)
|
||||
@@ -64,7 +64,7 @@ func send_to_cache(resource_path := "", resource_to_cache: Resource = null) -> v
|
||||
|
||||
func get_resource_path(resource_path := "") -> String:
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
var test = resource_path.replace("res://Assets/", "user://resource_packs/" + i + "/")
|
||||
var test = resource_path.replace("res://Assets/", Global.config_path.path_join("resource_packs/" + i + "/"))
|
||||
if FileAccess.file_exists(test):
|
||||
return test
|
||||
return resource_path
|
||||
|
@@ -134,13 +134,13 @@ static func get_pure_resource_path(resource_path := "") -> String:
|
||||
if Settings.file.visuals.resource_packs.is_empty() == false:
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
var new_path = get_override_resource_path(resource_path, i)
|
||||
new_path = new_path.replace("user://custom_characters/", "user://resource_packs/" + new_path + "/Sprites/Players/CustomCharacters/")
|
||||
new_path = new_path.replace(Global.config_path.path_join("custom_characters"), Global.config_path.path_join("resource_packs/" + new_path + "/Sprites/Players/CustomCharacters/"))
|
||||
if FileAccess.file_exists(new_path):
|
||||
return new_path
|
||||
return resource_path
|
||||
|
||||
static func get_override_resource_path(resource_path := "", resource_pack := "") -> String:
|
||||
if resource_pack != "":
|
||||
return resource_path.replace("res://Assets", "user://resource_packs/" + resource_pack)
|
||||
return resource_path.replace("res://Assets", Global.config_path.path_join("resource_packs/" + resource_pack))
|
||||
else:
|
||||
return resource_path
|
||||
|
@@ -168,7 +168,16 @@ func apply_properties(properties := {}) -> void:
|
||||
if value is Array:
|
||||
property_node.set(i, Vector2(value[0], value[1]))
|
||||
else:
|
||||
property_node.set(i, properties[i])
|
||||
var obj = property_node
|
||||
for p in i.split("."):
|
||||
if not is_instance_valid(obj): continue
|
||||
if obj.get(p) is Object:
|
||||
if obj.has_method("duplicate"):
|
||||
obj.set(p, obj[p].duplicate(true))
|
||||
obj = obj[p]
|
||||
else:
|
||||
obj.set(p, properties[i])
|
||||
continue
|
||||
|
||||
func get_variation_json(json := {}) -> Dictionary:
|
||||
var level_theme = Global.level_theme
|
||||
@@ -276,8 +285,8 @@ func get_config_file(resource_pack := "") -> void:
|
||||
print("resource pack to use: " + resource_pack)
|
||||
|
||||
func get_resource_pack_path(res_path := "", resource_pack := "") -> String:
|
||||
var user_path := res_path.replace("res://Assets", "user://resource_packs/" + resource_pack)
|
||||
user_path = user_path.replace("user://custom_characters/", "user://resource_packs/" + resource_pack + "/Sprites/Players/CustomCharacters/")
|
||||
var user_path := res_path.replace("res://Assets", Global.config_path.path_join("resource_packs/" + resource_pack))
|
||||
user_path = user_path.replace(Global.config_path.path_join("custom_characters"), Global.config_path.path_join("resource_packs/" + resource_pack + "/Sprites/Players/CustomCharacters/"))
|
||||
if FileAccess.file_exists(user_path):
|
||||
return user_path
|
||||
else:
|
||||
@@ -306,7 +315,7 @@ func clear_cache() -> void:
|
||||
cache.clear()
|
||||
property_cache.clear()
|
||||
|
||||
func load_image_from_path(path := "") -> ImageTexture:
|
||||
func load_image_from_path(path := "") -> Texture2D:
|
||||
if path.contains("res://"):
|
||||
if path.contains("NULL"):
|
||||
return null
|
||||
|
@@ -282,7 +282,8 @@ func parse_tiles() -> void:
|
||||
for i in entity_layer_nodes:
|
||||
if is_instance_valid(i) == false:
|
||||
continue
|
||||
saved_entity_layers[idx] = i.duplicate(DUPLICATE_USE_INSTANTIATION)
|
||||
if load_play == false:
|
||||
saved_entity_layers[idx] = i.duplicate(DUPLICATE_USE_INSTANTIATION)
|
||||
if i is Player:
|
||||
i.direction = 1
|
||||
i.velocity = Vector2.ZERO
|
||||
@@ -366,8 +367,6 @@ func close_save_menu() -> void:
|
||||
menu_open = false
|
||||
current_state = EditorState.TILE_MENU
|
||||
|
||||
const CUSTOM_LEVEL_DIR := "user://custom_levels/"
|
||||
|
||||
func handle_tile_cursor() -> void:
|
||||
Input.set_custom_mouse_cursor(null)
|
||||
var snapped_position = ((%TileCursor.get_global_mouse_position() - CURSOR_OFFSET).snapped(Vector2(16, 16))) + CURSOR_OFFSET
|
||||
@@ -402,9 +401,9 @@ func handle_tile_cursor() -> void:
|
||||
|
||||
if current_state == EditorState.IDLE:
|
||||
if Input.is_action_just_pressed("scroll_up"):
|
||||
selected_tile_index += 1
|
||||
if Input.is_action_just_pressed("scroll_down"):
|
||||
selected_tile_index -= 1
|
||||
if Input.is_action_just_pressed("scroll_down"):
|
||||
selected_tile_index += 1
|
||||
|
||||
if Input.is_action_just_pressed("editor_copy"):
|
||||
copy_node(tile_position)
|
||||
|
@@ -32,6 +32,7 @@ func handle_movement(delta: float) -> void:
|
||||
move_and_slide()
|
||||
|
||||
func destroy() -> void:
|
||||
await get_tree().physics_frame
|
||||
AudioManager.play_sfx("icicle_break", global_position)
|
||||
summon_particles()
|
||||
queue_free()
|
||||
|
@@ -2,16 +2,20 @@ extends Enemy
|
||||
|
||||
@export var player_range := 24
|
||||
|
||||
@export_enum("Up", "Down", "Left", "Right") var plant_direction := 0
|
||||
|
||||
func _enter_tree() -> void:
|
||||
$Animation.play("Hide")
|
||||
|
||||
func _ready() -> void:
|
||||
print(abs(global_rotation_degrees))
|
||||
if is_equal_approx(abs(global_rotation_degrees), 180) == false:
|
||||
$Sprite/Hitbox/UpsideDownExtension.queue_free()
|
||||
$Timer.start()
|
||||
|
||||
func on_timeout() -> void:
|
||||
var player = get_tree().get_first_node_in_group("Players")
|
||||
if abs(player.global_position.x - global_position.x) >= player_range:
|
||||
$Animation.play("Rise")
|
||||
if plant_direction < 2:
|
||||
if abs(player.global_position.x - global_position.x) >= player_range:
|
||||
$Animation.play("Rise")
|
||||
elif (abs(player.global_position.y - global_position.y) >= player_range and abs(player.global_position.x - global_position.x) >= player_range * 2):
|
||||
$Animation.play("Rise")
|
||||
|
@@ -1,8 +1,11 @@
|
||||
extends Node2D
|
||||
const COIN_SPARKLE = preload("res://Scenes/Prefabs/Particles/CoinSparkle.tscn")
|
||||
|
||||
@export var COIN_SPARKLE: PackedScene = null
|
||||
|
||||
@export var spinning_coin_scene: PackedScene = null
|
||||
|
||||
var can_spawn_particles := true
|
||||
|
||||
signal collected
|
||||
|
||||
func area_entered(area: Area2D) -> void:
|
||||
@@ -11,11 +14,16 @@ func area_entered(area: Area2D) -> void:
|
||||
|
||||
func collect() -> void:
|
||||
collected.emit()
|
||||
$Hitbox.area_entered.disconnect(area_entered)
|
||||
Global.coins += 1
|
||||
DiscoLevel.combo_meter += 10
|
||||
Global.score += 200
|
||||
AudioManager.play_sfx("coin", global_position)
|
||||
queue_free()
|
||||
if can_spawn_particles and Settings.file.visuals.extra_particles == 1:
|
||||
summon_particle()
|
||||
$Sprite.queue_free()
|
||||
else:
|
||||
queue_free()
|
||||
|
||||
func summon_block_coin() -> void:
|
||||
var node = spinning_coin_scene.instantiate()
|
||||
@@ -25,5 +33,5 @@ func summon_block_coin() -> void:
|
||||
|
||||
func summon_particle() -> void:
|
||||
var node = COIN_SPARKLE.instantiate()
|
||||
node.global_position = global_position
|
||||
add_sibling(node)
|
||||
node.finished.connect(queue_free)
|
||||
add_child(node)
|
||||
|
@@ -4,7 +4,9 @@ extends Node2D
|
||||
var already_collected := false
|
||||
const COLLECTION_SFXS := [preload("uid://drr1qqeuhmv6m"), preload("uid://de1tktivtggdv"), preload("uid://cdtlca36qsba5"), preload("uid://dd47k4c5sypwp"), preload("uid://chi2nogc2op4i")]
|
||||
const SPINNING_RED_COIN = preload("res://Scenes/Prefabs/Entities/Items/SpinningRedCoin.tscn")
|
||||
var can_spawn_particles := false
|
||||
|
||||
@onready var COIN_SPARKLE = load("res://Scenes/Prefabs/Particles/RedCoinSparkle.tscn")
|
||||
|
||||
func _ready() -> void:
|
||||
if ChallengeModeHandler.is_coin_collected(id):
|
||||
@@ -23,8 +25,15 @@ func collected() -> void:
|
||||
ChallengeModeHandler.red_coins += 1
|
||||
Global.score += 200
|
||||
ChallengeModeHandler.set_value(id, true)
|
||||
if can_spawn_particles and Settings.file.visuals.extra_particles == 1:
|
||||
summon_particle()
|
||||
queue_free()
|
||||
|
||||
func summon_particle() -> void:
|
||||
var node = COIN_SPARKLE.instantiate()
|
||||
node.global_position = global_position
|
||||
add_sibling(node)
|
||||
|
||||
func summon_bounced_coin() -> void:
|
||||
var node = SPINNING_RED_COIN.instantiate()
|
||||
node.id = id
|
||||
|
23
Scripts/Classes/Entities/Items/SpinningCoin.gd
Executable file → Normal file
23
Scripts/Classes/Entities/Items/SpinningCoin.gd
Executable file → Normal file
@@ -1,20 +1,29 @@
|
||||
extends Node2D
|
||||
const COIN_SPARKLE = preload("res://Scenes/Prefabs/Particles/CoinSparkle.tscn")
|
||||
|
||||
@export var particle: PackedScene = null
|
||||
|
||||
var velocity := Vector2(0, -300)
|
||||
|
||||
var can_spawn_particles := true
|
||||
|
||||
func _ready() -> void:
|
||||
Global.coins += 1
|
||||
Global.score += 200
|
||||
AudioManager.play_sfx("coin", global_position)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
global_position += velocity * delta
|
||||
velocity.y += (15 / delta) * delta
|
||||
if get_node_or_null("Sprite") != null:
|
||||
global_position += velocity * delta
|
||||
velocity.y += (15 / delta) * delta
|
||||
|
||||
func vanish() -> void:
|
||||
queue_free()
|
||||
if can_spawn_particles and Settings.file.visuals.extra_particles == 1:
|
||||
summon_particle()
|
||||
$Sprite.queue_free()
|
||||
else:
|
||||
queue_free()
|
||||
|
||||
func summon_particle() -> void:
|
||||
var node = COIN_SPARKLE.instantiate()
|
||||
node.global_position = global_position
|
||||
add_sibling(node)
|
||||
var node = particle.instantiate()
|
||||
node.finished.connect(queue_free)
|
||||
add_child(node)
|
||||
|
@@ -8,6 +8,9 @@ const collection_sounds := [preload("uid://drr1qqeuhmv6m"), preload("uid://de1tk
|
||||
|
||||
var already_collected := false
|
||||
|
||||
var can_spawn_particles := false
|
||||
@onready var COIN_SPARKLE = load("res://Scenes/Prefabs/Particles/RedCoinSparkle.tscn")
|
||||
|
||||
func _ready() -> void:
|
||||
already_collected = ChallengeModeHandler.is_coin_collected(id)
|
||||
if already_collected == false:
|
||||
@@ -25,4 +28,12 @@ func _physics_process(delta: float) -> void:
|
||||
velocity.y += (15 / delta) * delta
|
||||
|
||||
func vanish() -> void:
|
||||
if can_spawn_particles and Settings.file.visuals.extra_particles == 1:
|
||||
summon_particle()
|
||||
queue_free()
|
||||
|
||||
func summon_particle() -> void:
|
||||
var node = COIN_SPARKLE.instantiate()
|
||||
node.finished.connect(queue_free)
|
||||
node.global_position = $Sprite.global_position
|
||||
add_sibling(node)
|
||||
|
@@ -18,7 +18,7 @@ func get_character_sprite_path(player_id := 0) -> String:
|
||||
var character = Player.CHARACTERS[int(Global.player_characters[player_id])]
|
||||
var path = "res://Assets/Sprites/Players/" + character + "/CheckpointFlag.json"
|
||||
if int(Global.player_characters[player_id]) > 3:
|
||||
path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
|
||||
path = path.replace("res://Assets/Sprites/Players", Global.config_path.path_join("custom_characters"))
|
||||
return path
|
||||
|
||||
func activate(player: Player) -> void:
|
||||
|
@@ -49,14 +49,13 @@ func update_direction_textures() -> void:
|
||||
i.frame = int(Track.DIRECTIONS[i.get_index()] == starting_direction)
|
||||
for i in [$Start, $Connect, $End]:
|
||||
i.texture = texture
|
||||
$DirectionArrow.global_rotation = Vector2(connecting_direction).angle()
|
||||
|
||||
func on_mouse_entered(area_idx := 0) -> void:
|
||||
mouse_in_areas |= (1 << area_idx)
|
||||
print(mouse_in_areas)
|
||||
|
||||
func on_mouse_exited(area_idx := 0) -> void:
|
||||
mouse_in_areas &= ~(1 << area_idx)
|
||||
print(mouse_in_areas)
|
||||
|
||||
func is_mouse_in_area(area_idx := 0) -> bool:
|
||||
return mouse_in_areas & (1 << area_idx) != 0
|
||||
|
@@ -43,6 +43,11 @@ func run_pipe_check() -> void:
|
||||
exit_pipe()
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if enter_direction >= 2:
|
||||
$Hitbox.scale.y = 8
|
||||
else:
|
||||
$Hitbox.scale.y = 1
|
||||
|
||||
if Engine.is_editor_hint() == false:
|
||||
in_game()
|
||||
update_visuals()
|
||||
@@ -98,12 +103,13 @@ func in_game() -> void:
|
||||
if exit_only:
|
||||
return
|
||||
for i in hitbox.get_overlapping_areas():
|
||||
if i.owner is Player:
|
||||
if i.owner is Player and can_enter:
|
||||
run_player_check(i.owner)
|
||||
|
||||
func run_player_check(player: Player) -> void:
|
||||
# guzlad: Added support for characters with a hitbox height below 1.0 to enter pipes underwater
|
||||
if Global.player_action_pressed(get_input_direction(enter_direction), player.player_id) and can_enter and (player.is_on_floor() or enter_direction == 1 or player.gravity_vector != Vector2.DOWN or (!player.is_on_floor() and enter_direction == 3)) and player.state_machine.state.name == "Normal":
|
||||
print(player.is_actually_on_floor())
|
||||
if Global.player_action_pressed(get_input_direction(enter_direction), player.player_id) and (player.is_on_floor() or enter_direction == 1):
|
||||
can_enter = false
|
||||
pipe_entered.emit()
|
||||
DiscoLevel.can_meter_tick = false
|
||||
|
@@ -23,6 +23,8 @@ var RUN_SPEED := 160.0 # The player's speed while running, measu
|
||||
var GROUND_RUN_ACCEL := 1.25 # The player's acceleration while running, measured in px/frame
|
||||
var RUN_SKID := 8.0 # The player's turning deceleration while running, measured in px/frame
|
||||
|
||||
var SKID_THRESHOLD := 100.0 # The horizontal speed required, to be able to start skidding.
|
||||
|
||||
var DECEL := 3.0 # The player's deceleration while no buttons are pressed, measured in px/frame
|
||||
var AIR_ACCEL := 3.0 # The player's acceleration while in midair, measured in px/frame
|
||||
var AIR_SKID := 1.5 # The player's turning deceleration while in midair, measured in px/frame
|
||||
@@ -65,7 +67,12 @@ var crouching := false:
|
||||
return crouching
|
||||
var skidding := false
|
||||
|
||||
var bumping := false
|
||||
var can_bump_sfx := true
|
||||
var can_bump_jump = false
|
||||
var can_bump_crouch = false
|
||||
var can_bump_swim = false
|
||||
var can_bump_fly = false
|
||||
|
||||
@export var player_id := 0
|
||||
const ONE_UP_NOTE = preload("uid://dopxwjj37gu0l")
|
||||
@@ -134,6 +141,7 @@ static var CHARACTER_PALETTES := [
|
||||
|
||||
const ANIMATION_FALLBACKS := {
|
||||
"JumpFall": "Jump",
|
||||
"JumpBump": "Bump",
|
||||
"Fall": "Move",
|
||||
"Pipe": "Idle",
|
||||
"Walk": "Move",
|
||||
@@ -142,10 +150,24 @@ const ANIMATION_FALLBACKS := {
|
||||
"LookUp": "Idle",
|
||||
"Crouch": "Idle",
|
||||
"CrouchFall": "Crouch",
|
||||
"CrouchAttack": "Attack",
|
||||
"CrouchJump": "Crouch",
|
||||
"CrouchBump": "Bump",
|
||||
"CrouchMove": "Crouch",
|
||||
"IdleAttack": "Attack",
|
||||
"CrouchAttack": "IdleAttack",
|
||||
"MoveAttack": "IdleAttack",
|
||||
"WalkAttack": "MoveAttack",
|
||||
"RunAttack": "MoveAttack",
|
||||
"SkidAttack": "MoveAttack",
|
||||
"FlyIdle": "SwimIdle",
|
||||
"FlyUp": "SwimUp",
|
||||
"FlyMove": "SwimMove",
|
||||
"FlyAttack": "SwimAttack",
|
||||
"FlyBump": "SwimBump",
|
||||
"FlagSlide": "Climb",
|
||||
"WaterMove": "Move",
|
||||
"WaterIdle": "Idle",
|
||||
"SwimBump": "Bump",
|
||||
"DieFreeze": "Die",
|
||||
"StarJump": "Jump",
|
||||
"StarFall": "StarJump"
|
||||
@@ -166,6 +188,8 @@ static var classic_physics := false
|
||||
|
||||
var swim_stroke := false
|
||||
|
||||
var skid_frames := 0
|
||||
|
||||
var simulated_velocity := Vector2.ZERO
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -192,13 +216,14 @@ func _ready() -> void:
|
||||
camera.enabled = false
|
||||
handle_power_up_states(0)
|
||||
set_power_state_frame()
|
||||
handle_invincible_palette()
|
||||
if Global.level_editor == null:
|
||||
recenter_camera()
|
||||
|
||||
func apply_character_physics() -> void:
|
||||
var path = "res://Assets/Sprites/Players/" + character + "/CharacterInfo.json"
|
||||
if int(Global.player_characters[player_id]) > 3:
|
||||
path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
|
||||
path = path.replace("res://Assets/Sprites/Players", Global.config_path.path_join("custom_characters/"))
|
||||
path = ResourceSetter.get_pure_resource_path(path)
|
||||
var json = JSON.parse_string(FileAccess.open(path, FileAccess.READ).get_as_text())
|
||||
for i in json.physics:
|
||||
@@ -264,6 +289,8 @@ func _physics_process(delta: float) -> void:
|
||||
elif velocity.y > 15:
|
||||
can_bump_sfx = true
|
||||
handle_water_detection()
|
||||
%SkidParticles.visible = Settings.file.visuals.extra_particles == 1
|
||||
%SkidParticles.emitting = ((skidding and skid_frames > 2) or crouching) and is_on_floor() and abs(velocity.x) > 25 and Settings.file.visuals.extra_particles == 1
|
||||
if $SkidSFX.playing:
|
||||
if (is_actually_on_floor() and skidding) == false:
|
||||
$SkidSFX.stop()
|
||||
@@ -327,7 +354,7 @@ func apply_character_sfx_map() -> void:
|
||||
var custom_character := false
|
||||
if int(Global.player_characters[player_id]) > 3:
|
||||
custom_character = true
|
||||
path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
|
||||
path = path.replace("res://Assets/Sprites/Players", Global.config_path.path_join("custom_characters/"))
|
||||
path = ResourceSetter.get_pure_resource_path(path)
|
||||
var json = JSON.parse_string(FileAccess.open(path, FileAccess.READ).get_as_text())
|
||||
|
||||
@@ -337,7 +364,7 @@ func apply_character_sfx_map() -> void:
|
||||
if FileAccess.file_exists(res_path) == false or custom_character:
|
||||
var directory = "res://Assets/Sprites/Players/" + character + "/" + json[i]
|
||||
if int(Global.player_characters[player_id]) > 3:
|
||||
directory = directory.replace("res://Assets/Sprites/Players", "user://custom_characters")
|
||||
directory = directory.replace("res://Assets/Sprites/Players", Global.config_path.path_join("custom_characters/"))
|
||||
directory = ResourceSetter.get_pure_resource_path(directory)
|
||||
if FileAccess.file_exists(directory):
|
||||
json[i] = directory
|
||||
@@ -414,9 +441,12 @@ func bump_ceiling() -> void:
|
||||
AudioManager.play_sfx("bump", global_position)
|
||||
velocity.y = CEILING_BUMP_SPEED
|
||||
can_bump_sfx = false
|
||||
bumping = true
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
AudioManager.kill_sfx("small_jump")
|
||||
AudioManager.kill_sfx("big_jump")
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
bumping = false
|
||||
|
||||
func super_star() -> void:
|
||||
DiscoLevel.combo_meter += 1
|
||||
@@ -550,6 +580,7 @@ func die(pit := false) -> void:
|
||||
Global.p_switch_active = false
|
||||
Global.p_switch_timer = 0
|
||||
stop_all_timers()
|
||||
Global.total_deaths += 1
|
||||
sprite.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
state_machine.transition_to("Dead", {"Pit": pit})
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
@@ -574,7 +605,7 @@ func death_load() -> void:
|
||||
Global.death_load = true
|
||||
|
||||
# Handle lives decrement for CAMPAIGN and MARATHON
|
||||
if [Global.GameMode.CAMPAIGN, Global.GameMode.MARATHON].has(Global.current_game_mode):
|
||||
if [Global.GameMode.CAMPAIGN, Global.GameMode.MARATHON, Global.GameMode.LEVEL_EDITOR, Global.GameMode.CUSTOM_LEVEL].has(Global.current_game_mode):
|
||||
if Settings.file.difficulty.inf_lives == 0:
|
||||
Global.lives -= 1
|
||||
|
||||
@@ -630,6 +661,10 @@ func set_power_state_frame() -> void:
|
||||
$ResourceSetterNew.update_resource()
|
||||
if %Sprite.sprite_frames != null:
|
||||
can_pose = %Sprite.sprite_frames.has_animation("PoseDoor")
|
||||
can_bump_jump = %Sprite.sprite_frames.has_animation("JumpBump")
|
||||
can_bump_crouch = %Sprite.sprite_frames.has_animation("CrouchBump")
|
||||
can_bump_swim = %Sprite.sprite_frames.has_animation("SwimBump")
|
||||
can_bump_fly = %Sprite.sprite_frames.has_animation("FlyBump")
|
||||
|
||||
func get_power_up(power_name := "") -> void:
|
||||
if is_dead:
|
||||
@@ -647,8 +682,7 @@ func get_power_up(power_name := "") -> void:
|
||||
await power_up_animation(power_name)
|
||||
else:
|
||||
return
|
||||
if new_power_state.hitbox_size == "Big" and power_state.hitbox_size == "Small":
|
||||
check_for_block()
|
||||
check_for_block()
|
||||
power_state = new_power_state
|
||||
Global.player_power_states[player_id] = str(power_state.get_index())
|
||||
can_hurt = true
|
||||
@@ -670,10 +704,18 @@ func power_up_animation(new_power_state := "") -> void:
|
||||
if Settings.file.visuals.transform_style == 0:
|
||||
sprite.speed_scale = 3
|
||||
sprite.play("Grow")
|
||||
var rainbow = new_power_state != "Big" and (power_state.state_name != "Big" and new_power_state != "Small")
|
||||
if rainbow:
|
||||
transforming = true
|
||||
sprite.material.set_shader_parameter("enabled", true)
|
||||
await get_tree().create_timer(0.4, true).timeout
|
||||
power_state = get_node("PowerStates/" + new_power_state)
|
||||
sprite.sprite_frames = new_frames
|
||||
handle_invincible_palette()
|
||||
sprite.play("Grow")
|
||||
await get_tree().create_timer(0.4, true).timeout
|
||||
if rainbow:
|
||||
sprite.material.set_shader_parameter("enabled", false)
|
||||
transforming = false
|
||||
else:
|
||||
sprite.speed_scale = 0
|
||||
@@ -693,6 +735,7 @@ func power_up_animation(new_power_state := "") -> void:
|
||||
sprite.sprite_frames = old_frames
|
||||
await get_tree().create_timer(0.05).timeout
|
||||
else:
|
||||
handle_invincible_palette()
|
||||
sprite.stop()
|
||||
sprite.material.set_shader_parameter("enabled", true)
|
||||
transforming = true
|
||||
@@ -712,11 +755,12 @@ func dispense_stored_item() -> void:
|
||||
func get_character_sprite_path(power_stateto_use := power_state.state_name) -> String:
|
||||
var path = "res://Assets/Sprites/Players/" + character + "/" + power_stateto_use + ".json"
|
||||
if int(Global.player_characters[player_id]) > 3:
|
||||
path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
|
||||
path = path.replace("res://Assets/Sprites/Players", Global.config_path.path_join("custom_characters/"))
|
||||
return path
|
||||
|
||||
func enter_pipe(pipe: PipeArea, warp_to_level := true) -> void:
|
||||
z_index = -10
|
||||
can_bump_sfx = false
|
||||
Global.can_pause = false
|
||||
Global.can_time_tick = false
|
||||
pipe_enter_direction = pipe.get_vector(pipe.enter_direction)
|
||||
@@ -761,7 +805,7 @@ func exit_pipe(pipe: PipeArea) -> void:
|
||||
pipe_enter_direction = -pipe.get_vector(pipe.enter_direction)
|
||||
AudioManager.play_sfx("pipe", global_position)
|
||||
state_machine.transition_to("Pipe")
|
||||
await get_tree().create_timer(0.6, false).timeout
|
||||
await get_tree().create_timer(0.65, false).timeout
|
||||
Global.can_pause = true
|
||||
state_machine.transition_to("Normal")
|
||||
Global.can_time_tick = true
|
||||
|
@@ -20,7 +20,7 @@ func update_visuals() -> void:
|
||||
func run_player_check(player: Player) -> void:
|
||||
if Global.player_action_pressed(get_input_direction(enter_direction), player.player_id) and can_enter:
|
||||
can_enter = false
|
||||
Checkpoint.passed = false
|
||||
Checkpoint.passed_checkpoints.clear()
|
||||
player.enter_pipe(self, false)
|
||||
await get_tree().create_timer(1, false).timeout
|
||||
$CanvasLayer.show()
|
||||
|
@@ -104,15 +104,9 @@ func _enter_tree() -> void:
|
||||
await get_tree().process_frame
|
||||
AudioManager.stop_music_override(AudioManager.MUSIC_OVERRIDES.NONE, true)
|
||||
|
||||
const PLAYER = preload("res://Scenes/Prefabs/Entities/Player.tscn")
|
||||
|
||||
func spawn_in_extra_players() -> void:
|
||||
await ready
|
||||
for i in Global.connected_players - 1:
|
||||
var player_node = PLAYER.instantiate()
|
||||
player_node.player_id = i + 1
|
||||
player_node.global_position = get_tree().get_first_node_in_group("Players").global_position + Vector2(16 * (i + 1), 0)
|
||||
add_child(player_node)
|
||||
return
|
||||
|
||||
func update_theme() -> void:
|
||||
if auto_set_theme:
|
||||
|
@@ -113,7 +113,7 @@ func play_sfx(stream_name = "", position := Vector2.ZERO, pitch := 1.0) -> void:
|
||||
var stream = stream_name
|
||||
var is_custom = false
|
||||
if stream_name is String:
|
||||
is_custom = sfx_library[stream_name].contains("user://custom_characters")
|
||||
is_custom = sfx_library[stream_name].contains(Global.config_path.path_join("custom_characters"))
|
||||
stream = import_stream(sfx_library[stream_name])
|
||||
if is_custom == false:
|
||||
player.stream = ResourceSetter.get_resource(stream, player)
|
||||
@@ -203,7 +203,17 @@ func load_sfx_map(json := {}) -> void:
|
||||
func handle_music() -> void:
|
||||
if Global.in_title_screen:
|
||||
current_level_theme = ""
|
||||
AudioServer.set_bus_effect_enabled(1, 0, Global.game_paused)
|
||||
|
||||
# guzlad: hack in the elif because it doesn't unpause itself like the normal music_player does
|
||||
if Global.game_paused and Settings.file.audio.pause_bgm == 0:
|
||||
AudioManager.music_player.stream_paused = true
|
||||
AudioManager.music_override_player.stream_paused = true
|
||||
return
|
||||
elif AudioManager.music_override_player.stream_paused == true:
|
||||
AudioManager.music_override_player.stream_paused = false
|
||||
|
||||
AudioServer.set_bus_effect_enabled(1, 0, Global.game_paused and Settings.file.audio.pause_bgm == 1)
|
||||
|
||||
if is_instance_valid(Global.current_level):
|
||||
if Global.current_level.music == null or current_music_override != MUSIC_OVERRIDES.NONE:
|
||||
music_player.stop()
|
||||
@@ -236,7 +246,7 @@ func handle_music_override() -> void:
|
||||
func create_stream_from_json(json_path := "") -> AudioStream:
|
||||
if json_path.contains(".json") == false:
|
||||
var path = ResourceSetter.get_pure_resource_path(json_path)
|
||||
if path.contains("user://"):
|
||||
if path.contains(Global.config_path):
|
||||
match json_path.get_slice(".", 1):
|
||||
"wav":
|
||||
return AudioStreamWAV.load_from_file(ResourceSetter.get_pure_resource_path(json_path))
|
||||
|
@@ -26,11 +26,13 @@ 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
|
||||
const ROM_POINTER_PATH := "user://rom_pointer.smb"
|
||||
const ROM_PATH := "user://baserom.nes"
|
||||
const ROM_ASSETS_PATH := "user://resource_packs/BaseAssets"
|
||||
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 := 0
|
||||
|
||||
@@ -60,6 +62,8 @@ 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:
|
||||
@@ -169,8 +173,47 @@ func _ready() -> void:
|
||||
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
|
||||
@@ -202,6 +245,14 @@ func _process(delta: float) -> void:
|
||||
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)
|
||||
|
||||
func handle_p_switch(delta: float) -> void:
|
||||
if p_switch_active and get_tree().paused == false:
|
||||
@@ -264,6 +315,7 @@ 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
|
||||
@@ -304,6 +356,7 @@ func transition_to_scene(scene_path := "") -> void:
|
||||
$Transition/AnimationPlayer.play("RESET")
|
||||
$Transition.hide()
|
||||
transitioning_scene = false
|
||||
transition_finished.emit()
|
||||
|
||||
|
||||
|
||||
@@ -330,7 +383,7 @@ func close_freeze() -> void:
|
||||
$Transition/Freeze.hide()
|
||||
$Transition.hide()
|
||||
|
||||
var recording_dir = "user://marathon_recordings/"
|
||||
var recording_dir = config_path.path_join("marathon_recordings")
|
||||
|
||||
func update_game_status() -> void:
|
||||
var lives_str := str(Global.lives)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
extends Node
|
||||
|
||||
const SAVE_DIR := "user://saves/CAMPAIGN.sav"
|
||||
var SAVE_DIR : String = Global.config_path.path_join("saves/CAMPAIGN.sav")
|
||||
|
||||
var visited_levels := "1000000000000000000000000000000010000000000000000000"
|
||||
|
||||
@@ -71,24 +71,23 @@ func write_save(campaign: String = Global.current_campaign, force := false) -> v
|
||||
if Global.debugged_in and not force:
|
||||
return
|
||||
var save = null
|
||||
DirAccess.make_dir_recursive_absolute("user://saves")
|
||||
DirAccess.make_dir_recursive_absolute("user://resource_packs")
|
||||
DirAccess.make_dir_recursive_absolute("user://custom_characters")
|
||||
DirAccess.make_dir_recursive_absolute("user://custom_levels")
|
||||
var save_json = {}
|
||||
var path = "user://saves/" + campaign + ".sav"
|
||||
var path = Global.config_path.path_join("saves/" + campaign + ".sav")
|
||||
if FileAccess.file_exists(path):
|
||||
save = FileAccess.open("user://saves/" + campaign + ".sav", FileAccess.READ)
|
||||
save = FileAccess.open(path, FileAccess.READ)
|
||||
save_json = JSON.parse_string(save.get_as_text())
|
||||
save.close()
|
||||
else:
|
||||
save_json = SAVE_TEMPLATE.duplicate(true)
|
||||
match Global.current_game_mode:
|
||||
Global.GameMode.CAMPAIGN:
|
||||
if Global.world_num < 0:
|
||||
Global.world_num = 1
|
||||
if Global.high_score < Global.score:
|
||||
Global.high_score = Global.score
|
||||
save_json["World"] = Global.world_num
|
||||
save_json["Level"] = Global.level_num
|
||||
save_json["Lives"] = Global.lives
|
||||
save_json["Coins"] = Global.coins
|
||||
save_json["Score"] = Global.score
|
||||
save_json["GameWin"] = Global.game_beaten
|
||||
@@ -150,7 +149,8 @@ func clear_save() -> void:
|
||||
visited_levels[0][0] = "1"
|
||||
var save = SAVE_TEMPLATE.duplicate(true)
|
||||
apply_save(save)
|
||||
DirAccess.remove_absolute("user://saves/" + Global.current_campaign + ".sav")
|
||||
var save_path = Global.config_path.path_join("saves" + Global.current_campaign + ".sav")
|
||||
DirAccess.remove_absolute(save_path)
|
||||
write_save(Global.current_campaign)
|
||||
|
||||
func clear_array(arr := []) -> void:
|
||||
@@ -172,9 +172,10 @@ func get_level_idx(world_num := 1, level_num := 1) -> int:
|
||||
return ((world_num - 1) * 4) + (level_num - 1)
|
||||
|
||||
func load_achievements() -> void:
|
||||
if FileAccess.file_exists("user://achievements.sav") == false:
|
||||
var path = Global.config_path.path_join("achievements.sav")
|
||||
if FileAccess.file_exists(path) == false:
|
||||
write_achievements()
|
||||
var file = FileAccess.open("user://achievements.sav", FileAccess.READ)
|
||||
var file = FileAccess.open(path, FileAccess.READ)
|
||||
var idx := 0
|
||||
for i in file.get_as_text():
|
||||
Global.achievements[idx] = i
|
||||
@@ -183,6 +184,7 @@ func load_achievements() -> void:
|
||||
file.close()
|
||||
|
||||
func write_achievements() -> void:
|
||||
var file = FileAccess.open("user://achievements.sav", FileAccess.WRITE)
|
||||
var path = Global.config_path.path_join("achievements.sav")
|
||||
var file = FileAccess.open(path, FileAccess.WRITE)
|
||||
file.store_string(Global.achievements)
|
||||
file.close()
|
||||
|
@@ -19,6 +19,7 @@ var file := {
|
||||
"extra_bgm": 1,
|
||||
"skid_sfx": 1,
|
||||
"extra_sfx": 0,
|
||||
"pause_bgm": 1,
|
||||
"menu_bgm": 0
|
||||
},
|
||||
"game": {
|
||||
@@ -34,17 +35,23 @@ var file := {
|
||||
"move_left": "Left",
|
||||
"move_right": "Right",
|
||||
"move_up": "Up",
|
||||
"move_down": "Down"
|
||||
"move_down": "Down",
|
||||
"ui_accept": "Z",
|
||||
"ui_back": "X",
|
||||
"pause": "Escape"
|
||||
},
|
||||
"controller":
|
||||
{
|
||||
"jump": 0,
|
||||
"run": 2,
|
||||
"action": 2,
|
||||
"jump": [0, 1],
|
||||
"run": [2, 3],
|
||||
"action": [2, 3],
|
||||
"move_left": "0,-1",
|
||||
"move_right": "0,1",
|
||||
"move_up": "1,-1",
|
||||
"move_down": "1,1"
|
||||
"move_down": "1,1",
|
||||
"ui_accept": 0,
|
||||
"ui_back": 1,
|
||||
"pause": 6
|
||||
},
|
||||
"visuals":
|
||||
{
|
||||
@@ -62,7 +69,8 @@ var file := {
|
||||
"visible_timers": 0,
|
||||
"transition_animation": 0,
|
||||
"colour_pipes": 1,
|
||||
"firebar_style": 0
|
||||
"firebar_style": 0,
|
||||
"extra_particles": 0
|
||||
},
|
||||
"difficulty":
|
||||
{
|
||||
@@ -79,10 +87,10 @@ var file := {
|
||||
}
|
||||
}
|
||||
|
||||
const SETTINGS_DIR := "user://settings.cfg"
|
||||
static var SETTINGS_DIR := Global.config_path.path_join("settings.cfg")
|
||||
|
||||
func _enter_tree() -> void:
|
||||
DirAccess.make_dir_absolute("user://resource_packs")
|
||||
DirAccess.make_dir_absolute(Global.config_path.path_join("resource_packs"))
|
||||
load_settings()
|
||||
await get_tree().physics_frame
|
||||
apply_settings()
|
||||
|
@@ -201,7 +201,7 @@ func gen_time_string(timer_dict := {}) -> String:
|
||||
|
||||
func save_recording() -> void:
|
||||
var recording := [timer, current_recording, levels, str(["Mario", "Luigi", "Toad", "Toadette"].find(get_tree().get_first_node_in_group("Players").character)), anim_list]
|
||||
var recording_dir = "user://marathon_recordings/" + Global.current_campaign
|
||||
var recording_dir = Global.config_path.path_join("marathon_recordings/" + Global.current_campaign)
|
||||
DirAccess.make_dir_recursive_absolute(recording_dir)
|
||||
var file = FileAccess.open(recording_dir + "/" + str(Global.world_num) + "-" + str(Global.level_num) + ("warp" if is_warp_run else "") + ".json", FileAccess.WRITE)
|
||||
file.store_string(compress_recording(JSON.stringify(recording, "", false, true)))
|
||||
@@ -240,7 +240,7 @@ func load_best_marathon() -> void:
|
||||
anim_list = recording[4].duplicate()
|
||||
|
||||
func load_recording(world_num := 0, level_num := 0, is_warpless := true, campaign := "SMB1") -> Array:
|
||||
var recording_dir = "user://marathon_recordings/" + campaign
|
||||
var recording_dir = Global.config_path.path_join("marathon_recordings/" + campaign)
|
||||
var path = recording_dir + "/" + str(world_num) + "-" + str(level_num) + ("" if is_warpless else "warp") + ".json"
|
||||
print(path)
|
||||
if FileAccess.file_exists(path) == false:
|
||||
@@ -257,12 +257,12 @@ func load_best_times(campaign = Global.current_campaign) -> void:
|
||||
best_level_any_times.clear()
|
||||
for world_num in 8:
|
||||
for level_num in 4:
|
||||
var path = "user://marathon_recordings/" + campaign + "/" + str(world_num + 1) + "-" + str(level_num + 1) + ".json"
|
||||
var path = Global.config_path.path_join("marathon_recordings/" + campaign + "/" + str(world_num + 1) + "-" + str(level_num + 1) + ".json")
|
||||
if FileAccess.file_exists(path):
|
||||
best_level_warpless_times[world_num][level_num] = load_recording(world_num + 1, level_num + 1, true, campaign)[0]
|
||||
else:
|
||||
best_level_warpless_times[world_num][level_num] = -1
|
||||
path = "user://marathon_recordings/" + campaign + "/" + str(world_num + 1) + "-" + str(level_num + 1) +"warp" + ".json"
|
||||
path = Global.config_path.path_join("marathon_recordings/" + campaign + "/" + str(world_num + 1) + "-" + str(level_num + 1) +"warp" + ".json")
|
||||
if FileAccess.file_exists(path):
|
||||
best_level_any_times[str(world_num + 1) + "-" + str(level_num + 1)] = load_recording(world_num + 1, level_num + 1, false, campaign)[0]
|
||||
check_for_medal_achievement()
|
||||
|
@@ -19,7 +19,7 @@ func physics_update(_delta: float) -> void:
|
||||
if player.input_direction != 0 and climb_direction == 0 and not cutscene:
|
||||
player.direction = -player.input_direction
|
||||
player.sprite.scale.x = player.direction
|
||||
player.global_position.x = vine.global_position.x - (8 * player.direction)
|
||||
player.global_position.x = vine.global_position.x - (6 * player.direction)
|
||||
if not cutscene and not auto_climb:
|
||||
climb_direction = sign(Input.get_axis("move_up" + "_" + str(player.player_id),"move_down" + "_" + str(player.player_id)))
|
||||
if vine.can_tele and player.global_position.y - 64 < vine.top_point and climb_direction == -1:
|
||||
|
@@ -84,7 +84,7 @@ func grounded(delta: float) -> void:
|
||||
func handle_ground_movement(delta: float) -> void:
|
||||
if player.skidding:
|
||||
ground_skid(delta)
|
||||
elif (player.input_direction != player.velocity_direction) and player.input_direction != 0 and abs(player.velocity.x) > 100 and not player.crouching:
|
||||
elif (player.input_direction != player.velocity_direction) and player.input_direction != 0 and abs(player.velocity.x) > player.SKID_THRESHOLD and not player.crouching:
|
||||
print([player.input_direction, player.velocity_direction])
|
||||
player.skidding = true
|
||||
elif player.input_direction != 0 and not player.crouching:
|
||||
@@ -112,9 +112,11 @@ func deceleration(delta: float) -> void:
|
||||
|
||||
func ground_skid(delta: float) -> void:
|
||||
var target_skid := player.RUN_SKID
|
||||
player.skid_frames += 1
|
||||
player.velocity.x = move_toward(player.velocity.x, 1 * player.input_direction, (target_skid / delta) * delta)
|
||||
if abs(player.velocity.x) < 10 or player.input_direction == player.velocity_direction or player.input_direction == 0:
|
||||
player.skidding = false
|
||||
player.skid_frames = 0
|
||||
|
||||
func in_air() -> void:
|
||||
if Global.player_action_just_pressed("jump", player.player_id):
|
||||
@@ -186,22 +188,47 @@ func get_animation_name() -> String:
|
||||
if player.attacking:
|
||||
if player.crouching:
|
||||
return "CrouchAttack"
|
||||
if player.is_actually_on_floor():
|
||||
return "Attack"
|
||||
elif player.in_water or player.flight_meter > 0:
|
||||
return "SwimAttack"
|
||||
elif player.is_actually_on_floor():
|
||||
if player.skidding:
|
||||
return "SkidAttack"
|
||||
elif abs(player.velocity.x) >= 5 and not player.is_actually_on_wall():
|
||||
if player.in_water:
|
||||
return "SwimAttack"
|
||||
elif player.flight_meter > 0:
|
||||
return "FlyAttack"
|
||||
elif abs(player.velocity.x) < player.RUN_SPEED - 10:
|
||||
return "WalkAttack"
|
||||
else:
|
||||
return "RunAttack"
|
||||
else:
|
||||
return "IdleAttack"
|
||||
else:
|
||||
return "AirAttack"
|
||||
if player.in_water:
|
||||
return "SwimAttack"
|
||||
elif player.flight_meter > 0:
|
||||
return "FlyAttack"
|
||||
else:
|
||||
return "AirAttack"
|
||||
if player.crouching and not wall_pushing:
|
||||
if player.velocity.y > 0 and player.is_on_floor() == false:
|
||||
return "CrouchFall"
|
||||
if player.bumping and player.can_bump_crouch:
|
||||
return "CrouchBump"
|
||||
elif player.is_on_floor() == false:
|
||||
if player.velocity.y > 0:
|
||||
return "CrouchFall"
|
||||
elif player.velocity.y < 0:
|
||||
return "CrouchJump"
|
||||
elif player.is_actually_on_floor():
|
||||
if abs(player.velocity.x) >= 5 and not player.is_actually_on_wall():
|
||||
return "CrouchMove"
|
||||
return "Crouch"
|
||||
if player.is_actually_on_floor():
|
||||
if player.skidding:
|
||||
return "Skid"
|
||||
elif abs(player.velocity.x) >= 5 and not player.is_actually_on_wall():
|
||||
if player.in_water or player.flight_meter > 0:
|
||||
if player.in_water:
|
||||
return "WaterMove"
|
||||
elif player.flight_meter > 0:
|
||||
return "FlyMove"
|
||||
elif abs(player.velocity.x) < player.RUN_SPEED - 10:
|
||||
return "Walk"
|
||||
else:
|
||||
@@ -213,13 +240,26 @@ func get_animation_name() -> String:
|
||||
return "LookUp"
|
||||
return "Idle"
|
||||
else:
|
||||
if player.in_water or player.flight_meter > 0:
|
||||
if player.in_water:
|
||||
if swim_up_meter > 0:
|
||||
return "SwimUp"
|
||||
if player.bumping and player.can_bump_swim:
|
||||
return "SwimBump"
|
||||
else:
|
||||
return "SwimUp"
|
||||
else:
|
||||
return "SwimIdle"
|
||||
elif player.flight_meter > 0:
|
||||
if swim_up_meter > 0:
|
||||
if player.bumping and player.can_bump_fly:
|
||||
return "FlyBump"
|
||||
else:
|
||||
return "FlyUp"
|
||||
else:
|
||||
return "FlyIdle"
|
||||
if player.has_jumped:
|
||||
if player.velocity.y < 0:
|
||||
if player.bumping and player.can_bump_jump:
|
||||
return "JumpBump"
|
||||
elif player.velocity.y < 0:
|
||||
if player.is_invincible:
|
||||
return "StarJump"
|
||||
return "Jump"
|
||||
|
@@ -9,6 +9,7 @@ func enter(_msg := {}) -> void:
|
||||
physics_update(0)
|
||||
|
||||
func physics_update(delta: float) -> void:
|
||||
player.velocity = Vector2.ZERO
|
||||
player.global_position += (ENTER_SPEED * (player.pipe_enter_direction * player.pipe_move_direction)) * delta
|
||||
if player.pipe_enter_direction.x != 0:
|
||||
player.sprite.speed_scale = 1
|
||||
|
@@ -26,6 +26,7 @@ func handle_main_hud() -> void:
|
||||
$ModernHUD.visible = Settings.file.visuals.modern_hud
|
||||
$Main/RedCoins.hide()
|
||||
$Main/CoinCount.show()
|
||||
%IGT.hide()
|
||||
%Combo.hide()
|
||||
$Timer.paused = Settings.file.difficulty.time_limit == 2
|
||||
$%Time.show()
|
||||
@@ -71,6 +72,7 @@ func handle_modern_hud() -> void:
|
||||
$ModernHUD/TopLeft/RedCoins.hide()
|
||||
$ModernHUD/TopLeft/CoinCount.show()
|
||||
%ModernPB.hide()
|
||||
%ModernIGT.hide()
|
||||
%ModernCoinCount.text = "*" + str(Global.coins).pad_zeros(2)
|
||||
%ModernScore.text = str(Global.score).pad_zeros(9)
|
||||
%ModernTime.text = "⏲" + str(Global.time).pad_zeros(3)
|
||||
@@ -147,6 +149,11 @@ func handle_yoshi_radar() -> void:
|
||||
func handle_speedrun_timer() -> void:
|
||||
%Time.hide()
|
||||
%Stopwatch.show()
|
||||
%IGT.show()
|
||||
%IGT.modulate.a = int([Global.GameMode.MARATHON, Global.GameMode.MARATHON_PRACTICE].has(Global.current_game_mode) and get_tree().get_first_node_in_group("Players") != null)
|
||||
%IGT.text = "⏲" + (str(Global.time).pad_zeros(3))
|
||||
%ModernIGT.visible = %IGT.modulate.a == 1
|
||||
%ModernIGT.text = %IGT.text
|
||||
var late = SpeedrunHandler.timer > SpeedrunHandler.best_time
|
||||
var diff = SpeedrunHandler.best_time - SpeedrunHandler.timer
|
||||
%PB.visible = SpeedrunHandler.best_time > 0 and (SpeedrunHandler.timer > 0 or Global.current_level != null)
|
||||
|
@@ -25,7 +25,7 @@ func _exit_tree() -> void:
|
||||
Global.get_node("GameHUD").show()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if Input.is_action_just_pressed("jump_0") and can_skip:
|
||||
if Input.is_action_just_pressed("ui_accept") and can_skip:
|
||||
go_to_menu()
|
||||
|
||||
func go_to_menu() -> void:
|
||||
|
@@ -2,6 +2,7 @@ class_name LevelEditorVisibleNode
|
||||
extends Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
update()
|
||||
if Global.level_editor != null:
|
||||
Global.level_editor.editor_start.connect(update)
|
||||
|
@@ -82,12 +82,12 @@ func do_lost_levels_firework_check() -> void:
|
||||
if coin_digit == time_digit:
|
||||
if coin_digit % 2 == 0:
|
||||
await show_fireworks(6)
|
||||
if coin_digit % 11 == 0:
|
||||
spawn_one_up_note()
|
||||
AudioManager.play_sfx("1_up", global_position)
|
||||
Global.lives += 1
|
||||
else:
|
||||
await show_fireworks(3)
|
||||
if Global.coins % 11 == 0:
|
||||
spawn_one_up_note()
|
||||
AudioManager.play_sfx("1_up", global_position)
|
||||
Global.lives += 1
|
||||
|
||||
const ONE_UP_NOTE = preload("uid://dopxwjj37gu0l")
|
||||
|
||||
|
@@ -21,8 +21,11 @@ func _ready() -> void:
|
||||
func _process(_delta: float) -> void:
|
||||
print(can_continue)
|
||||
if Input.is_action_just_pressed("jump_0") and can_continue:
|
||||
go_back_to_title()
|
||||
can_continue = false
|
||||
if Global.transitioning_scene:
|
||||
await Global.transition_finished
|
||||
await get_tree().create_timer(0.15, false).timeout
|
||||
go_back_to_title()
|
||||
|
||||
|
||||
func go_back_to_title() -> void:
|
||||
|
@@ -17,6 +17,9 @@ func on_player_entered(player: Player) -> void:
|
||||
player.gravity_vector = new_vector
|
||||
player.global_position.y -= 16
|
||||
player.global_rotation = -player.gravity_vector.angle() + deg_to_rad(90)
|
||||
player.get_node("CameraHandler").global_rotation = 0
|
||||
player.get_node("CameraHandler").position.x = 0
|
||||
player.get_node("CameraHandler").can_diff = false
|
||||
player.reset_physics_interpolation()
|
||||
|
||||
func on_player_exited(player: Player) -> void:
|
||||
@@ -26,4 +29,5 @@ func on_player_exited(player: Player) -> void:
|
||||
player.global_position.y += 16
|
||||
player.velocity.y *= 1.1
|
||||
player.global_rotation = -player.gravity_vector.angle() + deg_to_rad(90)
|
||||
player.get_node("CameraHandler").position.x = 0
|
||||
player.reset_physics_interpolation()
|
||||
|
@@ -34,10 +34,9 @@ func save_level(level_name := "Unnamed Level", level_author := "You", level_desc
|
||||
return level_file
|
||||
|
||||
func write_file(json := {}, lvl_file_name := "") -> void:
|
||||
DirAccess.make_dir_absolute(LevelEditor.CUSTOM_LEVEL_DIR)
|
||||
for i in "<>:?!/":
|
||||
lvl_file_name = lvl_file_name.replace(i, "")
|
||||
var file = FileAccess.open(LevelEditor.CUSTOM_LEVEL_DIR + lvl_file_name, FileAccess.WRITE)
|
||||
var file = FileAccess.open(Global.config_path.path_join("custom_levels/" + lvl_file_name), FileAccess.WRITE)
|
||||
file.store_string(JSON.stringify(json, "", false))
|
||||
file.close()
|
||||
print("saved")
|
||||
|
@@ -77,7 +77,9 @@ func _ready() -> void:
|
||||
SaveManager.write_save(Global.current_campaign)
|
||||
DiscordManager.set_discord_status("Playing " + Global.current_campaign + ": " + str(world_num) + "-" + str(Global.level_num))
|
||||
$BG/Control/WorldNum.text = str(world_num) +"-" + str(Global.level_num)
|
||||
if Settings.file.difficulty.inf_lives:
|
||||
if [Global.GameMode.CUSTOM_LEVEL, Global.GameMode.LEVEL_EDITOR].has(Global.current_game_mode):
|
||||
$BG/Control/LivesCount.text = "☠ * " + str(Global.total_deaths)
|
||||
elif Settings.file.difficulty.inf_lives:
|
||||
$BG/Control/LivesCount.text = "* ∞"
|
||||
elif Global.lives < 100:
|
||||
$BG/Control/LivesCount.text = "* " + (str(Global.lives).lpad(2, " "))
|
||||
@@ -113,7 +115,7 @@ func show_best_time() -> void:
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if can_transition:
|
||||
if Input.is_action_just_pressed("jump_0"):
|
||||
if Input.is_action_just_pressed("ui_accept"):
|
||||
transition()
|
||||
|
||||
func _exit_tree() -> void:
|
||||
|
@@ -25,7 +25,9 @@ func _ready() -> void:
|
||||
func _process(_delta: float) -> void:
|
||||
if can_exit and Input.is_action_just_pressed("jump_0"):
|
||||
SaveManager.write_save()
|
||||
if seen or Global.current_campaign == "SMBANN" or Global.world_num > 8 or Global.current_game_mode != Global.GameMode.CAMPAIGN:
|
||||
if Global.current_campaign == "SMBANN":
|
||||
Global.open_disco_results()
|
||||
elif seen or Global.world_num > 8 or Global.current_game_mode != Global.GameMode.CAMPAIGN:
|
||||
Global.transition_to_scene("res://Scenes/Levels/TitleScreen.tscn")
|
||||
else:
|
||||
CreditsLevel.go_to_title_screen = false
|
||||
|
@@ -24,7 +24,7 @@ func update() -> void:
|
||||
if resource_setter != null:
|
||||
var path = "res://Assets/Sprites/Players/" + character + "/" + Player.POWER_STATES[int(power_state)] + ".json"
|
||||
if Player.CHARACTERS.find(character) > 3:
|
||||
path = path.replace("res://Assets/Sprites/Players/", "user://custom_characters/")
|
||||
path = path.replace("res://Assets/Sprites/Players/", Global.config_path.path_join("custom_characters/"))
|
||||
var json = resource_setter.get_resource(load(path))
|
||||
sprite_frames = json
|
||||
if sprite_frames == null:
|
||||
|
@@ -9,7 +9,7 @@ func _ready() -> void:
|
||||
get_resource_packs()
|
||||
|
||||
func open_folder() -> void:
|
||||
OS.shell_show_in_file_manager(ProjectSettings.globalize_path("user://resource_packs"), true)
|
||||
OS.shell_show_in_file_manager(ProjectSettings.globalize_path(Global.config_path.path_join("resource_packs")), true)
|
||||
|
||||
func get_resource_packs() -> void:
|
||||
for i in containers:
|
||||
@@ -17,12 +17,12 @@ func get_resource_packs() -> void:
|
||||
i.queue_free()
|
||||
containers = []
|
||||
resource_packs = []
|
||||
for i in DirAccess.get_directories_at("user://resource_packs"):
|
||||
for i in DirAccess.get_directories_at(Global.config_path.path_join("resource_packs")):
|
||||
resource_packs.append(i)
|
||||
for i in resource_packs:
|
||||
var pack_info_path = "user://resource_packs/" + i + "/" + "pack_info.json"
|
||||
var pack_info_path = Global.config_path.path_join("resource_packs/" + i + "/pack_info.json")
|
||||
if FileAccess.file_exists(pack_info_path) and i != Global.ROM_PACK_NAME:
|
||||
create_container("user://resource_packs/" + i)
|
||||
create_container(Global.config_path.path_join("resource_packs/" + i))
|
||||
|
||||
func create_container(resource_pack := "") -> void:
|
||||
var container = RESOURCE_PACK_CONTAINER.instantiate()
|
||||
@@ -36,7 +36,7 @@ func create_container(resource_pack := "") -> void:
|
||||
container.icon = ImageTexture.create_from_image(image)
|
||||
elif FileAccess.file_exists(resource_pack + "/icon.gif"):
|
||||
container.icon = GifManager.animated_texture_from_file(resource_pack + "/icon.gif")
|
||||
container.pack_name = resource_pack.replace("user://resource_packs/", "")
|
||||
container.pack_name = resource_pack.replace(Global.config_path.path_join("resource_packs"), "")
|
||||
$"../ScrollContainer/VBoxContainer".add_child(container)
|
||||
containers.append(container)
|
||||
container.add_to_group("Options")
|
||||
|
@@ -12,15 +12,15 @@ const base_info_json := {
|
||||
func create_template() -> void:
|
||||
get_directories("res://Assets", files, directories)
|
||||
for i in directories:
|
||||
DirAccess.make_dir_recursive_absolute(i.replace("res://Assets", "user://resource_packs/new_pack"))
|
||||
DirAccess.make_dir_recursive_absolute(i.replace("res://Assets", Global.config_path.path_join("resource_packs/new_pack")))
|
||||
for i in files:
|
||||
var destination = i
|
||||
if destination.contains("res://"):
|
||||
destination = i.replace("res://Assets", "user://resource_packs/new_pack")
|
||||
destination = i.replace("res://Assets", Global.config_path.path_join("resource_packs/new_pack"))
|
||||
else:
|
||||
destination = i.replace("user://resource_packs/BaseAssets", "user://resource_packs/new_pack")
|
||||
destination = i.replace(Global.config_path.path_join("resource_packs/BaseAssets"), Global.config_path.path_join("resource_packs/new_pack"))
|
||||
print("Copying '" + i + "' to: '" + destination)
|
||||
if i.contains(".bgm") or i.contains(".json") or i.contains("user://"):
|
||||
if i.contains(".bgm") or i.contains(".json") or i.contains(Global.config_path):
|
||||
DirAccess.copy_absolute(i, destination)
|
||||
else:
|
||||
var resource = load(i)
|
||||
@@ -33,7 +33,9 @@ func create_template() -> void:
|
||||
file.store_buffer(resource.data)
|
||||
file.close()
|
||||
|
||||
var file = FileAccess.open("user://resource_packs/new_pack/pack_info.json", FileAccess.WRITE)
|
||||
var pack_info_path = Global.config_path.path_join("resource_packs/new_pack/pack_info.json")
|
||||
DirAccess.make_dir_recursive_absolute(pack_info_path.get_base_dir())
|
||||
var file = FileAccess.open(pack_info_path, FileAccess.WRITE)
|
||||
file.store_string(JSON.stringify(base_info_json, "\t"))
|
||||
file.close()
|
||||
print("Done")
|
||||
@@ -51,7 +53,7 @@ func get_files(base_dir := "", files := []) -> void:
|
||||
i = i.replace(".import", "")
|
||||
print(i)
|
||||
var target_path = base_dir + "/" + i
|
||||
var rom_assets_path = target_path.replace("res://Assets", "user://resource_packs/BaseAssets")
|
||||
var rom_assets_path = target_path.replace("res://Assets", Global.config_path.path_join("resource_packs/BaseAssets"))
|
||||
if FileAccess.file_exists(rom_assets_path):
|
||||
files.append(rom_assets_path)
|
||||
else:
|
||||
|
@@ -93,6 +93,7 @@ func open_story_options() -> void:
|
||||
func continue_story() -> void:
|
||||
Global.current_game_mode = Global.GameMode.CAMPAIGN
|
||||
if Global.game_beaten or Global.debug_mode:
|
||||
go_back_to_first_level()
|
||||
$CanvasLayer/StoryMode/QuestSelect.open()
|
||||
else:
|
||||
$CanvasLayer/StoryMode/NoBeatenCharSelect.open()
|
||||
@@ -124,6 +125,8 @@ func get_highscore() -> void:
|
||||
|
||||
func clear_stats() -> void:
|
||||
Global.clear_saved_values()
|
||||
|
||||
func go_back_to_first_level() -> void:
|
||||
Global.world_num = 1
|
||||
Global.level_num = 1
|
||||
LevelTransition.level_to_transition_to = Level.get_scene_string(Global.world_num, Global.level_num)
|
||||
|
@@ -51,6 +51,9 @@ func transition_style_changed(new_value := 0) -> void:
|
||||
func firebar_style_changed(new_value := 0) -> void:
|
||||
Settings.file.visuals.firebar_style = new_value
|
||||
|
||||
func extra_particles(new_value := 0) -> void:
|
||||
Settings.file.visuals.extra_particles = new_value
|
||||
|
||||
func set_value(value_name := "", value = null) -> void:
|
||||
{
|
||||
"parallax_style": parallax_style_changed,
|
||||
@@ -67,5 +70,6 @@ func set_value(value_name := "", value = null) -> void:
|
||||
"bridge_animation": bridge_changed,
|
||||
"transition_animation": transform_style_changed,
|
||||
"colour_pipes": colourful_pipes_changed,
|
||||
"firebar_style": firebar_style_changed
|
||||
"firebar_style": firebar_style_changed,
|
||||
"extra_particles": extra_particles
|
||||
}[value_name].call(value)
|
||||
|
@@ -21,6 +21,9 @@ func skid_changed(new_value := 0) -> void:
|
||||
func extra_sfx_changed(new_value := 0) -> void:
|
||||
Settings.file.audio.extra_sfx = new_value
|
||||
|
||||
func pause_bgm_changed(new_value := 0) -> void:
|
||||
Settings.file.audio.pause_bgm = new_value
|
||||
|
||||
func menu_bgm_changed(new_value := 0) -> void:
|
||||
Settings.file.audio.menu_bgm = new_value
|
||||
|
||||
@@ -36,5 +39,6 @@ func set_value(value_name := "", value := 0) -> void:
|
||||
"extra_bgm": athletic_changed,
|
||||
"skid_sfx": skid_changed,
|
||||
"extra_sfx": extra_sfx_changed,
|
||||
"pause_bgm": pause_bgm_changed,
|
||||
"menu_bgm": menu_bgm_changed
|
||||
}[value_name].call(value)
|
||||
|
@@ -41,21 +41,23 @@ func get_custom_characters() -> void:
|
||||
idx += 1
|
||||
print(Player.CHARACTER_NAMES)
|
||||
|
||||
DirAccess.make_dir_recursive_absolute("user://custom_characters")
|
||||
for i in DirAccess.get_directories_at("user://custom_characters"):
|
||||
if FileAccess.file_exists("user://custom_characters/" + i + "/CharacterInfo.json"):
|
||||
var char_path = "user://custom_characters/" + i + "/"
|
||||
var json = JSON.parse_string(FileAccess.open(char_path + "CharacterInfo.json", FileAccess.READ).get_as_text())
|
||||
var base_path = Global.config_path
|
||||
var char_dir = base_path.path_join("custom_characters")
|
||||
for i in DirAccess.get_directories_at(char_dir):
|
||||
var char_path = char_dir.path_join(i)
|
||||
var char_info_path = char_path.path_join("CharacterInfo.json")
|
||||
if FileAccess.file_exists(char_info_path):
|
||||
var json = JSON.parse_string(FileAccess.open(char_path.path_join("CharacterInfo.json"), FileAccess.READ).get_as_text())
|
||||
Player.CHARACTERS.append(i)
|
||||
Player.CHARACTER_NAMES.append(json.name)
|
||||
if FileAccess.file_exists(char_path + "CharacterColour.json"):
|
||||
Player.CHARACTER_COLOURS.append(load(char_path + "CharacterColour.json"))
|
||||
if FileAccess.file_exists(char_path + "LifeIcon.json"):
|
||||
GameHUD.character_icons.append(load(char_path + "LifeIcon.json"))
|
||||
if FileAccess.file_exists(char_path + "ColourPalette.json"):
|
||||
Player.CHARACTER_PALETTES.append(load(char_path + "ColourPalette.json"))
|
||||
if FileAccess.file_exists(char_path + "SFX.json"):
|
||||
AudioManager.character_sfx_map[i] = JSON.parse_string(FileAccess.open(char_path + "SFX.json", FileAccess.READ).get_as_text())
|
||||
if FileAccess.file_exists(char_path.path_join("CharacterColour.json")):
|
||||
Player.CHARACTER_COLOURS.append(load(char_path.path_join("CharacterColour.json")))
|
||||
if FileAccess.file_exists(char_path.path_join("LifeIcon.json")):
|
||||
GameHUD.character_icons.append(load(char_path.path_join("LifeIcon.json")))
|
||||
if FileAccess.file_exists(char_path.path_join("ColourPalette.json")):
|
||||
Player.CHARACTER_PALETTES.append(load(char_path.path_join("ColourPalette.json")))
|
||||
if FileAccess.file_exists(char_path.path_join("SFX.json")):
|
||||
AudioManager.character_sfx_map[i] = JSON.parse_string(FileAccess.open(char_path.path_join("SFX.json"), FileAccess.READ).get_as_text())
|
||||
|
||||
func open() -> void:
|
||||
get_custom_characters()
|
||||
|
@@ -4,7 +4,6 @@ signal level_selected(container: CustomLevelContainer)
|
||||
|
||||
const CUSTOM_LEVEL_CONTAINER = preload("uid://dt20tjug8m6oh")
|
||||
|
||||
const CUSTOM_LEVEL_PATH := "user://custom_levels/"
|
||||
const base64_charset := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
signal closed
|
||||
@@ -25,7 +24,8 @@ func open(refresh_list := true) -> void:
|
||||
set_process(true)
|
||||
|
||||
func open_folder() -> void:
|
||||
OS.shell_show_in_file_manager(ProjectSettings.globalize_path(CUSTOM_LEVEL_PATH))
|
||||
var custom_level_path = Global.config_path.path_join("custom_levels")
|
||||
OS.shell_show_in_file_manager(ProjectSettings.globalize_path(custom_level_path))
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if Input.is_action_just_pressed("ui_back"):
|
||||
@@ -41,11 +41,12 @@ func refresh() -> void:
|
||||
if i is CustomLevelContainer:
|
||||
i.queue_free()
|
||||
containers.clear()
|
||||
get_levels("user://custom_levels")
|
||||
get_levels("user://custom_levels/downloaded")
|
||||
get_levels(Global.config_path.path_join("custom_levels"))
|
||||
get_levels(Global.config_path.path_join("custom_levels/downloaded"))
|
||||
|
||||
func get_levels(path := "user://custom_levels") -> void:
|
||||
DirAccess.make_dir_recursive_absolute(path)
|
||||
func get_levels(path : String = "") -> void:
|
||||
if path == "":
|
||||
path = Global.config_path.path_join("custom_levels")
|
||||
var idx := 0
|
||||
for i in DirAccess.get_files_at(path):
|
||||
if i.contains(".lvl") == false:
|
||||
|
@@ -6,7 +6,6 @@ static var current_level_file := ""
|
||||
static var has_entered := false
|
||||
|
||||
var selected_lvl_idx := 0
|
||||
const CUSTOM_LEVEL_PATH := "user://custom_levels/"
|
||||
const base64_charset := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
static var page_number_save := -1
|
||||
static var last_played_container = null
|
||||
@@ -47,6 +46,7 @@ func _ready() -> void:
|
||||
%LevelList.close()
|
||||
|
||||
func clear_saved_stuff() -> void:
|
||||
last_played_container = null
|
||||
%LSSLevelInfo.saved_stuff.clear()
|
||||
saved_search_values = [-1, -1, -1]
|
||||
%LSSBrowser.number_of_pages = -1
|
||||
@@ -78,7 +78,6 @@ func edit_level() -> void:
|
||||
|
||||
func play_level() -> void:
|
||||
Global.current_game_mode = Global.GameMode.CUSTOM_LEVEL
|
||||
Settings.file.difficulty.inf_lives = 1
|
||||
LevelEditor.load_play = true
|
||||
$CharacterSelect.open()
|
||||
await $CharacterSelect.selected
|
||||
@@ -88,7 +87,6 @@ func play_level() -> void:
|
||||
func online_play() -> void:
|
||||
lss_level_played()
|
||||
Global.current_game_mode = Global.GameMode.CUSTOM_LEVEL
|
||||
Settings.file.difficulty.inf_lives = 1
|
||||
LevelEditor.load_play = true
|
||||
$LSSCharacterSelect.open()
|
||||
await $LSSCharacterSelect.selected
|
||||
|
@@ -29,6 +29,9 @@ func set_focus(enabled := false) -> void:
|
||||
i.focus_mode = 0 if enabled == false else 2
|
||||
|
||||
func continue_to_next_level() -> void:
|
||||
if Global.world_num == 8 and Global.level_num == 4:
|
||||
go_to_menu()
|
||||
return
|
||||
Global.current_level.transition_to_next_level()
|
||||
Global.disco_level_continued.emit()
|
||||
close()
|
||||
|
@@ -21,7 +21,7 @@ func _ready() -> void:
|
||||
|
||||
func open(container: OnlineLevelContainer) -> void:
|
||||
container_to_play = container.duplicate()
|
||||
has_downloaded = FileAccess.file_exists("user://custom_levels/downloaded/" + container.level_id + ".lvl") or saved_stuff.is_empty() == false
|
||||
has_downloaded = FileAccess.file_exists(Global.config_path.path_join("custom_levels/downloaded/" + container.level_id + ".lvl")) or saved_stuff.is_empty() == false
|
||||
show()
|
||||
level_thumbnail = container.level_thumbnail
|
||||
%Download.text = "DOWNLOAD"
|
||||
@@ -66,7 +66,7 @@ func close() -> void:
|
||||
set_process(false)
|
||||
|
||||
func download_level() -> void:
|
||||
DirAccess.make_dir_recursive_absolute("user://custom_levels/downloaded")
|
||||
DirAccess.make_dir_recursive_absolute(Global.config_path.path_join("custom_levels/downloaded"))
|
||||
var url = "https://levelsharesquare.com/api/levels/" + level_id + "/code"
|
||||
print(url)
|
||||
$DownloadLevel.request(url, [], HTTPClient.METHOD_GET)
|
||||
@@ -85,7 +85,7 @@ func on_request_completed(result: int, response_code: int, headers: PackedString
|
||||
func level_downloaded(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
var string = body.get_string_from_utf8()
|
||||
var json = JSON.parse_string(string)
|
||||
var file = FileAccess.open("user://custom_levels/downloaded/" + level_id + ".lvl", FileAccess.WRITE)
|
||||
var file = FileAccess.open(Global.config_path.path_join("custom_levels/downloaded/" + level_id + ".lvl"), FileAccess.WRITE)
|
||||
var data = null
|
||||
if json.levelData.data is Array:
|
||||
data = get_json_from_bytes(json.levelData.data)
|
||||
@@ -101,11 +101,11 @@ func level_downloaded(result: int, response_code: int, headers: PackedStringArra
|
||||
func save_thumbnail() -> void:
|
||||
if OnlineLevelContainer.cached_thumbnails.has(level_id):
|
||||
var thumbnail = OnlineLevelContainer.cached_thumbnails.get(level_id)
|
||||
DirAccess.make_dir_recursive_absolute("user://custom_levels/downloaded/thumbnails")
|
||||
thumbnail.get_image().save_png("user://custom_levels/downloaded/thumbnails/"+ level_id + ".png")
|
||||
DirAccess.make_dir_recursive_absolute(Global.config_path.path_join("custom_levels/downloaded/thumbnails"))
|
||||
thumbnail.get_image().save_png(Global.config_path.path_join("custom_levels/downloaded/thumbnails/" + level_id + ".png"))
|
||||
|
||||
func play_level() -> void:
|
||||
var file_path := "user://custom_levels/downloaded/" + level_id + ".lvl"
|
||||
var file_path := Global.config_path.path_join("custom_levels/downloaded/" + level_id + ".lvl")
|
||||
var file = JSON.parse_string(FileAccess.open(file_path, FileAccess.READ).get_as_text())
|
||||
LevelEditor.level_file = file
|
||||
set_process(false)
|
||||
|
@@ -48,6 +48,10 @@ func setup_rating_stars() -> void:
|
||||
var rating = calculate_rating()
|
||||
|
||||
var idx := 0
|
||||
if ratings.is_empty():
|
||||
for i in %RatingStars.get_children():
|
||||
i.region_rect.position.x = 16
|
||||
return
|
||||
for i in %RatingStars.get_children():
|
||||
i.region_rect.position.x = 16 if idx > rating else (0 if abs(idx - rating) >= 0.5 else 8)
|
||||
idx += 1
|
||||
|
@@ -42,7 +42,7 @@ func _process(_delta: float) -> void:
|
||||
grab_focus()
|
||||
else:
|
||||
focus_mode = Control.FOCUS_NONE
|
||||
if Input.is_action_just_pressed("jump_0") and selected and visible:
|
||||
if Input.is_action_just_pressed("ui_accept") and selected and visible:
|
||||
select()
|
||||
elif Input.is_action_just_pressed("ui_right") and selected and visible and config != {}:
|
||||
open_config_menu()
|
||||
|
@@ -7,16 +7,21 @@ const VALID_HASHES := [
|
||||
]
|
||||
|
||||
var args: PackedStringArray
|
||||
var rom_arg: String = ""
|
||||
|
||||
func _ready() -> void:
|
||||
args = OS.get_cmdline_args()
|
||||
Global.get_node("GameHUD").hide()
|
||||
|
||||
# Try command line ROMs first
|
||||
for path in args:
|
||||
if path.is_valid_filename():
|
||||
if handle_rom(path):
|
||||
return
|
||||
for i in range(args.size()):
|
||||
match args[i]:
|
||||
"-rom":
|
||||
if i + 1 < args.size():
|
||||
rom_arg = args[i + 1].replace("\\", "/")
|
||||
print("ROM argument found: ", rom_arg)
|
||||
if rom_arg != "" and handle_rom(rom_arg):
|
||||
return
|
||||
|
||||
# Fallback: local ROM
|
||||
var local_rom := find_local_rom()
|
||||
|
@@ -3,8 +3,9 @@ extends HBoxContainer
|
||||
|
||||
@export var settings_category := "video"
|
||||
@export var selected := false
|
||||
@export var can_bind_escape := false
|
||||
|
||||
@export var action_name := ""
|
||||
@export var action_names := [""]
|
||||
@export var title := ""
|
||||
|
||||
@export_enum("Keyboard", "Controller") var type := 0
|
||||
@@ -22,7 +23,9 @@ var can_remap := true
|
||||
|
||||
var current_device_brand := 0
|
||||
|
||||
var input_event: InputEvent = null
|
||||
var current_binding_idx := 0
|
||||
|
||||
var input_events: Array[InputEvent] = [null, null]
|
||||
|
||||
const button_id_translation := [
|
||||
["A", "B", "✕"],
|
||||
@@ -42,17 +45,35 @@ const button_id_translation := [
|
||||
"DPad R"
|
||||
]
|
||||
|
||||
func _ready() -> void:
|
||||
update_value()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if selected:
|
||||
handle_inputs()
|
||||
$Cursor.modulate.a = int(selected)
|
||||
|
||||
func update_value() -> void:
|
||||
$Title.text = tr(title) + ":"
|
||||
$Value.text = get_event_string(input_event) if not awaiting_input else "Press Any..."
|
||||
if awaiting_input:
|
||||
$Value.text = "Press Any..."
|
||||
else:
|
||||
if current_binding_idx == 0:
|
||||
$Value.text = "(" + get_event_string(input_events[0]) + "), " + get_event_string(input_events[1]) + " "
|
||||
else:
|
||||
$Value.text = " " + get_event_string(input_events[0]) + " ,(" + get_event_string(input_events[1]) + ")"
|
||||
|
||||
func handle_inputs() -> void:
|
||||
if selected and can_remap:
|
||||
if Input.is_action_just_pressed("ui_accept"):
|
||||
begin_remap()
|
||||
if can_remap:
|
||||
if selected:
|
||||
if Input.is_action_just_pressed("ui_accept"):
|
||||
begin_remap()
|
||||
if Input.is_action_just_pressed("ui_right"):
|
||||
current_binding_idx = 1
|
||||
update_value()
|
||||
elif Input.is_action_just_pressed("ui_left"):
|
||||
current_binding_idx = 0
|
||||
update_value()
|
||||
|
||||
func begin_remap() -> void:
|
||||
$Timer.stop()
|
||||
@@ -62,6 +83,7 @@ func begin_remap() -> void:
|
||||
get_parent().can_input = false
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
awaiting_input = true
|
||||
update_value()
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if awaiting_input == false: return
|
||||
@@ -69,35 +91,56 @@ func _input(event: InputEvent) -> void:
|
||||
if event.is_pressed() == false:
|
||||
return
|
||||
|
||||
if event is InputEventKey:
|
||||
if event is InputEventKey and not can_bind_escape:
|
||||
if event.as_text_physical_keycode() == "Escape":
|
||||
cancel_remap()
|
||||
map_event_to_action(null, current_binding_idx)
|
||||
return
|
||||
|
||||
if type == 0 and event is InputEventKey:
|
||||
map_event_to_action(event)
|
||||
map_event_to_action(event, current_binding_idx)
|
||||
elif type == 1 and (event is InputEventJoypadButton or event is InputEventJoypadMotion):
|
||||
if event is InputEventJoypadMotion:
|
||||
event.axis_value = sign(event.axis_value)
|
||||
map_event_to_action(event)
|
||||
map_event_to_action(event, current_binding_idx)
|
||||
|
||||
func map_event_to_action(event) -> void:
|
||||
var action = action_name + "_" + str(player_idx)
|
||||
var events = InputMap.action_get_events(action).duplicate()
|
||||
events[type] = event
|
||||
InputMap.action_erase_events(action)
|
||||
for i in events:
|
||||
InputMap.action_add_event(action, i)
|
||||
input_changed.emit(action, event)
|
||||
input_event = event
|
||||
func map_event_to_action(event, idx := 0) -> void:
|
||||
for action_name in action_names:
|
||||
var action = action_name
|
||||
if action.contains("ui_") == false and action != "pause":
|
||||
action = action_name + "_" + str(player_idx)
|
||||
var replace_event = null
|
||||
var events = InputMap.action_get_events(action).duplicate()
|
||||
var matching_type_events := []
|
||||
for i in events:
|
||||
if type == 0 and i is InputEventKey:
|
||||
matching_type_events.append(i)
|
||||
elif type == 1 and (i is InputEventJoypadButton or i is InputEventJoypadMotion):
|
||||
matching_type_events.append(i)
|
||||
if matching_type_events.size() - 1 < idx or matching_type_events.is_empty():
|
||||
events.append(event)
|
||||
else:
|
||||
replace_event = matching_type_events[clamp(idx, 0, matching_type_events.size() - 1)]
|
||||
var itr := 0
|
||||
for i in events:
|
||||
if i == replace_event:
|
||||
events[itr] = event
|
||||
itr += 1
|
||||
InputMap.action_erase_events(action)
|
||||
for i in events:
|
||||
InputMap.action_add_event(action, i)
|
||||
input_changed.emit(action, event)
|
||||
input_events[idx] = event
|
||||
awaiting_input = false
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
rebinding_input = false
|
||||
get_parent().can_input = true
|
||||
can_remap = true
|
||||
update_value()
|
||||
|
||||
func get_event_string(event: InputEvent) -> String:
|
||||
var event_string := ""
|
||||
if event == null:
|
||||
return "---"
|
||||
if event is InputEventKey:
|
||||
event_string = OS.get_keycode_string(event.keycode)
|
||||
elif event is InputEventJoypadButton:
|
||||
@@ -126,18 +169,23 @@ func get_event_string(event: InputEvent) -> String:
|
||||
else:
|
||||
direction = "Down"
|
||||
event_string = stick + " " + direction
|
||||
else:
|
||||
pass
|
||||
return event_string
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is not InputEventJoypadButton and event is not InputEventJoypadMotion:
|
||||
return
|
||||
var device_name = Input.get_joy_name(event.device)
|
||||
var old_brand = current_device_brand
|
||||
if device_name.to_upper().contains("NINTENDO") or device_name.to_upper().contains("SWITCH") or device_name.to_upper().contains("WII"):
|
||||
current_device_brand = 1
|
||||
elif device_name.to_upper().contains("PS") or device_name.to_upper().contains("PLAYSTATION"):
|
||||
current_device_brand = 2
|
||||
else:
|
||||
current_device_brand = 0
|
||||
if old_brand != current_device_brand:
|
||||
update_value()
|
||||
|
||||
func cancel_remap() -> void:
|
||||
awaiting_input = false
|
||||
@@ -145,3 +193,4 @@ func cancel_remap() -> void:
|
||||
rebinding_input = false
|
||||
get_parent().can_input = true
|
||||
can_remap = true
|
||||
update_value()
|
||||
|
@@ -14,6 +14,8 @@ signal option_2_selected
|
||||
signal option_3_selected
|
||||
signal option_4_selected
|
||||
|
||||
signal closed
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if active:
|
||||
handle_inputs()
|
||||
@@ -28,6 +30,8 @@ func handle_inputs() -> void:
|
||||
selected_index = clamp(selected_index, 0, options.size() - 1)
|
||||
if Input.is_action_just_pressed("ui_accept"):
|
||||
option_selected()
|
||||
elif Input.is_action_just_pressed("pause") or Input.is_action_just_pressed("ui_back"):
|
||||
close()
|
||||
|
||||
func option_selected() -> void:
|
||||
emit_signal("option_" + str(selected_index + 1) + "_selected")
|
||||
@@ -51,6 +55,7 @@ func close() -> void:
|
||||
active = false
|
||||
selected_index = 0
|
||||
hide()
|
||||
closed.emit()
|
||||
for i in 2:
|
||||
await get_tree().physics_frame
|
||||
Global.game_paused = false
|
||||
|
Reference in New Issue
Block a user