extends CraftyGame
const MOVE_SPEED := 7.0
const GRAVITY := 20.0
const AUTO_SAVE_INTERVAL := 15.0
const QUEST_XP_REWARD := 25
const QUEST_CREDIT_REWARD := 10
const POTION_COST := 8
var _auto_save_accum := 0.0
func get_prediction_params() -> Dictionary:
return {"move_speed": MOVE_SPEED, "gravity": GRAVITY}
func _game_init() -> void:
var spawn_root := get_node_or_null("SpawnPoints")
if spawn_root:
for child in spawn_root.get_children():
if child is Node3D:
spawn_points.append(child.global_position)
if spawn_points.is_empty():
spawn_points = [
Vector3(-6, 1, -6),
Vector3(6, 1, -6),
Vector3(-6, 1, 6),
Vector3(6, 1, 6)
]
func _game_start() -> void:
Crafty.set_time_limit(1800.0)
Crafty.send_announcement("Quest Arena started")
func _game_end() -> void:
for p in get_players():
_save_player_snapshot(p)
Crafty.send_announcement("Quest Arena session saved")
func _player_joined(player) -> void:
if player.has_method("respawn"):
player.respawn(get_random_spawn_point())
_load_player_snapshot(player)
_sync_player_hud_fields(player)
func _player_left(player) -> void:
_save_player_snapshot(player)
func _process(delta: float) -> void:
super._process(delta)
if not Crafty.is_server():
return
for p in get_players():
apply_default_movement(p, delta, MOVE_SPEED, GRAVITY)
_handle_player_actions(p)
_auto_save_accum += delta
if _auto_save_accum >= AUTO_SAVE_INTERVAL:
_auto_save_accum = 0.0
for p in get_players():
_save_player_snapshot(p)
func _handle_player_actions(player) -> void:
if player.input.is_action_just_pressed("quest_complete"):
_complete_quest(player)
if player.input.is_action_just_pressed("buy_potion"):
_buy_potion(player)
func _complete_quest(player) -> void:
var progress := Crafty.data.load(player, "quest_progress")
if progress == null:
progress = {"main": 0}
progress["main"] = int(progress.get("main", 0)) + 1
Crafty.data.save(player, "quest_progress", progress)
var xp := int(Crafty.data.load(player, "xp") if Crafty.data.load(player, "xp") != null else 0)
xp += QUEST_XP_REWARD
Crafty.data.save(player, "xp", xp)
var level := 1 + int(xp / 100)
Crafty.data.save(player, "level", level)
var awarded := await Crafty.economy.award(player, QUEST_CREDIT_REWARD, "quest_complete")
if awarded:
Crafty.send_announcement("%s completed a quest (+%d credits)" % [str(player.get("display_name")), QUEST_CREDIT_REWARD])
_sync_player_hud_fields(player)
func _buy_potion(player) -> void:
var purchased := await Crafty.economy.spend(player, POTION_COST, "potion_purchase")
if not purchased:
Crafty.send_announcement("%s cannot afford a potion" % str(player.get("display_name")))
return
var inventory := Crafty.data.load(player, "inventory")
if inventory == null:
inventory = {"potions": 0}
inventory["potions"] = int(inventory.get("potions", 0)) + 1
Crafty.data.save(player, "inventory", inventory)
Crafty.send_announcement("%s bought a potion" % str(player.get("display_name")))
_sync_player_hud_fields(player)
func _load_player_snapshot(player) -> void:
var level = Crafty.data.load(player, "level")
if level == null:
level = 1
var xp = Crafty.data.load(player, "xp")
if xp == null:
xp = 0
var inventory = Crafty.data.load(player, "inventory")
if inventory == null:
inventory = {"potions": 0}
var quest_progress = Crafty.data.load(player, "quest_progress")
if quest_progress == null:
quest_progress = {"main": 0}
Crafty.data.save(player, "level", level)
Crafty.data.save(player, "xp", xp)
Crafty.data.save(player, "inventory", inventory)
Crafty.data.save(player, "quest_progress", quest_progress)
func _save_player_snapshot(player) -> void:
# Data API is write-through to in-memory cache; backend flush is handled by SDK.
var level = Crafty.data.load(player, "level")
var xp = Crafty.data.load(player, "xp")
var inventory = Crafty.data.load(player, "inventory")
var quest_progress = Crafty.data.load(player, "quest_progress")
Crafty.data.save(player, "level", 1 if level == null else level)
Crafty.data.save(player, "xp", 0 if xp == null else xp)
Crafty.data.save(player, "inventory", {"potions": 0} if inventory == null else inventory)
Crafty.data.save(player, "quest_progress", {"main": 0} if quest_progress == null else quest_progress)
func _sync_player_hud_fields(player) -> void:
var level := int(Crafty.data.load(player, "level"))
var xp := int(Crafty.data.load(player, "xp"))
var inventory := Crafty.data.load(player, "inventory")
var quest_progress := Crafty.data.load(player, "quest_progress")
var balance := await Crafty.economy.get_balance(player)
player.set_synced("level", level)
player.set_synced("xp", xp)
player.set_synced("potions", int(inventory.get("potions", 0)))
player.set_synced("quest_main", int(quest_progress.get("main", 0)))
player.set_synced("credits", balance)