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:
@@ -28,13 +28,15 @@ var is_random := false
|
||||
|
||||
signal updated
|
||||
|
||||
var current_resource_pack := ""
|
||||
|
||||
@export var force_properties := {}
|
||||
var update_on_spawn := true
|
||||
|
||||
func _init() -> void:
|
||||
set_process_mode(Node.PROCESS_MODE_ALWAYS)
|
||||
|
||||
func _ready() -> void:
|
||||
func _enter_tree() -> void:
|
||||
safety_check()
|
||||
if update_on_spawn:
|
||||
update_resource()
|
||||
@@ -70,8 +72,12 @@ func get_resource(json_file: JSON) -> Resource:
|
||||
var resource: Resource = null
|
||||
var resource_path = json_file.resource_path
|
||||
config_to_use = {}
|
||||
current_resource_pack = ""
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
resource_path = get_resource_pack_path(resource_path, i)
|
||||
var new_path = get_resource_pack_path(resource_path, i)
|
||||
if resource_path != new_path or current_resource_pack == "":
|
||||
current_resource_pack = i
|
||||
resource_path = new_path
|
||||
|
||||
var source_json = JSON.parse_string(FileAccess.open(resource_path, FileAccess.READ).get_as_text())
|
||||
if source_json == null:
|
||||
@@ -135,7 +141,6 @@ func get_resource(json_file: JSON) -> Resource:
|
||||
var idx := 0
|
||||
for i in json.get("source"):
|
||||
var frame_path = ResourceSetter.get_pure_resource_path(json_file.resource_path.replace(json_file.resource_path.get_file(), i))
|
||||
print(frame_path)
|
||||
resource.set_frame_texture(idx, load_image_from_path(frame_path))
|
||||
idx += 1
|
||||
else:
|
||||
@@ -158,7 +163,12 @@ func apply_properties(properties := {}) -> void:
|
||||
if property_node == null:
|
||||
return
|
||||
for i in properties.keys():
|
||||
property_node.set(i, properties[i])
|
||||
if property_node.get(i) is Vector2:
|
||||
var value = properties[i]
|
||||
if value is Array:
|
||||
property_node.set(i, Vector2(value[0], value[1]))
|
||||
else:
|
||||
property_node.set(i, properties[i])
|
||||
|
||||
func get_variation_json(json := {}) -> Dictionary:
|
||||
var level_theme = Global.level_theme
|
||||
@@ -166,6 +176,7 @@ func get_variation_json(json := {}) -> Dictionary:
|
||||
level_theme = force_properties.Theme
|
||||
|
||||
for i in json.keys().filter(func(key): return key.contains("config:")):
|
||||
get_config_file(current_resource_pack)
|
||||
if config_to_use != {}:
|
||||
var option_name = i.get_slice(":", 1)
|
||||
if config_to_use.options.has(option_name):
|
||||
@@ -255,15 +266,19 @@ func get_variation_json(json := {}) -> Dictionary:
|
||||
|
||||
return json
|
||||
|
||||
func get_config_file(resource_pack := "") -> void:
|
||||
if FileAccess.file_exists("user://resource_packs/" + resource_pack + "/config.json"):
|
||||
config_to_use = JSON.parse_string(FileAccess.open("user://resource_packs/" + resource_pack + "/config.json", FileAccess.READ).get_as_text())
|
||||
if config_to_use == null:
|
||||
Global.log_error("Error parsing Config File! (" + resource_pack + ")")
|
||||
config_to_use = {}
|
||||
else:
|
||||
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/")
|
||||
if FileAccess.file_exists(user_path):
|
||||
if FileAccess.file_exists("user://resource_packs/" + resource_pack + "/config.json"):
|
||||
config_to_use = JSON.parse_string(FileAccess.open("user://resource_packs/" + resource_pack + "/config.json", FileAccess.READ).get_as_text())
|
||||
if config_to_use == null:
|
||||
Global.log_error("Error parsing Config File! (" + resource_pack + ")")
|
||||
config_to_use = {}
|
||||
return user_path
|
||||
else:
|
||||
return res_path
|
||||
|
@@ -105,7 +105,7 @@ var undo_redo = UndoRedo.new()
|
||||
|
||||
func _ready() -> void:
|
||||
$TileMenu.hide()
|
||||
Global.set_discord_status("In The Level Editor...")
|
||||
DiscordManager.set_discord_status("In The Level Editor...")
|
||||
Global.level_editor = self
|
||||
playing_level = false
|
||||
menu_open = $TileMenu.visible
|
||||
@@ -131,6 +131,10 @@ func _ready() -> void:
|
||||
$Info.hide()
|
||||
%Grid.hide()
|
||||
play_level()
|
||||
_physics_process(0)
|
||||
set_physics_process(false)
|
||||
for i in [$TileMenu]:
|
||||
i.queue_free()
|
||||
else:
|
||||
Global.current_game_mode = Global.GameMode.LEVEL_EDITOR
|
||||
else:
|
||||
@@ -147,7 +151,8 @@ func _physics_process(delta: float) -> void:
|
||||
handle_tile_cursor()
|
||||
if [EditorState.IDLE, EditorState.TRACK_EDITING].has(current_state):
|
||||
handle_camera(delta)
|
||||
%ThemeName.text = Global.level_theme
|
||||
if is_instance_valid(%ThemeName):
|
||||
%ThemeName.text = Global.level_theme
|
||||
handle_hud()
|
||||
if Input.is_action_just_pressed("editor_open_menu"):
|
||||
if current_state == EditorState.IDLE:
|
||||
@@ -155,7 +160,7 @@ func _physics_process(delta: float) -> void:
|
||||
elif current_state == EditorState.TILE_MENU:
|
||||
close_tile_menu()
|
||||
if Input.is_action_just_pressed("editor_play") and (current_state == EditorState.IDLE or current_state == EditorState.PLAYTESTING) and Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
|
||||
Checkpoint.passed = false
|
||||
Checkpoint.passed_checkpoints.clear()
|
||||
if current_state == EditorState.PLAYTESTING:
|
||||
stop_testing()
|
||||
else:
|
||||
@@ -294,6 +299,8 @@ func return_to_editor() -> void:
|
||||
return_editor_tiles()
|
||||
%Camera.enabled = true
|
||||
%Camera.make_current()
|
||||
KeyItem.total_collected = 0
|
||||
Door.unlocked_doors.clear()
|
||||
editor_start.emit()
|
||||
current_state = EditorState.IDLE
|
||||
handle_hud()
|
||||
|
@@ -10,6 +10,8 @@ var fly_wave := PI
|
||||
|
||||
var dead := false
|
||||
|
||||
var times_kicked := 0 ## For anti-infinite scoring in Challenge mode
|
||||
|
||||
func _ready() -> void:
|
||||
if has_meta("fly_2"):
|
||||
fly_wave = 0
|
||||
@@ -64,6 +66,7 @@ func summon_shell(flipped := false, launch := false) -> void:
|
||||
DiscoLevel.combo_amount += 1
|
||||
var shell = load(shell_scene).instantiate()
|
||||
shell.flipped = flipped
|
||||
shell.times_kicked = times_kicked
|
||||
shell.old_entity = self.duplicate()
|
||||
if launch:
|
||||
AudioManager.play_sfx("kick", global_position)
|
||||
|
@@ -10,8 +10,8 @@ func _physics_process(delta: float) -> void:
|
||||
|
||||
func handle_collision() -> void:
|
||||
$HeadHitbox.position.y = (-length * 16) + 8
|
||||
$Collision.shape.size.y = (length * 16)
|
||||
$Collision.position.y = (-length * 8)
|
||||
$Collision.shape.size.y = (length * 16) - 2
|
||||
$Collision.position.y = -$Collision.shape.size.y / 2
|
||||
$BodyHitbox.position.y = $Collision.position.y
|
||||
|
||||
func handle_part_animation(delta: float) -> void:
|
||||
|
@@ -17,8 +17,8 @@ func _physics_process(delta: float) -> void:
|
||||
velocity.y += (15 / delta) * delta
|
||||
velocity.y = clamp(velocity.y, -INF, 150)
|
||||
if is_on_floor():
|
||||
velocity.y = -150
|
||||
if is_on_wall() or is_on_ceiling():
|
||||
velocity.y = -125
|
||||
if is_on_wall() or (abs(get_floor_normal().x) > 0 and is_on_ceiling()):
|
||||
hit()
|
||||
move_and_slide()
|
||||
|
||||
|
@@ -10,7 +10,7 @@ func _ready() -> void:
|
||||
owner.queue_free()
|
||||
return
|
||||
owner.show()
|
||||
if Checkpoint.passed:
|
||||
if owner.passed:
|
||||
sprite.hide()
|
||||
activated.show()
|
||||
|
||||
|
@@ -87,6 +87,7 @@ func player_exit(player: Player) -> void:
|
||||
exiting_door_id = -1
|
||||
can_enter = false
|
||||
LevelEditor.play_door_transition = false
|
||||
if same_scene_exiting_door != null: same_scene_exiting_door.get_node("Sprite").play("Idle")
|
||||
same_scene_exiting_door = null
|
||||
player.global_position = global_position
|
||||
player.recenter_camera()
|
||||
|
@@ -102,7 +102,8 @@ func in_game() -> void:
|
||||
run_player_check(i.owner)
|
||||
|
||||
func run_player_check(player: Player) -> void:
|
||||
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) and player.state_machine.state.name == "Normal":
|
||||
# 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":
|
||||
can_enter = false
|
||||
pipe_entered.emit()
|
||||
DiscoLevel.can_meter_tick = false
|
||||
|
@@ -1,24 +1,41 @@
|
||||
class_name Player
|
||||
extends CharacterBody2D
|
||||
|
||||
var AIR_ACCEL := 3.0
|
||||
var AIR_SKID := 1.5
|
||||
var DECEL := 3.0
|
||||
var FALL_GRAVITY := 25.0
|
||||
var GROUND_RUN_ACCEL := 1.25
|
||||
var GROUND_WALK_ACCEL := 4.0
|
||||
var JUMP_GRAVITY := 11.0
|
||||
var JUMP_HEIGHT := 300.0
|
||||
var JUMP_INCR := 8.0
|
||||
var SWIM_GRAVITY := 2.5
|
||||
var SWIM_SPEED := 95.0
|
||||
var MAX_FALL_SPEED := 280
|
||||
var MAX_SWIM_FALL_SPEED := 200
|
||||
var RUN_SKID := 8.0
|
||||
var RUN_SPEED := 160
|
||||
var WALK_SKID := 8.0
|
||||
var WALK_SPEED := 96.0
|
||||
var CEILING_BUMP_SPEED := 45.0
|
||||
#region Physics properies, these can be changed within a custom character's CharacterInfo.json
|
||||
var JUMP_GRAVITY := 11.0 # The player's gravity while jumping, measured in px/frame
|
||||
var JUMP_HEIGHT := 300.0 # The strength of the player's jump, measured in px/sec
|
||||
var JUMP_INCR := 8.0 # How much the player's X velocity affects their jump speed
|
||||
var JUMP_CANCEL_DIVIDE := 1.5 # When the player cancels their jump, their Y velocity gets divided by this value
|
||||
var JUMP_HOLD_SPEED_THRESHOLD := 0.0 # When the player's Y velocity goes past this value while jumping, their gravity switches to FALL_GRAVITY
|
||||
|
||||
var BOUNCE_HEIGHT := 200.0 # The strength at which the player bounces off enemies, measured in px/sec
|
||||
var BOUNCE_JUMP_HEIGHT := 300.0 # The strength at which the player bounces off enemies while holding jump, measured in px/sec
|
||||
|
||||
var FALL_GRAVITY := 25.0 # The player's gravity while falling, measured in px/frame
|
||||
var MAX_FALL_SPEED := 280.0 # The player's maximum fall speed, measured in px/sec
|
||||
var CEILING_BUMP_SPEED := 45.0 # The speed at which the player falls after hitting a ceiling, measured in px/sec
|
||||
|
||||
var WALK_SPEED := 96.0 # The player's speed while walking, measured in px/sec
|
||||
var GROUND_WALK_ACCEL := 4.0 # The player's acceleration while walking, measured in px/frame
|
||||
var WALK_SKID := 8.0 # The player's turning deceleration while running, measured in px/frame
|
||||
|
||||
var RUN_SPEED := 160.0 # The player's speed while running, measured in px/sec
|
||||
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 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
|
||||
|
||||
var SWIM_SPEED := 95.0 # The player's horizontal speed while swimming, measured in px/sec
|
||||
var SWIM_GROUND_SPEED := 45.0 # The player's horizontal speed while grounded underwater, measured in px/sec
|
||||
var SWIM_HEIGHT := 100.0 # The strength of the player's swim, measured in px/sec
|
||||
var SWIM_GRAVITY := 2.5 # The player's gravity while swimming, measured in px/frame
|
||||
var MAX_SWIM_FALL_SPEED := 200.0 # The player's maximum fall speed while swimming, measured in px/sec
|
||||
|
||||
var DEATH_JUMP_HEIGHT := 300.0 # The strength of the player's "jump" during the death animation, measured in px/sec
|
||||
#endregion
|
||||
|
||||
@onready var camera_center_joint: Node2D = $CameraCenterJoint
|
||||
|
||||
@onready var sprite: AnimatedSprite2D = %Sprite
|
||||
@@ -57,6 +74,8 @@ var pipe_move_direction := 1
|
||||
var stomp_combo := 0
|
||||
|
||||
var is_invincible := false
|
||||
var can_pose := false
|
||||
var is_posing := false
|
||||
|
||||
const COMBO_VALS := [100, 200, 400, 500, 800, 1000, 2000, 4000, 5000, 8000, null]
|
||||
|
||||
@@ -125,7 +144,7 @@ const ANIMATION_FALLBACKS := {
|
||||
"WaterIdle": "Idle",
|
||||
"DieFreeze": "Die",
|
||||
"StarJump": "Jump",
|
||||
"StarFall": "JumpFall"
|
||||
"StarFall": "StarJump"
|
||||
}
|
||||
|
||||
var palette_transform := true
|
||||
@@ -272,12 +291,8 @@ func apply_gravity(delta: float) -> void:
|
||||
if in_water or flight_meter > 0:
|
||||
gravity = SWIM_GRAVITY
|
||||
else:
|
||||
if gravity_vector.y > 0:
|
||||
if velocity.y > 0:
|
||||
gravity = FALL_GRAVITY
|
||||
elif gravity_vector.y < 0:
|
||||
if velocity.y < 0:
|
||||
gravity = FALL_GRAVITY
|
||||
if sign(gravity_vector.y) * velocity.y + JUMP_HOLD_SPEED_THRESHOLD > 0.0:
|
||||
gravity = FALL_GRAVITY
|
||||
velocity += (gravity_vector * ((gravity / (1.5 if low_gravity else 1.0)) / delta)) * delta
|
||||
var target_fall: float = MAX_FALL_SPEED
|
||||
if in_water:
|
||||
@@ -363,30 +378,32 @@ func is_actually_on_ceiling() -> bool:
|
||||
return true
|
||||
return false
|
||||
|
||||
func enemy_bounce_off(add_combo := true) -> void:
|
||||
func enemy_bounce_off(add_combo := true, award_score := true) -> void:
|
||||
if add_combo:
|
||||
add_stomp_combo()
|
||||
add_stomp_combo(award_score)
|
||||
jump_cancelled = not Global.player_action_pressed("jump", player_id)
|
||||
await get_tree().physics_frame
|
||||
if Global.player_action_pressed("jump", player_id):
|
||||
velocity.y = -300
|
||||
velocity.y = sign(gravity_vector.y) * -BOUNCE_JUMP_HEIGHT
|
||||
gravity = JUMP_GRAVITY
|
||||
has_jumped = true
|
||||
else:
|
||||
velocity.y = -200
|
||||
velocity.y = sign(gravity_vector.y) * -BOUNCE_HEIGHT
|
||||
|
||||
func add_stomp_combo() -> void:
|
||||
func add_stomp_combo(award_score := true) -> void:
|
||||
if stomp_combo >= 10:
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE or Settings.file.difficulty.inf_lives:
|
||||
Global.score += 10000
|
||||
score_note_spawner.spawn_note(10000)
|
||||
else:
|
||||
Global.lives += 1
|
||||
AudioManager.play_global_sfx("1_up")
|
||||
score_note_spawner.spawn_one_up_note()
|
||||
if award_score:
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE or Settings.file.difficulty.inf_lives:
|
||||
Global.score += 10000
|
||||
score_note_spawner.spawn_note(10000)
|
||||
else:
|
||||
Global.lives += 1
|
||||
AudioManager.play_global_sfx("1_up")
|
||||
score_note_spawner.spawn_one_up_note()
|
||||
else:
|
||||
Global.score += COMBO_VALS[stomp_combo]
|
||||
score_note_spawner.spawn_note(COMBO_VALS[stomp_combo])
|
||||
if award_score:
|
||||
Global.score += COMBO_VALS[stomp_combo]
|
||||
score_note_spawner.spawn_note(COMBO_VALS[stomp_combo])
|
||||
stomp_combo += 1
|
||||
|
||||
func bump_ceiling() -> void:
|
||||
@@ -528,6 +545,7 @@ func die(pit := false) -> void:
|
||||
Global.p_switch_active = false
|
||||
Global.p_switch_timer = 0
|
||||
stop_all_timers()
|
||||
sprite.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
state_machine.transition_to("Dead", {"Pit": pit})
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
get_tree().paused = true
|
||||
@@ -545,34 +563,56 @@ func die(pit := false) -> void:
|
||||
func death_load() -> void:
|
||||
power_state = get_node("PowerStates/Small")
|
||||
Global.player_power_states = "0000"
|
||||
|
||||
if Global.death_load:
|
||||
return
|
||||
Global.death_load = true
|
||||
if Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
|
||||
LevelTransition.level_to_transition_to = "res://Scenes/Levels/LevelEditor.tscn"
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
|
||||
return
|
||||
if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
|
||||
owner.stop_testing()
|
||||
return
|
||||
|
||||
# Handle lives decrement for CAMPAIGN and MARATHON
|
||||
if [Global.GameMode.CAMPAIGN, Global.GameMode.MARATHON].has(Global.current_game_mode):
|
||||
if Settings.file.difficulty.inf_lives == 0:
|
||||
Global.lives -= 1
|
||||
Global.death_load = true
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE:
|
||||
Global.transition_to_scene("res://Scenes/Levels/ChallengeMiss.tscn")
|
||||
elif Global.time <= 0:
|
||||
Global.transition_to_scene("res://Scenes/Levels/TimeUp.tscn")
|
||||
elif Global.lives <= 0 and Settings.file.difficulty.inf_lives == 0:
|
||||
Global.death_load = false
|
||||
Global.transition_to_scene("res://Scenes/Levels/GameOver.tscn")
|
||||
else:
|
||||
LevelPersistance.reset_states()
|
||||
if Global.current_game_mode == Global.GameMode.BOO_RACE:
|
||||
|
||||
# Full dispatch table for death handling
|
||||
var death_actions = {
|
||||
Global.GameMode.CUSTOM_LEVEL: func():
|
||||
LevelTransition.level_to_transition_to = "res://Scenes/Levels/LevelEditor.tscn"
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn"),
|
||||
|
||||
Global.GameMode.LEVEL_EDITOR: func():
|
||||
owner.stop_testing(),
|
||||
|
||||
Global.GameMode.CHALLENGE: func():
|
||||
Global.transition_to_scene("res://Scenes/Levels/ChallengeMiss.tscn"),
|
||||
|
||||
Global.GameMode.BOO_RACE: func():
|
||||
Global.reset_values()
|
||||
Global.clear_saved_values()
|
||||
Global.death_load = false
|
||||
Level.start_level_path = Global.current_level.scene_file_path
|
||||
Global.current_level.reload_level()
|
||||
Global.current_level.reload_level(),
|
||||
|
||||
"time_up": func():
|
||||
Global.transition_to_scene("res://Scenes/Levels/TimeUp.tscn"),
|
||||
|
||||
"game_over": func():
|
||||
Global.death_load = false
|
||||
Global.transition_to_scene("res://Scenes/Levels/GameOver.tscn"),
|
||||
|
||||
"default_reload": func():
|
||||
LevelPersistance.reset_states()
|
||||
Global.current_level.reload_level()
|
||||
}
|
||||
|
||||
# Determine which action to take
|
||||
if death_actions.has(Global.current_game_mode):
|
||||
death_actions[Global.current_game_mode].call()
|
||||
elif Global.time <= 0:
|
||||
death_actions["time_up"].call()
|
||||
elif Global.lives <= 0 and Settings.file.difficulty.inf_lives == 0:
|
||||
death_actions["game_over"].call()
|
||||
else:
|
||||
death_actions["default_reload"].call()
|
||||
|
||||
func time_up() -> void:
|
||||
die()
|
||||
@@ -583,6 +623,8 @@ func set_power_state_frame() -> void:
|
||||
if power_state != null:
|
||||
$ResourceSetterNew.resource_json = load(get_character_sprite_path())
|
||||
$ResourceSetterNew.update_resource()
|
||||
if %Sprite.sprite_frames != null:
|
||||
can_pose = %Sprite.sprite_frames.has_animation("PoseDoor")
|
||||
|
||||
func get_power_up(power_name := "") -> void:
|
||||
if is_dead:
|
||||
@@ -652,7 +694,7 @@ func power_up_animation(new_power_state := "") -> void:
|
||||
await get_tree().create_timer(0.6).timeout
|
||||
transforming = false
|
||||
get_tree().paused = false
|
||||
sprite.process_mode = Node.PROCESS_MODE_PAUSABLE
|
||||
sprite.process_mode = Node.PROCESS_MODE_INHERIT
|
||||
if Global.player_action_just_pressed("jump", player_id):
|
||||
jump()
|
||||
return
|
||||
|
@@ -3,6 +3,8 @@ extends Enemy
|
||||
|
||||
var moving := false
|
||||
|
||||
var moving_time := 0.0
|
||||
|
||||
const MOVE_SPEED := 192
|
||||
const AIR_MOVE_SPEED := 64
|
||||
|
||||
@@ -15,7 +17,7 @@ var can_kick := false
|
||||
|
||||
var player: Player = null
|
||||
|
||||
const COMBO_VALS := [500, 800, 1000, 2000, 4000, 5000, 8000, null]
|
||||
const COMBO_VALS := [100, 200, 400, 500, 800, 1000, 2000, 4000, 5000, 8000, null]
|
||||
|
||||
var wake_meter := 0.0 ## SMB1R IS WOKE
|
||||
|
||||
@@ -25,6 +27,8 @@ var can_update := true
|
||||
|
||||
var can_air_kick := false
|
||||
|
||||
var times_kicked := 0
|
||||
|
||||
func _ready() -> void:
|
||||
$Sprite.flip_v = flipped
|
||||
if flipped:
|
||||
@@ -40,14 +44,12 @@ func on_player_stomped_on(stomped_player: Player) -> void:
|
||||
return
|
||||
if not moving:
|
||||
direction = sign(global_position.x - stomped_player.global_position.x)
|
||||
kick()
|
||||
kick(stomped_player)
|
||||
else:
|
||||
DiscoLevel.combo_meter += 10
|
||||
moving = false
|
||||
AudioManager.play_sfx("enemy_stomp", global_position)
|
||||
stomped_player.enemy_bounce_off()
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE and stomped_player.stomp_combo >= 10:
|
||||
die_from_object(stomped_player)
|
||||
stomped_player.enemy_bounce_off(true, moving_time > 0.1)
|
||||
|
||||
func block_bounced(_block: Block) -> void:
|
||||
velocity.y = -200
|
||||
@@ -59,19 +61,50 @@ func on_player_hit(hit_player: Player) -> void:
|
||||
return
|
||||
if not moving:
|
||||
direction = sign(global_position.x - hit_player.global_position.x )
|
||||
kick()
|
||||
kick(hit_player)
|
||||
else:
|
||||
hit_player.damage()
|
||||
|
||||
func award_score(award_level: int) -> void:
|
||||
if award_level >= 10:
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE or Settings.file.difficulty.inf_lives:
|
||||
$ScoreNoteSpawner.spawn_note(10000)
|
||||
else:
|
||||
AudioManager.play_global_sfx("1_up")
|
||||
Global.lives += 1
|
||||
$ScoreNoteSpawner.spawn_one_up_note()
|
||||
else:
|
||||
$ScoreNoteSpawner.spawn_note(COMBO_VALS[award_level])
|
||||
|
||||
func get_kick_award(hit_player: Player) -> int:
|
||||
var award_level = hit_player.stomp_combo + 2
|
||||
if award_level > 10:
|
||||
award_level = 10
|
||||
# Award special amounts of points if close to waking up.
|
||||
if wake_meter > 7 - 0.04:
|
||||
award_level = 9
|
||||
elif wake_meter > 7 - 0.25:
|
||||
award_level = 5
|
||||
elif wake_meter > 7 - 0.75:
|
||||
award_level = 3
|
||||
return award_level
|
||||
|
||||
func kick() -> void:
|
||||
func kick(hit_player: Player) -> void:
|
||||
update_hitbox()
|
||||
DiscoLevel.combo_meter += 25
|
||||
moving = true
|
||||
moving_time = 0.0
|
||||
if can_air_kick:
|
||||
$ScoreNoteSpawner.spawn_note(8000)
|
||||
else:
|
||||
$ScoreNoteSpawner.spawn_note(400)
|
||||
award_score(get_kick_award(hit_player))
|
||||
AudioManager.play_sfx("kick", global_position)
|
||||
|
||||
# Limit the number of times you can kick the same shell.
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE:
|
||||
times_kicked += 1
|
||||
if times_kicked >= 7:
|
||||
die_from_object(hit_player)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
handle_movement(delta)
|
||||
@@ -79,6 +112,7 @@ func _physics_process(delta: float) -> void:
|
||||
handle_block_collision()
|
||||
if moving:
|
||||
wake_meter = 0
|
||||
moving_time += delta
|
||||
$Sprite.play("Spin")
|
||||
else:
|
||||
combo = 0
|
||||
@@ -94,6 +128,7 @@ func handle_waking(delta: float) -> void:
|
||||
|
||||
func summon_original_entity() -> void:
|
||||
old_entity.global_position = global_position
|
||||
old_entity.times_kicked = times_kicked
|
||||
add_sibling(old_entity)
|
||||
queue_free()
|
||||
|
||||
@@ -105,17 +140,12 @@ func handle_block_collision() -> void:
|
||||
i.shell_block_hit.emit(self)
|
||||
|
||||
func add_combo() -> void:
|
||||
if combo >= 7:
|
||||
if Global.current_game_mode == Global.GameMode.CHALLENGE or Settings.file.difficulty.inf_lives:
|
||||
Global.score += 10000
|
||||
$ScoreNoteSpawner.spawn_note(10000)
|
||||
else:
|
||||
AudioManager.play_global_sfx("1_up")
|
||||
Global.lives += 1
|
||||
$ScoreNoteSpawner.spawn_one_up_note()
|
||||
else:
|
||||
$ScoreNoteSpawner.spawn_note(COMBO_VALS[combo])
|
||||
award_score(combo + 3)
|
||||
if combo < 7:
|
||||
combo += 1
|
||||
elif Global.current_game_mode == Global.GameMode.CHALLENGE and moving_time > 12.0:
|
||||
# Force limit on how long you can let a shell hit respawning enemies.
|
||||
die()
|
||||
|
||||
func update_hitbox() -> void:
|
||||
can_kick = false
|
||||
|
@@ -66,6 +66,9 @@ var sky_scroll_speed := -4.0
|
||||
|
||||
const disco_sfx_threshold := [0.05, 0.5, 0.8]
|
||||
|
||||
var primary_layer_size = Vector2(512, 512)
|
||||
var secondary_layer_size = Vector2(512, 512)
|
||||
var sky_layer_size = Vector2(512, 512)
|
||||
|
||||
func set_second_y_offset(value := 0.0) -> void:
|
||||
second_layer_offset.y = -value
|
||||
@@ -188,6 +191,10 @@ func update_visuals() -> void:
|
||||
$SecondaryLayer/Mushrooms.get_node("Tint").visible = can_mushroom_tint
|
||||
$SecondaryLayer/Trees.get_node("Tint").visible = can_tree_tint
|
||||
|
||||
$PrimaryLayer.repeat_size = primary_layer_size
|
||||
$SecondaryLayer.repeat_size = secondary_layer_size
|
||||
$SkyLayer.repeat_size = sky_layer_size
|
||||
|
||||
var tree_tint_amount = inverse_lerp(1, 0, parallax_amount)
|
||||
var mushroom_tint_amount = tree_tint_amount
|
||||
if can_mushroom_tint == false:
|
||||
|
@@ -159,7 +159,7 @@ func transition_to_next_level() -> void:
|
||||
first_load = true
|
||||
SaveManager.write_save()
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
|
||||
Checkpoint.passed = false
|
||||
Checkpoint.passed_checkpoints.clear()
|
||||
|
||||
func reload_level() -> void:
|
||||
LevelTransition.level_to_transition_to = Level.start_level_path
|
||||
|
@@ -224,8 +224,6 @@ func handle_music() -> void:
|
||||
music_player.get_stream_playback().switch_to_clip(1)
|
||||
elif music_player.get_stream_playback().get_current_clip_index() != 0:
|
||||
music_player.get_stream_playback().switch_to_clip(0)
|
||||
if DiscoLevel.in_disco_level:
|
||||
music_player.pitch_scale = 2
|
||||
|
||||
func handle_music_override() -> void:
|
||||
if music_override_player.stream is AudioStreamInteractive and music_override_player.is_playing():
|
||||
|
63
Scripts/Classes/Singletons/DiscordManager.gd
Normal file
63
Scripts/Classes/Singletons/DiscordManager.gd
Normal file
@@ -0,0 +1,63 @@
|
||||
extends Node
|
||||
|
||||
var enabled: bool = ProjectSettings.get_setting("application/use_discord", false) and not (OS.has_feature("linux") and OS.has_feature("arm64"))
|
||||
var rpc = null
|
||||
|
||||
class DiscordRPCStub:
|
||||
var app_id
|
||||
var start_timestamp
|
||||
var details
|
||||
var state
|
||||
var large_image
|
||||
var small_image
|
||||
|
||||
func start(): pass
|
||||
func refresh(): pass
|
||||
func get_is_discord_working() -> bool: return false
|
||||
func shutdown(): pass
|
||||
|
||||
func _ready() -> void:
|
||||
if enabled:
|
||||
rpc = Engine.get_singleton("DiscordRPC")
|
||||
else:
|
||||
rpc = DiscordRPCStub.new()
|
||||
setup_discord_rpc()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if enabled:
|
||||
rpc.run_callbacks()
|
||||
|
||||
func setup_discord_rpc() -> void:
|
||||
if not enabled:
|
||||
return
|
||||
rpc.app_id = 1331261692381757562
|
||||
rpc.start_timestamp = int(Time.get_unix_time_from_system())
|
||||
rpc.details = "In Title Screen.."
|
||||
if rpc.get_is_discord_working():
|
||||
rpc.refresh()
|
||||
|
||||
func set_discord_status(details: String = "") -> void:
|
||||
if not enabled:
|
||||
return
|
||||
rpc.details = details
|
||||
if rpc.get_is_discord_working():
|
||||
rpc.refresh()
|
||||
|
||||
func update_discord_status(details: String) -> void:
|
||||
if not enabled:
|
||||
return
|
||||
rpc.details = details
|
||||
rpc.state = details
|
||||
rpc.large_image = (Global.level_theme + Global.theme_time).to_lower()
|
||||
rpc.small_image = Global.current_campaign.to_lower()
|
||||
if rpc.get_is_discord_working():
|
||||
rpc.refresh()
|
||||
|
||||
func refresh_discord_rpc() -> void:
|
||||
if not enabled:
|
||||
return
|
||||
if not rpc.get_is_discord_working():
|
||||
return
|
||||
Global.update_game_status()
|
||||
update_discord_status("")
|
||||
rpc.refresh()
|
1
Scripts/Classes/Singletons/DiscordManager.gd.uid
Normal file
1
Scripts/Classes/Singletons/DiscordManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://yx2impqs0lo5
|
@@ -117,7 +117,7 @@ var can_time_tick := true:
|
||||
if value == false:
|
||||
pass
|
||||
|
||||
var player_power_states := "1000"
|
||||
var player_power_states := "0000"
|
||||
|
||||
var connected_players := 1
|
||||
|
||||
@@ -169,7 +169,6 @@ func _ready() -> void:
|
||||
get_server_version()
|
||||
if OS.is_debug_build():
|
||||
debug_mode = false
|
||||
setup_discord_rpc()
|
||||
check_for_rom()
|
||||
|
||||
func check_for_rom() -> void:
|
||||
@@ -263,9 +262,10 @@ func activate_p_switch() -> void:
|
||||
|
||||
func reset_values() -> void:
|
||||
PlayerGhost.idx = 0
|
||||
Checkpoint.passed = false
|
||||
Checkpoint.passed_checkpoints.clear()
|
||||
Checkpoint.sublevel_id = 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)
|
||||
@@ -332,32 +332,11 @@ func close_freeze() -> void:
|
||||
|
||||
var recording_dir = "user://marathon_recordings/"
|
||||
|
||||
func setup_discord_rpc() -> void:
|
||||
DiscordRPC.app_id = 1331261692381757562
|
||||
DiscordRPC.start_timestamp = int(Time.get_unix_time_from_system())
|
||||
DiscordRPC.details = "In Title Screen.."
|
||||
if DiscordRPC.get_is_discord_working():
|
||||
DiscordRPC.refresh()
|
||||
|
||||
func set_discord_status(details := "") -> void:
|
||||
DiscordRPC.details = details
|
||||
if DiscordRPC.get_is_discord_working():
|
||||
DiscordRPC.refresh()
|
||||
|
||||
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
|
||||
DiscordRPC.large_image = (Global.level_theme + Global.theme_time).to_lower()
|
||||
DiscordRPC.small_image = Global.current_campaign.to_lower()
|
||||
DiscordRPC.state = string
|
||||
|
||||
func refresh_discord_rpc() -> void:
|
||||
if DiscordRPC.get_is_discord_working() == false:
|
||||
return
|
||||
update_game_status()
|
||||
DiscordRPC.refresh()
|
||||
|
||||
func open_marathon_results() -> void:
|
||||
get_node("GameHUD/MarathonResults").open()
|
||||
|
@@ -43,7 +43,8 @@ const SAVE_TEMPLATE := {
|
||||
-1.0, -1.0, -1.0, -1.0
|
||||
],
|
||||
"HighScore": 0,
|
||||
"ExtraWorldWin": false
|
||||
"ExtraWorldWin": false,
|
||||
"CurrentQuest": 1
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +96,7 @@ func write_save(campaign: String = Global.current_campaign, force := false) -> v
|
||||
save_json["LevelsVisited"] = visited_levels
|
||||
save_json["HighScore"] = Global.high_score
|
||||
save_json["ExtraWorldWin"] = Global.extra_worlds_win
|
||||
save_json["SecondQuest"] = Global.second_quest
|
||||
Global.GameMode.CHALLENGE:
|
||||
save_json["ChallengeScores"] = ChallengeModeHandler.top_challenge_scores
|
||||
save_json["RedCoins"] = ChallengeModeHandler.red_coins_collected
|
||||
@@ -137,6 +139,7 @@ func apply_save(json := {}) -> void:
|
||||
DiscoLevel.level_ranks = json.get("Ranks")
|
||||
if json.has("BooBestTimes"):
|
||||
BooRaceHandler.best_times = json.get("BooBestTimes").duplicate()
|
||||
Global.second_quest = json.get("SecondQuest", false)
|
||||
|
||||
func clear_save() -> void:
|
||||
for i in [BooRaceHandler.cleared_boo_levels, ChallengeModeHandler.top_challenge_scores, ChallengeModeHandler.red_coins_collected, visited_levels]:
|
||||
|
@@ -61,7 +61,8 @@ var file := {
|
||||
"bridge_animation": 0,
|
||||
"visible_timers": 0,
|
||||
"transition_animation": 0,
|
||||
"colour_pipes": 1
|
||||
"colour_pipes": 1,
|
||||
"firebar_style": 0
|
||||
},
|
||||
"difficulty":
|
||||
{
|
||||
|
@@ -276,9 +276,18 @@ func run_finished() -> void:
|
||||
if Global.current_game_mode == Global.GameMode.BOO_RACE:
|
||||
pass
|
||||
else:
|
||||
var best = best_level_warpless_times[Global.world_num - 1][Global.level_num - 1]
|
||||
if is_warp_run:
|
||||
best = best_level_any_times.get(str(Global.world_num) + "-" + str(Global.level_num), -1)
|
||||
var best := -1
|
||||
if Global.current_game_mode == Global.GameMode.MARATHON_PRACTICE:
|
||||
if is_warp_run:
|
||||
best = best_level_any_times.get(str(Global.world_num) + "-" + str(Global.level_num), -1)
|
||||
else:
|
||||
best = best_level_warpless_times[Global.world_num - 1][Global.level_num - 1]
|
||||
else:
|
||||
if is_warp_run:
|
||||
best = marathon_best_any_time
|
||||
else:
|
||||
best = marathon_best_warpless_time
|
||||
|
||||
if best <= 0 or best > timer:
|
||||
if Global.current_game_mode == Global.GameMode.MARATHON_PRACTICE:
|
||||
save_recording()
|
||||
|
@@ -13,7 +13,7 @@ func enter(msg := {}) -> void:
|
||||
player.set_collision_mask_value(i + 1, false)
|
||||
player.gravity = player.JUMP_GRAVITY
|
||||
if msg["Pit"] == false:
|
||||
player.velocity.y = -300
|
||||
player.velocity.y = -player.DEATH_JUMP_HEIGHT
|
||||
|
||||
func physics_update(delta: float) -> void:
|
||||
if can_fall:
|
||||
|
@@ -1,11 +1,15 @@
|
||||
extends PlayerState
|
||||
|
||||
func enter(_msg := {}) -> void:
|
||||
player.can_hurt = false
|
||||
player.has_jumped = false
|
||||
player.crouching = false
|
||||
player.get_node("CameraCenterJoint/RightWall").set_collision_layer_value(1, false)
|
||||
|
||||
func physics_update(delta: float) -> void:
|
||||
if player.is_posing:
|
||||
player.velocity.x = 0
|
||||
return
|
||||
player.input_direction = 1
|
||||
player.can_run = false
|
||||
player.normal_state.handle_movement(delta)
|
||||
|
@@ -27,7 +27,7 @@ func physics_update(delta: float) -> void:
|
||||
handle_death_pits()
|
||||
|
||||
func handle_death_pits() -> void:
|
||||
if player.global_position.y > 64 and not Level.in_vine_level and player.auto_death_pit:
|
||||
if player.global_position.y > 64 and not Level.in_vine_level and player.auto_death_pit and player.gravity_vector == Vector2.DOWN:
|
||||
player.die(true)
|
||||
elif player.global_position.y < Global.current_level.vertical_height - 32 and player.gravity_vector == Vector2.UP:
|
||||
player.die(true)
|
||||
@@ -95,7 +95,7 @@ func handle_ground_movement(delta: float) -> void:
|
||||
func ground_acceleration(delta: float) -> void:
|
||||
var target_move_speed := player.WALK_SPEED
|
||||
if player.in_water or player.flight_meter > 0:
|
||||
target_move_speed = 45
|
||||
target_move_speed = player.SWIM_GROUND_SPEED
|
||||
var target_accel := player.GROUND_WALK_ACCEL
|
||||
if (Global.player_action_pressed("run", player.player_id) and abs(player.velocity.x) >= player.WALK_SPEED) and (not player.in_water and player.flight_meter <= 0) and player.can_run:
|
||||
target_move_speed = player.RUN_SPEED
|
||||
@@ -105,7 +105,6 @@ func ground_acceleration(delta: float) -> void:
|
||||
target_accel = player.RUN_SKID
|
||||
else:
|
||||
target_accel = player.WALK_SKID
|
||||
|
||||
player.velocity.x = move_toward(player.velocity.x, target_move_speed * player.input_direction, (target_accel / delta) * delta)
|
||||
|
||||
func deceleration(delta: float) -> void:
|
||||
@@ -133,14 +132,9 @@ func handle_air_movement(delta: float) -> void:
|
||||
|
||||
if Global.player_action_pressed("jump", player.player_id) == false and player.has_jumped and not player.jump_cancelled:
|
||||
player.jump_cancelled = true
|
||||
if player.gravity_vector.y > 0:
|
||||
if player.velocity.y < 0:
|
||||
player.velocity.y /= 1.5
|
||||
player.gravity = player.FALL_GRAVITY
|
||||
elif player.gravity_vector.y < 0:
|
||||
if player.velocity.y > 0:
|
||||
player.velocity.y /= 1.5
|
||||
player.gravity = player.FALL_GRAVITY
|
||||
if sign(player.gravity_vector.y * player.velocity.y) < 0.0:
|
||||
player.velocity.y /= player.JUMP_CANCEL_DIVIDE
|
||||
player.gravity = player.FALL_GRAVITY
|
||||
|
||||
func air_acceleration(delta: float) -> void:
|
||||
var target_speed = player.WALK_SPEED
|
||||
@@ -171,7 +165,7 @@ func swim_acceleration(delta: float) -> void:
|
||||
func swim_up() -> void:
|
||||
if player.swim_stroke:
|
||||
player.play_animation("SwimIdle")
|
||||
player.velocity.y = -100 * player.gravity_vector.y
|
||||
player.velocity.y = -player.SWIM_HEIGHT * player.gravity_vector.y
|
||||
AudioManager.play_sfx("swim", player.global_position)
|
||||
swim_up_meter = 0.5
|
||||
player.crouching = false
|
||||
|
@@ -7,10 +7,17 @@ static var character_icons := [preload("res://Assets/Sprites/Players/Mario/LifeI
|
||||
|
||||
const RANK_COLOURS := {"F": Color.DIM_GRAY, "D": Color.WEB_MAROON, "C": Color.PALE_GREEN, "B": Color.DODGER_BLUE, "A": Color.RED, "S": Color.GOLD, "P": Color.PURPLE}
|
||||
|
||||
var delta_time := 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
Global.level_theme_changed.connect(update_character_info)
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
func _process(delta: float) -> void:
|
||||
if not get_tree().paused and $Timer.paused:
|
||||
delta_time += delta
|
||||
if delta_time >= 1:
|
||||
delta_time -= 1
|
||||
on_timeout()
|
||||
handle_main_hud()
|
||||
handle_pausing()
|
||||
|
||||
@@ -20,7 +27,7 @@ func handle_main_hud() -> void:
|
||||
$Main/RedCoins.hide()
|
||||
$Main/CoinCount.show()
|
||||
%Combo.hide()
|
||||
|
||||
$Timer.paused = Settings.file.difficulty.time_limit == 2
|
||||
$%Time.show()
|
||||
%Stopwatch.hide()
|
||||
%PB.hide()
|
||||
@@ -86,6 +93,8 @@ func handle_challenge_mode_hud() -> void:
|
||||
$Main/CoinCount.hide()
|
||||
var red_coins_collected = ChallengeModeHandler.current_run_red_coins_collected
|
||||
var idx := 0
|
||||
if Global.world_num > 8:
|
||||
return
|
||||
if Global.in_title_screen:
|
||||
red_coins_collected = int(ChallengeModeHandler.red_coins_collected[Global.world_num - 1][Global.level_num - 1])
|
||||
for i in [$Main/RedCoins/Coin1, $Main/RedCoins/Coin2, $Main/RedCoins/Coin3, $Main/RedCoins/Coin4, $Main/RedCoins/Coin5]:
|
||||
@@ -173,7 +182,7 @@ func activate_pause_menu() -> void:
|
||||
const HURRY_UP = preload("res://Assets/Audio/BGM/HurryUp.mp3")
|
||||
|
||||
func on_timeout() -> void:
|
||||
if Global.can_time_tick and is_instance_valid(Global.current_level) and Settings.file.difficulty.time_limit == 1:
|
||||
if Global.can_time_tick and is_instance_valid(Global.current_level) and Settings.file.difficulty.time_limit > 0:
|
||||
if Global.level_editor != null:
|
||||
if Global.level_editor.current_state != LevelEditor.EditorState.PLAYTESTING:
|
||||
return
|
||||
|
@@ -8,29 +8,33 @@ extends Node2D
|
||||
signal crossed(player: Player)
|
||||
signal respawned
|
||||
|
||||
static var passed := false
|
||||
var passed := false
|
||||
static var respawn_position := Vector2.ZERO
|
||||
static var level := ""
|
||||
static var sublevel_id := 0
|
||||
static var keys_collected := 0
|
||||
static var old_state := [[], []]
|
||||
static var unlocked_doors := []
|
||||
|
||||
static var passed_checkpoints := []
|
||||
|
||||
var id := ""
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if Global.level_editor != null:
|
||||
if sublevel_id != Global.level_editor.sub_level_id and passed:
|
||||
passed = false
|
||||
id = get_id()
|
||||
passed = passed_checkpoints.has(id)
|
||||
if passed:
|
||||
LevelPersistance.active_nodes = old_state.duplicate(true)
|
||||
|
||||
func _ready() -> void:
|
||||
if [Global.GameMode.CHALLENGE, Global.GameMode.MARATHON_PRACTICE].has(Global.current_game_mode):
|
||||
if [Global.GameMode.CHALLENGE, Global.GameMode.MARATHON_PRACTICE].has(Global.current_game_mode) or Global.current_campaign == "SMBANN":
|
||||
queue_free()
|
||||
return
|
||||
if has_meta("is_flag") == false:
|
||||
hide()
|
||||
if Settings.file.difficulty.checkpoint_style != 0:
|
||||
queue_free()
|
||||
if passed and PipeArea.exiting_pipe_id == -1 and Global.current_game_mode != Global.GameMode.LEVEL_EDITOR and Level.vine_return_level == "":
|
||||
if passed and PipeArea.exiting_pipe_id == -1 and Global.current_game_mode != Global.GameMode.LEVEL_EDITOR and Level.vine_return_level == "" and passed_checkpoints[passed_checkpoints.size() - 1] == id:
|
||||
for i in nodes_to_delete:
|
||||
i.queue_free()
|
||||
for i in get_tree().get_nodes_in_group("Players"):
|
||||
@@ -49,8 +53,10 @@ func on_area_entered(area: Area2D) -> void:
|
||||
var player: Player = area.owner
|
||||
player.passed_checkpoint()
|
||||
passed = true
|
||||
passed_checkpoints.append(id)
|
||||
keys_collected = KeyItem.total_collected
|
||||
old_state = LevelPersistance.active_nodes.duplicate(true)
|
||||
unlocked_doors = Door.unlocked_doors.duplicate()
|
||||
Level.start_level_path = Global.current_level.scene_file_path
|
||||
if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR or Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
|
||||
sublevel_id = Global.level_editor.sub_level_id
|
||||
@@ -60,6 +66,11 @@ func on_area_entered(area: Area2D) -> void:
|
||||
respawn_position = global_position
|
||||
crossed.emit(area.owner)
|
||||
|
||||
func get_id() -> String:
|
||||
if Global.level_editor != null:
|
||||
return str(Global.level_editor.sub_level_id) + "," + str(Vector2i(global_position)) + "," + get_parent().name
|
||||
else:
|
||||
return Global.current_level.scene_file_path + "," + str(Vector2i(global_position)) + "," + get_parent().name
|
||||
|
||||
func on_tree_exiting() -> void:
|
||||
pass # Replace with function body.
|
||||
|
@@ -32,9 +32,26 @@ func update_cam_limit() -> void:
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
$Overlay.modulate.a = int($SmallCastleVisual.use_sprite == false)
|
||||
if Global.level_editor != null && scene_file_path == "res://Scenes/Prefabs/LevelObjects/EndFinalCastle.tscn":
|
||||
var is_smbs: bool = Global.current_campaign == "SMBS"
|
||||
$SmallCastleVisual.visible = !is_smbs
|
||||
$SmallCastleVisual2.visible = is_smbs
|
||||
if get_node_or_null("Wall") != null:
|
||||
%Wall.visible = show_walls
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
for i: Player in get_tree().get_nodes_in_group("Players"):
|
||||
if i.can_pose and i.global_position >= global_position and i.sprite.sprite_frames.has_animation("PoseDoor"):
|
||||
i.is_posing = true; i.can_pose = false
|
||||
i.global_position = global_position
|
||||
i.play_animation("PoseDoor")
|
||||
i.sprite.animation_finished.connect(on_pose_finished.bind(i))
|
||||
i.sprite.animation_looped.connect(on_pose_finished.bind(i))
|
||||
|
||||
func on_pose_finished(player: Player) -> void:
|
||||
player.is_posing = false
|
||||
player.z_index = -2
|
||||
|
||||
func on_music_finished() -> void:
|
||||
do_sequence()
|
||||
|
||||
|
@@ -29,7 +29,8 @@ func player_touch(player: Player) -> void:
|
||||
get_tree().call_group("Enemies", "flag_die")
|
||||
give_points(player)
|
||||
Global.can_time_tick = false
|
||||
player.z_index = -2
|
||||
if player.can_pose == false:
|
||||
player.z_index = -2
|
||||
player.global_position.x = $Flag.global_position.x + 3
|
||||
$Animation.play("FlagDown")
|
||||
player.state_machine.transition_to("FlagPole")
|
||||
|
@@ -118,13 +118,14 @@ func apply_level_data(data := "") -> void:
|
||||
level.can_backscroll = bool(values[4])
|
||||
level.vertical_height = -int(values[5])
|
||||
level.time_limit = int(values[6])
|
||||
%ThemeTime.selected = values[1]
|
||||
%LevelMusic.selected = values[2]
|
||||
%Campaign.selected = values[3]
|
||||
%BackScroll.set_pressed_no_signal(bool(values[4]))
|
||||
%HeightLimit.value = values[5]
|
||||
%TimeLimit.value = values[6]
|
||||
%SubLevelID.selected = editor.sub_level_id
|
||||
if is_instance_valid($TileMenu):
|
||||
%ThemeTime.selected = values[1]
|
||||
%LevelMusic.selected = values[2]
|
||||
%Campaign.selected = values[3]
|
||||
%BackScroll.set_pressed_no_signal(bool(values[4]))
|
||||
%HeightLimit.value = values[5]
|
||||
%TimeLimit.value = values[6]
|
||||
%SubLevelID.selected = editor.sub_level_id
|
||||
ResourceSetterNew.cache.clear()
|
||||
Global.level_theme_changed.emit()
|
||||
|
||||
@@ -140,12 +141,13 @@ func apply_bg_data(data := "") -> void:
|
||||
value = (decode_from_base64_2char(i))
|
||||
else:
|
||||
value = (base64_charset.find(i))
|
||||
if SELECTORS[id] is SpinBox:
|
||||
SELECTORS[id].value = value
|
||||
elif SELECTORS[id] is Button:
|
||||
SELECTORS[id].set_pressed_no_signal(bool(value))
|
||||
else:
|
||||
SELECTORS[id].selected = value
|
||||
if is_instance_valid($TileMenu):
|
||||
if SELECTORS[id] is SpinBox:
|
||||
SELECTORS[id].value = value
|
||||
elif SELECTORS[id] is Button:
|
||||
SELECTORS[id].set_pressed_no_signal(bool(value))
|
||||
else:
|
||||
SELECTORS[id].selected = value
|
||||
level_bg.set_value(value, BG_VALUES[id])
|
||||
id += 1
|
||||
|
||||
|
@@ -41,6 +41,10 @@ func _ready() -> void:
|
||||
Global.p_switch_active = false
|
||||
Lakitu.present = false
|
||||
Global.p_switch_timer = -1
|
||||
if Checkpoint.passed_checkpoints.is_empty() == false:
|
||||
Door.unlocked_doors = Checkpoint.unlocked_doors.duplicate()
|
||||
else:
|
||||
Door.unlocked_doors = []
|
||||
if Global.current_campaign == "SMBANN":
|
||||
DiscoLevel.reset_values()
|
||||
DiscoLevel.first_load = true
|
||||
@@ -71,7 +75,7 @@ func _ready() -> void:
|
||||
|
||||
if Global.current_game_mode == Global.GameMode.CAMPAIGN:
|
||||
SaveManager.write_save(Global.current_campaign)
|
||||
Global.set_discord_status("Playing " + Global.current_campaign + ": " + str(world_num) + "-" + str(Global.level_num))
|
||||
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:
|
||||
$BG/Control/LivesCount.text = "* ∞"
|
||||
|
@@ -25,3 +25,6 @@ func update_next_level_info() -> void:
|
||||
func go_to_level() -> void:
|
||||
first_load = true
|
||||
Global.transition_to_scene(LevelTransition.level_to_transition_to)
|
||||
|
||||
func play_pipe_sfx() -> void:
|
||||
AudioManager.play_global_sfx("pipe")
|
||||
|
@@ -17,6 +17,7 @@ func on_timeout() -> void:
|
||||
$AnimationPlayer.stop()
|
||||
var node = item.instantiate()
|
||||
node.global_position = $Joint.global_position
|
||||
node.hide()
|
||||
add_sibling(node)
|
||||
$Joint.remote_path = node.get_path()
|
||||
item_amount += 1
|
||||
@@ -27,10 +28,12 @@ func on_timeout() -> void:
|
||||
node.z_index = -10
|
||||
$AnimationPlayer.play(get_direction_string([Vector2.DOWN, Vector2.UP, Vector2.RIGHT, Vector2.LEFT][direction]))
|
||||
await get_tree().process_frame
|
||||
node.show()
|
||||
node.reset_physics_interpolation()
|
||||
await $AnimationPlayer.animation_finished
|
||||
$Joint.remote_path = ""
|
||||
if is_instance_valid(node):
|
||||
node.velocity = Vector2.ZERO
|
||||
node.set_process(true)
|
||||
node.z_index = z_old
|
||||
node.set_physics_process(true)
|
||||
|
@@ -11,6 +11,7 @@ var character := ""
|
||||
func _ready() -> void:
|
||||
Global.player_characters_changed.connect(update)
|
||||
Global.level_theme_changed.connect(update)
|
||||
animation_changed.connect(on_animation_changed)
|
||||
update()
|
||||
|
||||
func update() -> void:
|
||||
@@ -30,3 +31,7 @@ func update() -> void:
|
||||
return
|
||||
if sprite_frames.get_frame_texture(animation, frame):
|
||||
offset.y = -(sprite_frames.get_frame_texture(animation, frame).get_height() / 2.0)
|
||||
|
||||
func on_animation_changed() -> void:
|
||||
if sprite_frames.has_animation(animation) == false and Player.ANIMATION_FALLBACKS.has(animation):
|
||||
play(Player.ANIMATION_FALLBACKS[animation])
|
||||
|
@@ -115,17 +115,18 @@ func check_for_ghost() -> void:
|
||||
else:
|
||||
$CanvasLayer/MarathonMode/HasWarp/CharacterSelect.open()
|
||||
|
||||
func get_highscore() -> void:
|
||||
%HighScore.text = "TOP- " + str(Global.high_score).pad_zeros(6)
|
||||
if Global.world_num == 1 and Global.level_num == 1 and Global.score <= 0:
|
||||
%StoryOptions.selected_index = 0
|
||||
else:
|
||||
%StoryOptions.selected_index = 1
|
||||
|
||||
func new_game() -> void:
|
||||
if Global.score > 0 or Global.coins > 0 or Global.player_power_states != "0000" or Global.world_num > 1 or Global.level_num > 1:
|
||||
$CanvasLayer/SaveDeletionWarning.open()
|
||||
await $CanvasLayer/SaveDeletionWarning.selected
|
||||
if $CanvasLayer/SaveDeletionWarning.selected_index == 1:
|
||||
active_options.active = true
|
||||
return
|
||||
Global.current_game_mode = Global.GameMode.CAMPAIGN
|
||||
SaveManager.clear_save()
|
||||
start_game()
|
||||
func clear_stats() -> void:
|
||||
Global.clear_saved_values()
|
||||
Global.world_num = 1
|
||||
Global.level_num = 1
|
||||
LevelTransition.level_to_transition_to = Level.get_scene_string(Global.world_num, Global.level_num)
|
||||
|
||||
func start_game() -> void:
|
||||
PipeCutscene.seen_cutscene = false
|
||||
@@ -135,6 +136,7 @@ func start_game() -> void:
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
|
||||
|
||||
func start_full_run() -> void:
|
||||
Global.second_quest = false
|
||||
Global.current_game_mode = Global.GameMode.MARATHON
|
||||
SpeedrunHandler.timer = 0
|
||||
if SpeedrunHandler.is_warp_run:
|
||||
@@ -151,6 +153,7 @@ func start_full_run() -> void:
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
|
||||
|
||||
func start_level_run() -> void:
|
||||
Global.second_quest = false
|
||||
Global.current_game_mode = Global.GameMode.MARATHON_PRACTICE
|
||||
SpeedrunHandler.timer = 0
|
||||
if SpeedrunHandler.is_warp_run:
|
||||
@@ -169,6 +172,7 @@ func _exit_tree() -> void:
|
||||
Global.in_title_screen = false
|
||||
|
||||
func challenge_hunt_selected() -> void:
|
||||
Global.second_quest = false
|
||||
Global.current_game_mode = Global.GameMode.CHALLENGE
|
||||
Global.reset_values()
|
||||
Global.clear_saved_values()
|
||||
@@ -222,6 +226,21 @@ func open_options() -> void:
|
||||
func quit_game() -> void:
|
||||
get_tree().quit()
|
||||
|
||||
func new_game_selected() -> void:
|
||||
Global.second_quest = false
|
||||
Global.current_game_mode = Global.GameMode.CAMPAIGN
|
||||
if Global.game_beaten:
|
||||
%QuestSelect.open()
|
||||
else:
|
||||
$CanvasLayer/StoryMode/NewUnbeatenGame/NoBeatenCharSelect.open()
|
||||
|
||||
func continue_game() -> void:
|
||||
SaveManager.apply_save(SaveManager.load_save(Global.current_campaign))
|
||||
Global.current_game_mode = Global.GameMode.CAMPAIGN
|
||||
if Global.game_beaten:
|
||||
$CanvasLayer/StoryMode/ContinueBeatenGame/WorldSelect.open()
|
||||
else:
|
||||
$CanvasLayer/StoryMode/ContinueUnbeatenGame/CharacterSelect.open()
|
||||
|
||||
func on_story_options_closed() -> void:
|
||||
$CanvasLayer/Options2.open()
|
||||
|
@@ -48,6 +48,9 @@ func transition_style_changed(new_value := 0) -> void:
|
||||
Global.fade_transition = bool(new_value)
|
||||
Settings.file.visuals.transition_animation = new_value
|
||||
|
||||
func firebar_style_changed(new_value := 0) -> void:
|
||||
Settings.file.visuals.firebar_style = new_value
|
||||
|
||||
func set_value(value_name := "", value = null) -> void:
|
||||
{
|
||||
"parallax_style": parallax_style_changed,
|
||||
@@ -63,5 +66,6 @@ func set_value(value_name := "", value = null) -> void:
|
||||
"resource_packs": resource_pack_loaded,
|
||||
"bridge_animation": bridge_changed,
|
||||
"transition_animation": transform_style_changed,
|
||||
"colour_pipes": colourful_pipes_changed
|
||||
"colour_pipes": colourful_pipes_changed,
|
||||
"firebar_style": firebar_style_changed
|
||||
}[value_name].call(value)
|
||||
|
@@ -29,7 +29,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()
|
||||
SpeedrunHandler.is_warp_run = true
|
||||
Global.reset_values()
|
||||
Level.first_load = true
|
||||
|
@@ -106,3 +106,7 @@ func select() -> void:
|
||||
func close() -> void:
|
||||
active = false
|
||||
hide()
|
||||
|
||||
|
||||
func on_selected() -> void:
|
||||
pass # Replace with function body.
|
||||
|
@@ -12,13 +12,14 @@ static var page_number_save := -1
|
||||
static var last_played_container = null
|
||||
|
||||
static var saved_search_values := [-1, -1, -1]
|
||||
static var level_id := ""
|
||||
|
||||
func _ready() -> void:
|
||||
has_entered = true
|
||||
ResourceSetterNew.cache.clear()
|
||||
ResourceSetter.cache.clear()
|
||||
Global.get_node("GameHUD").hide()
|
||||
Checkpoint.passed = false
|
||||
Checkpoint.passed_checkpoints.clear()
|
||||
Global.world_num = 1
|
||||
Global.level_num = 1
|
||||
Global.reset_values()
|
||||
@@ -84,8 +85,20 @@ func play_level() -> void:
|
||||
LevelTransition.level_to_transition_to = ("res://Scenes/Levels/LevelEditor.tscn")
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
|
||||
|
||||
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
|
||||
LevelTransition.level_to_transition_to = ("res://Scenes/Levels/LevelEditor.tscn")
|
||||
Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
|
||||
|
||||
func lss_level_played() -> void:
|
||||
last_played_container = %LSSLevelInfo.container_to_play.duplicate()
|
||||
level_id = %LSSLevelInfo.container_to_play.level_id
|
||||
print(level_id)
|
||||
page_number_save = %LSSBrowser.page_number
|
||||
saved_search_values[0] = %LSSBrowser.page_number
|
||||
saved_search_values[1] = %LSSBrowser.filter
|
||||
|
@@ -9,6 +9,7 @@ var active := false
|
||||
var starting_value := -1
|
||||
|
||||
@export var has_speedrun_stuff := false
|
||||
@export var has_challenge_stuff := false
|
||||
@export var has_disco_stuff := false
|
||||
|
||||
const LEVEL_ICONS := {
|
||||
@@ -98,6 +99,7 @@ var visited_levels := "0000"
|
||||
|
||||
func setup_visuals() -> void:
|
||||
%MarathonBits.visible = Global.current_game_mode == Global.GameMode.MARATHON_PRACTICE
|
||||
%ChallengeBits.visible = Global.current_game_mode == Global.GameMode.CHALLENGE
|
||||
var idx := 0
|
||||
for i in %SlotContainer.get_children():
|
||||
if i.visible == false:
|
||||
@@ -127,6 +129,12 @@ func setup_challenge_mode_bits(container: HBoxContainer, level_num := 1) -> void
|
||||
i.get_node("Full").visible = collected
|
||||
container.get_node("Score/Full").visible = ChallengeModeHandler.top_challenge_scores[Global.world_num - 1][level_num - 1] >= ChallengeModeHandler.CHALLENGE_TARGETS[Global.current_campaign][Global.world_num - 1][level_num - 1]
|
||||
|
||||
func update_score() -> void:
|
||||
if has_challenge_stuff == false: return
|
||||
var target = ChallengeModeHandler.CHALLENGE_TARGETS[Global.current_campaign][Global.world_num - 1][selected_level]
|
||||
%ScoreTarget.text = "/" + str(target)
|
||||
%HighScore.text = "SCORE: " + ("-----" if ChallengeModeHandler.top_challenge_scores[Global.world_num - 1][selected_level] <= 0 else str(int(ChallengeModeHandler.top_challenge_scores[Global.world_num - 1][selected_level])).pad_zeros(5))
|
||||
|
||||
func update_pb() -> void:
|
||||
if has_speedrun_stuff == false: return
|
||||
var best_warpless_time = SpeedrunHandler.best_level_warpless_times[Global.world_num - 1][selected_level]
|
||||
@@ -175,6 +183,9 @@ func select_world() -> void:
|
||||
func slot_selected(idx := 0) -> void:
|
||||
selected_level = idx
|
||||
update_pb()
|
||||
update_score()
|
||||
if Settings.file.audio.extra_sfx == 1:
|
||||
AudioManager.play_global_sfx("menu_move")
|
||||
|
||||
func cleanup() -> void:
|
||||
await get_tree().process_frame
|
||||
@@ -187,3 +198,7 @@ func cleanup() -> void:
|
||||
func close() -> void:
|
||||
active = false
|
||||
hide()
|
||||
|
||||
|
||||
func on_level_selected() -> void:
|
||||
pass # Replace with function body.
|
||||
|
@@ -4,7 +4,7 @@ signal closed
|
||||
|
||||
const LEVEL_INFO_URL := "https://levelsharesquare.com/api/levels/"
|
||||
|
||||
var level_id := ""
|
||||
static var level_id := ""
|
||||
|
||||
var has_downloaded := false
|
||||
|
||||
@@ -30,7 +30,9 @@ func open(container: OnlineLevelContainer) -> void:
|
||||
else:
|
||||
%Download.grab_focus()
|
||||
setup_visuals(container)
|
||||
level_id = container.level_id
|
||||
reset_process()
|
||||
|
||||
func reset_process() -> void:
|
||||
await get_tree().physics_frame
|
||||
set_process(true)
|
||||
|
||||
@@ -49,6 +51,7 @@ func setup_visuals(container: OnlineLevelContainer) -> void:
|
||||
else: value = container.get(i)
|
||||
%SelectedOnlineLevel.set(i, value)
|
||||
saved_stuff[i] = value
|
||||
level_id = saved_stuff.level_id
|
||||
%SelectedOnlineLevel.setup_visuals()
|
||||
%Download.visible = not has_downloaded
|
||||
%OnlinePlay.visible = has_downloaded
|
||||
@@ -70,6 +73,7 @@ func download_level() -> void:
|
||||
%Download.text = "DOWNLOADING..."
|
||||
|
||||
func open_lss() -> void:
|
||||
print(level_id)
|
||||
OS.shell_open("https://levelsharesquare.com/levels/" + str(level_id))
|
||||
|
||||
func on_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
@@ -104,6 +108,7 @@ func play_level() -> void:
|
||||
var file_path := "user://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)
|
||||
var info = file["Info"]
|
||||
LevelEditor.level_author = info["Author"]
|
||||
LevelEditor.level_name = info["Name"]
|
||||
|
@@ -25,11 +25,11 @@ func setup_visuals() -> void:
|
||||
target_time = SpeedrunHandler.GOLD_WARPLESS_TIMES[Global.current_campaign]
|
||||
%Target.text = SpeedrunHandler.gen_time_string(SpeedrunHandler.format_time(target_time))
|
||||
var medal_index := -1
|
||||
if SpeedrunHandler.timer < target_time:
|
||||
if SpeedrunHandler.timer <= target_time:
|
||||
medal_index = 2
|
||||
elif SpeedrunHandler.timer < target_time * SpeedrunHandler.MEDAL_CONVERSIONS[1]:
|
||||
elif SpeedrunHandler.timer <= target_time * SpeedrunHandler.MEDAL_CONVERSIONS[1]:
|
||||
medal_index = 1
|
||||
elif SpeedrunHandler.timer < target_time * SpeedrunHandler.MEDAL_CONVERSIONS[0]:
|
||||
elif SpeedrunHandler.timer <= target_time * SpeedrunHandler.MEDAL_CONVERSIONS[0]:
|
||||
medal_index = 0
|
||||
%Medal.get_node("Full").visible = medal_index >= 0
|
||||
%Medal.get_node("Full").region_rect.position = Vector2(8 * medal_index, 0)
|
||||
|
@@ -6,11 +6,14 @@ var active := false
|
||||
|
||||
var selected_index := 0
|
||||
|
||||
var old_quest := false
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if active:
|
||||
handle_input()
|
||||
|
||||
func open() -> void:
|
||||
old_quest = Global.second_quest
|
||||
show()
|
||||
await get_tree().process_frame
|
||||
[%FirstQuest, %SecondQuest][int(Global.second_quest)].grab_focus()
|
||||
@@ -21,7 +24,7 @@ func handle_input() -> void:
|
||||
select()
|
||||
close()
|
||||
elif Input.is_action_just_pressed("ui_back"):
|
||||
Global.second_quest = false
|
||||
Global.second_quest = old_quest
|
||||
close()
|
||||
cancelled.emit()
|
||||
return
|
||||
|
@@ -1,46 +1,85 @@
|
||||
class_name ROMVerifier
|
||||
extends Node
|
||||
|
||||
const VALID_HASH := "c9b34443c0414f3b91ef496d8cfee9fdd72405d673985afa11fb56732c96152b"
|
||||
const VALID_HASHES := [
|
||||
"6a54024d5abe423b53338c9b418e0c2ffd86fed529556348e52ffca6f9b53b1a",
|
||||
"c9b34443c0414f3b91ef496d8cfee9fdd72405d673985afa11fb56732c96152b"
|
||||
]
|
||||
|
||||
var args: PackedStringArray
|
||||
|
||||
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
|
||||
|
||||
# Fallback: local ROM
|
||||
var local_rom := find_local_rom()
|
||||
if local_rom != "" and handle_rom(local_rom):
|
||||
return
|
||||
|
||||
# Otherwise wait for dropped files
|
||||
get_window().files_dropped.connect(on_file_dropped)
|
||||
await get_tree().physics_frame
|
||||
|
||||
# Window setup
|
||||
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
|
||||
DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, false)
|
||||
|
||||
|
||||
func find_local_rom() -> String:
|
||||
var exe_dir := OS.get_executable_path().get_base_dir()
|
||||
var dir := DirAccess.open(exe_dir)
|
||||
if not dir:
|
||||
return ""
|
||||
for file_name in dir.get_files():
|
||||
if file_name.to_lower().ends_with(".nes"):
|
||||
return exe_dir.path_join(file_name)
|
||||
return ""
|
||||
|
||||
func on_file_dropped(files: PackedStringArray) -> void:
|
||||
for i in files:
|
||||
if i.contains(".zip"):
|
||||
for file in files:
|
||||
if file.ends_with(".zip"):
|
||||
zip_error()
|
||||
return
|
||||
elif is_valid_rom(i):
|
||||
Global.rom_path = i
|
||||
verified()
|
||||
copy_rom(i)
|
||||
if handle_rom(file):
|
||||
return
|
||||
error()
|
||||
|
||||
func copy_rom(file_path := "") -> void:
|
||||
func handle_rom(path: String) -> bool:
|
||||
if not is_valid_rom(path):
|
||||
return false
|
||||
Global.rom_path = path
|
||||
copy_rom(path)
|
||||
verified()
|
||||
return true
|
||||
|
||||
func copy_rom(file_path: String) -> void:
|
||||
DirAccess.copy_absolute(file_path, Global.ROM_PATH)
|
||||
|
||||
static func get_hash(file_path := "") -> String:
|
||||
var file_bytes = FileAccess.open(file_path, FileAccess.READ).get_buffer(40976)
|
||||
var data = file_bytes.slice(16)
|
||||
static func get_hash(file_path: String) -> String:
|
||||
var file := FileAccess.open(file_path, FileAccess.READ)
|
||||
if not file:
|
||||
return ""
|
||||
var file_bytes := file.get_buffer(40976)
|
||||
var data := file_bytes.slice(16)
|
||||
return Marshalls.raw_to_base64(data).sha256_text()
|
||||
|
||||
static func is_valid_rom(rom_path := "") -> bool:
|
||||
return get_hash(rom_path) == VALID_HASH
|
||||
return get_hash(rom_path) in VALID_HASHES
|
||||
|
||||
|
||||
func error() -> void:
|
||||
%Error.show()
|
||||
$ErrorSFX.play()
|
||||
|
||||
func zip_error() -> void:
|
||||
$ErrorSFX.play()
|
||||
%ZipError.show()
|
||||
$ErrorSFX.play()
|
||||
|
||||
func verified() -> void:
|
||||
$BGM.queue_free()
|
||||
@@ -48,15 +87,17 @@ func verified() -> void:
|
||||
%SuccessMSG.show()
|
||||
$SuccessSFX.play()
|
||||
await get_tree().create_timer(3, false).timeout
|
||||
|
||||
var target_scene := "res://Scenes/Levels/TitleScreen.tscn"
|
||||
if not Global.rom_assets_exist:
|
||||
Global.transition_to_scene("res://Scenes/Levels/RomResourceGenerator.tscn")
|
||||
else:
|
||||
Global.transition_to_scene("res://Scenes/Levels/TitleScreen.tscn")
|
||||
target_scene = "res://Scenes/Levels/RomResourceGenerator.tscn"
|
||||
Global.transition_to_scene(target_scene)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
Global.get_node("GameHUD").show()
|
||||
|
||||
func create_file_pointer(file_path := "") -> void:
|
||||
var pointer = FileAccess.open(Global.ROM_POINTER_PATH, FileAccess.WRITE)
|
||||
pointer.store_string(file_path)
|
||||
pointer.close()
|
||||
func create_file_pointer(file_path: String) -> void:
|
||||
var pointer := FileAccess.open(Global.ROM_POINTER_PATH, FileAccess.WRITE)
|
||||
if pointer:
|
||||
pointer.store_string(file_path)
|
||||
pointer.close()
|
||||
|
@@ -23,8 +23,6 @@ var can_exit := true:
|
||||
can_exit = value
|
||||
pass
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if active and (Input.is_action_just_pressed("ui_back") or Input.is_action_just_pressed("editor_open_menu")):
|
||||
@@ -39,6 +37,8 @@ func open() -> void:
|
||||
size = Vector2.ZERO
|
||||
add_properties()
|
||||
show()
|
||||
editing_node.tree_exiting.connect(close)
|
||||
|
||||
|
||||
func add_properties() -> void:
|
||||
for i in properties:
|
||||
|
@@ -39,6 +39,8 @@ func open() -> void:
|
||||
setup_visuals()
|
||||
show()
|
||||
await get_tree().process_frame
|
||||
if Global.current_game_mode != Global.GameMode.CAMPAIGN:
|
||||
selected_world = clamp(selected_world, 0, 7)
|
||||
$%SlotContainer.get_child(selected_world).grab_focus()
|
||||
active = true
|
||||
|
||||
@@ -80,6 +82,8 @@ func handle_input() -> void:
|
||||
|
||||
func slot_focused(idx := 0) -> void:
|
||||
selected_world = idx
|
||||
if Settings.file.audio.extra_sfx == 1:
|
||||
AudioManager.play_global_sfx("menu_move")
|
||||
|
||||
func select_world() -> void:
|
||||
if owner is Level:
|
||||
|
Reference in New Issue
Block a user