    if (const char* T = getenv("RTK_T")) {   // TEMPORARY TEST HOOK
        std::string t = T;
        auto envi = [](const char* n, int d) { const char* v = getenv(n); return v ? std::atoi(v) : d; };
        std::vector<std::array<int, 3>> clicks;
        if (const char* c = getenv("RTK_CLICK")) {
            int f, x, y, n;
            while (std::sscanf(c, "%d:%d:%d%n", &f, &x, &y, &n) == 3) { clicks.push_back({f, x, y}); c += n; if (*c == ',') ++c; }
        }
        Entity* foe = nullptr;
        for (int i = 0; i < opt.frames; ++i) {
            if (!getenv("RTK_KEEPPAUSE")) GameState::ResetGamePauseState();   // RTK_KEEPPAUSE: windows keep the game paused (5x-4)
            Entity* pl = EntityManager::GetPlayer();
            if ((i == 5 || i == 14) && !getenv("RTK_NOCLOSE")) { MouseDown(640, 60, true); frame(); MouseUp(640, 60, true); }
            for (auto& c : clicks) if (c[0] == i) { firstMove = true; MouseMove(c[1], c[2]); MouseDown(c[1], c[2], true); frame(); frame(); MouseUp(c[1], c[2], true); }
            if (i == 30) {
                if (t == "list")
                    for (unsigned k = 0; Entity* e = EntityManager::EnumEntities(k); ++k)
                        std::printf("[t] ent id=%u %s at %d,%d hp=%d/%d ranged=%d enemy=%d boss=%d\n", e->GetEntityData()->id, e->GetEntityData()->name.c_str(), e->tileX, e->tileY, e->GetHP(), e->GetHpMax(), e->GetAttackRanged(), (int)e->IsEnemy(), (int)e->IsBoss());
                if (envi("RTK_BELT1", 0)) { GameState::AddItem((uint32_t)envi("RTK_BELT1", 0), 3, false, false, false); GameState::BindBeltItemTo(1, (uint32_t)envi("RTK_BELT1", 0)); BeltBarWindow::UpdateBeltItems(); BeltBarWindow::UpdateContents(); }
                if (envi("RTK_BUFF", 0)) { GameState::ActivateItemBuff(683, (uint32_t)envi("RTK_BUFF", 0)); GameState::ActivateItemBuff(684, (uint32_t)envi("RTK_BUFF", 0) / 2); }
                if (envi("RTK_SECOND", 0)) GameState::secondTutorial = envi("RTK_SECOND", 0);
                if (envi("RTK_LEVEL", 0)) GameState::SetResourceAmountValidated(GameState::kLevel, (uint32_t)envi("RTK_LEVEL", 0));
                if (envi("RTK_HP", 0)) pl->SetHP(envi("RTK_HP", 0));
                if (envi("RTK_CRYSTALS", 0)) GameState::SetResourceAmountValidated(GameState::kCrystal, (uint32_t)envi("RTK_CRYSTALS", 0));
                if (envi("RTK_ITEM", 0)) { GameState::AddItem((uint32_t)envi("RTK_ITEM", 0), 3, false, false, false); BeltBarWindow::AutoBind((uint32_t)envi("RTK_ITEM", 0)); BeltBarWindow::UpdateBeltItems(); BeltBarWindow::UpdateContents(); }
                if (envi("RTK_SHP", 0)) { std::vector<Entity*> v; EntityManager::GetPlayerAndSoldiers(v); for (Entity* e : v) if (e != pl && e->GetHpMax() > 0) e->SetHP(envi("RTK_SHP", 0)); }
                if (envi("RTK_REPAIR", 0)) { for (unsigned k = 0; Items::ItemInfo* in = Items::EnumItemInfo(k); ++k) if (in->durability >= 10 && in->cost > 0) { GameState::PlayerItem* it = GameState::AddItem(in->id, 1, false, false, false); if (it) { it->f10 = in->durability - 4; it->f0c = in->durability / 3; std::printf("[t] repair item %u dur %u/%u/%u cost %u/%u\n", in->id, it->f0c, it->f10, in->durability, in->cost, in->cost2); RepairWindow::SetParameters(it); RepairWindow::Show(); } break; } }
                if (envi("RTK_RAID", 0)) { int n = envi("RTK_RAID", 0); for (unsigned k = 0; Locations::LocationInfo* l = Locations::EnumLocationInfo(k); ++k) if (l->mission && l->startMap && --n == 0) { std::printf("[t] raid location %u map %u\n", l->id, l->startMap); RaidInfoWindow::SetParameters(l, l->startMap, envi("RTK_RAIDDONE", 0) != 0); RaidInfoWindow::Show(); break; } }
                if (envi("RTK_RAIDEND", 0)) { int n = envi("RTK_RAIDEND", 0); for (unsigned k = 0; Locations::LocationInfo* l = Locations::EnumLocationInfo(k); ++k) if (l->mission && l->startMap && --n == 0) { std::printf("[t] raid end location %u map %u count %d\n", l->id, l->startMap, GameState::GetMapCompletionCount(l->maps[0].id)); RaidCompleteWindow::SetParameters(l->id); RaidCompleteWindow::Show(); break; } }
                if (envi("RTK_SULTANT", 0)) GameState::SetEventStartTime(0x5dd, (uint32_t)Timer::GetGlobalTime() - (uint32_t)envi("RTK_SULTANT", 0));
                if (envi("RTK_SULTAN", 0)) SultanArrivingWindow::Show();
                if (envi("RTK_WORLD", 0)) GlobalMapWindow::Show();
                if (envi("RTK_GOMAP", 0)) GlobalMapWindow::SwitchMap((uint32_t)envi("RTK_GOMAP", 0), false, false);
            }
            if (i == envi("RTK_AT", 30)) {
                if (envi("RTK_BOSS", 0)) { for (unsigned k = 0; Entity* e = EntityManager::EnumEntities(k); ++k) if (e->IsBoss() && !e->IsDead()) { std::printf("[t] boss %u at %d,%d map %u task %u\n", e->GetEntityData()->id, e->tileX, e->tileY, e->GetBossMapID(), e->GetBossTaskID()); pl->GetAI()->ClickedEntity(e); break; } }
                if (envi("RTK_CAMPEND", 0) || envi("RTK_CAMPPERF", 0)) { int n = envi("RTK_CAMPEND", 0) + envi("RTK_CAMPPERF", 0); for (unsigned k = 0; Locations::LocationInfo* l = Locations::EnumLocationInfo(k); ++k) if (!l->mission && l->campaign && --n == 0) { Tasks::TaskInfo* ct = Tasks::GetCampaignCompletionTask(l->id); std::printf("[t] campaign location %u campaign %u task %u\n", l->id, l->campaign, ct ? ct->id : 0); if (envi("RTK_CAMPEND", 0)) { CampaignCompleteWindow::SetParameters(l->id); CampaignCompleteWindow::Show(); } else { CampaignPerfectedWindow::SetParameters(l->id, ct); CampaignPerfectedWindow::Show(); } break; } }
                if (envi("RTK_EASY", 0)) StartRaidingWindow::Show();
                if (envi("RTK_HEALCARD", 0)) { std::vector<Entity*> v; EntityManager::GetPlayerAndSoldiers(v); for (Entity* e : v) if (e != pl && e->GetHP() < e->GetHpMax()) { BattleBarWindow::ShowHealSoldier(e); break; } }
                foe = envi("RTK_FOE", 0) ? EntityManager::GetNearestEnemyTo(pl, (uint32_t)envi("RTK_FOE", 0)) : EntityManager::GetNearestEnemy(pl, false, true);
                if (foe) std::printf("[t] foe %s at %d,%d hp=%d ranged=%d; hero at %d,%d\n", foe->GetEntityData()->name.c_str(), foe->tileX, foe->tileY, foe->GetHP(), foe->GetAttackRanged(), pl->tileX, pl->tileY);
                if (t == "fight" && foe) pl->GetAI()->ClickedEntity(foe);
                if (t == "aggro" && foe) pl->GetAI()->ClickedTile(foe->tileX + envi("RTK_DX", 2), foe->tileY + envi("RTK_DY", 0), 0, 0);
            }
            if (envi("RTK_SPELL", 0) && i == envi("RTK_SPELLAT", 200) && foe) {   // RTK_SPELL=slot (1..3) single, 11..13 area
                int sl = envi("RTK_SPELL", 0); pl->AddAP(1000);
                std::printf("[t] spell %d on foe hp=%d defMagic=%d ap=%d\n", sl, foe->GetHP(), foe->GetDefenseMagic(), pl->GetAP());
                if (sl == 99) { foe->GetAI()->linked = pl; foe->GetAI()->MagicHit(0.5f, false, 1.f, false, 3); }
                else                 if (sl >= 10) { pl->GetAI()->StartedMagicAttackArea(AI::GetWaypoint(foe->tileX, foe->tileY, false)); pl->GetAI()->MagicAttackArea((unsigned)sl - 10); pl->GetAI()->MagicAttackAreaFinished((unsigned)sl - 10); }
                else { pl->GetAI()->StartedMagicAttack(foe); pl->GetAI()->MagicAttack((unsigned)sl); }
                std::printf("[t] ap after=%d\n", pl->GetAP());
            }
            if (i == envi("RTK_SMOVE", -1)) {
                int tx = pl->tileX + 2, ty = pl->tileY;
                if (envi("RTK_SMENEMY", 0)) for (unsigned k = 0; Entity* e = EntityManager::EnumEntities(k); ++k) if (e->IsEnemy() && !e->IsDead() && e->tileX > 0) { tx = e->tileX; ty = e->tileY; break; }   // RTK_SMOVE=<frame> aims spell RTK_SMSPELL (default 2) at the foe; RTK_SMACC=<frame> accepts, RTK_SMDEC declines
                for (int k = 8; k < 10; ++k) GameState::mBossMapPositions[k] = k == 8 ? tx : ty;
                GameState::mBossMapPositions[10] = envi("RTK_SMW", 11); GameState::mBossMapPositions[11] = envi("RTK_SMW", 11);
                SpellMovement::Activate(Spells::GetSpellInfo((uint32_t)envi("RTK_SMSPELL", 2)), tx, ty);
                int ex, ey; SpellMovement::GetEpicenterPos(ex, ey); std::printf("[t] SpellMovement aims at %d,%d (hero %d,%d) active=%d\n", ex, ey, pl->tileX, pl->tileY, (int)SpellMovement::Activated());
            }
            if (i == envi("RTK_SMACC", -1)) { std::printf("[t] Accept\n"); SpellMovement::Accept(); std::printf("[t] active=%d\n", (int)SpellMovement::Activated()); }
            if (i == envi("RTK_SMDEC", -1)) { std::printf("[t] Decline\n"); SpellMovement::Decline(); std::printf("[t] active=%d\n", (int)SpellMovement::Activated()); }
            if (i == envi("RTK_SMMOVE", -1)) { int ex, ey; SpellMovement::GetEpicenterPos(ex, ey); std::printf("[t] epicenter %d,%d active=%d\n", ex, ey, (int)SpellMovement::Activated()); }
            if (i == envi("RTK_ONSPELL", -1)) { pl->AddAP(1000); std::printf("[t] OnSpell(1) ap=%d\n", pl->GetAP()); BottomBattleWindow::OnSpell(1, 0, 0, false); std::printf("[t] OnManaBar\n"); BottomBattleWindow::EnableFuryGlow(); }
            if (const char* ac = getenv("RTK_AUTOCAST")) { int f = 0, n = 0, sl = 0; while (std::sscanf(ac, "%d:%d%n", &f, &sl, &n) == 2) { if (f == i) { if (sl >= 10) BottomBattleWindow::HelpWithSpell((unsigned)sl - 10, false); else std::printf("[t] OnAutoCast(%d)=%d\n", sl, (int)BottomBattleWindow::OnAutoCast((unsigned)sl)); } ac += n; if (*ac == ',') ++ac; } }
            if (const char* tl = getenv("RTK_TILE")) { int f, x, y; if (std::sscanf(tl, "%d:%d:%d", &f, &x, &y) == 3 && f == i) { std::printf("[t] tap tile %d,%d\n", x, y); pl->GetAI()->ClickedTile(x, y, 0, 0); } }
            if (const char* cl = getenv("RTK_COLLECT")) { int f = 0, n = 0; while (std::sscanf(cl, "%d%n", &f, &n) == 1) { if (f == i) { std::printf("[t] collect one\n"); BuildingHovers::CollectOne(0); } cl += n; if (*cl == ',') ++cl; } }
            if (i == envi("RTK_WIN", -1)) { std::printf("[t] win: the enemies hang by a thread\n"); for (unsigned k = 0; Entity* e = EntityManager::EnumEntities(k); ++k) if (e->IsEnemy() && !e->IsDead()) e->SetHP(1); }
            if (const char* dg = getenv("RTK_DRAG")) { int f, x1, y1, x2, y2; if (std::sscanf(dg, "%d:%d:%d:%d:%d", &f, &x1, &y1, &x2, &y2) == 5) { if (i == f) { firstMove = true; MouseMove(x1, y1); MouseDown(x1, y1, true); } if (i > f && i <= f + 10) { firstMove = true; } if (i > f && i <= f + 10) MouseMove(x1 + (x2 - x1) * (i - f) / 10, y1 + (y2 - y1) * (i - f) / 10); if (i == f + 11) { MouseUp(x2, y2, true); std::printf("[t] drag done\n"); } } }
            if (const char* dg = getenv("RTK_DRAG2")) { int f, x1, y1, x2, y2; if (std::sscanf(dg, "%d:%d:%d:%d:%d", &f, &x1, &y1, &x2, &y2) == 5) { if (i == f) { firstMove = true; MouseMove(x1, y1); MouseDown(x1, y1, true); } if (i > f && i <= f + 10) { firstMove = true; } if (i > f && i <= f + 10) MouseMove(x1 + (x2 - x1) * (i - f) / 10, y1 + (y2 - y1) * (i - f) / 10); if (i == f + 11) { MouseUp(x2, y2, true); std::printf("[t] drag2 done\n"); } } }
            if (i == envi("RTK_EQCHK", -1)) { for (unsigned b = 0; b < 10; ++b) if (GameState::PlayerItem* it = GameState::GetItemAt(b)) std::printf("[t] bind %u = %u\n", b, it->id); }
            if (i == envi("RTK_PROF", -1)) { for (unsigned k = 0; Professions::Profession* p = Professions::EnumProfession(k); ++k) std::printf("[t] prof %u %s type=%d tab=%u lv=%zu obj=%zu unlock=%u ul=%d pts=%u lvl=%u\n", p->id, p->name, (int)p->type, p->tab, p->levels.size(), p->objects.size(), p->unlockLevel, (int)p->IsUnlocked(), GameState::GetProfessionPoints(p->id), Professions::GetPlayerProfessionLevel(p->id)); GameState::AddItem(440, 1, false, false, false); GameState::AddItem(441, 1, false, false, false); GameState::AddItem(447, 1, false, false, false); Professions::AddProfessionPoint(4, 60); GameState::AddProfessionPoints(7, (uint32_t)envi("RTK_VALOR", 0)); if (envi("RTK_HERB", 0)) { GameState::CompleteTask(1443, false); GameState::AddProfessionPoints(3, (uint32_t)envi("RTK_HERB", 0)); } GameState::PlayerItem* it = nullptr; uint32_t t = Professions::GetProfessionTool(4, true, &it, false); std::printf("[t] tool4=%u item=%u best=%u worst=%u lvl4=%u prob=%d istool440=%d/%d rep1locked=%d lvl=%d task0=%d\n", t, it ? it->id : 0, Professions::GetProfessionTool(4, false, nullptr, true), Professions::GetProfessionTool(4, false, nullptr, false), Professions::GetPlayerProfessionLevel(4), Professions::GetItemProbability(4, 475), (int)Professions::IsProfessionTool(440), (int)Items::GetItemInfo(440)->IsProfessionTool(), (int)Items::GetItemInfo(475)->IsLockedByReputation(true), GameState::GetLevel(), (int)GameState::TaskCompleted(0)); }
            if (i == envi("RTK_CRAFT", -1)) { std::set<Map::Decor*> seen; for (int y = 0; y < Map::GetGridHeight(); ++y) for (int x = 0; x < Map::GetGridWidth(); ++x) { Map::Decor* d = Map::GetDecoration(x, y); if (!d || !d->meta || !seen.insert(d).second || !d->meta->FindChildData(kExpCraft)) continue; const char32_t* pm = d->GetProgressMessage(); std::printf("[t] craft %u at %d,%d f4c=%u vis=%d prof=%d req=%u locked=%d msg=%d\n", d->id, d->x, d->y, d->f4c, (int)d->visible, (int)Professions::IsProfessionObject(d->id), d->GetRequiredItem(), (int)d->IsLocked(), pm ? 1 : 0); } if (MetaData* c = Locations::GetMapNodeContents(GameState::GetCurrentMapID())) for (unsigned k = 0; k < c->GetChildrenCount(); ++k) { Items::ItemInfo* in = Items::GetItemInfo((uint32_t)c->GetChild(k)->GetInt()); std::printf("[t] content %d rep=%u lvl=%u\n", c->GetChild(k)->GetInt(), in ? in->reputationId : 0, in ? in->reputationLevel : 0); } else std::printf("[t] no contents\n"); std::printf("[t] herb unlocked=%d gen=%u\n", (int)Professions::GetProfession(3)->IsUnlocked(), Professions::GenerateProfessionObject(Professions::kProfession)); std::printf("[t] map %u tileset %d quality %u\n", GameState::GetCurrentMapID(), Map::GetTileset(), Locations::GetMapNodeQuality(GameState::GetCurrentMapID())); }
            if (const char* gt = getenv("RTK_GATHER")) { int f, x, y; if (std::sscanf(gt, "%d:%d:%d", &f, &x, &y) == 3 && f == i) { Map::Decor* d = nullptr; for (int yy = 0; yy < Map::GetGridHeight() && !d; ++yy) for (int xx = 0; xx < Map::GetGridWidth() && !d; ++xx) { Map::Decor* e = Map::GetDecoration(xx, yy); if (e && e->visible && Professions::IsProfessionObject(e->id) && (envi("RTK_GFIN", 0) || std::abs(e->x - pl->tileX) + std::abs(e->y - pl->tileY) < 9)) { d = e; x = e->x; y = e->y; } } std::printf("[t] gather %u at %d,%d\n", d ? d->id : 0, x, y); if (d && envi("RTK_GFIN", 0)) { for (int k = 0; k < envi("RTK_GFIN", 0); ++k) d->Finish(); std::printf("[t] finished\n"); } if (d) { int wx = x, wy = y; Map::TileCoordinatesToWorld(wx, wy); BuildingHovers::OnDecorClick(d, wx, wy); } } }
            if (i == envi("RTK_GCHK", -1)) { GameState::PlayerItem* t = nullptr; Professions::GetProfessionTool(3, true, &t, false); std::printf("[t] herb pts=%u tool=%u dur=%u items462=%d\n", GameState::GetProfessionPoints(3), t ? t->id : 0, t ? t->f0c : 0, GameState::GetItemAmount(462, false)); }
            if (i == envi("RTK_INV", -1)) { std::printf("[t] OnInventory\n"); BeltBarWindow::OnInventory(); std::printf("[t] char visible=%d\n", (int)CharacterInfoWindow::IsVisible()); }
            if (i == envi("RTK_INVTAB", -1)) { std::printf("[t] tab 3\n"); CharacterInfoWindow::ShowInventoryTab(3); }
            if (i == envi("RTK_SETINFO", -1)) { std::printf("[t] SetInfo\n"); uint32_t pick = 1; for (unsigned b = 0; b != 10; ++b) if (GameState::PlayerItem* it = GameState::GetItemAt(b)) { Sets::Set* st = Sets::GetSetForItem(it->id); std::printf("[t] bind %u item %u set %u\n", b, it->id, st ? st->id : 0); if (st && pick == 1) pick = st->id; } if (const char* ps = getenv("RTK_SETID")) pick = (uint32_t)atoi(ps); if (getenv("RTK_SETGIVE")) { Sets::Set* st = Sets::GetSet(pick); for (unsigned j = 0; j != 3; ++j) { uint32_t id = (uint32_t)st->slots[st->bonusSlots[0]->GetChild(j)->GetInt() - 1]->GetChild(0)->GetInt(); GameState::PlayerItem* it = GameState::AddItem(id, 1, false, false, false); std::printf("[t] give %u\n", id); if (j < 2 && it) GameState::BindItemTo(GameState::ExternalItemBindingToInternal(it->info->slot), it); } } SetInfoWindow::SelectSet(pick); SetInfoWindow::Show(); }
            if (i == envi("RTK_CSW", -1)) {   // RTK_CSWKIND 1 profession (RTK_CSWID), 2 item, 3 spell, 4 battle slot, 5 unit 0x195
                int kind = envi("RTK_CSWKIND", 1);
                if (kind == 1) { GameState::AddProfessionPoints((uint32_t)envi("RTK_CSWID", 3), (uint32_t)envi("RTK_CSWPTS", 0)); CraftSuccessWindow::SetParameters(Professions::GetProfession((uint32_t)envi("RTK_CSWID", 3))); }
                else if (kind == 2) CraftSuccessWindow::SetParameters(GameState::AddItem((uint32_t)envi("RTK_CSWID", 440), 1, false, false, false));
                else if (kind == 3) CraftSuccessWindow::SetParameters(Spells::GetSpellInfo((uint32_t)envi("RTK_CSWID", 2)));
                else if (kind == 4) CraftSuccessWindow::SetParameters(CraftSuccessWindow::kWarriorSlot);
                else CraftSuccessWindow::SetParameters(EntityFactory::GetEntityByID(0x195));
                CraftSuccessWindow::Show();
            }
            if (i == envi("RTK_BELTPT", -1)) BeltBarWindow::ShowProfessionPoint(640.f, 400.f, Professions::GetProfession((uint32_t)envi("RTK_PTID", 4)), (uint32_t)envi("RTK_PTHAVE", 5));
            if (i == envi("RTK_CRAFTWIN", -1)) { Collections::Collection* c = Collections::EnumCollection((unsigned)envi("RTK_COLL", 0)); std::printf("[t] collection %u type %u from %u to %u\n", c ? c->id : 0, c ? c->type : 0, c ? c->from : 0, c ? c->to : 0); if (c) { Collections::Collection* st = Collections::GetCollectionStart(c->from); if (st) c = st; } CraftingWindow::SetParameters(c); if (envi("RTK_HELPIMP", 0)) CraftingWindow::HelpImprove(); if (c && envi("RTK_GIVE", 0)) { GameState::AddItem(c->from, 1, false, false, false); for (auto& pt : c->parts) if (pt.item) GameState::AddItem(pt.item, (int)pt.amount - (envi("RTK_GIVE", 0) == 2 ? 1 : 0), false, false, false); } CraftingWindow::Show(); if (c) { std::printf("[t] chain start %u from %u to %u parts %u/%u %u/%u %u/%u\n", c->id, c->from, c->to, c->parts[0].item, c->parts[0].amount, c->parts[1].item, c->parts[1].amount, c->parts[2].item, c->parts[2].amount); CraftingWindow::OnTab(Items::GetItemInfo(c->from) ? Items::GetItemInfo(c->from)->itemLevel : 0); } }
            if (i == envi("RTK_CRAFTITEM", -1)) { if (envi("RTK_CITAB", 0) < 0) {} CraftItemWindow::Show(); if (envi("RTK_CITAB", 0) > 0) { if (envi("RTK_CIGIVE", 0)) for (unsigned k = 0; Collections::Collection* c = Collections::EnumCollection(k); ++k) if (c->tab == (unsigned)envi("RTK_CITAB", 0) && c->type == 1) { for (auto& pt : c->parts) if (pt.item) GameState::AddItem(pt.item, (int)pt.amount - (envi("RTK_CIGIVE", 0) == 2 ? 1 : 0), false, false, false); std::printf("[t] gave parts of collection %u (to %u)\n", c->id, c->to); } CraftItemWindow::OnTab((unsigned)envi("RTK_CITAB", 0)); } else CraftItemWindow::OnTab(0); }
            if (i == envi("RTK_LEVELINFO", -1)) { std::printf("[t] LevelInfo\n"); LevelInfoWindow::Show(); }
            if (i == envi("RTK_LEVELHIDE", -1)) { std::printf("[t] LevelInfo hide visible=%d\n", (int)LevelInfoWindow::IsVisible()); LevelInfoWindow::Hide(); }
            if (i == envi("RTK_INVHIDE", -1)) { std::printf("[t] Hide\n"); CharacterInfoWindow::Hide(); }
            if (i == envi("RTK_INVCHK", -1)) std::printf("[t] char visible=%d z=%.4f raise=%d\n", (int)CharacterInfoWindow::IsVisible(), CharacterInfoWindow::IsVisible() ? CharacterInfoWindow::GetZ() : 0.f, (int)CharacterInfoWindow::CanRaiseBelt());
            if (i == envi("RTK_CHESTSWIN", -1)) { ChestsWindow::Show(); std::printf("[t] chests window visible=%d\n", (int)ChestsWindow::IsVisible()); }   // 5p-3
            if (i == envi("RTK_CHESTSCHK", -1)) std::printf("[t] chests window visible=%d\n", (int)ChestsWindow::IsVisible());
            if (i == envi("RTK_CHESTSEL_F", -1)) {   // 5p-4: a selector chosen (RTK_CHESTSEL 0..3; -1 the starter chest 53, RTK_STARTFLAG); RTK_CHESTGOT of its set received
                static const char* const sets[4] = {"architect_chest", "warrior_chest", "hunter_chest", "collector_chest"};
                const int c = envi("RTK_CHESTSEL", 0);
                if (c >= 0) {
                    Setting set(sets[c]);
                    for (int k = 0; k < envi("RTK_CHESTGOT", 0); ++k) {
                        const uint32_t id = (uint32_t)set.GetChild((unsigned)k).GetInt();
                        if (c == 0) GameState::SetChestBuildingReceivedCount(id, 1);
                        else if (c == 2) { Items::ItemInfo* ii = Items::GetItemInfo(id); const MetaData* d = ii && ii->meta ? ii->meta->FindChildData(0x27) : nullptr; if (EntityData* e = d ? EntityFactory::GetEntityByID(d->GetInt()) : nullptr) GameState::SetChestEntityReceivedCount(e->id, 1); }
                        else GameState::SetChestItemReceivedCount(id, 1);
                    }
                    ChestsWindow::SetChest((unsigned)c);
                } else {
                    if (!GameState::GetItemAmount(694, false)) GameState::AddItem(694, 1, false, false, false);
                    ChestsWindow::SetStarterChestMode(envi("RTK_STARTFLAG", 1) != 0, 53);
                }
                std::printf("[t] chest selected %d visible=%d\n", c, (int)ChestsWindow::IsVisible());
            }
            if (i == envi("RTK_GIVECRYS", -1)) GameState::AddCrystals(envi("RTK_CRYS", 500));   // 5p-5
            if (i == envi("RTK_TASKWIN", -1)) { TaskInfoWindow::SetTask((uint32_t)envi("RTK_TASKID", 0x75b), false); TaskInfoWindow::Show(); }   // 5p-5b
            if (i == envi("RTK_ITEMCARD", -1)) { const uint32_t id = (uint32_t)envi("RTK_CARDID", 757); GameState::PlayerItem* p = GameState::GetFirstItemByID(id, false); if (!p) p = GameState::AddItem(id, 1, false, false, false); CharacterInfoWindow::Show(); CharacterInfoWindow::ShowInventoryItem(id, 0, p); }   // 5p-5b
            if (i == envi("RTK_KEYS", -1)) {   // 5p-6: the keys
                for (unsigned c = 0; c < 200; ++c) if (Chests::ChestInfo* ci = Chests::GetChestInfo(c)) if (ci->requiredItem) { Items::ItemInfo* k = Items::GetItemInfo(ci->requiredItem); std::printf("[t] chest %u type %u lvl %u key %u %s\n", c, ci->type, ci->level, ci->requiredItem, k ? k->name : "?"); }
                for (int id : {55,58,93,97,100,121,122,123,124,125,127,137,138,151,172,176,177,178,179,180,185,186,189,252,253,254,348,384,385,386,387,388,513,538,539}) { Items::ItemInfo* it = Items::GetItemInfo((uint32_t)id); std::printf("[t] item %d %s type %u shop %u cost %u/%u premium %d\n", id, it ? it->name : "?", it ? it->type : 0, it ? it->shopTab : 0, it ? it->cost : 0, it ? it->cost2 : 0, it ? (int)it->premium : -1); }
            }
            if (i == envi("RTK_SHOPVIS", -1)) std::printf("[t] shop visible %d shown %d\n", (int)ItemShopWindow::IsVisible(), (int)ItemShopWindow::Queue()->shown);
            if (i == envi("RTK_NEED", -1)) { NeedItemWindow::SetParameters((uint32_t)envi("RTK_NEEDITEM", 136), nullptr); NeedItemWindow::Show(); std::printf("[t] need shown %d shop %d\n", (int)NeedItemWindow::IsVisible(), (int)ItemShopWindow::IsVisible()); }   // 5q-5a
            if (i == envi("RTK_NEEDBUY", -1)) { NeedItemWindow::SetParameters((uint32_t)envi("RTK_NEEDITEM", 136), nullptr); NeedItemWindow::OnBuy(); std::printf("[t] need buy: shop %d\n", (int)ItemShopWindow::IsVisible()); if (envi("RTK_CONT", 0)) ItemShopWindow::SetContinuationAfterTargetIsPurchased(new GUI::Callback([] { std::printf("[t] continuation ran\n"); })); }
            if (i == envi("RTK_DAILY", -1)) {   // 5r-1
                auto pr = [](const char* w) { std::printf("[t] daily %s time %u days %u avail %d count %u (now %u, max %d)\n", w, GameState::GetDailyBonusTime(), GameState::GetDailyBonusDays(), (int)GameState::IsDailyBonusAvailable(), GameState::GetReceivedDailyBonusCount(), (uint32_t)Timer::GetGlobalTime(), Setting("daily_bonus_count").GetInt()); };
                pr("start");
                if (envi("RTK_DAILYRUN", 1)) {
                    GameState::UpdateDailyBonusTime(false); pr("update");
                    GameState::UpdateDailyBonusTime(true); pr("force");
                    GameState::UpdateDailyBonusTime(false); pr("same day");
                    for (int n = 0; n < 8; ++n) GameState::UpdateDailyBonusTime(true);
                    pr("force x8");
                    GameState::SetDailyBonusStatus(1); pr("status 1");
                    GameState::DailyBonusReceived(); pr("received");
                }
                for (unsigned n = 0; Tavern::TavernInfo* t = Tavern::EnumTavernInfo(n); ++n) if (GameState::GetSoldierAcquireCount(t->entity)) std::printf("[t] soldier %u count %u first %u recent %u\n", t->entity, GameState::GetSoldierAcquireCount(t->entity), GameState::GetSoldierAcquireTime(t->entity), GameState::GetSoldierRecentTime(t->entity));
                Map::Save(0);
            }
            if (i == envi("RTK_WARRIOR", -1)) {   // 5r-2
                auto pr = [](uint32_t id) { Tavern::TavernInfo* t = Tavern::GetTavernInfo(id); if (!t) { std::printf("[t] warrior %u none\n", id); return; } std::printf("[t] warrior %u unit %u type %u slot %u hp %d-%d atk %u def %u gold %u crys %u\n", t->id, t->entity, t->type, t->slot, t->hpMin, t->hpMax, t->attack, t->defense, t->gold, t->crystals); };
                Tavern::TavernInfo* f = Tavern::EnumTavernInfo(0); const uint32_t a = f->id; pr(a);
                Override::AddParameter(Override::kWarrior, a, 0, "hp_min", "77"); Override::AddParameter(Override::kWarrior, a, 0, "cost_cb", "9"); Override::AddParameter(Override::kWarrior, a, 0, "damage", "13");
                Override::AddParameter(Override::kWarrior, 999, a, "slot", "4"); Override::AddParameter(Override::kWarrior, 998, 12345, "id", "998");
                Override::Apply(Override::kAll); pr(a); pr(999); pr(998); pr(0);
            }
            if (i == envi("RTK_DAILYWIN", -1)) { for (int n = 0; n < envi("RTK_DAILYPRE", 0); ++n) GameState::UpdateDailyBonusTime(true); if (envi("RTK_DAILYFORCE", 1)) DailyBonusWindow::ForceBonus(); DailyBonusWindow::Show(); std::printf("[t] dailywin shown %d days %u\n", (int)DailyBonusWindow::IsVisible(), GameState::GetDailyBonusDays()); }   // 5r-3
            if (i == envi("RTK_DAILYVIS", -1) || i == envi("RTK_DAILYVIS2", -1) || i == envi("RTK_DAILYVIS3", -1)) std::printf("[t] dailywin visible %d count %u days %u item148 %d chestwin %d crys %d\n", (int)DailyBonusWindow::IsVisible(), GameState::GetReceivedDailyBonusCount(), GameState::GetDailyBonusDays(), GameState::GetItemAmount(148, false), (int)ChestOpenedWindow::IsVisible(), (int)GameState::GetResourceAmount(GameState::kCrystal));
            { static std::set<int> adv; if (adv.empty()) { const char* a = getenv("RTK_DAYSKIP"); while (a && *a) { adv.insert(atoi(a)); a = strchr(a, ','); if (a) ++a; } } if (adv.count(i)) { Timer::timeAdvance += i >= envi("RTK_BIGSKIP", 1 << 30) ? 180000 : envi("RTK_ADVSEC", 90000); std::printf("[t] advance adv=%d f=%d days %u time %u avail %d crys %d\n", Timer::timeAdvance, i, GameState::GetDailyBonusDays(), GameState::GetDailyBonusTime(), (int)GameState::IsDailyBonusAvailable(), (int)GameState::GetResourceAmount(GameState::kCrystal)); } }   // 5r-5
            if (i == envi("RTK_DAILYDBG", -1)) std::printf("[t] dailydbg wins %d combat %d hover %d world %d map %u paused %d avail %d days %u since %d\n", WindowManager::GetShownWindowCount(), (int)GameState::IsCombatActive(), (int)BuildingHovers::IsHoverVisible(), (int)BuildingHovers::IsWorldDialogVisible(), GameState::GetCurrentMapID(), (int)GameState::IsPaused(), (int)GameState::IsDailyBonusAvailable(), GameState::GetDailyBonusDays(), Timer::GetGlobalTime() - (int)GameState::GetDailyBonusTime());
            if (i == 31 && envi("RTK_SHOPUNLOCK", 0)) GameState::CompleteTask((unsigned)Setting("shop_unlock_task").GetInt(), false);
            if (i == envi("RTK_TASKSHOP", -1)) { TaskInfoWindow::SetTask((uint32_t)envi("RTK_TASK", 0x5b7), envi("RTK_TASKBOSS", 1) != 0); TaskInfoWindow::Show(); std::printf("[t] task boss form shown\n"); }
            if (i == envi("RTK_SETITEM", -1)) { SetInfoWindow::SelectSet((uint32_t)envi("RTK_SET", 1)); SetInfoWindow::Show(); }
            if (i == envi("RTK_SETITEM", -1) + 30) { SetInfoWindow::OnItem((unsigned)envi("RTK_SLOT", 0)); std::printf("[t] set item: shop %d\n", (int)ItemShopWindow::IsVisible()); }   // 5q-5b
            if (i == envi("RTK_NOTENOUGH", -1)) { NotEnoughWindow::AddItemRequirement((unsigned)envi("RTK_NEEDITEM", 136), 1); NotEnoughWindow::Show(); }
            if (i == envi("RTK_LEVELINFO", -1)) LevelInfoWindow::Show();
            if (i == envi("RTK_BUYITEM", -1)) CastleTopWindow::OnBuyItem((uint32_t)envi("RTK_NEEDITEM", 136));   // 5q-5c
            if (i == 31 && envi("RTK_BELTEMPTY", 0)) { GameState::BindBeltItemTo(1, (uint32_t)envi("RTK_BELTEMPTY", 0)); BeltBarWindow::UpdateBeltItems(); BeltBarWindow::UpdateContents(); }
            if (i == envi("RTK_HELPSCAN", -1)) for (unsigned k = 0; Items::ItemInfo* in = Items::EnumItemInfo(k); ++k) { uint32_t m = GlobalMapWindow::GetMissionMapForItem(in->id, 0), c = GlobalMapWindow::GetMapForCraftItem(in->id, 0); if ((m || c) && ItemShopWindow::ItemCanBeBought(in->id, 0)) std::printf("[t] scan item %u mission %u craft %u type %u rep %u\n", in->id, m, c, in->type, in->reputationId); }
            if (i == envi("RTK_HELP", -1)) { Tasks::TaskSubtask st; st.id = (uint32_t)envi("RTK_HELPID", 1); st.type = envi("RTK_HELPTYPE", 0x1a); st.value = (uint32_t)envi("RTK_HELPVAL", 136); bool r = st.OnHelp(true); std::printf("[t] help type %d val %u -> %d shop %d need %d\n", st.type, st.value, (int)r, (int)ItemShopWindow::IsVisible(), (int)NeedItemWindow::IsVisible()); }   // 5q-5d
            if (i == envi("RTK_SHOT", -1)) { GameState::CompleteTask(1237, false); GameState::AddItem(133, 1, false, false, false); GameState::AddItem(134, 1, false, false, false); GameState::StartTask(1180); std::printf("[t] shot: task 1180 started\n"); }   // 5x-4
            if (const char* sc = getenv("RTK_SHOTCHK")) { int f = 0, n = 0; while (std::sscanf(sc, "%d%n", &f, &n) == 1) { if (f == i) std::printf("[t] shot f=%d settings=%d screenshot=%d arrow=%d task1180=%d\n", i, (int)SettingsWindow::IsVisible(), (int)BottomScreenshotWindow::IsVisible(), (int)BuildingHovers::ArrowVisible(), (int)GameState::TaskCompleted(1180)); if (f == i) std::printf("[t] shot subtask1329=%u\n", GameState::GetSubTaskDone(1329)); sc += n; if (*sc == ',') ++sc; } }   // 5x-4
            if (i == envi("RTK_FEAT", -1)) { GameState::AddItem(0x2b6, 1, false, false, false); GameState::ResetTask(0x75b); GameState::StartTask(0x75b); GameState::SetFeaturedTaskClickTime(0x75b, (uint32_t)Timer::GetGlobalTime()); HUDWindow::UpdateTasks(); Tasks::Update(true); std::printf("[t] feat: starter chest key, task 0x75b started active=%d\n", (int)Tasks::IsTaskActive(0x75b, false)); }   // 5x-5
            if (const char* fc = getenv("RTK_FEATCHK")) { int f = 0, n = 0; while (std::sscanf(fc, "%d%n", &f, &n) == 1) { if (f == i) std::printf("[t] feat f=%d offset=%d chests=%d shop=%d exchange=%d\n", i, CastleTopWindow::GetFeaturedOffset(), (int)ChestsWindow::IsVisible(), (int)ItemShopWindow::IsVisible(), (int)ExchangeWindow::IsVisible()); fc += n; if (*fc == ',') ++fc; } }   // 5x-5
            if (i == envi("RTK_SHOPVIS2", -1)) std::printf("[t] shop visible %d need %d\n", (int)ItemShopWindow::IsVisible(), (int)NeedItemWindow::IsVisible());
            if (i == envi("RTK_SHOP", -1)) { ItemShopWindow::Show(); std::printf("[t] shop shown %d\n", (int)ItemShopWindow::IsVisible()); }   // 5q-2
            if (i == envi("RTK_SHOPLIST", -1)) {   // 5q-1: the shop's lists
                for (int id : {122, 513, 348, 349, 0x88, 56, 771, 1, 0x2d2}) std::printf("[t] canBuy %d: %d\n", id, (int)ItemShopWindow::ItemCanBeBought((uint32_t)id, 0));
                std::printf("[t] pack1: %d\n", (int)ItemShopWindow::PackCanBeBought(1));
                if (envi("RTK_HALLO", 0)) GameState::StartTask(0x77b); ItemShopWindow::PrepareSpecialEventCost(); Items::ItemInfo* h = Items::GetItemInfo(0x2d2); std::printf("[t] 0x2d2 %s sell %d costItem %u x%u cost2 %u halloween %d\n", h->name, (int)h->sellable, h->costItem, h->costItemCount, h->cost2, (int)Tasks::IsTaskActive(0x77b, true));
            }
            if (i == envi("RTK_KEYMAP", -1)) {   // 5p-6: a map's chest key rolls (RTK_KMAP)
                const uint32_t m = (uint32_t)envi("RTK_KMAP", 91);
                if (SaveManager::SaveBlock* b = SaveManager::GetMapData(m)) { GameState::SetCurrentMapID(m); Map::Load(b, 1, false, false); }
                int got4 = 0, got2 = 0; uint32_t k = 0; for (int r = 0; r < 4000; ++r) { if (uint32_t x = Map::RollHeldChestKey(4, false)) { ++got4; k = x; } if (Map::RollHeldChestKey(2, true)) ++got2; }
                for (unsigned q = 0; Entity* e = EntityManager::EnumEntities(q); ++q) if (e->IsBoss()) std::printf("[t] boss %s active=%d dead=%d\n", e->GetEntityData()->name.c_str(), (int)e->IsActive(), (int)e->IsDead());
                std::printf("[t] keymap %u key %u: completion %d/4000, boss %d/4000\n", m, k, got4, got2);
            }
            if (i == envi("RTK_ADVANCE", -1)) Timer::AdvanceGlobalTime((uint32_t)envi("RTK_ADV", 864000));   // 5p-5: the starter offer runs out
            if (i == envi("RTK_LUCKITEM", -1)) GameState::AddItem((uint32_t)envi("RTK_LUCKID", 0), 1, false, false, false);   // 5p-5: a luck item owned
            for (const char* key : {"RTK_BUYCHK", "RTK_BUYCHK2", "RTK_BUYCHK3"})   // 5p-5: a purchase's state
                if (i == envi(key, -1)) std::printf("[t] buy f=%d crystals=%d items %u %u %u %u starter694=%u processed=%u chests=%d opened=%d found=%d char=%d\n", i, GameState::GetResourceAmount(GameState::kCrystal), GameState::GetItemAmount(756, false), GameState::GetItemAmount(757, false), GameState::GetItemAmount(758, false), GameState::GetItemAmount(759, false), GameState::GetItemAmount(694, false), GameState::GetProcessedChest(), (int)ChestsWindow::IsVisible(), (int)ChestOpenedWindow::IsVisible(), (int)FoundItemsWindow::IsVisible(), (int)CharacterInfoWindow::IsVisible());
            if (i == envi("RTK_CHESTWIN", -1)) {   // 5p-2: ChestOpenedWindow with a chest's roll (RTK_CHESTID, RTK_CHESTTX: the chests window's mode)
                Chests::ChestInfo* c = Chests::GetChestInfo((uint32_t)envi("RTK_CHESTID", 57)); Chests::DropItem d[16]; unsigned n = c ? c->GenerateContents(d, 16, false) : 0;
                FoundItemsWindow::ClearCollected(); FoundItemsWindow::SetHeader(StringTable::GetString("CAMPAIGN_INFO_FOUND"));
                for (unsigned k = 0; k < n; ++k) { std::printf("[t] drop %u %u x%d\n", d[k].type, d[k].item, d[k].amount); if (d[k].type == 0xb) FoundItemsWindow::AddCollectedItem(d[k].item, d[k].amount); else FoundItemsWindow::AddCollectedResource((int)d[k].type, d[k].amount); }
                if (envi("RTK_CHESTTX", 0)) ChestOpenedWindow::SetChestTransactionMode(c->id);
                if (envi("RTK_CHESTRET", 0)) ChestOpenedWindow::SetReturnToChestWindow(1);
                ChestOpenedWindow::SetName(c ? c->name : nullptr); ChestOpenedWindow::Show();
                std::printf("[t] chestwin visible=%d gold=%d\n", (int)ChestOpenedWindow::IsVisible(), GameState::GetResourceAmount(GameState::kGold));
            }
            if (i == envi("RTK_CHESTCHK", -1)) std::printf("[t] chestwin visible=%d found=%d gold=%d item134=%d\n", (int)ChestOpenedWindow::IsVisible(), (int)FoundItemsWindow::IsVisible(), GameState::GetResourceAmount(GameState::kGold), GameState::GetItemAmount(134, false));
            if (i == envi("RTK_CHESTS", -1)) {   // 5p-1: the chest data, rolls and picks
                for (uint32_t id : {3u, 9u, 27u, 53u, 57u, 63u, 87u}) { Chests::ChestInfo* c = Chests::GetChestInfo(id); if (!c) { std::printf("[t] chest %u missing\n", id); continue; } std::printf("[t] chest %u type %u lvl %u key %u quest %u count %u-%u items %zu crystals %u cents %u forCrystals %d chestItem %u reroll %u rw %d sku %s\n", c->id, c->type, c->level, c->requiredItem, c->requiredQuest, c->countMin, c->countMax, c->items.size(), c->crystals, c->cents, (int)c->SoldForCrystals(), c->chestItem, c->rerollPrice, (int)c->rewardWindow, c->sku ? c->sku : "-"); for (size_t k = 0; k < c->items.size() && k < 4; ++k) std::printf("[t]   item %u -> %u amount %u-%u prob %d\n", c->items[k].id, c->items[k].item, c->items[k].amountMin, c->items[k].amountMax, c->items[k].probability); for (int roll = 0; roll < 3; ++roll) { Chests::DropItem d[40]; unsigned n = c->GenerateContents(d, 40, roll == 2); std::printf("[t]   roll%s:", roll == 2 ? " all" : ""); for (unsigned k = 0; k < n; ++k) std::printf(" [%u %u/%u x%d p%d]", d[k].type, d[k].item, d[k].object, d[k].amount, d[k].probability); std::printf("\n"); } }
                for (uint32_t it : {0x2f4u, 0x2b6u, 0x2fbu, 0x211u}) std::printf("[t] item %u chest %u isChest %d\n", it, Chests::GetChestForItem(it), (int)Chests::IsChestItem(it));
                for (uint32_t lvl : {1u, 9u, 20u, 28u}) { Chests::ChestInfo* a = Chests::GetChestForLevelByType(6, lvl, true); Chests::ChestInfo* b = Chests::GetRandomChestByType(2); std::printf("[t] level %u: byType6 %u  random type2 %u\n", lvl, a ? a->id : 0, b ? b->id : 0); }
                const char* ids = "57,59,60,61,62"; MetaData* m = ParseCustomStyleData(ids, ",", "1"); Chests::ChestInfo* f = Chests::GetChestForLevel(m, 14, true); std::printf("[t] forLevel(57..62, 14) %u\n", f ? f->id : 0); delete m;
                const char* dl = "1|2=3,4"; MetaData* q = ParseItemDropCommaDividedList(dl, false); std::printf("[t] droplist kids %u first kids %u\n", q->GetChildrenCount(), q->GetChild(0)->GetChildrenCount()); delete q;
                GameState::SetChestItemReceivedCount(5, 7); std::printf("[t] received item5 %u item6 %u\n", GameState::GetChestItemReceivedCount(5), GameState::GetChestItemReceivedCount(6));
            }
            if (envi("RTK_ARENAWIN", -1) >= 0 && i % 20 == 10) std::printf("[t] f=%d difficulty window %d start400 %u\n", i, (int)ArenaDifficultyWindow::IsVisible(), GameState::GetEventStartTime(0x400));   // 5s-4
            if (i == envi("RTK_FINDSP", -1)) { std::printf("[t] map %d\n", GameState::GetCurrentMapID()); for (uint32_t spn : {0x598u, 0x4b4u, 0x4b6u, 0x4e4u, 0x578u}) { Entity* e = EntityManager::GetEntityBySpawnPoint(spn); std::printf("[t] spawn %#x: %s id %u at %d,%d hp %d\n", spn, e ? e->GetEntityData()->name.c_str() : "-", e ? e->GetEntityData()->id : 0, e ? e->tileX : -1, e ? e->tileY : -1, e ? e->GetHP() : -1); } std::printf("[t] event1 start %u diff %u task5b1 started %d done %d\n", GameState::GetEventStartTime(1), GameState::GetEventDifficulty(1), (int)GameState::IsTaskStarted(0x5b1), (int)GameState::TaskCompleted(0x5b1)); }   // 5s-7
            if (i == envi("RTK_ARENAWIN", -1)) { ArenaEventWindow::SetParameters((unsigned)envi("RTK_ARENAPAR", -1)); ArenaEventWindow::Show(); std::printf("[t] arena event window shown %d\n", (int)ArenaEventWindow::IsVisible()); }   // 5s-2
            if (envi("RTK_ARENAWIN", -1) >= 0 && i % 20 == 0) std::printf("[t] f=%d arena event window %d paused %d arrow %d crystals %d end2 %u start400 %u start1 %u end1 %u start2 %u diff1 %u done1 %u t5b1 %u/%d\n", i, (int)ArenaEventWindow::IsVisible(), (int)GameState::IsPaused(), (int)BuildingHovers::ArrowVisible(), (int)GameState::GetResourceAmount(GameState::kCrystal), GameState::GetEventEndTime(2), GameState::GetEventStartTime(0x400), GameState::GetEventStartTime(1), GameState::GetEventEndTime(1), GameState::GetEventStartTime(2), GameState::GetEventDifficulty(1), GameState::GetEventCompletionCount(1), GameState::GetTaskBeginTime(0x5b1), (int)GameState::TaskCompleted(0x5b1));
            if (i == envi("RTK_ARENAQ", -1)) {   // 5s-1: the arena event queries (RTK_ARENAQ_SET: event 2 ended 100 s ago, event 1 started 50 s ago and won once)
                auto a = [](const char32_t* w) { std::string o; for (; w && *w; ++w) o += *w < 128 ? (char)*w : '?'; return o; };
                if (envi("RTK_ARENAQ_SET", 0) == 2) { const uint32_t now = (uint32_t)Timer::GetGlobalTime(); GameState::SetEventStartTime(1, now - 8000); GameState::SetEventStartTime(2, now - 99999); GameState::AddEventCompletion(1); }   // 5s-3b: both events over their time
                if (envi("RTK_ARENAUNLOCK", 0)) { GameState::CompleteTask(0x5b0, false); GameState::CompleteTask(0x512, false); if (envi("RTK_ARENAUNLOCK", 0) == 2) GameState::AddEventCompletion(2); }
                if (envi("RTK_NOBELT", 0)) { GameState::SetBeltItemMode(true); for (unsigned b = 0; b < GameState::GetBeltSlotCount(); ++b) { uint32_t id = GameState::GetBeltItemAt(b); if (id) GameState::RemoveItem(id, GameState::GetItemAmount(id, true)); } GameState::SetBeltItemMode(false); BeltBarWindow::UpdateBeltItems(); }   // 5s-6: no orbs on the belt
                if (envi("RTK_ARENAQ_SET", 0) == 1) { const uint32_t now = (uint32_t)Timer::GetGlobalTime(); GameState::SetEventEndTime(2, now - 100); GameState::SetEventStartTime(1, now - 50); GameState::AddEventCompletion(1); GameState::AddArena2WinByLevel(5); }
                for (unsigned ev = 1; ev <= 2; ++ev) std::printf("[t] event %u name '%s' active %d unlocked %d cooldown %u remaining %u completions %u end %u\n[t]   desc '%s'\n", ev, a(ArenaEventWindow::GetEventName(ev)).c_str(), (int)ArenaEventWindow::IsEventActive(ev), (int)ArenaEventWindow::IsEventUnlocked(ev), ArenaEventWindow::GetEventCooldownTime(ev), ArenaEventWindow::GetEventRemainingTime(ev), GameState::GetEventCompletionCount(ev), GameState::GetEventEndTime(ev), a(ArenaEventWindow::GetEventDescription(ev)).c_str());
                std::printf("[t] arena notifications:\n"); GetNotifications().PurgeNotifications(); GameState::UpdateNotifications(); GetNotifications().FlushNotifications();
            }
            if (i == envi("RTK_NOTIF", -1)) {   // 5r-6: each source's reminder, then the real pause event (RTK_NOTIFOFF: setting off, RTK_BOSSF: a boss fight 10 s old)
                if (envi("RTK_NOTIFOFF", 0)) SettingsWindow::SetNotificationState(0);
                if (envi("RTK_BOSSF", 0)) { for (unsigned k = 0; EntityData* d = EntityFactory::EnumEntity(k); ++k) if (d->restoreTime > 0) { std::printf("[t] boss entity %u restore %d\n", d->id, d->restoreTime); GameState::SetBossFightTimer(0x7777, (uint32_t)Timer::GetGlobalTime() - 10); GameState::BossFight(0x7777) = {{d->id, 50u}}; break; } }
                if (envi("RTK_NOTIFSET", 0)) { std::set<Map::Building*> seen; for (int y = 0; y < Map::GetGridHeight(); ++y) for (int x = 0; x < Map::GetGridWidth(); ++x) { Map::Building* b = Map::GetBuilding(x, y); if (!b || !seen.insert(b).second) continue; if (b->data->buildingClass == 0 && envi("RTK_NOTIFSET", 0) == 1) b->stateTime = (uint32_t)Timer::GetGlobalTime() - 100; if (b->data->buildingClass == 4 && b->WorkerAssigned(0) && b->WorkerIsWorking(0)) b->resources[b->data->produceResource] = 10; } }   // 1: a tax house 100 s into its 1800 and a gatherer at 10 of 50; 2: the gatherer only
                std::printf("[t] hp %d/%d regen %d next %.1f farmmap %u\n", pl->GetHP(), pl->GetHpMax(), pl->GetHPRegeneration(), GameState::mNextHP, Locations::GetNearestUnfinishedFarmMapTime());
                { std::set<Map::Building*> seen; for (int y = 0; y < Map::GetGridHeight(); ++y) for (int x = 0; x < Map::GetGridWidth(); ++x) { Map::Building* b = Map::GetBuilding(x, y); if (!b || !seen.insert(b).second) continue; int c = (int)b->data->buildingClass; if (c == 0 || c == 4 || c == 0xd) std::printf("[t] bld %u class %d state %u collect %d gathered %d worker %d/%d arg0 %u contract0 %d\n", b->data->id, c, b->stateTime, b->data->collectTime, c == 4 ? b->GetGatheredResCount() : -1, (int)b->WorkerAssigned(0), (int)(b->WorkerAssigned(0) && b->WorkerIsWorking(0)), b->patchArg[0], b->patchContract[0]); } }
                std::printf("[t] gamestate part:\n"); GetNotifications().PurgeNotifications(); GameState::UpdateNotifications(); GetNotifications().FlushNotifications();
                std::printf("[t] map part:\n"); GetNotifications().PurgeNotifications(); Map::UpdateNotifications(); GetNotifications().FlushNotifications();
                g_lastSystemNotificationTime = -1;
                std::printf("[t] pause event:\n"); SDL_Event ev{}; ev.type = SDL_EVENT_WILL_ENTER_BACKGROUND; SDL_PushEvent(&ev); Game::main_Loop_Func();
            }
            if (i == envi("RTK_NOTIF", -1) + 1) { std::printf("[t] after pause: last %d\n", g_lastSystemNotificationTime); SDL_Event ev{}; ev.type = SDL_EVENT_DID_ENTER_FOREGROUND; SDL_PushEvent(&ev); Game::main_Loop_Func(); }
            if (i == envi("RTK_PVPFIGHT", -1)) {   // 5t-4: a generated rival fought (the ambush's way into the PvP arena 0x91)
                PvP::LoadPvPData(1, nullptr, 0, nullptr);
                PvP::PlayerInfo* r = nullptr;
                for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) if (p->type == 1 && p->gid > 0) { r = p; break; }
                if (r) {
                    if (envi("RTK_PVPWEAK", 0)) { r->level = 1; r->warriorCount = 0; for (auto& w : r->warriors) w = PvP::PlayerInfo::WarriorInfo(); for (auto& it : r->equipment.items) it = PvP::PlayerEquipmentInfo::ItemInfo(); }
                    r->valor = (uint32_t)r->GetValorForVictory();
                    std::printf("[t] pvp rival gid=%d level=%d warriors=%d valor=%u (victories %u defeats %u, valor item %d)\n", r->gid, r->level, r->warriorCount, r->valor, PvP::GetVictoryCount(), PvP::GetDefeatCount(), GameState::GetItemAmount(0x249, false));
                    PlayerCompetitionWindow::SetSelectedPlayerGID(r->gid, false);
                    if (Entity* hero = EntityManager::CreateEntity(r->male ? 0xc : 0xd, true, true)) {
                        GameState::SetCombat(new AggroCombat());
                        hero->CreateSquad();
                        hero->GetAI()->UpdateLastTarget();
                        hero->player = false;
                        GameState::GetActiveCombat()->BeginCombat(EntityManager::GetPlayer()->GetSquad(), hero->GetSquad());
                        GameState::GetActiveCombat()->ForceBossFight(6, 0x91);
                        GameState::DropGamePauseState();
                    }
                }
            }
            if (envi("RTK_PVPFIGHT", -1) >= 0 && i > envi("RTK_PVPFIGHT", -1)) {
                static bool autoOn = false, done = false;
                BaseCombat* c = GameState::GetActiveCombat();
                if (!autoOn && c && c->GetType() == 6 && GameState::GetCurrentMapID() == 0x91 && i % 10 == 0) {
                    if (auto* a = dynamic_cast<ArenaCombat*>(c)) { a->AutoCombat(); autoOn = true; std::printf("[t] f=%d auto combat on, state %d\n", i, c->GetState()); }
                }
                if (i % 50 == 0 && c) std::printf("[t] f=%d map %u combat type %d state %d\n", i, GameState::GetCurrentMapID(), c->GetType(), c->GetState());
                PvP::PlayerInfo* r = PvP::GetPlayerInfoByGID(PlayerCompetitionWindow::GetSelectedPlayerGID(), 0xff);
                if (!done && r && r->defeated != 0) {
                    done = true;
                    std::printf("[t] f=%d result: rival defeated=%d wins=%d losses=%d lastFight=%u valor=%u; victories %u defeats %u\n", i, r->defeated, r->wins, r->losses, r->lastFight, r->valor, PvP::GetVictoryCount(), PvP::GetDefeatCount());
                }
                if (done && i % 50 == 0) std::printf("[t] f=%d after: victories %u, loading %d, collected valor %d\n", i, PvP::GetVictoryCount(), (int)PvP::IsLoadingData(), GameState::GetMapItemCollectionInfo(0x91, 0x249));
            }
            if (i == envi("RTK_PVPWIN", -1)) {   // 5t-5: the PvP button opens the opponents' window
                if (!GameState::TaskCompleted(0x74d)) GameState::CompleteTask(0x74d, false);
                if (envi("RTK_PVPDONE", 0)) PvP::SetCompletedPvPTutorial(true);
                std::printf("[t] f=%d pvp button: task 0x74d %d, tutorial done %d, city %d\n", i, (int)GameState::TaskCompleted(0x74d), (int)PvP::IsCompletedPvPTutorial(), (int)GameState::IsPlayerCity());
                CastleTopWindow::OnPvP(0xffffffffu);
            }
            if (envi("RTK_PVPWIN", -1) >= 0 && i > envi("RTK_PVPWIN", -1) && i % 20 == 0) {
                int n1 = 0; std::string first; for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) if (p->type == 1) { if (!n1++ && p->name) first.assign(p->name, p->name + std::char_traits<char32_t>::length(p->name)); } std::printf("[t] f=%d first rival %s\n", i, first.c_str());
                PvP::PlayerInfo* s = PvP::GetPlayerInfoByGID(PlayerCompetitionWindow::GetSelectedPlayerGID(), 0xff);
                BaseCombat* c = GameState::GetActiveCombat();
                std::printf("[t] f=%d pvp window %d queued %d list1 %d selected %d (%s def %d) map %u world %d combat %d/%d victories %u valor %u\n", i, (int)PlayerCompetitionWindow::IsVisible(), (int)PlayerCompetitionWindow::CombatQueued(), n1, PlayerCompetitionWindow::GetSelectedPlayerGID(), s && s->name ? std::string(s->name, s->name + std::char_traits<char32_t>::length(s->name)).c_str() : "-", s ? s->defeated : -1, GameState::GetCurrentMapID(), (int)GlobalMapWindow::IsVisible(), c ? c->GetType() : -1, c ? c->GetState() : -1, PvP::GetVictoryCount(), GameState::GetProfessionPoints(7));
                if (s) { std::printf("[t] f=%d rival slots", i); for (int k = 0; k != 10; ++k) if (s->equipment.items[k].id) std::printf(" %d", k); std::printf(" (info window %d)\n", (int)PlayerInfoWindow::IsVisible()); }   // 5u
                if (envi("RTK_PVPAUTO", 0) && c && c->GetType() == 6) if (auto* a = dynamic_cast<ArenaCombat*>(c)) { static bool on = false; if (!on && c->GetState() > 0) { a->AutoCombat(); on = true; std::printf("[t] auto combat on\n"); } }
            }
            if (i == envi("RTK_NAMETAG", -1) - 1) for (unsigned k = 0; Entity* e = EntityManager::EnumEntities(k); ++k) std::printf("[t] ent %u at %d,%d player %d enemy %d active %d appeared %d talk %u\n", e->GetEntityData()->id, e->tileX, e->tileY, (int)e->IsPlayer(), (int)e->IsEnemy(), (int)e->IsActive(), (int)e->IsAppeared(), e->GetTalkTask());
            if (i == envi("RTK_NAMETAG", -1)) {   // 5u: a worker given the first rival's GUID shows his name tag
                PvP::LoadPvPData(1, nullptr, 0, nullptr);
                PvP::PlayerInfo* r = nullptr;
                for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) if (p->type == 1 && p->gid > 0) { r = p; break; }
                for (unsigned k = 0; Entity* e = EntityManager::EnumEntities(k); ++k)
                    if (r && !e->IsPlayer() && !e->IsEnemy() && e->IsActive() && !e->IsDead() && !e->GetTalkTask() && e->GetEntityData()->id == (uint32_t)envi("RTK_NAMEID", 0)) { e->SetGUID((uint32_t)r->gid); std::printf("[t] f=%d name tag on entity %u at %d,%d gid %d\n", i, e->GetEntityData()->id, e->tileX, e->tileY, r->gid); float wx = 0, wy = 0; e->GetWorldPos(wx, wy); Render::CenterOn(wx, wy); break; }
            }
            if (i == envi("RTK_PVPLOAD", -1)) {   // 5t-3: the offline server's list, the cache, the tutorial's end
                auto dump = [](int type) {
                    int n = 0;
                    for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) {
                        if (p->type != type) continue;
                        ++n;
                        std::u32string nm = p->name ? p->name : U"", c = p->str410 ? p->str410 : U"";
                        int items = 0, looks = 0;
                        for (auto& it : p->equipment.items) if (it.uniqueId) ++items;
                        for (auto& it : p->equipment.customs) if (it.id) ++looks;
                        std::printf("[t]  rival gid=%d %s (%s) male=%d level=%d prof7=%d items=%d looks=%d warriors=%d last=%u l/w=%d/%d def=%d\n", p->gid, std::string(nm.begin(), nm.end()).c_str(), std::string(c.begin(), c.end()).c_str(), p->male, p->level, p->f10, items, looks, p->warriorCount, p->lastFight, p->losses, p->wins, p->defeated);
                        for (int b = 0; b < 10; ++b) if (p->equipment.items[b].uniqueId) { const Items::ItemInfo* in = Items::GetItemInfo(p->equipment.items[b].id); std::printf("[t]    item %d: %u %s lvl %u\n", b, p->equipment.items[b].id, in ? in->name : "?", in ? in->level : 0); }
                        for (int w = 0; w < p->warriorCount; ++w) std::printf("[t]    warrior %u hp %d/%d\n", p->warriors[w].id, p->warriors[w].f08, p->warriors[w].hp);
                    }
                    return n;
                };
                std::printf("[t] player level %d squad %u, tutorial done %d\n", GameState::GetLevel(), SoldierSlots::GetOccupiedSlotCount(), (int)PvP::IsCompletedPvPTutorial());
                PvP::LoadPvPData(1, [](bool ok) { std::printf("[t] list 1 loaded ok=%d\n", ok); }, 0, nullptr);
                std::printf("[t] type 1: %d rivals, tutorial done %d, refresh in %d s, loading %d\n", dump(1), (int)PvP::IsCompletedPvPTutorial(), (int)PvP::GetRefreshTime(1) - Timer::GetGlobalTime(), (int)PvP::IsLoadingData());
                std::printf("[t] type 200 (shadows done): %d\n", dump(200));
                // a fight's record, saved into the cache, then the list again from the cache file
                for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) if (p->type == 1) { p->lastFight = 4242; p->wins = 1; p->losses = 2; p->defeated = 1; break; }
                PvP::UpdateCachedData(1);
                PvP::Cache::Free("pc1");
                PvP::ClearPlayerInfo(1);
                PvP::LoadPvPData(1, [](bool ok) { std::printf("[t] list 1 from the cache ok=%d\n", ok); }, 0, nullptr);
                std::printf("[t] type 1 again: %d rivals\n", dump(1));
                PvP::ClearPlayerInfo(4);
                PvP::LoadPvPData(4, nullptr, 0, nullptr);
                std::printf("[t] type 4: %d rivals, random gid %d\n", dump(4), PvP::GetRandomPlayerGID(4, true));
                PvP::LoadPvPData(5, nullptr, 0, nullptr);
                int five = 0; for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) if (p->type == 5) ++five;
                std::printf("[t] type 5: %d\n", five);
            }
            if (i == envi("RTK_PVPSAVE", -1)) {   // 5t-2: the player's own state block read as a rival's save; the cache's file round trip
                SaveManager::SaveBlock* b = SaveManager::GetGameStateData();
                if (b->data.empty()) b->MergeChunks();
                PvP::PvPSave sv; sv.data = b->data; sv.gid = 77; sv.lastFight = 1234; sv.losses = 2; sv.wins = 3;
                bool ok = PvP::LoadPlayerInfo(sv, 2, envi("RTK_PVPNAME", 0) ? U"Rival" : nullptr);
                for (unsigned k = 0; PvP::PlayerInfo* p = PvP::EnumPlayers(k); ++k) if (p->gid == 77) {
                    std::u32string nm = p->name ? p->name : U"", c = p->str410 ? p->str410 : U"", own = p->str414 ? p->str414 : U"";
                    std::printf("[t] pvp ok=%d gid=%d type=%d male=%d level=%d prof7=%d f418=%d losses=%d wins=%d warriors=%d name=%s castle=%s own=%s\n", ok, p->gid, p->type, p->male, p->level, p->f10, p->f418, p->losses, p->wins, p->warriorCount, std::string(nm.begin(), nm.end()).c_str(), std::string(c.begin(), c.end()).c_str(), std::string(own.begin(), own.end()).c_str());
                    for (int w = 0; w < p->warriorCount; ++w) std::printf("[t]  warrior %u hp %d/%d\n", p->warriors[w].id, p->warriors[w].f08, p->warriors[w].hp);
                    for (int w = 0; w < 10; ++w) if (p->equipment.items[w].uniqueId) std::printf("[t]  item %d uid %u id %u %u/%u\n", w, p->equipment.items[w].uniqueId, p->equipment.items[w].id, p->equipment.items[w].f08, p->equipment.items[w].f0c);
                    for (int w = 0; w < 32; ++w) if (p->equipment.customs[w].id) std::printf("[t]  custom %d id %u\n", w, p->equipment.customs[w].id);
                    p->defeated = 5;
                }
                std::printf("[t] random gid type 2: %d, type 1: %d, type 3: %d\n", PvP::GetRandomPlayerGID(2, false), PvP::GetRandomPlayerGID(1, false), PvP::GetRandomPlayerGID(3, false));
                PvP::SaveCache c; c.data = "abc"; c.time = 99; c.count = 1; c.lastFight = c.losses = c.wins = c.defeated = {0};
                PvP::Cache::Set("pc2", c, 99);
                PvP::UpdateCachedData(2);
                PvP::Cache::Free("pc2");
                PvP::SaveCache r;
                bool got = PvP::Cache::Get("pc2", r);
                std::printf("[t] cache got=%d valid=%d data=%s time=%u count=%u rec=%u/%u/%u/%u\n", got, (int)PvP::Cache::IsValid("pc2"), r.data.c_str(), r.time, r.count, r.count ? r.lastFight[0] : 0, r.count ? r.losses[0] : 0, r.count ? r.wins[0] : 0, r.count ? r.defeated[0] : 0);
                PvP::RemoveCachedData(2, false);
                std::printf("[t] soft remove: valid=%d\n", (int)PvP::Cache::IsValid("pc2"));
                PvP::RemoveCachedData(2, true);
                PvP::SaveCache g; std::printf("[t] hard remove: got=%d\n", (int)PvP::Cache::Get("pc2", g));
            }
            if (i == envi("RTK_TAGS", -1)) {   // 5r-7: the calendar on chosen local dates, then the tags now
                const int dates[][3] = {{2026,11,22},{2026,11,23},{2026,11,26},{2026,11,29},{2026,11,30},{2026,12,1},{2027,1,6},{2027,1,7},{2024,11,24},{2024,11,25},{2024,12,1},{2024,12,2},{2025,11,24},{2025,11,30},{2026,10,19}};
                for (auto& d : dates) { std::tm t{}; t.tm_year = d[0] - 1900; t.tm_mon = d[1] - 1; t.tm_mday = d[2]; t.tm_hour = 12; t.tm_isdst = -1; time_t w = std::mktime(&t); std::printf("[t] date %d-%02d-%02d xmas %d thanks %d\n", d[0], d[1], d[2], (int)Tags::CalendarActive("xmas_2012", w), (int)Tags::CalendarActive("thanksgiving_2012", w)); }
                for (unsigned k = 0; Tags::Tag* tg = Tags::EnumTag(k); ++k) std::printf("[t] tag %s active %d\n", tg->name, (int)tg->IsActive());
            }
            if (const char* ac = getenv("RTK_ACTION")) { int f, a, v; if (std::sscanf(ac, "%d:%d:%d", &f, &a, &v) == 3 && f == i) { mActionToDo = a; mActionValue = v; std::printf("[t] action %d value %d\n", a, v); } }
            if (i == envi("RTK_SLEEP", -1)) SDL_Delay(2100);
            if (const char* sl = getenv("RTK_SLEEPS")) { int f = 0, n = 0; while (std::sscanf(sl, "%d%n", &f, &n) == 1) { if (f == i) SDL_Delay(1100); sl += n; if (*sl == ',') ++sl; } }
            if (i == envi("RTK_RETREAT", -1)) { std::printf("[t] retreat\n"); pl->GetAI()->Retreat(); }
            if (i % 20 == 0) {
                std::vector<Entity*> v; EntityManager::GetPlayerAndSoldiers(v);
                std::printf("[t] f=%d tut=%d/%d wd=%d dlg=%d shown=%d combat=%d hero=%d@%d,%d", i, GameState::tutorial, GameState::secondTutorial, (int)BuildingHovers::IsWorldDialogVisible(), (int)PlayerTopWindow::IsPlayerDialogVisible(), (int)WindowManager::GetShownWindowCount(), (int)GameState::IsCombatActive(), pl ? pl->GetHP() : -1, pl ? pl->tileX : -1, pl ? pl->tileY : -1);
                for (Entity* e : v) if (e != pl && e->GetHpMax() > 0) std::printf(" sold=%d", e->GetHP());
                if (foe) std::printf(" foe=%d f36=%d act=%d dead=%d dis=%d app=%d", foe->GetHP(), (int)foe->f36, (int)foe->IsActive(), (int)foe->IsDead(), (int)foe->IsDisappearing(), (int)foe->IsAppeared());
                if (BaseCombat* cc = GameState::GetActiveCombat()) std::printf(" ctype=%d cstate=%d paused=%d", cc->GetType(), cc->GetState(), (int)cc->IsPaused());
                std::printf(" crystals=%u head=%s range=%.4f:", (unsigned)GameState::GetResourceAmount(GameState::kCrystal), WindowManager::Head()->name.c_str(), WindowManager::GetTopWindowRange());
                { int k = 0; for (WindowManager::WindowQueue* w = WindowManager::Head(); w && k < 4; w = w->next, ++k) std::printf(" %s(%d,%.4f)", w->name.c_str(), (int)w->IsVisible(), w->ZRange()); }
                std::printf("\n");
            }
            if (i == envi("RTK_PRES", -1)) {   // 5v: the warehouse stores a building, the presents tab gets one
                if (envi("RTK_PRESLEVEL", 0)) GameState::SetResourceAmountValidated(GameState::kLevel, (uint32_t)envi("RTK_PRESLEVEL", 0));
                std::printf("[t] pres before: warehouse=%d presents=%d free=%d size=%d packs=%d level=%d\n", PresentsContainer::GetPresentCount(0), PresentsContainer::GetPresentCount(1), PresentsContainer::GetWareHouseFreeSize(), PresentsContainer::GetWareHouseSize(), PresentsContainer::GetPresentPacksCount(), GameState::GetLevel());
                if (envi("RTK_PRESADD", 0)) {
                    Map::Building* pick = nullptr;
                    for (int x = 0; x < 120 && !pick; ++x) for (int y = 0; y < 120 && !pick; ++y) { Map::Building* b = Map::GetBuilding(x, y); if (b && !b->data->IsHQ()) pick = b; }
                    if (pick) {
                        std::printf("[t] pres store %s id=%u at %d,%d\n", pick->data->name.c_str(), pick->data->id, pick->x, pick->y);
                        PresentsContainer::AddToWarehouse(pick);
                        Map::RemoveBuilding(pick->x, pick->y, false, false);
                    }
                    PresentsContainer::AddPresent(1, 1, 5, nullptr)->f0d = true;
                }
            }
            if (i == envi("RTK_PRES", -1) + 100) {
                for (int tab = 0; tab < 2; ++tab) for (unsigned k = 0; PresentsContainer::Present* p = PresentsContainer::GetPresent(tab, k); ++k) { const char32_t* nm = p->GetName(); std::printf("[t] pres tab=%d type=%d id=%u b=%p f=%d%d name=%s\n", tab, p->type, p->id, (void*)p->building, (int)p->f0c, (int)p->f0d, nm ? std::string(nm, nm + std::char_traits<char32_t>::length(nm)).c_str() : "-"); }
                std::printf("[t] pres after: warehouse=%d presents=%d free=%d packs=%d", PresentsContainer::GetPresentCount(0), PresentsContainer::GetPresentCount(1), PresentsContainer::GetWareHouseFreeSize(), PresentsContainer::GetPresentPacksCount());
                for (int k = 0; PresentsContainer::PresentPack* pk = PresentsContainer::GetPackByNum((unsigned)k); ++k) std::printf(" pack%u(shown=%d cost=%u items=%d)", pk->id, (int)pk->shown, pk->cost, (int)pk->items.size());
                std::printf("\n");
                if (envi("RTK_PRESDEL", 0)) {
                    PresentsContainer::DeletePresent(PresentsContainer::GetPresent(0, 0), true);
                    PresentsContainer::DeletePresent(PresentsContainer::GetPresent(1, 0), true);
                    PresentsContainer::BuyPack(PresentsContainer::GetPackByNum(0));
                    std::printf("[t] pres deleted: warehouse=%d presents=%d", PresentsContainer::GetPresentCount(0), PresentsContainer::GetPresentCount(1));
                    for (unsigned k = 0; PresentsContainer::Present* p = PresentsContainer::GetPresent(1, k); ++k) std::printf(" %d/%u", p->type, p->id);
                    std::printf("\n");
                }
                if (envi("RTK_PRESADD", 0)) Map::Save(0);
            }
            frame();
        }
    } else
