/battle/report-stats

Метод принимает отчет о завершенном бое и двигает счетчики objectives, которые известны только из боя.

Адрес метода

/battle/report-stats

Требует сессию пользователя

Обработка идемпотентна по battleId: клиент повторяет отправку отчета при сбое сети, поэтому повторный отчет с тем же battleId не двигает счетчики, но возвращает актуальное состояние.

battleId должен совпадать с серверной боевой сессией — отчёт с неизвестным или просроченным (дольше 6 часов) battleId отклоняется с ошибкой по параметру battleId. Режим боя (gameMode) определяется сервером по найденной сессии, а не берётся из отчёта — значение gameMode в теле запроса игнорируется.

Подходят два вида сессий:

  • уровень — battleId, который вернул /level/start или /level/continue (32 hex-символа). Режим — campaign или dungeon, по самому уровню;
  • арена — числовой battle_id, который вернул /arena/fight/start (или /arena/fight/rebattle). Режим — arena (gameMode = 2). Учитывается только строка атаки самого игрока: зеркальная строка защиты боем не является и отчёта не порождает.

Оба вида сессий выдаются сервером и оплачены игроком (энергией — уровень, попыткой или билетом — арена), поэтому исключений «режим из отчёта» здесь нет и быть не может: battleReported() двигает все общие счётчики (враги, гемы, комбо, урон), так что любая лазейка по gameMode открыла бы фарм всех счётчиков разом.

Счетчики, которые сервер знает сам (battles_played, battles_lost, levels_completed, campaign_levels_completed, dungeon_levels_completed, campaign_max_level_reached, dungeon_max_level_reached), из отчета не берутся — они приходят из /level/complete, где режим и результат серверные. Иначе бой посчитался бы дважды.

Аренные счётчики (arena_battles_played, arena_wins, arena_losses, arena_max_ap, arena_league_reached) из отчёта тоже не берутся: отчёт существует только у боя, доигранного до конца, а сдача и брошенный бой на арене — это тоже поражения, которые нужно посчитать. Они приходят из ArenaManager::applyResult() — единственной точки, через которую проходит любая завершённая атака.

Параметры

Тело запроса повторяет клиентский DTO BattleStatsReport. Поля, которых нет в таблице ниже, игнорируются.

Параметр Обязательный Тип Описание
battleId ДА string Идентификатор боя, по нему обеспечивается идемпотентность
gameMode НЕТ int Не используется — режим боя всегда определяется сервером по найденной сессии battleId. Поле оставлено для совместимости с клиентским DTO и полностью игнорируется
outcome НЕТ string win или loss. Другие значения отклоняются с ошибкой по параметру outcome
minHeroHpDuringBattle НЕТ int Минимальный запас здоровья героя за бой
enemiesDefeated НЕТ int Количество побежденных врагов за бой
combosActivated НЕТ int Количество активированных комбо
longestComboLength НЕТ int Самое длинное комбо за бой
damageDealtByChips НЕТ int Урон, нанесенный чипами
damageDealtBySkills НЕТ int Урон, нанесенный скиллами
maxDamageInSingleHit НЕТ int Максимальный урон одним ударом
damageTaken НЕТ int Полученный урон
healingDone НЕТ int Восстановленное здоровье
chipsMatchedByColor НЕТ object { red, blue, green, yellow, purple }
bonusActivations НЕТ object { cat, dog, pepe }
damageDealtByElement НЕТ object { poison, fire, bleed }
skillsUsage НЕТ object { distinctIdsByColor, distinctIdsByFaction, totalActivations }
hero НЕТ object { buffs, debuffs }, у каждого { peakSimultaneous, removedEarly }
enemies НЕТ object { buffs, debuffs }, у каждого { peakSimultaneous, removedEarly }

Счетчики

Накопительные: enemies_defeated, gems_matched_<color>, combos_activated, <cat|dog|pepe>_bonuses_activated, gem_damage_dealt, skill_damage_dealt, damage_received, health_restored, <poison|fire|bleed>_damage_dealt, debuffs_removed_from_self, buffs_removed_from_enemy. При победе — battle_won_no_damage_taken (damageTaken = 0), battle_won_no_skills (skillsUsage.totalActivations = 0), battle_won_1_hp (minHeroHpDuringBattle = 1), battle_won_low_hp (minHeroHpDuringBattle < 10).

Счетчики-максимумы: combo_max_length, max_damage_in_single_hit, max_simultaneous_buffs_on_self, max_simultaneous_debuffs_on_enemy, max_unique_color_skills_in_battle, max_unique_faction_skills_in_battle.

Отсутствующее поле это не ноль

Счетчики условий победы двигаются только если соответствующее поле реально пришло в отчете: battle_won_no_damage_taken требует damageTaken, battle_won_no_skills — skillsUsage.totalActivations, battle_won_1_hp и battle_won_low_hp — minHeroHpDuringBattle. Без этих данных условие не считается выполненным, иначе отчет без них засчитывал бы достижение сам собой.

Числовые значения отчета ограничены сверху разумным пределом: заведомо невозможное значение урезается до предела с записью в лог, а не отклоняет отчет целиком — иначе одно поле стоило бы игроку всех счетчиков за бой.

Результат

{
    "response": {
        "questsDirty": true,
        "achievementsDirty": false,
        "unclaimedQuestsCount": 1,
        "unclaimedAchievementsCount": 0,
        "dailyChestProgress": {
            "points": 20,
            "claimableChestsCount": 0
        },
        "pendingCompletions": [
            {
                "id": "quest_6a71ba248ee7b2.78729389",
                "type": "quest",
                "templateId": "dq_combos_10",
                "tierIndex": 0,
                "occurredAt": 1786010916
            }
        ]
    },
    "update": {
        "member": {
            "wallet": [],
            "options": {}
        }
    }
}
Поле Тип Описание
questsDirty bool Состояние ежедневных заданий изменилось — клиенту нужно перечитать quests state
achievementsDirty bool Состояние достижений изменилось — клиенту нужно перечитать achievements state
unclaimedQuestsCount int Количество ежедневных заданий с доступной наградой
unclaimedAchievementsCount int Количество достижений с доступной наградой
dailyChestProgress object Короткое состояние daily chest progress
pendingCompletions array Очередь pending completions

При повторном отчете с тем же battleId оба флага dirty будут false.