Ники, общий рейтинг (топ-10 по картам), таблица Tab, сдача в гонке, таймер Parkour
- Ники: профиль user://profile.cfg (client_id + ник), панель при первом запуске и по N; Net.nick_of(id); ники над призраками, в HUD/итогах гонки и таблицах - Рейтинг на сервере: лучшее время каждого игрока по картам race/parkour/metro, топ-10, user://leaderboard.json (атомарная запись, лимиты, проверка карты/комнаты/времени) - Таблица лидеров по Tab, доски топ-3 над порталами в хабе, итоги гонки с общим рейтингом - Гонка: сдача (G, удержание 1,5 с), RACE_GIVEUP; Parkour: таймер, финиш на вершине, R — перезапуск - Новые RPC (submit_profile, recv_nick, submit_record, recv_record_result, request_leaderboard, recv_leaderboard): клиент и сервер выкладываются вместе - Тесты: nicks_lb_test, race_giveup_test, parkour_run_test, nick_ui_test, ui_tour; README обновлён Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WxZo3ekR5m1af437Qzqwc1
This commit is contained in:
+44
-1
@@ -6,6 +6,8 @@ extends Node
|
||||
# --rounds=<сколько кругов пройти> --quit-race-time=<выйти из игры на этой секунде гонки>
|
||||
# --die-at-gate=<n>: после ворот n умереть (проверка возрождения лицом по трассе)
|
||||
# --fall-at-gate=<n>: после ворот n упасть в пустоту (проверка срыва ниже ворот)
|
||||
# --gu1=<план>, --gu2=<план>: сдача в круге 1 / 2. План: «cancel@1,giveup@2» — когда пройдено столько ворот,
|
||||
# держать G 1,0 с и отпустить (отмена) / держать до сдачи (проверка race_giveup_test.sh)
|
||||
# Факты печатаются строками «[имя] …»; сверяет их tools/test/race_game_test.sh.
|
||||
|
||||
const Data = preload("res://maps/race/race_data.gd")
|
||||
@@ -36,6 +38,11 @@ var spectator_logged := false
|
||||
var music_logged := false
|
||||
var music_cd_logged := false
|
||||
var freeze_logged := false
|
||||
var gu_plan := {1: [], 2: []}
|
||||
var gu_hold := -1.0
|
||||
var gu_mode := ""
|
||||
var gu_done := {}
|
||||
var gu_after_cancel := false
|
||||
|
||||
func _ready() -> void:
|
||||
for a in OS.get_cmdline_user_args():
|
||||
@@ -46,6 +53,10 @@ func _ready() -> void:
|
||||
if a.begins_with("--quit-race-time="): quit_race_time = float(a.substr(17))
|
||||
if a.begins_with("--die-at-gate="): die_gate = int(a.substr(14))
|
||||
if a.begins_with("--fall-at-gate="): fall_gate = int(a.substr(15))
|
||||
if a.begins_with("--gu1=") or a.begins_with("--gu2="):
|
||||
for e in a.substr(6).split(","):
|
||||
var q := e.split("@")
|
||||
gu_plan[int(a.substr(4, 1))].append({"mode": q[0], "gate": int(q[1])})
|
||||
route = JSON.parse_string(FileAccess.get_file_as_string("res://tools/test/race_route.json")).safe
|
||||
|
||||
func gp(w: Array) -> Vector3:
|
||||
@@ -117,7 +128,7 @@ func _physics_process(_delta: float) -> void:
|
||||
key(k, false)
|
||||
|
||||
func _wait() -> void:
|
||||
for k in ["move_forward", "sprint", "jump"]:
|
||||
for k in ["move_forward", "sprint", "jump", "giveup"]:
|
||||
key(k, false)
|
||||
if rules.waiting_for_race():
|
||||
if not spectator_logged:
|
||||
@@ -143,12 +154,44 @@ func _race() -> void:
|
||||
say("ВЫХОЖУ из игры в разгар гонки (время %.1f)" % rules.race_time())
|
||||
get_tree().quit()
|
||||
return
|
||||
if rules.gave_up.has(rules.my_id):
|
||||
for k in ["move_forward", "sprint", "jump", "giveup"]:
|
||||
key(k, false)
|
||||
if gu_hold >= 0.0: # только что сдались: фиксируем, где мы и заморожены ли
|
||||
gu_hold = -1.0
|
||||
var d := Vector2(p.global_position.x - Data.START_SLOTS[0].x, p.global_position.z - Data.START_SLOTS[0].z).length()
|
||||
say("СДАЛСЯ_БОТ unix=%.3f на_старте=%s заморожен=%s" % [Time.get_unix_time_from_system(), d < 2.0, p.input_frozen])
|
||||
return
|
||||
if rules.finish.has(rules.my_id):
|
||||
for k in ["move_forward", "sprint", "jump"]:
|
||||
key(k, false)
|
||||
return
|
||||
if rules.race_time() < delay:
|
||||
return
|
||||
# --- сдача ---
|
||||
var cur_round := rounds_done + 1
|
||||
if gu_after_cancel:
|
||||
gu_after_cancel = false
|
||||
say("ПОСЛЕ_ОТМЕНЫ hold=%.2f сдался=%s" % [rules._giveup_hold, rules.gave_up.has(rules.my_id)])
|
||||
if gu_hold < 0.0 and gu_plan.has(cur_round):
|
||||
for e in gu_plan[cur_round]:
|
||||
var gk := "%d%s%d" % [cur_round, e.mode, e.gate]
|
||||
if not gu_done.has(gk) and rules.passed.get(rules.my_id, 0) == e.gate and not p.is_dead:
|
||||
gu_done[gk] = true
|
||||
gu_hold = 0.0
|
||||
gu_mode = e.mode
|
||||
say("УДЕРЖИВАЮ G (%s) после ворот %d" % [e.mode, e.gate])
|
||||
if gu_hold >= 0.0:
|
||||
for k in ["move_forward", "sprint", "jump"]:
|
||||
key(k, false)
|
||||
key("giveup", true)
|
||||
gu_hold += get_physics_process_delta_time()
|
||||
if gu_mode == "cancel" and gu_hold >= 1.0:
|
||||
say("ОТМЕНА_УДЕРЖАНИЯ: отпускаю на %.2f с, шкала=%.2f сдался=%s" % [gu_hold, rules._giveup_hold, rules.gave_up.has(rules.my_id)])
|
||||
key("giveup", false)
|
||||
gu_hold = -1.0
|
||||
gu_after_cancel = true
|
||||
return
|
||||
# --- проверки возрождения ---
|
||||
var g: int = rules.passed.get(rules.my_id, 0)
|
||||
if not special_done and die_gate >= 0 and g == die_gate and not p.is_dead:
|
||||
|
||||
Reference in New Issue
Block a user