mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-22 15:38:14 +00:00
added the game
This commit is contained in:
10
Scripts/Classes/Components/AchievementProgressCalculator.gd
Normal file
10
Scripts/Classes/Components/AchievementProgressCalculator.gd
Normal file
@@ -0,0 +1,10 @@
|
||||
class_name AchievementProgressCalculator
|
||||
extends Node
|
||||
|
||||
@export var target_number := 8
|
||||
|
||||
func _ready() -> void:
|
||||
get_progress()
|
||||
|
||||
func get_progress() -> int:
|
||||
return 0
|
@@ -0,0 +1 @@
|
||||
uid://dwrso5q5r5bak
|
17
Scripts/Classes/Components/AnimationPauser.gd
Normal file
17
Scripts/Classes/Components/AnimationPauser.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
class_name AnimationPauser
|
||||
extends Node
|
||||
|
||||
@export var animation_player: AnimationPlayer = null
|
||||
|
||||
@export var paused := false
|
||||
|
||||
signal just_paused
|
||||
signal resumed
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
animation_player.speed_scale = int(not paused)
|
||||
|
||||
func on_switch_hit() -> void:
|
||||
paused = not paused
|
||||
if paused: just_paused.emit()
|
||||
else: resumed.emit()
|
1
Scripts/Classes/Components/AnimationPauser.gd.uid
Normal file
1
Scripts/Classes/Components/AnimationPauser.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cb0spbe0l8mof
|
75
Scripts/Classes/Components/BasicEnemyMovement.gd
Normal file
75
Scripts/Classes/Components/BasicEnemyMovement.gd
Normal file
@@ -0,0 +1,75 @@
|
||||
class_name BasicEnemyMovement
|
||||
extends Node
|
||||
|
||||
@export var ledge_detection_cast: RayCast2D = null
|
||||
|
||||
var can_move := true
|
||||
|
||||
@export var auto_call := true
|
||||
|
||||
@export var move_speed := 32
|
||||
@export var second_quest_speed := 36
|
||||
|
||||
@onready var current_speed := move_speed
|
||||
@export var bounce_on_land := false
|
||||
@export var bounce_height := -200
|
||||
@export var visuals: Node2D
|
||||
|
||||
@export var follow_player := false
|
||||
|
||||
var can_hit := true
|
||||
|
||||
var can_bounce := true
|
||||
|
||||
var active := true
|
||||
|
||||
func _ready() -> void:
|
||||
if owner is CharacterBody2D:
|
||||
owner.floor_constant_speed = true
|
||||
owner.floor_max_angle = 0.80
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if auto_call:
|
||||
handle_movement(delta)
|
||||
if visuals != null:
|
||||
visuals.scale.x = owner.direction
|
||||
|
||||
func handle_movement(delta: float) -> void:
|
||||
if active == false: return
|
||||
if Global.second_quest and owner is Enemy:
|
||||
move_speed = second_quest_speed
|
||||
apply_gravity(delta)
|
||||
if owner.is_on_wall():
|
||||
wall_hit()
|
||||
elif ledge_detection_cast != null and owner.is_on_floor():
|
||||
ledge_detection_cast.floor_normal = owner.get_floor_normal()
|
||||
ledge_detection_cast.position.x = abs(ledge_detection_cast.position.x) * owner.direction
|
||||
if ledge_detection_cast.is_colliding() == false:
|
||||
wall_hit()
|
||||
if follow_player and owner.is_on_floor():
|
||||
player_direction_check()
|
||||
current_speed = abs(owner.velocity.x)
|
||||
if current_speed < move_speed:
|
||||
current_speed = move_speed
|
||||
if owner.is_on_floor():
|
||||
current_speed = move_speed
|
||||
if bounce_on_land:
|
||||
owner.velocity.y = bounce_height
|
||||
owner.velocity.x = (current_speed if can_move else 0) * owner.direction
|
||||
owner.move_and_slide()
|
||||
|
||||
func apply_gravity(delta: float) -> void:
|
||||
owner.velocity.y += (Global.entity_gravity / delta) * delta
|
||||
owner.velocity.y = clamp(owner.velocity.y, -INF, Global.entity_max_fall_speed)
|
||||
|
||||
func player_direction_check() -> void:
|
||||
var target_player = get_tree().get_first_node_in_group("Players")
|
||||
owner.direction = sign(target_player.global_position.x - owner.global_position.x)
|
||||
|
||||
func wall_hit() -> void:
|
||||
if can_hit == false:
|
||||
return
|
||||
can_hit = false
|
||||
owner.direction *= -1
|
||||
await get_tree().create_timer(0.1, false).timeout
|
||||
can_hit = true
|
1
Scripts/Classes/Components/BasicEnemyMovement.gd.uid
Executable file
1
Scripts/Classes/Components/BasicEnemyMovement.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://dlq6o2rg1x7in
|
20
Scripts/Classes/Components/BasicStaticMovement.gd
Normal file
20
Scripts/Classes/Components/BasicStaticMovement.gd
Normal file
@@ -0,0 +1,20 @@
|
||||
class_name BasicStaticMovement
|
||||
extends Node
|
||||
|
||||
@export var auto_call := true
|
||||
|
||||
@export var visuals: Node2D = null
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if auto_call:
|
||||
handle_movement(delta)
|
||||
|
||||
func handle_movement(delta: float) -> void:
|
||||
apply_gravity(delta)
|
||||
if owner.is_on_floor():
|
||||
owner.velocity.x = lerpf(owner.velocity.x, 0, delta * 20)
|
||||
owner.move_and_slide()
|
||||
|
||||
func apply_gravity(delta: float) -> void:
|
||||
owner.velocity.y += (Global.entity_gravity / delta) * delta
|
||||
owner.velocity.y = clamp(owner.velocity.y, -INF, Global.entity_max_fall_speed)
|
1
Scripts/Classes/Components/BasicStaticMovement.gd.uid
Executable file
1
Scripts/Classes/Components/BasicStaticMovement.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://bx6r8sjar6cwr
|
4
Scripts/Classes/Components/BlockAnimations.gd
Executable file
4
Scripts/Classes/Components/BlockAnimations.gd
Executable file
@@ -0,0 +1,4 @@
|
||||
extends Node
|
||||
|
||||
func _ready() -> void:
|
||||
pass
|
1
Scripts/Classes/Components/BlockAnimations.gd.uid
Executable file
1
Scripts/Classes/Components/BlockAnimations.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://cfcyhay33ctae
|
33
Scripts/Classes/Components/BlockBouncingDetection.gd
Normal file
33
Scripts/Classes/Components/BlockBouncingDetection.gd
Normal file
@@ -0,0 +1,33 @@
|
||||
class_name BlockBouncingDetection
|
||||
extends Node
|
||||
|
||||
@export_enum("Collision", "Hitbox") var detection_type := 0
|
||||
@export var hitbox: Area2D = null
|
||||
|
||||
@export var can_change_direction := false
|
||||
|
||||
signal block_bounced(block: Block)
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if detection_type == 0:
|
||||
collision_detect()
|
||||
else:
|
||||
hitbox_detect()
|
||||
|
||||
func collision_detect() -> void:
|
||||
var collision: KinematicCollision2D = owner.move_and_collide(Vector2.DOWN, true)
|
||||
if is_instance_valid(collision):
|
||||
if collision.get_collider() is Block:
|
||||
if collision.get_collider().bouncing:
|
||||
block_bounced.emit(collision.get_collider())
|
||||
return
|
||||
|
||||
func hitbox_detect() -> void:
|
||||
if is_instance_valid(hitbox) == false: return
|
||||
for i in hitbox.get_overlapping_bodies():
|
||||
if i is Block:
|
||||
if i.bouncing:
|
||||
block_bounced.emit(i)
|
||||
if can_change_direction:
|
||||
owner.direction = sign(owner.global_position.x - i.global_position.x)
|
||||
return
|
1
Scripts/Classes/Components/BlockBouncingDetection.gd.uid
Executable file
1
Scripts/Classes/Components/BlockBouncingDetection.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://cmg61722ktg2m
|
23
Scripts/Classes/Components/BlockHitter.gd
Normal file
23
Scripts/Classes/Components/BlockHitter.gd
Normal file
@@ -0,0 +1,23 @@
|
||||
class_name BlockHitter
|
||||
extends Node
|
||||
|
||||
@export var hitbox: Area2D = null
|
||||
@export var can_break_bricks := false
|
||||
@export var enabled := true:
|
||||
set(value):
|
||||
enabled = value
|
||||
set_physics_process(value)
|
||||
|
||||
signal block_hit(block: Block)
|
||||
|
||||
func _ready() -> void:
|
||||
hitbox.set_collision_mask_value(3, true)
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
for i in hitbox.get_overlapping_bodies():
|
||||
if i is Block and i.global_position.y < owner.global_position.y:
|
||||
i.shell_block_hit.emit(self)
|
||||
block_hit.emit(i)
|
||||
if i is BrickBlock:
|
||||
if i.item == null:
|
||||
i.destroy()
|
1
Scripts/Classes/Components/BlockHitter.gd.uid
Normal file
1
Scripts/Classes/Components/BlockHitter.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dkjpfs3sm3go3
|
99
Scripts/Classes/Components/EditorPropertyExposer.gd
Normal file
99
Scripts/Classes/Components/EditorPropertyExposer.gd
Normal file
@@ -0,0 +1,99 @@
|
||||
class_name PropertyExposer
|
||||
extends Node
|
||||
|
||||
@export var properties: Array[String] = []
|
||||
@export var filters: Dictionary[String, String] = {}
|
||||
|
||||
@export var properties_force_selector: Dictionary[String, PackedScene] = {}
|
||||
|
||||
const base64_charset := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
|
||||
static var entity_map := {}
|
||||
|
||||
signal modifier_applied
|
||||
|
||||
func _ready() -> void:
|
||||
name = "EditorPropertyExposer"
|
||||
if entity_map.is_empty():
|
||||
entity_map = JSON.parse_string(FileAccess.open(EntityIDMapper.MAP_PATH, FileAccess.READ).get_as_text())
|
||||
|
||||
func get_string() -> String:
|
||||
var string = ""
|
||||
for i in properties:
|
||||
string += ","
|
||||
if owner is Track:
|
||||
if owner.get(i) is Array:
|
||||
for x in owner.get(i):
|
||||
string += base64_charset[(Track.DIRECTIONS.find(x))]
|
||||
if owner.get(i) is String:
|
||||
string += owner.get(i).replace(",", "&")
|
||||
elif owner.get(i) is PackedScene:
|
||||
var key = EntityIDMapper.get_map_id(owner.get(i).resource_path)
|
||||
if key == null or key == "":
|
||||
key = "!!"
|
||||
string += key
|
||||
elif owner.get(i) is int:
|
||||
if owner.get(i) >= 64:
|
||||
string += encode_to_base64_2char(owner.get(i))
|
||||
else:
|
||||
string += base64_charset[owner.get(i)]
|
||||
elif owner.get(i) is bool:
|
||||
string += base64_charset[int(owner.get(i))]
|
||||
elif owner.get(i) == null:
|
||||
string += "!!"
|
||||
|
||||
return string
|
||||
|
||||
func apply_string(entity_string := "") -> void:
|
||||
var idx := 2
|
||||
var slice = entity_string.split(",")
|
||||
for i in properties:
|
||||
if slice.size() <= idx:
|
||||
return
|
||||
var value = slice[idx]
|
||||
if owner is Track:
|
||||
if owner.get(i) is Array:
|
||||
for x in value:
|
||||
owner.get(i).append(Track.DIRECTIONS[base64_charset.find(x)])
|
||||
owner._ready()
|
||||
if owner.get(i) is String:
|
||||
owner.set(i, value.replace("&", ","))
|
||||
if owner.get(i) is PackedScene or (owner.get(i) == null and i == "item"):
|
||||
var scene = entity_map.get(value)
|
||||
if scene != null:
|
||||
owner.set(i, load(entity_map.get(value)[0]))
|
||||
elif owner.get(i) is int:
|
||||
var num = value
|
||||
if value.length() > 1:
|
||||
num = decode_from_base64_2char(value)
|
||||
else:
|
||||
num = base64_charset.find(value)
|
||||
owner.set(i, num)
|
||||
elif owner.get(i) is bool:
|
||||
owner.set(i, bool(base64_charset.find(value)))
|
||||
idx += 1
|
||||
modifier_applied.emit()
|
||||
|
||||
func encode_to_base64_2char(value: int) -> String:
|
||||
if value < 0 or value >= 4096:
|
||||
push_error("Value out of range for 2-char base64 encoding.")
|
||||
return ""
|
||||
|
||||
var char1 = base64_charset[(value >> 6) & 0b111111] # Top 6 bits
|
||||
var char2 = base64_charset[value & 0b111111] # Bottom 6 bits
|
||||
|
||||
return char1 + char2
|
||||
|
||||
func decode_from_base64_2char(encoded: String) -> int:
|
||||
if encoded.length() != 2:
|
||||
push_error("Encoded string must be exactly 2 characters.")
|
||||
return -1
|
||||
|
||||
var char1_val = base64_charset.find(encoded[0])
|
||||
var char2_val = base64_charset.find(encoded[1])
|
||||
|
||||
if char1_val == -1 or char2_val == -1:
|
||||
push_error("Invalid character in base64 string.")
|
||||
return -1
|
||||
|
||||
return (char1_val << 6) | char2_val
|
1
Scripts/Classes/Components/EditorPropertyExposer.gd.uid
Executable file
1
Scripts/Classes/Components/EditorPropertyExposer.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://ctfbuoxtnnl0q
|
25
Scripts/Classes/Components/EnemyPlayerDetection.gd
Normal file
25
Scripts/Classes/Components/EnemyPlayerDetection.gd
Normal file
@@ -0,0 +1,25 @@
|
||||
class_name EnemyPlayerDetection
|
||||
extends Node
|
||||
|
||||
@export var hitbox: Area2D = null
|
||||
|
||||
@export var height := 4
|
||||
|
||||
signal player_hit(player: Player)
|
||||
signal player_stomped_on(player: Player)
|
||||
signal invincible_player_hit(player: Player)
|
||||
|
||||
func _ready() -> void:
|
||||
hitbox.area_entered.connect(area_entered)
|
||||
|
||||
func area_entered(area: Area2D) -> void:
|
||||
if area.owner is Player:
|
||||
player_entered(area.owner)
|
||||
|
||||
func player_entered(player: Player) -> void:
|
||||
if player.is_invincible or player.has_hammer:
|
||||
invincible_player_hit.emit(player)
|
||||
elif (player.velocity.y >= 15 or (player.global_position.y + height < owner.global_position.y)) and player.in_water == false:
|
||||
player_stomped_on.emit(player)
|
||||
else:
|
||||
player_hit.emit(player)
|
1
Scripts/Classes/Components/EnemyPlayerDetection.gd.uid
Executable file
1
Scripts/Classes/Components/EnemyPlayerDetection.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://chj8hu207lrh
|
13
Scripts/Classes/Components/ExplosionDetection.gd
Executable file
13
Scripts/Classes/Components/ExplosionDetection.gd
Executable file
@@ -0,0 +1,13 @@
|
||||
class_name ExplosionDetection
|
||||
extends Node
|
||||
|
||||
@export var hitbox: Area2D = null
|
||||
signal explosion_entered(explosion: Node2D)
|
||||
|
||||
func _ready() -> void:
|
||||
if hitbox != null:
|
||||
hitbox.area_entered.connect(area_entered)
|
||||
|
||||
func area_entered(area: Area2D) -> void:
|
||||
if area.owner is Explosion:
|
||||
explosion_entered.emit(area.owner)
|
1
Scripts/Classes/Components/ExplosionDetection.gd.uid
Executable file
1
Scripts/Classes/Components/ExplosionDetection.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://ba18grqjixded
|
15
Scripts/Classes/Components/FireballDetection.gd
Executable file
15
Scripts/Classes/Components/FireballDetection.gd
Executable file
@@ -0,0 +1,15 @@
|
||||
class_name FireballDetection
|
||||
extends Node
|
||||
|
||||
@export var hitbox: Area2D = null
|
||||
@export var play_sfx_on_hit := false
|
||||
signal fireball_hit(fireball: FireBall)
|
||||
|
||||
func _ready() -> void:
|
||||
if hitbox != null:
|
||||
hitbox.area_entered.connect(area_entered)
|
||||
|
||||
func area_entered(area: Area2D) -> void:
|
||||
if area.owner is FireBall:
|
||||
fireball_hit.emit(area.owner)
|
||||
area.owner.hit(play_sfx_on_hit)
|
1
Scripts/Classes/Components/FireballDetection.gd.uid
Executable file
1
Scripts/Classes/Components/FireballDetection.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://dri2d5jtu0fbq
|
47
Scripts/Classes/Components/GibSpawner.gd
Normal file
47
Scripts/Classes/Components/GibSpawner.gd
Normal file
@@ -0,0 +1,47 @@
|
||||
class_name GibSpawner
|
||||
extends Node
|
||||
|
||||
@export var visuals: Node = null
|
||||
@export_enum("Spin", "Drop", "Poof") var gib_type := 0
|
||||
@export var play_death_sfx := true
|
||||
const ENTITY_GIB = preload("res://Scenes/Prefabs/Entities/EntityGib.tscn")
|
||||
|
||||
signal gib_about_to_spawn
|
||||
|
||||
|
||||
func summon_gib(direction := 1, play_sfx := play_death_sfx, override_gib_type := gib_type) -> void:
|
||||
gib_about_to_spawn.emit()
|
||||
if play_sfx:
|
||||
play_die_sfx()
|
||||
if override_gib_type == 2:
|
||||
summon_poof()
|
||||
return
|
||||
var node = ENTITY_GIB.instantiate()
|
||||
visuals.show()
|
||||
if visuals.has_node("ResourceSetterNew"):
|
||||
visuals.get_node("ResourceSetterNew").update_on_spawn = false
|
||||
node.visuals = visuals.duplicate()
|
||||
node.visuals.set_process(false)
|
||||
node.global_position = visuals.global_position
|
||||
node.visuals.position = Vector2.ZERO
|
||||
node.visuals.offset = Vector2.ZERO
|
||||
node.gib_type = override_gib_type
|
||||
node.direction = direction
|
||||
owner.add_sibling(node)
|
||||
|
||||
func play_die_sfx() -> void:
|
||||
AudioManager.play_sfx("kick", owner.global_position)
|
||||
|
||||
const SMOKE_PARTICLE = preload("uid://d08nv4qtfouv1")
|
||||
|
||||
func summon_poof() -> void:
|
||||
var particle = SMOKE_PARTICLE.instantiate()
|
||||
particle.global_position = visuals.global_position + Vector2(0, 8)
|
||||
owner.add_sibling(particle)
|
||||
|
||||
func stomp_die(player: Player, add_combo := true) -> void:
|
||||
DiscoLevel.combo_amount += 1
|
||||
AudioManager.play_sfx("enemy_stomp", owner.global_position)
|
||||
player.enemy_bounce_off(add_combo)
|
||||
summon_gib(1, false, 1)
|
||||
owner.queue_free()
|
1
Scripts/Classes/Components/GibSpawner.gd.uid
Executable file
1
Scripts/Classes/Components/GibSpawner.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://c3gg32ivrlq8n
|
15
Scripts/Classes/Components/IcicleDetection.gd
Executable file
15
Scripts/Classes/Components/IcicleDetection.gd
Executable file
@@ -0,0 +1,15 @@
|
||||
class_name IcicleDetection
|
||||
extends Node
|
||||
|
||||
@export var hitbox: Area2D = null
|
||||
|
||||
signal icicle_detected(icicle: Icicle)
|
||||
|
||||
func _ready() -> void:
|
||||
if hitbox != null:
|
||||
hitbox.area_entered.connect(area_entered)
|
||||
|
||||
func area_entered(area: Area2D) -> void:
|
||||
if area.owner is Icicle:
|
||||
if area.owner.falling:
|
||||
icicle_detected.emit(area.owner)
|
1
Scripts/Classes/Components/IcicleDetection.gd.uid
Executable file
1
Scripts/Classes/Components/IcicleDetection.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://dq860i312isk
|
23
Scripts/Classes/Components/LedgeDetectionCast.gd
Normal file
23
Scripts/Classes/Components/LedgeDetectionCast.gd
Normal file
@@ -0,0 +1,23 @@
|
||||
class_name LedgeDetectionCast
|
||||
extends RayCast2D
|
||||
|
||||
@export var floor_normal := Vector2.UP
|
||||
@export var ray_length := 24
|
||||
var floor_direction := 1
|
||||
var direction := 1
|
||||
|
||||
## Hypotenuse = floor_angle
|
||||
## Opposite = ???
|
||||
## Adjacent = position.x
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
target_position.y = ray_length
|
||||
if floor_normal.x > 0:
|
||||
floor_direction = 1
|
||||
elif floor_normal.x < 0:
|
||||
floor_direction = -1
|
||||
else:
|
||||
position.y = -(ray_length / 2.0)
|
||||
return
|
||||
position.y = ((-floor_normal.y * (position.x)) * (floor_direction)) - (ray_length / 2.0)
|
1
Scripts/Classes/Components/LedgeDetectionCast.gd.uid
Normal file
1
Scripts/Classes/Components/LedgeDetectionCast.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://blfnd65xcx78c
|
29
Scripts/Classes/Components/LevelPersistance.gd
Normal file
29
Scripts/Classes/Components/LevelPersistance.gd
Normal file
@@ -0,0 +1,29 @@
|
||||
class_name LevelPersistance
|
||||
extends Node
|
||||
|
||||
static var active_nodes := [[], []]
|
||||
|
||||
var active := false
|
||||
|
||||
@onready var path := get_path_string()
|
||||
|
||||
signal enabled
|
||||
signal enabled_2
|
||||
|
||||
static func reset_states() -> void:
|
||||
active_nodes = [[], []]
|
||||
Checkpoint.old_state = [[], []]
|
||||
|
||||
func _ready() -> void:
|
||||
return
|
||||
|
||||
func set_as_active() -> void:
|
||||
if owner.has_meta("no_persist"): return
|
||||
active_nodes[0].append(path)
|
||||
|
||||
func set_as_active_2() -> void:
|
||||
if owner.has_meta("no_persist"): return
|
||||
active_nodes[1].append(path)
|
||||
|
||||
func get_path_string() -> String:
|
||||
return Global.current_level.scene_file_path + str(Vector2i(owner.global_position / 8))
|
1
Scripts/Classes/Components/LevelPersistance.gd.uid
Normal file
1
Scripts/Classes/Components/LevelPersistance.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://maqpreddu5kg
|
18
Scripts/Classes/Components/OffScreenDespawner.gd
Normal file
18
Scripts/Classes/Components/OffScreenDespawner.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
class_name OffScreenDespawner
|
||||
extends Node
|
||||
|
||||
var can_despawn := false
|
||||
|
||||
func _ready() -> void:
|
||||
can_despawn = false
|
||||
await get_tree().create_timer(0.5, false).timeout
|
||||
can_despawn = true
|
||||
|
||||
func on_screen_exited() -> void:
|
||||
if Global.level_editor != null:
|
||||
if Global.level_editor.current_state == LevelEditor.EditorState.PLAYTESTING or Global.current_game_mode == Global.GameMode.CUSTOM_LEVEL:
|
||||
await get_tree().physics_frame
|
||||
if can_despawn:
|
||||
owner.queue_free()
|
||||
else:
|
||||
owner.queue_free()
|
1
Scripts/Classes/Components/OffScreenDespawner.gd.uid
Normal file
1
Scripts/Classes/Components/OffScreenDespawner.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://33no4mylhh1r
|
28
Scripts/Classes/Components/PSwitcher.gd
Normal file
28
Scripts/Classes/Components/PSwitcher.gd
Normal file
@@ -0,0 +1,28 @@
|
||||
class_name PSwitcher
|
||||
extends Node
|
||||
|
||||
var enabled := true
|
||||
@export_file("*.tscn") var new_scene := ""
|
||||
@export var new_offset := Vector2.ZERO
|
||||
|
||||
@export var properties := []
|
||||
|
||||
var is_switched := false
|
||||
|
||||
func _ready() -> void:
|
||||
Global.p_switch_toggle.connect(switch_to_other)
|
||||
if Global.p_switch_active and not is_switched:
|
||||
switch_to_other()
|
||||
|
||||
func switch_to_other() -> void:
|
||||
if enabled == false: return
|
||||
if new_scene != "":
|
||||
var new = load(new_scene).instantiate()
|
||||
new.global_position = owner.global_position + new_offset
|
||||
if new.has_node("PSwitcher"):
|
||||
new.get_node("PSwitcher").new_scene = owner.scene_file_path
|
||||
new.get_node("PSwitcher").is_switched = true
|
||||
for i in properties:
|
||||
new.set(i, owner.get(i))
|
||||
owner.call_deferred("add_sibling", new)
|
||||
owner.queue_free()
|
1
Scripts/Classes/Components/PSwitcher.gd.uid
Executable file
1
Scripts/Classes/Components/PSwitcher.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://bul1nbd2in1gn
|
11
Scripts/Classes/Components/PackStreamPlayer.gd
Normal file
11
Scripts/Classes/Components/PackStreamPlayer.gd
Normal file
@@ -0,0 +1,11 @@
|
||||
class_name PackStreamPlayer
|
||||
extends AudioStreamPlayer
|
||||
|
||||
@onready var resource_getter = ResourceGetter.new()
|
||||
|
||||
func _ready() -> void:
|
||||
update()
|
||||
Global.level_theme_changed.connect(update)
|
||||
|
||||
func update() -> void:
|
||||
stream = resource_getter.get_resource(stream)
|
1
Scripts/Classes/Components/PackStreamPlayer.gd.uid
Normal file
1
Scripts/Classes/Components/PackStreamPlayer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dmtw1jesw1vl7
|
70
Scripts/Classes/Components/ResourceGetter.gd
Normal file
70
Scripts/Classes/Components/ResourceGetter.gd
Normal file
@@ -0,0 +1,70 @@
|
||||
class_name ResourceGetter
|
||||
extends Node
|
||||
|
||||
var original_resource: Resource = null
|
||||
|
||||
static var cache := {}
|
||||
|
||||
func get_resource(resource: Resource) -> Resource:
|
||||
if resource == null:
|
||||
return null
|
||||
|
||||
if original_resource == null:
|
||||
original_resource = resource
|
||||
|
||||
if cache.has(original_resource.resource_path) and resource is not AtlasTexture:
|
||||
return cache.get(original_resource.resource_path)
|
||||
|
||||
var path := ""
|
||||
if original_resource is AtlasTexture:
|
||||
path = get_resource_path(original_resource.atlas.resource_path)
|
||||
else:
|
||||
path = get_resource_path(original_resource.resource_path)
|
||||
|
||||
if path == original_resource.resource_path:
|
||||
return original_resource
|
||||
|
||||
if original_resource is Texture:
|
||||
var new_resource = null
|
||||
if path.contains("user://"):
|
||||
new_resource = ImageTexture.create_from_image(Image.load_from_file(path))
|
||||
else:
|
||||
new_resource = load(path)
|
||||
send_to_cache(original_resource.resource_path, new_resource)
|
||||
if original_resource is AtlasTexture:
|
||||
var atlas = AtlasTexture.new()
|
||||
atlas.atlas = new_resource
|
||||
atlas.region = original_resource.region
|
||||
return atlas
|
||||
return new_resource
|
||||
|
||||
elif original_resource is AudioStream:
|
||||
if path.get_file().contains(".wav"):
|
||||
var new_resource = AudioStreamWAV.load_from_file(path)
|
||||
send_to_cache(original_resource.resource_path, new_resource)
|
||||
return new_resource
|
||||
elif path.get_file().contains(".mp3"):
|
||||
var new_resource = AudioStreamMP3.load_from_file(path)
|
||||
send_to_cache(original_resource.resource_path, new_resource)
|
||||
return new_resource
|
||||
|
||||
elif original_resource is Font:
|
||||
var new_font = FontFile.new()
|
||||
new_font.load_bitmap_font(path)
|
||||
send_to_cache(original_resource.resource_path, new_font)
|
||||
return new_font
|
||||
|
||||
send_to_cache(original_resource.resource_path, original_resource)
|
||||
|
||||
return original_resource
|
||||
|
||||
func send_to_cache(resource_path := "", resource_to_cache: Resource = null) -> void:
|
||||
if cache.has(resource_path) == false:
|
||||
cache.set(resource_path, resource_to_cache)
|
||||
|
||||
func get_resource_path(resource_path := "") -> String:
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
var test = resource_path.replace("res://Assets/", "user://resource_packs/" + i + "/")
|
||||
if FileAccess.file_exists(test):
|
||||
return test
|
||||
return resource_path
|
1
Scripts/Classes/Components/ResourceGetter.gd.uid
Normal file
1
Scripts/Classes/Components/ResourceGetter.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bsp584niccobr
|
146
Scripts/Classes/Components/ResourceSetter.gd
Normal file
146
Scripts/Classes/Components/ResourceSetter.gd
Normal file
@@ -0,0 +1,146 @@
|
||||
class_name ResourceSetter
|
||||
extends Node
|
||||
|
||||
@export var node_to_affect: Node = null
|
||||
@export var property_name := ""
|
||||
@export var themed_resource: ThemedResource = null
|
||||
@export var use_classic_theming := false
|
||||
@export var use_cache := true
|
||||
|
||||
signal sprites_updated
|
||||
|
||||
static var cache := {}
|
||||
|
||||
func _enter_tree() -> void:
|
||||
Global.level_theme_changed.connect(update_sprites)
|
||||
Global.level_time_changed.connect(update_sprites)
|
||||
|
||||
func _ready() -> void:
|
||||
update_sprites()
|
||||
|
||||
func update_sprites() -> void:
|
||||
cache.clear()
|
||||
if themed_resource == null:
|
||||
node_to_affect.set(property_name, null)
|
||||
return
|
||||
var resource = get_resource(themed_resource, node_to_affect, true, use_cache)
|
||||
node_to_affect.set(property_name, resource)
|
||||
if node_to_affect is AnimatedSprite2D:
|
||||
node_to_affect.play()
|
||||
sprites_updated.emit()
|
||||
|
||||
static func get_resource(resource: Resource, node: Node = null, assign := false, cache_enabled := true) -> RefCounted:
|
||||
if resource == null:
|
||||
return resource
|
||||
var og_path = resource.resource_path
|
||||
if resource is AtlasTexture:
|
||||
og_path = resource.atlas.resource_path
|
||||
if resource is ThemedResource:
|
||||
if resource.get(Global.level_theme) != null:
|
||||
resource = get_resource(resource.get(Global.level_theme))
|
||||
else:
|
||||
resource = get_resource(resource.Overworld)
|
||||
if resource is CampaignResource:
|
||||
if resource.get(Global.current_campaign) != null:
|
||||
resource = get_resource(resource.get(Global.current_campaign))
|
||||
else:
|
||||
resource = get_resource(resource.SMB1)
|
||||
|
||||
if assign:
|
||||
if resource is AtlasTexture:
|
||||
resource.filter_clip = true
|
||||
if resource is SpriteFrames:
|
||||
if node is not AnimatedSprite2D:
|
||||
resource = resource.get_frame_texture(resource.get_animation_names()[0], 0)
|
||||
if Settings.file.visuals.resource_packs.is_empty() == false:
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
resource = get_override_resource(resource, i)
|
||||
if cache.has(og_path) == false:
|
||||
cache[og_path] = resource.duplicate()
|
||||
if resource == null:
|
||||
pass
|
||||
return resource
|
||||
|
||||
static func get_override_resource(resource: Resource = null, resource_pack := "") -> Object:
|
||||
if resource == null:
|
||||
return
|
||||
if resource_pack == "":
|
||||
return
|
||||
var original_resource_path = resource.resource_path
|
||||
var resource_path = get_override_resource_path(resource.resource_path, resource_pack)
|
||||
if FileAccess.file_exists(resource_path):
|
||||
if resource is Texture:
|
||||
resource = create_image_from_path(resource_path)
|
||||
elif resource is SpriteFrames:
|
||||
resource = create_new_sprite_frames(resource, resource_pack)
|
||||
if resource is AudioStream:
|
||||
if resource_path.contains(".mp3"):
|
||||
var resource_loops = resource.has_loop()
|
||||
resource = AudioStreamMP3.load_from_file(resource_path)
|
||||
resource.set_loop(resource_loops)
|
||||
elif resource_path.contains(".wav"):
|
||||
resource = AudioStreamWAV.load_from_file(resource_path)
|
||||
if resource is FontVariation:
|
||||
resource_path = get_override_resource_path(resource.base_font.resource_path, resource_pack)
|
||||
if FileAccess.file_exists(resource_path):
|
||||
var new_font = FontFile.new()
|
||||
var variation = resource.duplicate()
|
||||
new_font.load_bitmap_font(resource_path.replace(".png", ".fnt"))
|
||||
variation.base_font = new_font
|
||||
resource = variation
|
||||
else:
|
||||
if resource is SpriteFrames:
|
||||
resource = create_new_sprite_frames(resource, resource_pack)
|
||||
if resource is AtlasTexture:
|
||||
resource_path = get_override_resource_path(resource.atlas.resource_path, resource_pack)
|
||||
if FileAccess.file_exists(resource_path):
|
||||
var new_resource = AtlasTexture.new()
|
||||
new_resource.atlas = create_image_from_path(get_override_resource_path(resource.atlas.resource_path, resource_pack))
|
||||
new_resource.region = resource.region
|
||||
return new_resource
|
||||
if resource is AudioStreamInteractive:
|
||||
resource = get_override_resource(resource.get_clip_stream(0), resource_pack)
|
||||
if resource is FontVariation:
|
||||
resource_path = get_override_resource_path(resource.base_font.resource_path, resource_pack)
|
||||
if FileAccess.file_exists(resource_path):
|
||||
var new_font = FontFile.new()
|
||||
var variation = resource.duplicate()
|
||||
new_font.load_bitmap_font(resource_path.replace(".png", ".fnt"))
|
||||
variation.base_font = new_font
|
||||
resource = variation
|
||||
return resource
|
||||
|
||||
static func create_image_from_path(file_path := "") -> ImageTexture:
|
||||
var image = Image.new()
|
||||
image.load(file_path)
|
||||
return ImageTexture.create_from_image(image)
|
||||
|
||||
static func create_new_sprite_frames(old_sprite_frames: SpriteFrames, resource_pack := "") -> SpriteFrames:
|
||||
var new_frames = SpriteFrames.new()
|
||||
new_frames.remove_animation("default")
|
||||
for i in old_sprite_frames.get_animation_names():
|
||||
new_frames.add_animation(i)
|
||||
for x in old_sprite_frames.get_frame_count(i):
|
||||
var frame = AtlasTexture.new()
|
||||
var old_frame = old_sprite_frames.get_frame_texture(i, x)
|
||||
frame.atlas = get_override_resource(old_frame.atlas, resource_pack)
|
||||
frame.region = old_frame.region
|
||||
new_frames.add_frame(i, frame, old_sprite_frames.get_frame_duration(i, x))
|
||||
new_frames.set_animation_loop(i, old_sprite_frames.get_animation_loop(i))
|
||||
new_frames.set_animation_speed(i, old_sprite_frames.get_animation_speed(i))
|
||||
return new_frames
|
||||
|
||||
static func get_pure_resource_path(resource_path := "") -> String:
|
||||
if Settings.file.visuals.resource_packs.is_empty() == false:
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
var new_path = get_override_resource_path(resource_path, i)
|
||||
new_path = new_path.replace("user://custom_characters/", "user://resource_packs/" + new_path + "/Sprites/Players/CustomCharacters/")
|
||||
if FileAccess.file_exists(new_path):
|
||||
return new_path
|
||||
return resource_path
|
||||
|
||||
static func get_override_resource_path(resource_path := "", resource_pack := "") -> String:
|
||||
if resource_pack != "":
|
||||
return resource_path.replace("res://Assets", "user://resource_packs/" + resource_pack)
|
||||
else:
|
||||
return resource_path
|
1
Scripts/Classes/Components/ResourceSetter.gd.uid
Executable file
1
Scripts/Classes/Components/ResourceSetter.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://cq6f682453q6o
|
313
Scripts/Classes/Components/ResourceSetterNew.gd
Normal file
313
Scripts/Classes/Components/ResourceSetterNew.gd
Normal file
@@ -0,0 +1,313 @@
|
||||
class_name ResourceSetterNew
|
||||
extends Node
|
||||
|
||||
@export var node_to_affect: Node = null
|
||||
@export var property_node: Node = null
|
||||
@export var property_name := ""
|
||||
@export var mode: ResourceMode = ResourceMode.SPRITE_FRAMES
|
||||
@export var resource_json: JSON = null:
|
||||
set(value):
|
||||
resource_json = value
|
||||
update_resource()
|
||||
|
||||
enum ResourceMode {SPRITE_FRAMES, TEXTURE, AUDIO, RAW}
|
||||
@export var use_cache := true
|
||||
|
||||
static var cache := {}
|
||||
static var property_cache := {}
|
||||
|
||||
var current_json_path := ""
|
||||
|
||||
static var state := [0, 0]
|
||||
|
||||
static var pack_configs := {}
|
||||
|
||||
var config_to_use := {}
|
||||
|
||||
var is_random := false
|
||||
|
||||
signal updated
|
||||
|
||||
@export var force_properties := {}
|
||||
var update_on_spawn := true
|
||||
|
||||
func _init() -> void:
|
||||
set_process_mode(Node.PROCESS_MODE_ALWAYS)
|
||||
|
||||
func _ready() -> void:
|
||||
safety_check()
|
||||
if update_on_spawn:
|
||||
update_resource()
|
||||
Global.level_time_changed.connect(update_resource)
|
||||
Global.level_theme_changed.connect(update_resource)
|
||||
|
||||
|
||||
func safety_check() -> void:
|
||||
if Settings.file.visuals.resource_packs.has("BaseAssets") == false:
|
||||
Settings.file.visuals.resource_packs.append("BaseAssets")
|
||||
|
||||
func update_resource() -> void:
|
||||
randomize()
|
||||
if is_inside_tree() == false or is_queued_for_deletion() or resource_json == null or node_to_affect == null:
|
||||
return
|
||||
if state != [Global.level_theme, Global.theme_time]:
|
||||
cache.clear()
|
||||
property_cache.clear()
|
||||
if node_to_affect != null:
|
||||
var resource = get_resource(resource_json)
|
||||
node_to_affect.set(property_name, resource)
|
||||
if node_to_affect is AnimatedSprite2D:
|
||||
node_to_affect.play()
|
||||
state = [Global.level_theme, Global.theme_time]
|
||||
updated.emit()
|
||||
|
||||
func get_resource(json_file: JSON) -> Resource:
|
||||
if cache.has(json_file.resource_path) and use_cache and force_properties.is_empty():
|
||||
if property_cache.has(json_file.resource_path):
|
||||
apply_properties(property_cache[json_file.resource_path])
|
||||
return cache[json_file.resource_path]
|
||||
|
||||
var resource: Resource = null
|
||||
var resource_path = json_file.resource_path
|
||||
config_to_use = {}
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
resource_path = get_resource_pack_path(resource_path, i)
|
||||
|
||||
var source_json = JSON.parse_string(FileAccess.open(resource_path, FileAccess.READ).get_as_text())
|
||||
if source_json == null:
|
||||
Global.log_error("Error parsing " + resource_path + "!")
|
||||
return
|
||||
var json = source_json.duplicate()
|
||||
var source_resource_path = ""
|
||||
if json.has("variations"):
|
||||
json = get_variation_json(json.variations)
|
||||
if json.has("source"):
|
||||
if json.get("source") is String:
|
||||
source_resource_path = json_file.resource_path.replace(json_file.resource_path.get_file(), json.source)
|
||||
else:
|
||||
Global.log_error("Error getting variations! " + resource_path)
|
||||
return
|
||||
for i in Settings.file.visuals.resource_packs:
|
||||
source_resource_path = get_resource_pack_path(source_resource_path, i)
|
||||
if json.has("rect"):
|
||||
resource = load_image_from_path(source_resource_path)
|
||||
var atlas = AtlasTexture.new()
|
||||
atlas.atlas = resource
|
||||
atlas.region = Rect2(json.rect[0], json.rect[1], json.rect[2], json.rect[3])
|
||||
resource = atlas
|
||||
if json.has("properties"):
|
||||
apply_properties(json.get("properties"))
|
||||
if use_cache:
|
||||
property_cache[json_file.resource_path] = json.properties.duplicate()
|
||||
elif source_json.has("properties"):
|
||||
apply_properties(source_json.get("properties"))
|
||||
if use_cache:
|
||||
property_cache[json_file.resource_path] = source_json.properties.duplicate()
|
||||
match mode:
|
||||
ResourceMode.SPRITE_FRAMES:
|
||||
var animation_json = {}
|
||||
if json.has("animations"):
|
||||
animation_json = json.get("animations")
|
||||
elif source_json.has("animations"):
|
||||
animation_json = source_json.get("animations")
|
||||
if animation_json != {}:
|
||||
resource = load_image_from_path(source_resource_path)
|
||||
if json.has("rect"):
|
||||
var atlas = AtlasTexture.new()
|
||||
atlas.atlas = resource
|
||||
atlas.region = Rect2(json.rect[0], json.rect[1], json.rect[2], json.rect[3])
|
||||
resource = atlas
|
||||
resource = create_sprite_frames_from_image(resource, animation_json)
|
||||
else:
|
||||
resource = load_image_from_path(source_resource_path)
|
||||
if json.has("rect"):
|
||||
var atlas = AtlasTexture.new()
|
||||
atlas.atlas = resource
|
||||
atlas.region = Rect2(json.rect[0], json.rect[1], json.rect[2], json.rect[3])
|
||||
resource = atlas
|
||||
var sprite_frames = SpriteFrames.new()
|
||||
sprite_frames.add_frame("default", resource)
|
||||
resource = sprite_frames
|
||||
ResourceMode.TEXTURE:
|
||||
if json.get("source") is Array:
|
||||
resource = AnimatedTexture.new()
|
||||
resource.frames = json.get("source").size()
|
||||
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:
|
||||
resource = load_image_from_path(source_resource_path)
|
||||
if json.has("rect"):
|
||||
var rect = json.rect
|
||||
var atlas = AtlasTexture.new()
|
||||
atlas.atlas = resource
|
||||
atlas.region = Rect2(rect[0], rect[1], rect[2], rect[3])
|
||||
resource = atlas
|
||||
ResourceMode.AUDIO:
|
||||
resource = load_audio_from_path(source_resource_path)
|
||||
ResourceMode.RAW:
|
||||
pass
|
||||
if cache.has(json_file.resource_path) == false and use_cache and not is_random:
|
||||
cache[json_file.resource_path] = resource
|
||||
return resource
|
||||
|
||||
func apply_properties(properties := {}) -> void:
|
||||
if property_node == null:
|
||||
return
|
||||
for i in properties.keys():
|
||||
property_node.set(i, properties[i])
|
||||
|
||||
func get_variation_json(json := {}) -> Dictionary:
|
||||
var level_theme = Global.level_theme
|
||||
if force_properties.has("Theme"):
|
||||
level_theme = force_properties.Theme
|
||||
|
||||
for i in json.keys().filter(func(key): return key.contains("config:")):
|
||||
if config_to_use != {}:
|
||||
var option_name = i.get_slice(":", 1)
|
||||
if config_to_use.options.has(option_name):
|
||||
json = get_variation_json(json[i][config_to_use.options[option_name]])
|
||||
break
|
||||
|
||||
if json.has(level_theme) == false:
|
||||
level_theme = "default"
|
||||
if json.has(level_theme):
|
||||
if json.get(level_theme).has("link"):
|
||||
json = get_variation_json(json[json.get(level_theme).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[level_theme])
|
||||
|
||||
var level_time = Global.theme_time
|
||||
if force_properties.has("Time"):
|
||||
level_time = force_properties.Time
|
||||
if json.has(level_time):
|
||||
json = get_variation_json(json[level_time])
|
||||
|
||||
var campaign = Global.current_campaign
|
||||
if force_properties.has("Campaign"):
|
||||
is_random = true
|
||||
campaign = force_properties.Campaign
|
||||
if json.has(campaign) == false:
|
||||
campaign = "SMB1"
|
||||
if json.has(campaign):
|
||||
if json.get(campaign).has("link"):
|
||||
json = get_variation_json(json[json.get(campaign).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[campaign])
|
||||
|
||||
if json.has("choices"):
|
||||
is_random = true
|
||||
json = get_variation_json(json.choices.pick_random())
|
||||
|
||||
var world = "World" + str(Global.world_num)
|
||||
if force_properties.has("World"):
|
||||
is_random = true
|
||||
world = "World" + str(force_properties.World)
|
||||
print(world)
|
||||
if json.has(world) == false:
|
||||
world = "World1"
|
||||
if json.has(world):
|
||||
if json.get(world).has("link"):
|
||||
json = get_variation_json(json[json.get(world).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[world])
|
||||
|
||||
var level_string = "Level" + str(Global.level_num)
|
||||
if json.has(level_string) == false:
|
||||
level_string = "Level1"
|
||||
if json.has(level_string):
|
||||
if json.get(level_string).has("link"):
|
||||
json = get_variation_json(json[json.get(level_string).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[level_string])
|
||||
|
||||
var game_mode = "GameMode:" + Global.game_mode_strings[Global.current_game_mode]
|
||||
if json.has(game_mode) == false:
|
||||
game_mode = "GameMode:" + Global.game_mode_strings[0]
|
||||
if json.has(game_mode):
|
||||
if json.get(game_mode).has("link"):
|
||||
json = get_variation_json(json[json.get(game_mode).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[game_mode])
|
||||
|
||||
var chara = "Character:" + Player.CHARACTERS[int(Global.player_characters[0])]
|
||||
if json.has(chara) == false:
|
||||
chara = "Character:Mario"
|
||||
if json.has(chara):
|
||||
if json.get(chara).has("link"):
|
||||
json = get_variation_json(json[json.get(chara).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[chara])
|
||||
|
||||
var boo = "RaceBoo:" + str(BooRaceHandler.boo_colour)
|
||||
if json.has(boo) == false:
|
||||
boo = "RaceBoo:0"
|
||||
if force_properties.has("RaceBoo"):
|
||||
boo = "RaceBoo:" + str(force_properties["RaceBoo"])
|
||||
if json.has(boo):
|
||||
if json.get(boo).has("link"):
|
||||
json = get_variation_json(json[json.get(boo).get("link")])
|
||||
else:
|
||||
json = get_variation_json(json[boo])
|
||||
|
||||
return json
|
||||
|
||||
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
|
||||
|
||||
func create_sprite_frames_from_image(image: Resource, animation_json := {}) -> SpriteFrames:
|
||||
var sprite_frames = SpriteFrames.new()
|
||||
sprite_frames.remove_animation("default")
|
||||
for anim_name in animation_json.keys():
|
||||
sprite_frames.add_animation(anim_name)
|
||||
for frame in animation_json[anim_name].frames:
|
||||
var frame_texture = AtlasTexture.new()
|
||||
frame_texture.atlas = image
|
||||
frame_texture.region = Rect2(frame[0], frame[1], frame[2], frame[3])
|
||||
frame_texture.filter_clip = true
|
||||
sprite_frames.add_frame(anim_name, frame_texture)
|
||||
sprite_frames.set_animation_loop(anim_name, animation_json[anim_name].loop)
|
||||
sprite_frames.set_animation_speed(anim_name, animation_json[anim_name].speed)
|
||||
|
||||
return sprite_frames
|
||||
|
||||
func clear_cache() -> void:
|
||||
for i in cache.keys():
|
||||
if cache[i] == null:
|
||||
cache.erase(i)
|
||||
cache.clear()
|
||||
property_cache.clear()
|
||||
|
||||
func load_image_from_path(path := "") -> ImageTexture:
|
||||
if path.contains("res://"):
|
||||
if path.contains("NULL"):
|
||||
return null
|
||||
return load(path)
|
||||
var image = Image.new()
|
||||
if path == "":
|
||||
print([path, owner.name])
|
||||
image.load(path)
|
||||
return ImageTexture.create_from_image(image)
|
||||
|
||||
func load_audio_from_path(path := "") -> AudioStream:
|
||||
var stream = null
|
||||
if path.contains("res://"):
|
||||
return load(path)
|
||||
if path.contains(".wav"):
|
||||
stream = AudioStreamWAV.load_from_file(path)
|
||||
elif path.contains(".mp3"):
|
||||
stream = AudioStreamMP3.load_from_file(path)
|
||||
return stream
|
1
Scripts/Classes/Components/ResourceSetterNew.gd.uid
Executable file
1
Scripts/Classes/Components/ResourceSetterNew.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://cbal8ms2oe1ik
|
12
Scripts/Classes/Components/ScalableCollisionPolygon.gd
Normal file
12
Scripts/Classes/Components/ScalableCollisionPolygon.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
@tool
|
||||
extends CollisionPolygon2D
|
||||
|
||||
@export var offset := Vector2.ZERO
|
||||
@export var height := 0.0
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
update()
|
||||
|
||||
func update() -> void:
|
||||
var height_to_use = height
|
||||
position.y = -height_to_use / 2 * scale.y - offset.y
|
@@ -0,0 +1 @@
|
||||
uid://cwti0ks5sfov3
|
17
Scripts/Classes/Components/ScalableCollisionShape.gd
Normal file
17
Scripts/Classes/Components/ScalableCollisionShape.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
@tool
|
||||
extends CollisionShape2D
|
||||
|
||||
@export var offset := Vector2.ZERO
|
||||
@export var link: Node2D
|
||||
|
||||
func _ready() -> void:
|
||||
set_process(Engine.is_editor_hint())
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
update()
|
||||
|
||||
func update() -> void:
|
||||
var height_to_use = shape.size.y
|
||||
if link != null:
|
||||
height_to_use *= link.scale.y * link.scale.y
|
||||
position.y = -height_to_use / 2 * scale.y - offset.y
|
1
Scripts/Classes/Components/ScalableCollisionShape.gd.uid
Normal file
1
Scripts/Classes/Components/ScalableCollisionShape.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cp1bh6fi6tpa5
|
27
Scripts/Classes/Components/ScoreNoteSpawner.gd
Normal file
27
Scripts/Classes/Components/ScoreNoteSpawner.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
class_name ScoreNoteSpawner
|
||||
extends Node
|
||||
const ONE_UP_NOTE = preload("res://Scenes/Parts/OneUpNote.tscn")
|
||||
const SCORE_NOTE = preload("res://Scenes/Parts/ScoreNote.tscn")
|
||||
@export var note_offset := Vector2(0, -8)
|
||||
@export var add_score := false
|
||||
@export var play_sfx := false
|
||||
|
||||
func spawn_note(amount = 100, amount_2 := 0) -> void:
|
||||
if amount is not int or amount_2 != 0:
|
||||
amount = amount_2
|
||||
var note = SCORE_NOTE.instantiate()
|
||||
note.global_position = owner.global_position + note_offset
|
||||
if add_score:
|
||||
Global.score += amount
|
||||
note.get_node("Container/Label").text = str(amount)
|
||||
if play_sfx:
|
||||
play_death_sfx()
|
||||
Global.current_level.add_child(note)
|
||||
|
||||
func play_death_sfx() -> void:
|
||||
AudioManager.play_sfx("kick", owner.global_position)
|
||||
|
||||
func spawn_one_up_note() -> void:
|
||||
var note = ONE_UP_NOTE.instantiate()
|
||||
note.global_position = owner.global_position + note_offset
|
||||
owner.add_sibling(note)
|
1
Scripts/Classes/Components/ScoreNoteSpawner.gd.uid
Executable file
1
Scripts/Classes/Components/ScoreNoteSpawner.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://5octqlf4ohel
|
21
Scripts/Classes/Components/SecondQuestReplaceComponent.gd
Normal file
21
Scripts/Classes/Components/SecondQuestReplaceComponent.gd
Normal file
@@ -0,0 +1,21 @@
|
||||
class_name SecondQuestReplacer
|
||||
extends Node
|
||||
|
||||
@export_file("*.tscn") var new_scene := ""
|
||||
@export var properties: Array[String] = []
|
||||
|
||||
func _ready() -> void:
|
||||
if Global.second_quest and new_scene != "" and new_scene != owner.scene_file_path:
|
||||
if owner.owner != null:
|
||||
await owner.owner.ready
|
||||
var node = load(new_scene).instantiate()
|
||||
node.global_position = owner.global_position
|
||||
node.global_rotation = owner.global_rotation
|
||||
for i in properties:
|
||||
node.set(i, owner.get(i))
|
||||
owner.add_sibling(node)
|
||||
if owner is RopeElevatorPlatform:
|
||||
owner.linked_platform.linked_platform = node
|
||||
owner.queue_free()
|
||||
else:
|
||||
queue_free()
|
@@ -0,0 +1 @@
|
||||
uid://d0mqkvopasu8k
|
18
Scripts/Classes/Components/ShellDetection.gd
Normal file
18
Scripts/Classes/Components/ShellDetection.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
class_name ShellDetection
|
||||
extends Node
|
||||
|
||||
@export var hitbox: Area2D = null
|
||||
|
||||
signal moving_shell_entered(shell: Node2D)
|
||||
|
||||
func _ready() -> void:
|
||||
hitbox.area_entered.connect(area_entered)
|
||||
|
||||
func area_entered(area: Area2D) -> void:
|
||||
if area.owner is Shell and area.owner != owner:
|
||||
if abs(area.owner.velocity.x) > 0:
|
||||
moving_shell_entered.emit(area.owner)
|
||||
area.owner.add_combo()
|
||||
|
||||
func destroy_shell(shell: Shell) -> void:
|
||||
shell.die_from_object(owner)
|
1
Scripts/Classes/Components/ShellDetection.gd.uid
Executable file
1
Scripts/Classes/Components/ShellDetection.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://bbww34oiexbx2
|
10
Scripts/Classes/Components/TileGrabber.gd
Executable file
10
Scripts/Classes/Components/TileGrabber.gd
Executable file
@@ -0,0 +1,10 @@
|
||||
class_name TileGrabber
|
||||
extends Node
|
||||
|
||||
@export var value_name := "item"
|
||||
@export var saved_node: Node = null
|
||||
@export var delete_grabbed := false
|
||||
|
||||
func tile_grabbed(tile: Node) -> void:
|
||||
saved_node = tile
|
||||
owner.set(value_name, saved_node)
|
1
Scripts/Classes/Components/TileGrabber.gd.uid
Executable file
1
Scripts/Classes/Components/TileGrabber.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://cxucnfgd5yivr
|
21
Scripts/Classes/Components/TilesetTextureSetter.gd
Normal file
21
Scripts/Classes/Components/TilesetTextureSetter.gd
Normal file
@@ -0,0 +1,21 @@
|
||||
class_name TilesetTextureSetter
|
||||
extends Node
|
||||
|
||||
@export var tile_map: TileMapLayer
|
||||
@export var texture: Texture = null:
|
||||
set(value):
|
||||
texture = value
|
||||
texture_changed.emit()
|
||||
|
||||
signal texture_changed
|
||||
|
||||
@export var atlas_id := 0
|
||||
|
||||
func _ready() -> void:
|
||||
update()
|
||||
texture_changed.connect(update)
|
||||
|
||||
func update() -> void:
|
||||
var source = tile_map.tile_set.get_source(atlas_id)
|
||||
if source != null:
|
||||
source.texture = texture
|
1
Scripts/Classes/Components/TilesetTextureSetter.gd.uid
Executable file
1
Scripts/Classes/Components/TilesetTextureSetter.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://73oviwf6bbys
|
33
Scripts/Classes/Components/TimerSprite.gd
Normal file
33
Scripts/Classes/Components/TimerSprite.gd
Normal file
@@ -0,0 +1,33 @@
|
||||
class_name TimerSprite
|
||||
extends Sprite2D
|
||||
|
||||
@export var max_value := 1.0
|
||||
@export var value_name := ""
|
||||
|
||||
@export_enum("Global", "Player", "Timer") var object := 0
|
||||
@export var timer: Timer = null
|
||||
|
||||
@export var warn_sfx: AudioStreamPlayer = null
|
||||
|
||||
@export var warn_threshold := 0.7
|
||||
|
||||
var can_warn := false
|
||||
|
||||
func _ready() -> void:
|
||||
texture = ResourceSetter.get_resource(texture, self)
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var node = owner if object == 1 else Global
|
||||
if object == 2:
|
||||
node = timer
|
||||
var value = node.get(value_name)
|
||||
var percent = inverse_lerp(max_value, 0, value)
|
||||
percent = clamp(percent, 0, 1)
|
||||
get_parent().visible = percent < 1 and Settings.file.visuals.visible_timers
|
||||
frame = lerp(0, 6, percent)
|
||||
if percent >= warn_threshold and Settings.file.audio.extra_sfx == 1:
|
||||
if can_warn:
|
||||
can_warn = false
|
||||
AudioManager.play_global_sfx("timer_warning")
|
||||
else:
|
||||
can_warn = true
|
1
Scripts/Classes/Components/TimerSprite.gd.uid
Normal file
1
Scripts/Classes/Components/TimerSprite.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dn5efttgugwvb
|
12
Scripts/Classes/Components/TimerStarter.gd
Executable file
12
Scripts/Classes/Components/TimerStarter.gd
Executable file
@@ -0,0 +1,12 @@
|
||||
class_name TimerStarter
|
||||
extends Node
|
||||
|
||||
func _ready() -> void:
|
||||
if Global.level_editor != null:
|
||||
Global.level_editor.level_start.connect(start_timers)
|
||||
start_timers()
|
||||
|
||||
func start_timers() -> void:
|
||||
for i in get_children():
|
||||
if i is Timer:
|
||||
i.start()
|
1
Scripts/Classes/Components/TimerStarter.gd.uid
Executable file
1
Scripts/Classes/Components/TimerStarter.gd.uid
Executable file
@@ -0,0 +1 @@
|
||||
uid://cucfssmfmttbk
|
19
Scripts/Classes/Components/TrackJoint.gd
Normal file
19
Scripts/Classes/Components/TrackJoint.gd
Normal file
@@ -0,0 +1,19 @@
|
||||
class_name TrackJoint
|
||||
extends Node
|
||||
|
||||
signal attached
|
||||
|
||||
@export var offset := Vector2(0, 8)
|
||||
@export var movement_node: Node = null
|
||||
@export var disable_physics := true
|
||||
var rider: TrackRider = null
|
||||
var is_attached := false
|
||||
|
||||
func detach() -> void:
|
||||
if rider == null: return
|
||||
owner.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_INHERIT
|
||||
rider.attached_entity = null
|
||||
rider.queue_free()
|
||||
get_parent().reparent(rider.get_parent())
|
||||
owner.reset_physics_interpolation()
|
||||
|
1
Scripts/Classes/Components/TrackJoint.gd.uid
Normal file
1
Scripts/Classes/Components/TrackJoint.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d4a7yp6e55u8t
|
Reference in New Issue
Block a user