Wire all twelve levels with billboard prefabs, autoload systems (inventory, achievements, mock shop, DE/EN/BY), and satire audio locks so the Title→End flow is playable with placeholder assets.
57 lines
1.5 KiB
GDScript
57 lines
1.5 KiB
GDScript
extends Node
|
|
## Achievement unlock + persistence.
|
|
|
|
signal unlocked(achievement_id: String, title: String)
|
|
|
|
var _defs: Array = []
|
|
var _unlocked: Dictionary = {} # id -> true
|
|
|
|
func _ready() -> void:
|
|
_load_defs()
|
|
|
|
func _load_defs() -> void:
|
|
var file := FileAccess.open("res://data/achievements.json", FileAccess.READ)
|
|
if file == null:
|
|
push_error("Missing achievements.json")
|
|
return
|
|
var parsed: Variant = JSON.parse_string(file.get_as_text())
|
|
if typeof(parsed) == TYPE_ARRAY:
|
|
_defs = parsed
|
|
|
|
func unlock(achievement_id: String) -> void:
|
|
if _unlocked.get(achievement_id, false):
|
|
return
|
|
_unlocked[achievement_id] = true
|
|
var title := achievement_id
|
|
for entry in _defs:
|
|
if str(entry.get("id", "")) == achievement_id:
|
|
title = Locale.tr_key(str(entry.get("title_key", achievement_id)))
|
|
break
|
|
unlocked.emit(achievement_id, title)
|
|
_check_all()
|
|
GameState.save_game()
|
|
|
|
func is_unlocked(achievement_id: String) -> bool:
|
|
return bool(_unlocked.get(achievement_id, false))
|
|
|
|
func get_defs() -> Array:
|
|
return _defs
|
|
|
|
func _check_all() -> void:
|
|
if _unlocked.get("all_burgers", false):
|
|
return
|
|
for entry in _defs:
|
|
var id := str(entry.get("id", ""))
|
|
if id == "all_burgers":
|
|
continue
|
|
if not _unlocked.get(id, false):
|
|
return
|
|
_unlocked["all_burgers"] = true
|
|
var title := Locale.tr_key("ach_all_title")
|
|
unlocked.emit("all_burgers", title)
|
|
|
|
func serialize() -> Dictionary:
|
|
return {"unlocked": _unlocked.duplicate()}
|
|
|
|
func deserialize(data: Dictionary) -> void:
|
|
_unlocked = data.get("unlocked", {}).duplicate()
|