hero-mark-2/autoloads/game.gd

365 lines
9.7 KiB
GDScript

extends Node
## difficulty levels
enum Difficulty {
SWEET, # slower enemies, infinite lives
SALTY, # normal enemies, infinite lives
SPICY, # normal enemies, 3 lives, DEFAULT
PUNGENT, # faster enemies, 3 lives
}
# score multiplier for easy mode
const EASY_DIFFICULTY_MODIFIER: float = 0.75
## resolution the game renders at
const RESOLUTION := Vector2(256,192)
const DIFFICULTY_NAMES := ["Sweet","Salty","Spicy","Pungent"]
#== collectibles ==#
var keys: int = 0 # collected keys
## which stars are collected
var stars_collected := [false,false,false,false,false]
var stars : int setget , _get_stars # total stars
## which stars are collected
var shards_collected := [false,false,false,false,false,false,false,false]
## how many shards collected
var shards: int setget , _get_shards # total shards
var arrows: int = 0 # current arrows
#== stats ==#
var lives: int = 2
var deaths: int = 0
var time: float = 0.0
#== score ==#
var score: int = 0
var arrows_bonus: int = 0
var collection_bonus: int = 0
var time_bonus: int = 0
var life_bonus: int = 0
var perfect_bonus: int = 0
var final_score: int = 0
var old_high_score: int = 0
#== state ==#
var current_sector := Vector2.ZERO
var respawn_point := Vector2(32,166)
var current_level: int = 0
var difficulty: int = Difficulty.SPICY setget _set_difficulty
var enemy_speed_factor: float = 1.0 # multiplier of enemy speed
var is_easy_mode: bool = false # whether to do easy-specific behaviors
var use_lives: bool = false
var can_pause: bool = true
var can_restart: bool = true
var current_palette: String = "default"
var still_playing: bool = false
var last_mm_button = null
var alternate_death = null
var can_use_shield: bool = false
#== marathon mode ==#
var marathon_mode: bool = false
var marathon_score: int = 0
var marathon_lives: int = 0
var marathon_shards: int = 0
var marathon_deaths: int = 0
func _get_stars() -> int:
return stars_collected.count(true)
func _get_shards() -> int:
return shards_collected.count(true)
# stuff to change when setting difficulty
func _set_difficulty(value: int) -> void:
difficulty = value
match difficulty:
Difficulty.SWEET:
is_easy_mode = true
enemy_speed_factor = 0.75
use_lives = false
Difficulty.SALTY:
is_easy_mode = false
enemy_speed_factor = 1.0
use_lives = false
Difficulty.SPICY:
is_easy_mode = false
enemy_speed_factor = 1.0
use_lives = true
Difficulty.PUNGENT:
is_easy_mode = false
enemy_speed_factor = 1.25
use_lives = true
#Instances a node
func instance_node(node:PackedScene,x:float,y:float,parent):
var Instance = node.instance()
Instance.global_position = Vector2(x,y)
parent.call_deferred("add_child", Instance)
#Get position in sectors
func get_sector(pos):
return (pos / RESOLUTION).floor()
#Return the current Map
func get_map():
return get_tree().get_nodes_in_group("map").front()
## tally up scores
func tally_scores() -> void:
var map = get_map()
# arrows bonus
arrows_bonus = arrows * 100
# collection bonus
if keys >= 50:
collection_bonus += 500
if _get_shards() >= 5:
collection_bonus += 500
# 100% collection
if keys >= 50 and _get_shards() >= 5:
collection_bonus += 250
shards_collected[5] = true
# 100% time bonus
if time < map.target_time_100:
time_bonus = max(2500 - int(2500.0 * time / map.target_time_100), 0) as int
shards_collected[6] = true
else:
# any% time bonus
if time < map.target_time_any:
time_bonus = max(2500 - int(2500.0 * time / map.target_time_any), 0) as int
shards_collected[6] = true
# life bonus
if deaths == 0:
life_bonus = 1500
shards_collected[7] = true
elif deaths == 1:
life_bonus = 500
# perfect bonus
if shards_collected[5] and shards_collected[6] and shards_collected[7]:
perfect_bonus += 1000
# final score
final_score = score + arrows_bonus + collection_bonus + time_bonus + life_bonus + perfect_bonus
# easy mode modifier
if difficulty == Difficulty.SWEET:
final_score *= EASY_DIFFICULTY_MODIFIER
if marathon_mode:
marathon_shards += shards_collected.count(true)
marathon_score += final_score
else:
Game.save()
#Go to new map
func change_map(map: PackedScene) -> void:
get_tree().paused = true
can_pause = false
Fade.fade_out(Options.transition_speed_secs)
yield(Fade, "fade_finished")
can_pause = true
# save deaths
if not marathon_mode:
var save_id = LevelData.levels[current_level].save_id
var save_data: Save.LevelSaveData = Save.current_file.levels[save_id]
save_data.deaths += deaths
Save.current_file.play_time += time
Save.current_file.save_to_file()
# clear
clear_collectibles()
StainLayer.reset()
#Loop is so no more than one level is loaded at a time
SceneManager.current_scene = map.instance()
#Clear data
func clear_collectibles() -> void:
# collectibles
keys = 0
stars_collected.fill(false)
shards_collected.fill(false)
arrows = 0
if not marathon_mode:
lives = 2
deaths = 0
# score
score = 0
collection_bonus = 0
time_bonus = 0
life_bonus = 0
perfect_bonus = 0
final_score = 0
#Save
func save():
if marathon_mode:
return
var new_super := Save.current_file.is_super_player()
# get level's save data object
var save_id = LevelData.levels[current_level].save_id
var save_data: Save.LevelSaveData = Save.current_file.levels[save_id]
old_high_score = max(save_data.score_100, save_data.score_any)
# save score and time depending on completion
if _get_shards() >= 5 && keys >= 50:
save_data.score_100 = max(save_data.score_100, final_score) as int
save_data.time_100 = min(save_data.time_100, time)
else:
save_data.score_any = max(save_data.score_any, final_score) as int
save_data.time_any = min(save_data.time_any, time)
# set shards
for i in 8:
if shards_collected[i]:
save_data.shards_collected[i] = true
# set keys
save_data.keys_collected = max(save_data.keys_collected, keys) as int
# mark as completed
save_data.completed = true
# add to playtime
Save.current_file.play_time += time
if new_super and Save.current_file.is_super_player():
Save.current_file.palette = "super_player"
# save the file
Save.current_file.save_to_file()
# smaller save function for bosses
func save_boss() -> void:
if marathon_mode:
return
var new_super := not Save.current_file.is_super_player()
var save_id = LevelData.levels[current_level].save_id
var save_data: Save.LevelSaveData = Save.current_file.levels[save_id]
save_data.time_any = min(save_data.time_any, time)
save_data.completed = true
Save.current_file.play_time += time
if new_super and Save.current_file.is_super_player():
Save.current_file.palette = "super_player"
Save.current_file.save_to_file()
# !!DEPRECATED!! convert milliseconds into M:SS:MS
func timeify(input):
if input <= 5999099:
var seconds = fmod(Game.time / 1000,60)
var minutes = floor((Game.time / 1000) / 60)
var centiseconds = fmod(floor(seconds * 100),100)
return ("%02d" % minutes) + ":" + ("%02d" % seconds) + "." + ("%02d" % centiseconds)
elif input == INF:
return "-:--.--"
else:
return "99:59.99"
# convert seconds into M:SS.MS
func format_time(seconds: float) -> String:
if is_inf(seconds) or is_nan(seconds): # infinite
return "--:--.--"
elif seconds >= 6000.0: # 10 minutes or greater
return "99:99.99"
else:
var minutes = floor(seconds / 60.0)
var centiseconds = fmod(floor(seconds * 100.0), 100.0)
return "%02d:%02d.%02d" % [minutes, fmod(seconds, 60.0), centiseconds]
#Restart level
func restart_level():
if can_restart:
Save.current_file.play_time += time
Save.current_file.levels[LevelData.levels[current_level].save_id].deaths += deaths
Save.current_file.save_to_file()
clear_collectibles()
Audio.ac_climb.stop()
Audio.ac_die.stop()
Engine.time_scale = 1.0
for tween in get_tree().get_processed_tweens():
tween.kill()
change_map(load(get_map().filename))
Audio.ac_music.stream_paused = false
#Freeze frame
func freeze_frame(freeze_time):
get_tree().paused = true
var timer = get_tree().create_timer(freeze_time, true)
timer.connect("timeout", get_tree(), "set_pause", [false])
return timer
#Check if 100%ed
func has_collection_bonus():
return _get_shards() == 5 && keys == 50
# called when player dies
func _on_player_died() -> void:
deaths += 1
if marathon_mode:
marathon_deaths += 1
if use_lives and lives <= 0:
still_playing = false
can_restart = false
can_pause = false
if not marathon_mode:
Save.current_file.play_time += time
Save.current_file.levels[LevelData.levels[current_level].save_id].deaths += deaths
Save.current_file.save_to_file()
clear_collectibles()
Audio.play_sound(Audio.a_game_over, Audio.ac_die)
get_tree().get_nodes_in_group("player")[0].queue_free()
var time_tween = create_tween()
time_tween.tween_property(Engine, "time_scale", 0.1, 0.3)
Audio.ac_music.stream_paused = true
yield(time_tween, "finished")
yield(get_tree().create_timer(1.0 * 0.1), "timeout")
Engine.time_scale = 1.0
Fade.fade_out(Options.transition_speed_secs)
yield(Fade, "fade_finished")
if marathon_mode:
SceneManager.current_scene = load("res://menus/main_menu.tscn").instance()
else:
var map = get_map()
var gover = load("res://menus/game_over.tscn").instance()
map.add_child(gover)
can_restart = true
can_pause = true
else:
# count death
lives -= 1
# play death sound
if alternate_death:
Audio.play_sound(alternate_death, Audio.ac_die)
else:
Audio.play_sound(Audio.a_die, Audio.ac_die)
alternate_death = null
# death score penalty
if use_lives == false && lives < 0:
score = max(0, score - 500) as int
# freezeframe
Game.freeze_frame(0.3)
func check_time_bonus():
var map = get_map()
if keys >= 50 and _get_shards() >= 5:
# 100% time bonus
if time < map.target_time_100:
return true
else:
return false
else:
# any% time bonus
if time < map.target_time_any:
return true
else:
return false