Merge remote-tracking branch 'upstream/main' into pulls/small-crouch-hitbox-fix

This commit is contained in:
KirbyKidJ
2025-09-26 10:51:17 -07:00
128 changed files with 14908 additions and 11655 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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:

View File

@@ -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()

View File

@@ -10,7 +10,7 @@ func _ready() -> void:
owner.queue_free()
return
owner.show()
if Checkpoint.passed:
if owner.passed:
sprite.hide()
activated.show()

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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():

View 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()

View File

@@ -0,0 +1 @@
uid://yx2impqs0lo5

View File

@@ -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()

View File

@@ -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]:

View File

@@ -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":
{

View File

@@ -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()

View File

@@ -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:

View File

@@ -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)

View File

@@ -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

View File

@@ -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