Player.gd 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. class_name Player
  2. extends CharacterBody2D
  3. var AIR_ACCEL := 3.0
  4. var AIR_SKID := 1.5
  5. var DECEL := 3.0
  6. var FALL_GRAVITY := 25.0
  7. var GROUND_RUN_ACCEL := 1.25
  8. var GROUND_WALK_ACCEL := 4.0
  9. var JUMP_GRAVITY := 11.0
  10. var JUMP_HEIGHT := 300.0
  11. var JUMP_INCR := 8.0
  12. var SWIM_GRAVITY := 2.5
  13. var SWIM_SPEED := 95.0
  14. var MAX_FALL_SPEED := 280
  15. var MAX_SWIM_FALL_SPEED := 200
  16. var RUN_SKID := 8.0
  17. var RUN_SPEED := 160
  18. var WALK_SKID := 8.0
  19. var WALK_SPEED := 96.0
  20. var CEILING_BUMP_SPEED := 45.0
  21. @onready var camera_center_joint: Node2D = $CameraCenterJoint
  22. @onready var sprite: AnimatedSprite2D = $Sprite
  23. @onready var camera: Camera2D = $Camera
  24. @onready var score_note_spawner: ScoreNoteSpawner = $ScoreNoteSpawner
  25. var has_jumped := false
  26. var direction := 1
  27. var input_direction := 0
  28. var flight_meter := 0.0
  29. var velocity_direction := 1
  30. var total_keys := 0
  31. @export var power_state: PowerUpState = null:
  32. set(value):
  33. power_state = value
  34. set_power_state_frame()
  35. var character := "Mario"
  36. var crouching := false
  37. var skidding := false
  38. var can_bump_sfx := true
  39. @export var player_id := 0
  40. const ONE_UP_NOTE = preload("uid://dopxwjj37gu0l")
  41. var gravity := FALL_GRAVITY
  42. var attacking := false
  43. var pipe_enter_direction := Vector2.ZERO#
  44. var pipe_move_direction := 1
  45. var stomp_combo := 0
  46. var is_invincible := false
  47. const COMBO_VALS := [100, 200, 400, 500, 800, 1000, 2000, 4000, 5000, 8000, null]
  48. @export_enum("Small", "Big", "Fire") var starting_power_state := 0
  49. @onready var state_machine: StateMachine = $States
  50. @onready var normal_state: Node = $States/Normal
  51. @export var auto_death_pit := true
  52. var can_hurt := true
  53. var in_water := false
  54. var has_hammer := false
  55. var spring_bouncing := false
  56. var low_gravity := false
  57. var gravity_vector := Vector2.DOWN
  58. var jump_cancelled := false
  59. var camera_pan_amount := 24
  60. var animating_camera := false
  61. var can_uncrouch := false
  62. var can_air_turn := false
  63. static var CHARACTERS := ["Mario", "Luigi", "Toad", "Toadette"]
  64. const POWER_STATES := ["Small", "Big", "Fire"]
  65. signal moved
  66. signal dead
  67. var is_dead := false
  68. static var CHARACTER_NAMES := ["CHAR_MARIO", "CHAR_LUIGI", "CHAR_TOAD", "CHAR_TOADETTE"]
  69. static var CHARACTER_COLOURS := [preload("res://Assets/Sprites/Players/Mario/CharacterColour.json"), preload("res://Assets/Sprites/Players/Luigi/CharacterColour.json"), preload("res://Assets/Sprites/Players/Toad/CharacterColour.json"), preload("res://Assets/Sprites/Players/Toadette/CharacterColour.json")]
  70. var can_timer_warn := true
  71. var colour_palette_texture: Texture = null
  72. static var CHARACTER_PALETTES := [
  73. preload("res://Assets/Sprites/Players/Mario/ColourPalette.json"),
  74. preload("res://Assets/Sprites/Players/Luigi/ColourPalette.json"),
  75. preload("res://Assets/Sprites/Players/Toad/ColourPalette.json"),
  76. preload("res://Assets/Sprites/Players/Toadette/ColourPalette.json")
  77. ]
  78. const ANIMATION_FALLBACKS := {
  79. "JumpFall": "Jump",
  80. "Fall": "Move",
  81. "Pipe": "Idle",
  82. "Walk": "Move",
  83. "Run": "Move",
  84. "PipeWalk": "Move",
  85. "LookUp": "Idle",
  86. "CrouchFall": "Crouch",
  87. "CrouchAttack": "Attack",
  88. "FlagSlide": "Climb",
  89. "WaterMove": "Move",
  90. "WaterIdle": "Idle",
  91. "DieFreeze": "Die",
  92. "StarJump": "Jump",
  93. "StarFall": "JumpFall"
  94. }
  95. var palette_transform := true
  96. var transforming := false
  97. static var camera_right_limit := 999999
  98. static var times_hit := 0
  99. var can_run := true
  100. var air_frames := 0
  101. static var classic_physics := false
  102. var swim_stroke := false
  103. var simulated_velocity := Vector2.ZERO
  104. func _ready() -> void:
  105. if classic_physics:
  106. apply_classic_physics()
  107. get_viewport().size_changed.connect(recenter_camera)
  108. show()
  109. $Checkpoint/Label.text = str(player_id + 1)
  110. $Checkpoint/Label.modulate = [Color("5050FF"), Color("F73910"), Color("1A912E"), Color("FFB762")][player_id]
  111. $Checkpoint/Label.visible = Global.connected_players > 1
  112. Global.can_pause = true
  113. character = CHARACTERS[int(Global.player_characters[player_id])]
  114. Global.can_time_tick = true
  115. if [Global.GameMode.BOO_RACE, Global.GameMode.MARATHON, Global.GameMode.MARATHON_PRACTICE].has(Global.current_game_mode) == false:
  116. apply_character_physics()
  117. apply_character_sfx_map()
  118. Global.level_theme_changed.connect(apply_character_sfx_map)
  119. Global.level_theme_changed.connect(apply_character_physics)
  120. Global.level_theme_changed.connect(set_power_state_frame)
  121. if Global.current_level.first_load and Global.current_game_mode == Global.GameMode.MARATHON_PRACTICE:
  122. Global.player_power_states[player_id] = "0"
  123. power_state = $PowerStates.get_node(POWER_STATES[int(Global.player_power_states[player_id])])
  124. if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
  125. camera.enabled = false
  126. handle_power_up_states(0)
  127. set_power_state_frame()
  128. if Global.level_editor == null:
  129. recenter_camera()
  130. await get_tree().create_timer(0.1, false).timeout
  131. for i in [$CameraCenterJoint/LeftWall/CollisionShape2D, $CameraCenterJoint/RightWall/CollisionShape2D]:
  132. i.set_deferred("disabled", false)
  133. func apply_character_physics() -> void:
  134. var path = "res://Assets/Sprites/Players/" + character + "/CharacterInfo.json"
  135. if int(Global.player_characters[player_id]) > 3:
  136. path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
  137. path = ResourceSetter.get_pure_resource_path(path)
  138. var json = JSON.parse_string(FileAccess.open(path, FileAccess.READ).get_as_text())
  139. for i in json.physics:
  140. set(i, json.physics[i])
  141. for i in get_tree().get_nodes_in_group("SmallCollisions"):
  142. var hitbox_scale = json.get("small_hitbox_scale", [1, 1])
  143. i.scale = Vector2(hitbox_scale[0], hitbox_scale[1])
  144. i.update()
  145. for i in get_tree().get_nodes_in_group("BigCollisions"):
  146. var hitbox_scale = json.get("big_hitbox_scale", [1, 1])
  147. i.scale = Vector2(hitbox_scale[0], hitbox_scale[1])
  148. i.update()
  149. func apply_classic_physics() -> void:
  150. var json = JSON.parse_string(FileAccess.open("res://Resources/ClassicPhysics.json", FileAccess.READ).get_as_text())
  151. for i in json:
  152. set(i, json[i])
  153. func recenter_camera() -> void:
  154. %CameraHandler.recenter_camera()
  155. %CameraHandler.update_camera_barriers()
  156. func reparent_camera() -> void:
  157. return
  158. func editor_level_start() -> void:
  159. if PipeArea.exiting_pipe_id == -1:
  160. power_state = get_node("PowerStates").get_child(starting_power_state)
  161. handle_power_up_states(0)
  162. set_power_state_frame()
  163. camera_make_current()
  164. recenter_camera()
  165. state_machine.transition_to("Normal")
  166. if camera_right_limit <= global_position.x:
  167. camera_right_limit = 99999999
  168. await get_tree().create_timer(0.1, false).timeout
  169. if camera_right_limit <= global_position.x:
  170. camera_right_limit = 99999999
  171. func _physics_process(delta: float) -> void:
  172. if Input.is_action_just_pressed("debug_reload"):
  173. set_power_state_frame()
  174. if Input.is_action_just_pressed("debug_noclip") and Global.debug_mode:
  175. state_machine.transition_to("NoClip")
  176. up_direction = -gravity_vector
  177. handle_directions()
  178. handle_block_collision_detection()
  179. handle_wing_flight(delta)
  180. air_frames = (air_frames + 1 if is_on_floor() == false else 0)
  181. for i in get_tree().get_nodes_in_group("StepCollision"):
  182. var on_wall := false
  183. for x in [$StepWallChecks/LWall, $StepWallChecks/RWall]:
  184. if x.is_colliding():
  185. on_wall = true
  186. var step_enabled = (not on_wall and air_frames < 4 and velocity.y >= 0)
  187. i.set_deferred("disabled", not step_enabled)
  188. if is_actually_on_ceiling() and can_bump_sfx:
  189. bump_ceiling()
  190. elif is_actually_on_floor() and not is_invincible:
  191. stomp_combo = 0
  192. elif velocity.y > 15:
  193. can_bump_sfx = true
  194. var old_water = in_water
  195. if $Hitbox.monitoring:
  196. in_water = $Hitbox.get_overlapping_areas().any(func(area: Area2D): return area is WaterArea) or $WaterDetect.get_overlapping_bodies().is_empty() == false
  197. if old_water != in_water and in_water == false and flight_meter <= 0:
  198. water_exited()
  199. if $SkidSFX.playing:
  200. if (is_actually_on_floor() and skidding) == false:
  201. $SkidSFX.stop()
  202. elif is_actually_on_floor() and skidding and Settings.file.audio.skid_sfx == 1:
  203. $SkidSFX.play()
  204. const BUBBLE_PARTICLE = preload("uid://bwjae1h1airtr")
  205. func summon_bubble() -> void:
  206. var bubble = BUBBLE_PARTICLE.instantiate()
  207. bubble.global_position = global_position + Vector2(0, -16 if power_state.hitbox_size == "Small" else -32)
  208. add_sibling(bubble)
  209. func _process(delta: float) -> void:
  210. handle_power_up_states(delta)
  211. handle_invincible_palette()
  212. if is_invincible:
  213. DiscoLevel.combo_meter = 100
  214. $Sprite/Hammer.visible = has_hammer
  215. func apply_gravity(delta: float) -> void:
  216. if in_water or flight_meter > 0:
  217. gravity = SWIM_GRAVITY
  218. else:
  219. if gravity_vector.y > 0:
  220. if velocity.y > 0:
  221. gravity = FALL_GRAVITY
  222. elif gravity_vector.y < 0:
  223. if velocity.y < 0:
  224. gravity = FALL_GRAVITY
  225. velocity += (gravity_vector * ((gravity / (1.5 if low_gravity else 1.0)) / delta)) * delta
  226. var target_fall: float = MAX_FALL_SPEED
  227. if in_water:
  228. target_fall = MAX_SWIM_FALL_SPEED
  229. if gravity_vector.y > 0:
  230. velocity.y = clamp(velocity.y, -INF, (target_fall / (1.2 if low_gravity else 1.0)))
  231. else:
  232. velocity.y = clamp(velocity.y, -(target_fall / (1.2 if low_gravity else 1.0)), INF)
  233. func camera_make_current() -> void:
  234. camera.enabled = true
  235. camera.make_current()
  236. func play_animation(animation_name := "") -> void:
  237. if sprite.sprite_frames == null: return
  238. animation_name = get_fallback_animation(animation_name)
  239. if sprite.animation != animation_name:
  240. sprite.play(animation_name)
  241. func get_fallback_animation(animation_name := "") -> String:
  242. if sprite.sprite_frames.has_animation(animation_name) == false and ANIMATION_FALLBACKS.has(animation_name):
  243. return get_fallback_animation(ANIMATION_FALLBACKS.get(animation_name))
  244. else:
  245. return animation_name
  246. func apply_character_sfx_map() -> void:
  247. var path = "res://Assets/Sprites/Players/" + character + "/SFX.json"
  248. var custom_character := false
  249. if int(Global.player_characters[player_id]) > 3:
  250. custom_character = true
  251. path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
  252. path = ResourceSetter.get_pure_resource_path(path)
  253. var json = JSON.parse_string(FileAccess.open(path, FileAccess.READ).get_as_text())
  254. for i in json:
  255. var res_path = "res://Assets/Audio/SFX/" + json[i]
  256. res_path = ResourceSetter.get_pure_resource_path(res_path)
  257. if FileAccess.file_exists(res_path) == false or custom_character:
  258. var directory = "res://Assets/Sprites/Players/" + character + "/" + json[i]
  259. if int(Global.player_characters[player_id]) > 3:
  260. directory = directory.replace("res://Assets/Sprites/Players", "user://custom_characters")
  261. directory = ResourceSetter.get_pure_resource_path(directory)
  262. if FileAccess.file_exists(directory):
  263. json[i] = directory
  264. else:
  265. json[i] = res_path
  266. else:
  267. json[i] = res_path
  268. AudioManager.load_sfx_map(json)
  269. func refresh_hitbox() -> void:
  270. $Hitbox.set_deferred("monitoring", false)
  271. $Hitbox.set_deferred("monitorable", false)
  272. await get_tree().physics_frame
  273. $Hitbox.set_deferred("monitoring", true)
  274. $Hitbox.set_deferred("monitorable", true)
  275. func is_actually_on_floor() -> bool:
  276. if is_on_floor():
  277. return true
  278. else:
  279. for i in get_tree().get_nodes_in_group("CollisionRays"):
  280. if i.is_on_floor():
  281. return true
  282. return false
  283. func is_actually_on_wall() -> bool:
  284. if is_on_wall():
  285. return true
  286. else:
  287. for i in get_tree().get_nodes_in_group("CollisionRays"):
  288. if i.is_on_wall():
  289. return true
  290. return false
  291. func is_actually_on_ceiling() -> bool:
  292. if is_on_ceiling():
  293. return true
  294. else:
  295. for i in get_tree().get_nodes_in_group("CollisionRays"):
  296. if i.is_on_ceiling():
  297. return true
  298. return false
  299. func enemy_bounce_off(add_combo := true) -> void:
  300. if add_combo:
  301. add_stomp_combo()
  302. jump_cancelled = not Global.player_action_pressed("jump", player_id)
  303. await get_tree().physics_frame
  304. if Global.player_action_pressed("jump", player_id):
  305. velocity.y = -300
  306. gravity = JUMP_GRAVITY
  307. has_jumped = true
  308. else:
  309. velocity.y = -200
  310. func add_stomp_combo() -> void:
  311. if stomp_combo >= 10:
  312. if Global.current_game_mode == Global.GameMode.CHALLENGE or Settings.file.difficulty.inf_lives:
  313. Global.score += 10000
  314. score_note_spawner.spawn_note(10000)
  315. else:
  316. Global.lives += 1
  317. AudioManager.play_global_sfx("1_up")
  318. score_note_spawner.spawn_one_up_note()
  319. else:
  320. Global.score += COMBO_VALS[stomp_combo]
  321. score_note_spawner.spawn_note(COMBO_VALS[stomp_combo])
  322. stomp_combo += 1
  323. func bump_ceiling() -> void:
  324. AudioManager.play_sfx("bump", global_position)
  325. velocity.y = CEILING_BUMP_SPEED
  326. can_bump_sfx = false
  327. await get_tree().create_timer(0.1).timeout
  328. AudioManager.kill_sfx("small_jump")
  329. AudioManager.kill_sfx("big_jump")
  330. func super_star() -> void:
  331. DiscoLevel.combo_meter += 1
  332. is_invincible = true
  333. $StarTimer.start()
  334. var colour_palette: Texture = null
  335. func stop_all_timers() -> void:
  336. flight_meter = -1
  337. for i in [$StarTimer, $HammerTimer]:
  338. i.stop()
  339. func handle_invincible_palette() -> void:
  340. sprite.material.set_shader_parameter("mode", !Settings.file.visuals.rainbow_style)
  341. $Sprite.material.set_shader_parameter("player_palette", $PlayerPalette.texture)
  342. $Sprite.material.set_shader_parameter("palette_size", colour_palette.get_width())
  343. $Sprite.material.set_shader_parameter("invincible_palette", $InvinciblePalette.texture)
  344. sprite.material.set_shader_parameter("palette_idx", POWER_STATES.find(power_state.state_name))
  345. sprite.material.set_shader_parameter("enabled", (is_invincible or (palette_transform and transforming)))
  346. func handle_block_collision_detection() -> void:
  347. if ["Pipe"].has(state_machine.state.name): return
  348. if velocity.y <= FALL_GRAVITY:
  349. for i in $BlockCollision.get_overlapping_bodies():
  350. if i is Block:
  351. if is_on_ceiling():
  352. i.player_block_hit.emit(self)
  353. func handle_directions() -> void:
  354. input_direction = 0
  355. if Global.player_action_pressed("move_right", player_id):
  356. input_direction = 1
  357. elif Global.player_action_pressed("move_left", player_id):
  358. input_direction = -1
  359. velocity_direction = sign(velocity.x)
  360. var use_big_collision := false
  361. func handle_power_up_states(delta) -> void:
  362. for i in get_tree().get_nodes_in_group("BigCollisions"):
  363. if i.owner == self:
  364. i.set_deferred("disabled", power_state.hitbox_size == "Small" or crouching)
  365. $Checkpoint.position.y = -24 if power_state.hitbox_size == "Small" or crouching else -40
  366. power_state.update(delta)
  367. func handle_wing_flight(delta: float) -> void:
  368. flight_meter -= delta
  369. if flight_meter <= 0 && $Sprite/Wings.visible:
  370. AudioManager.stop_music_override(AudioManager.MUSIC_OVERRIDES.WING)
  371. $Sprite/Wings.visible = flight_meter >= 0
  372. if flight_meter < 0:
  373. return
  374. %BigWing.visible = power_state.hitbox_size == "Big"
  375. %SmallWing.visible = power_state.hitbox_size == "Small"
  376. for i in [%SmallWing, %BigWing]:
  377. if velocity.y < 0:
  378. i.play("Flap")
  379. else:
  380. i.play("Idle")
  381. if flight_meter <= 3:
  382. $Sprite/Wings/AnimationPlayer.play("Flash")
  383. else:
  384. $Sprite/Wings/AnimationPlayer.play("RESET")
  385. func damage() -> void:
  386. if can_hurt == false or is_invincible:
  387. return
  388. times_hit += 1
  389. var damage_state = power_state.damage_state
  390. if damage_state != null:
  391. if Settings.file.difficulty.damage_style == 0:
  392. damage_state = get_node("PowerStates/Small")
  393. DiscoLevel.combo_meter -= 50
  394. AudioManager.play_sfx("damage", global_position)
  395. await power_up_animation(damage_state.state_name)
  396. power_state = get_node("PowerStates/" + damage_state.state_name)
  397. Global.player_power_states[player_id] = str(power_state.get_index())
  398. do_i_frames()
  399. else:
  400. die()
  401. var cam_direction := 1
  402. @onready var last_position := global_position
  403. @onready var camera_position = camera.global_position
  404. var camera_offset = Vector2.ZERO
  405. func point_to_camera_limit(point := 0, point_dir := -1) -> float:
  406. return point + ((get_viewport_rect().size.x / 2.0) * -point_dir)
  407. func point_to_camera_limit_y(point := 0, point_dir := -1) -> float:
  408. return point + ((get_viewport_rect().size.y / 2.0) * -point_dir)
  409. func passed_checkpoint() -> void:
  410. if Settings.file.difficulty.checkpoint_style == 0:
  411. $Checkpoint/Animation.play("Show")
  412. AudioManager.play_sfx("checkpoint", global_position)
  413. func do_i_frames() -> void:
  414. can_hurt = false
  415. for i in 25:
  416. $Sprite.hide()
  417. if get_tree() == null:
  418. return
  419. await get_tree().create_timer(0.04, false).timeout
  420. $Sprite.show()
  421. if get_tree() == null:
  422. return
  423. await get_tree().create_timer(0.04, false).timeout
  424. can_hurt = true
  425. refresh_hitbox()
  426. func die(pit := false) -> void:
  427. if state_machine.state.name == "Dead" or state_machine.state.name == "Pipe":
  428. return
  429. is_dead = true
  430. visible = not pit
  431. flight_meter = 0
  432. dead.emit()
  433. Global.p_switch_active = false
  434. Global.p_switch_timer = 0
  435. stop_all_timers()
  436. state_machine.transition_to("Dead", {"Pit": pit})
  437. process_mode = Node.PROCESS_MODE_ALWAYS
  438. get_tree().paused = true
  439. Level.can_set_time = true
  440. Level.first_load = true
  441. if Global.current_game_mode != Global.GameMode.BOO_RACE:
  442. AudioManager.set_music_override(AudioManager.MUSIC_OVERRIDES.DEATH, 999, false)
  443. await get_tree().create_timer(3).timeout
  444. else:
  445. AudioManager.set_music_override(AudioManager.MUSIC_OVERRIDES.RACE_LOSE, 999, false)
  446. await get_tree().create_timer(5).timeout
  447. death_load()
  448. func death_load() -> void:
  449. power_state = get_node("PowerStates/Small")
  450. Global.player_power_states = "0000"
  451. Global.death_load = true
  452. if Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
  453. LevelTransition.level_to_transition_to = "res://Scenes/Levels/LevelEditor.tscn"
  454. Global.transition_to_scene("res://Scenes/Levels/LevelTransition.tscn")
  455. return
  456. if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR:
  457. owner.stop_testing()
  458. return
  459. if [Global.GameMode.CAMPAIGN, Global.GameMode.MARATHON].has(Global.current_game_mode):
  460. if Settings.file.difficulty.inf_lives == 0:
  461. Global.lives -= 1
  462. Global.death_load = true
  463. if Global.current_game_mode == Global.GameMode.CHALLENGE:
  464. Global.transition_to_scene("res://Scenes/Levels/ChallengeMiss.tscn")
  465. elif Global.time <= 0:
  466. Global.transition_to_scene("res://Scenes/Levels/TimeUp.tscn")
  467. elif Global.lives <= 0 and Settings.file.difficulty.inf_lives == 0:
  468. Global.death_load = false
  469. Global.transition_to_scene("res://Scenes/Levels/GameOver.tscn")
  470. else:
  471. LevelPersistance.reset_states()
  472. if Global.current_game_mode == Global.GameMode.BOO_RACE:
  473. Global.reset_values()
  474. Global.clear_saved_values()
  475. Level.start_level_path = Global.current_level.scene_file_path
  476. Global.current_level.reload_level()
  477. func time_up() -> void:
  478. die()
  479. func set_power_state_frame() -> void:
  480. colour_palette = ResourceSetter.get_resource(preload("uid://b0quveyqh25dn"))
  481. $PlayerPalette/ResourceSetterNew.resource_json = (CHARACTER_PALETTES[int(Global.player_characters[player_id])])
  482. if power_state != null:
  483. $ResourceSetterNew.resource_json = load(get_character_sprite_path())
  484. $ResourceSetterNew.update_resource()
  485. func get_power_up(power_name := "") -> void:
  486. if is_dead:
  487. return
  488. Global.score += 1000
  489. DiscoLevel.combo_amount += 1
  490. score_note_spawner.spawn_note(1000)
  491. AudioManager.play_sfx("power_up", global_position)
  492. if Settings.file.difficulty.damage_style == 0 and power_state.state_name != power_name:
  493. if power_name != "Big" and power_state.state_name != "Big":
  494. power_name = "Big"
  495. var new_power_state = get_node("PowerStates/" + power_name)
  496. if new_power_state.power_tier >= power_state.power_tier and new_power_state != power_state:
  497. can_hurt = false
  498. await power_up_animation(power_name)
  499. else:
  500. return
  501. if new_power_state.hitbox_size == "Big" and power_state.hitbox_size == "Small":
  502. check_for_block()
  503. power_state = new_power_state
  504. Global.player_power_states[player_id] = str(power_state.get_index())
  505. can_hurt = true
  506. refresh_hitbox()
  507. func check_for_block() -> void:
  508. if test_move(global_transform, Vector2.UP * 2):
  509. crouching = true
  510. func power_up_animation(new_power_state := "") -> void:
  511. if normal_state.jump_buffer > 0:
  512. normal_state.jump_buffer += 10
  513. var old_frames = sprite.sprite_frames
  514. var new_frames = $ResourceSetterNew.get_resource(load(get_character_sprite_path(new_power_state)))
  515. sprite.process_mode = Node.PROCESS_MODE_ALWAYS
  516. $Sprite.show()
  517. get_tree().paused = true
  518. if get_node("PowerStates/" + new_power_state).hitbox_size != power_state.hitbox_size:
  519. sprite.speed_scale = 3
  520. sprite.play("Grow")
  521. await get_tree().create_timer(0.4, true).timeout
  522. sprite.sprite_frames = new_frames
  523. sprite.play("Grow")
  524. await get_tree().create_timer(0.4, true).timeout
  525. transforming = false
  526. else:
  527. if not palette_transform:
  528. for i in 6:
  529. sprite.sprite_frames = new_frames
  530. await get_tree().create_timer(0.05).timeout
  531. sprite.sprite_frames = old_frames
  532. await get_tree().create_timer(0.05).timeout
  533. else:
  534. sprite.stop()
  535. sprite.material.set_shader_parameter("enabled", true)
  536. transforming = true
  537. await get_tree().create_timer(0.6).timeout
  538. transforming = false
  539. get_tree().paused = false
  540. sprite.process_mode = Node.PROCESS_MODE_PAUSABLE
  541. if Global.player_action_just_pressed("jump", player_id):
  542. jump()
  543. return
  544. const RESERVE_ITEM = preload("res://Scenes/Prefabs/Entities/Items/ReserveItem.tscn")
  545. func dispense_stored_item() -> void:
  546. add_sibling(RESERVE_ITEM.instantiate())
  547. func get_character_sprite_path(power_stateto_use := power_state.state_name) -> String:
  548. var path = "res://Assets/Sprites/Players/" + character + "/" + power_stateto_use + ".json"
  549. if int(Global.player_characters[player_id]) > 3:
  550. path = path.replace("res://Assets/Sprites/Players", "user://custom_characters")
  551. return path
  552. func enter_pipe(pipe: PipeArea, warp_to_level := true) -> void:
  553. z_index = -10
  554. Global.can_pause = false
  555. Global.can_time_tick = false
  556. pipe_enter_direction = pipe.get_vector(pipe.enter_direction)
  557. if pipe_enter_direction.x != 0:
  558. global_position.y = pipe.global_position.y + 14
  559. AudioManager.play_sfx("pipe", global_position)
  560. state_machine.transition_to("Pipe")
  561. PipeArea.exiting_pipe_id = pipe.pipe_id
  562. hide_pipe_animation()
  563. if warp_to_level:
  564. await get_tree().create_timer(1, false).timeout
  565. if Global.current_game_mode == Global.GameMode.LEVEL_EDITOR or Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
  566. LevelEditor.play_pipe_transition = true
  567. owner.transition_to_sublevel(pipe.target_sub_level)
  568. else:
  569. Global.transition_to_scene(pipe.target_level)
  570. func hide_pipe_animation() -> void:
  571. if pipe_enter_direction.x != 0:
  572. await get_tree().create_timer(0.3, false).timeout
  573. hide()
  574. else:
  575. await get_tree().create_timer(0.6, false).timeout
  576. hide()
  577. func go_to_exit_pipe(pipe: PipeArea) -> void:
  578. Global.can_time_tick = false
  579. pipe_enter_direction = Vector2.ZERO
  580. state_machine.transition_to("Pipe")
  581. global_position = pipe.global_position + (pipe.get_vector(pipe.enter_direction) * 32)
  582. if pipe.enter_direction == 1:
  583. global_position = pipe.global_position + Vector2(0, -8)
  584. recenter_camera()
  585. if pipe.get_vector(pipe.enter_direction).y == 0:
  586. global_position.y += 16
  587. global_position.x -= 8 * pipe.get_vector(pipe.enter_direction).x
  588. reset_physics_interpolation()
  589. hide()
  590. func exit_pipe(pipe: PipeArea) -> void:
  591. show()
  592. pipe_enter_direction = -pipe.get_vector(pipe.enter_direction)
  593. AudioManager.play_sfx("pipe", global_position)
  594. state_machine.transition_to("Pipe")
  595. await get_tree().create_timer(0.6, false).timeout
  596. Global.can_pause = true
  597. state_machine.transition_to("Normal")
  598. Global.can_time_tick = true
  599. func jump() -> void:
  600. if spring_bouncing:
  601. return
  602. velocity.y = calculate_jump_height() * gravity_vector.y
  603. gravity = JUMP_GRAVITY
  604. AudioManager.play_sfx("small_jump" if power_state.hitbox_size == "Small" else "big_jump", global_position)
  605. has_jumped = true
  606. await get_tree().physics_frame
  607. has_jumped = true
  608. func calculate_jump_height() -> float: # Thanks wye love you xxx
  609. return -(JUMP_HEIGHT + JUMP_INCR * int(abs(velocity.x) / 25))
  610. const SMOKE_PARTICLE = preload("res://Scenes/Prefabs/Particles/SmokeParticle.tscn")
  611. func teleport_player(new_position := Vector2.ZERO) -> void:
  612. hide()
  613. do_smoke_effect()
  614. var old_state = state_machine.state.name
  615. state_machine.transition_to("Freeze")
  616. await get_tree().create_timer(0.5, false).timeout
  617. global_position = new_position
  618. recenter_camera()
  619. await get_tree().create_timer(0.5, false).timeout
  620. state_machine.transition_to(old_state)
  621. show()
  622. velocity.y = 0
  623. do_smoke_effect()
  624. func do_smoke_effect() -> void:
  625. for i in 2:
  626. var node = SMOKE_PARTICLE.instantiate()
  627. node.global_position = global_position - Vector2(0, 16 * i)
  628. add_sibling(node)
  629. if power_state.hitbox_size == "Small":
  630. break
  631. AudioManager.play_sfx("magic", global_position)
  632. func on_timeout() -> void:
  633. AudioManager.stop_music_override(AudioManager.MUSIC_OVERRIDES.STAR)
  634. await get_tree().create_timer(1, false).timeout
  635. is_invincible = false
  636. func on_area_entered(area: Area2D) -> void:
  637. if area.owner is Player and area.owner != self:
  638. if area.owner.velocity.y > 0 and area.owner.is_actually_on_floor() == false:
  639. area.owner.enemy_bounce_off(false)
  640. velocity.y = 50
  641. AudioManager.play_sfx("bump", global_position)
  642. func hammer_get() -> void:
  643. has_hammer = true
  644. $HammerTimer.start()
  645. AudioManager.set_music_override(AudioManager.MUSIC_OVERRIDES.HAMMER, 0, false)
  646. func on_hammer_area_entered(area: Area2D) -> void:
  647. pass
  648. func wing_get() -> void:
  649. AudioManager.set_music_override(AudioManager.MUSIC_OVERRIDES.WING, 0, false, false)
  650. flight_meter = 10
  651. func on_hammer_timeout() -> void:
  652. has_hammer = false
  653. AudioManager.stop_music_override(AudioManager.MUSIC_OVERRIDES.HAMMER)
  654. func water_exited() -> void:
  655. await get_tree().physics_frame
  656. if in_water: return
  657. normal_state.swim_up_meter = 0
  658. if velocity.y < 0:
  659. velocity.y = -250.0 if velocity.y < -50.0 or Global.player_action_pressed("move_up", player_id) else velocity.y
  660. has_jumped = true
  661. if Global.player_action_pressed("move_up", player_id):
  662. gravity = JUMP_GRAVITY
  663. else:
  664. gravity = FALL_GRAVITY
  665. func reset_camera_to_center() -> void:
  666. animating_camera = true
  667. var old_position = camera.position
  668. camera.global_position = get_viewport().get_camera_2d().get_screen_center_position()
  669. camera.reset_physics_interpolation()
  670. var tween = create_tween()
  671. tween.tween_property(camera, "position", old_position, 0.5)
  672. await tween.finished
  673. camera.position = old_position
  674. animating_camera = false
  675. func on_area_exited(area: Area2D) -> void:
  676. if area is WaterArea:
  677. water_exited()