202 lines
4.8 KiB
GDScript
202 lines
4.8 KiB
GDScript
extends Node
|
|
|
|
const SAVE_PATH = "user://achievements.json"
|
|
const _POPUP_SCRIPT = preload("res://scripts/achievement_popup.gd")
|
|
var achievements: Array = []
|
|
|
|
func _ready() -> void:
|
|
_define()
|
|
_load()
|
|
check_all()
|
|
|
|
func _define() -> void:
|
|
achievements = [
|
|
{
|
|
"id": "first_blood",
|
|
"title": "First Blood",
|
|
"description": "Kill your very first enemy.",
|
|
"condition_type": "kills_total",
|
|
"threshold": 1,
|
|
"reward": "+10 Max HP at the start of every run",
|
|
"color": Color(0.55, 0.08, 0.08),
|
|
"icon_char": "I",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "slime_slayer",
|
|
"title": "Slime Slayer",
|
|
"description": "Kill 25 Blue Slimes.",
|
|
"condition_type": "kills_blue_slime",
|
|
"threshold": 25,
|
|
"reward": "Shurikens pierce 1 additional enemy",
|
|
"color": Color(0.15, 0.2, 0.65),
|
|
"icon_char": "B",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "fire_bane",
|
|
"title": "Fire Bane",
|
|
"description": "Kill 50 Fire Slimes.",
|
|
"condition_type": "kills_fire_slime",
|
|
"threshold": 50,
|
|
"reward": "Fireball permanently deals +20% more damage",
|
|
"color": Color(0.75, 0.28, 0.05),
|
|
"icon_char": "F",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "apprentice",
|
|
"title": "Apprentice",
|
|
"description": "Cast 50 spells in total.",
|
|
"condition_type": "spells_total",
|
|
"threshold": 50,
|
|
"reward": "Cauldron brews with only 2 fruits instead of 3",
|
|
"color": Color(0.45, 0.1, 0.7),
|
|
"icon_char": "A",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "slime_hunter",
|
|
"title": "Slime Hunter",
|
|
"description": "Kill 100 enemies in total.",
|
|
"condition_type": "kills_total",
|
|
"threshold": 100,
|
|
"reward": "Each run starts with 1 random fruit already in the cauldron",
|
|
"color": Color(0.15, 0.5, 0.15),
|
|
"icon_char": "H",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "survivor",
|
|
"title": "Survivor",
|
|
"description": "Survive 3 minutes in a single run.",
|
|
"condition_type": "survive_best",
|
|
"threshold": 180,
|
|
"reward": "Regenerate 5 HP every 10 seconds",
|
|
"color": Color(0.1, 0.4, 0.65),
|
|
"icon_char": "S",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "veteran",
|
|
"title": "Veteran",
|
|
"description": "Play 15 runs.",
|
|
"condition_type": "runs_played",
|
|
"threshold": 15,
|
|
"reward": "Start each run with 1 random perk already applied",
|
|
"color": Color(0.6, 0.45, 0.05),
|
|
"icon_char": "V",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "archmage",
|
|
"title": "Archmage",
|
|
"description": "Cast 300 spells in total.",
|
|
"condition_type": "spells_total",
|
|
"threshold": 300,
|
|
"reward": "All spells permanently deal +15% more damage",
|
|
"color": Color(0.25, 0.05, 0.5),
|
|
"icon_char": "M",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "iron_witch",
|
|
"title": "Iron Witch",
|
|
"description": "Survive 7 minutes in a single run.",
|
|
"condition_type": "survive_best",
|
|
"threshold": 420,
|
|
"reward": "+25 Max HP permanently",
|
|
"color": Color(0.25, 0.35, 0.5),
|
|
"icon_char": "W",
|
|
"unlocked": false
|
|
},
|
|
{
|
|
"id": "exterminator",
|
|
"title": "Exterminator",
|
|
"description": "Kill 500 enemies in total.",
|
|
"condition_type": "kills_total",
|
|
"threshold": 500,
|
|
"reward": "Level-up screen shows 4 perk cards instead of 3",
|
|
"color": Color(0.65, 0.05, 0.05),
|
|
"icon_char": "X",
|
|
"unlocked": false
|
|
},
|
|
]
|
|
|
|
func check_all() -> void:
|
|
var newly_unlocked: Array = []
|
|
for ach in achievements:
|
|
if ach.unlocked:
|
|
continue
|
|
if _meets(ach):
|
|
ach.unlocked = true
|
|
newly_unlocked.append(ach)
|
|
if not newly_unlocked.is_empty():
|
|
_save()
|
|
for ach in newly_unlocked:
|
|
_show_popup(ach)
|
|
|
|
func _show_popup(ach: Dictionary) -> void:
|
|
var popup = _POPUP_SCRIPT.new()
|
|
get_tree().root.add_child(popup)
|
|
popup.show_unlock(ach)
|
|
|
|
func _meets(ach: Dictionary) -> bool:
|
|
var d = StatsManager.data
|
|
var t: int = ach.threshold
|
|
match ach.condition_type:
|
|
"kills_total":
|
|
var total = 0
|
|
for v in d["kills"].values():
|
|
total += v
|
|
return total >= t
|
|
"kills_blue_slime":
|
|
return d["kills"]["blue_slime"] >= t
|
|
"kills_fire_slime":
|
|
return d["kills"]["fire_slime"] >= t
|
|
"spells_total":
|
|
var total = 0
|
|
for v in d["spells_cast"].values():
|
|
total += v
|
|
return total >= t
|
|
"survive_best":
|
|
return d["longest_run_seconds"] >= t
|
|
"runs_played":
|
|
return d["runs_played"] >= t
|
|
return false
|
|
|
|
func get_unlocked_count() -> int:
|
|
var n = 0
|
|
for ach in achievements:
|
|
if ach.unlocked:
|
|
n += 1
|
|
return n
|
|
|
|
func _save() -> void:
|
|
var ids: Array = []
|
|
for ach in achievements:
|
|
if ach.unlocked:
|
|
ids.append(ach.id)
|
|
var f = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
|
if f == null:
|
|
return
|
|
f.store_string(JSON.stringify(ids))
|
|
f.close()
|
|
|
|
func _load() -> void:
|
|
if not FileAccess.file_exists(SAVE_PATH):
|
|
return
|
|
var f = FileAccess.open(SAVE_PATH, FileAccess.READ)
|
|
if f == null:
|
|
return
|
|
var j = JSON.new()
|
|
var text = f.get_as_text()
|
|
f.close()
|
|
if j.parse(text) != OK:
|
|
return
|
|
var ids = j.get_data()
|
|
if typeof(ids) != TYPE_ARRAY:
|
|
return
|
|
for ach in achievements:
|
|
ach.unlocked = ach.id in ids
|