Перейти к содержанию

PulseCaster City

Автономная экономика зданий

Производственные здания — это точки работы на карте. У них нет владельца, директора, отдельного кошелька, ручного склада, оборудования, производственных заказов или управляемого найма. Вместимость задаётся каталогом здания, а смена всегда запускается с конкретным building_id.

Сырьё и результат принадлежат персонажу:

  1. при старте смены сырьё на все запланированные этапы переносится из city_character_inventory в резерв смены;
  2. завершённый этап погашает соответствующую часть резерва и сразу выдаёт результат персонажу;
  3. отмена возвращает сырьё только незавершённых этапов;
  4. зарплата фиксируется при старте смены и начисляется отдельно от произведённого товара.

workhub возвращает все рецепты построенного объекта как постоянные, неограниченные заказы. Для каждого рецепта API показывает расход на один этап (needed_per_stage), количество в инвентаре, выпуск, длительность, диапазон зарплаты и доступные экземпляры здания с их координатами, вместимостью и активными сменами. Клиент пересчитывает полный расход и ожидаемый выпуск при смене выбранной длительности и передаёт выбранный building_id в StartWork.

Производства, парк, кальянная, столовая и ресторан не изнашиваются. Для них не создаются ремонтные заказы. Старые endpoints директоров, контрактов, производственных заказов, объектных продаж, оборудования и рабочих мест отвечают HTTP 410 со статусом economy_model_retired. Read-only карточка автономного здания содержит только карту, рецепты, вместимость, активные смены и рыночную статистику.

Игровой workhub не содержит слоя «Я управляю». Мэрская вкладка служб показывает только больницу и пожарную часть; автономные производства и заведения не возвращаются в её management read model. В административном реестре автономные здания остаются доступными для размещения, перемещения и удаления, но не получают ссылку на объектное управление.

Рынок ресурсов

Ресурсный лот создаёт сам персонаж. Выставленное количество изымается из доступного инвентаря в escrow. Цена лота фиксирована его автором; рекомендация рынка её не меняет.

  • срок лота — семь суток;
  • разрешены частичные покупки и ручная отмена;
  • остаток отменённого или истёкшего лота возвращается продавцу;
  • общая биржа использует listing_scope=general;
  • источник — дом продавца или персональная ячейка ратуши;
  • покупка создаёт city_character_market_deliveries, а не выдаёт предмет сразу;
  • покупатель получает груз действием receive, либо другой персонаж доставляет его действием deliver.

Рекомендация цены использует реальные продажи и активное предложение. Снимок пересчитывается не чаще раза в пять минут; новое рекомендуемое значение ограничено изменением ±15% от предыдущего. Зарплатный рынок также использует пятиминутный снимок, а конкретная зарплата записывается в смену при старте.

Основная страница рынка работает от всего инвентаря персонажа и больше не делится на «ресурсы» и «прочие предметы». Единственная вкладка «Ресурсы и материалы» объединяет ресурсные и обычные предметные лоты в одной таблице. Материалы создают лот city_resource_market_offers, а остальные разрешённые к торговле предметы — city_market_offers; тип лота клиент выбирает автоматически. На форме размещения явно подписаны товар, количество и цена за штуку; для ресурсов рядом показывается единая сглаженная рекомендация цены и сумма лота. Для совместимости miniapp-resolver принимает как slug/название города, так и числовой channel_id, но клиент всегда передаёт slug.

На рынке персонажа названия вкладок описывают действие игрока:

  • «Продажа» содержит форму нового лота, собственные активные и завершённые лоты и золотые заявки мэрии. Золотую заявку можно частично закрыть прямо из подходящего инвентаря без промежуточного лота;
  • «Покупка» содержит только активные предложения других продавцов;
  • каждая строка показывает начальное количество, остаток и уже проданное количество;
  • завершённые лоты имеют статусы sold, cancelled или expired. При истечении обычного предметного лота escrow автоматически возвращается персонажу так же, как у ресурсного лота.

Мэрский рынок использует тот же inventory-first layout. Во вкладке «Покупка» мэрия выкупает лоты жителей только в городской склад. Во вкладке «Продажа» город резервирует ресурс со склада и создаёт публичный семидневный лот. Городская заявка на закупку резервирует бюджет, принимает частичные продажи игроков и всегда складывает купленное на городской склад.

В блоке управления городским складом один выбранный запас можно направить:

  • на стройку — создаётся существующий city_delivery_orders, ресурс резервируется со склада и появляется как работа курьера;
  • в городской магазин — ресурс сразу переносится в city_shop_inventory;
  • на рынок — создаётся новый публичный лот города или пополняется выбранный активный лот.

Витрины столовой и ресторана

У заведений нет собственного запаса еды. Повар получает блюдо в свой инвентарь и выставляет его в escrow-витрину конкретного building_id с listing_scope=venue_showcase.

Покупатель выбирает конкретный offer_id:

  • eat атомарно списывает блюдо, деньги покупателя, налог и начисляет остаток продавцу, затем применяет эффект еды;
  • buy (навынос) выполняет тот же расчёт и выдаёт блюдо в инвентарь покупателя;
  • отмена или истечение через семь суток возвращает остаток повару.

Столовая принимает canteen_meal, vegetable_soup и sweet_tea. Ресторан принимает только restaurant_meal. Если активных предложений нет, статус заведения возвращает meal_required; системная еда не создаётся.

Статус страницы заведения возвращает building_id, подходящие блюда текущего персонажа в showcase_inventory и те же resource_market_quotes, что использует общий рынок. Клиент показывает форму размещения прямо под витриной посетителя и позволяет снять собственный активный лот.

В пользовательском разделе «Сервисы» столовая и ресторан всегда остаются доступными как точки входа в витрины, даже если краткий статус временно не загрузился. Они не возвращаются в управление мэра: руководителей у этих заведений нет. На странице заведения игрок выбирает конкретный лот повара; запросы eat и buy обязательно передают его offer_id и building_id.

HTTP API miniapp

  • POST /city/miniapp/channels/{route}/resource-market — выставить общий лот персонажа.
  • POST /city/miniapp/channels/{route}/resource-market/buy — частично или полностью купить общий лот.
  • POST /city/miniapp/channels/{route}/resource-market/cancel — отменить свой лот.
  • GET /city/miniapp/channels/{route}/resource-market/deliveries — покупки в доставке и история получения.
  • POST /city/miniapp/channels/{route}/resource-market/receive — самостоятельно получить доставку.
  • POST /city/miniapp/channels/{route}/resource-market/deliver — доставить покупку курьером.
  • GET /city/miniapp/channels/{route}/services/{slug}/showcase?building_id=... — витрина заведения.
  • POST /city/miniapp/channels/{route}/services/{slug}/showcase/list — выставить блюдо; тело содержит building_id.
  • POST /city/miniapp/channels/{route}/services/{slug}/showcase/cancel — снять собственный витринный лот.
  • POST /city/miniapp/channels/{route}/services/{slug}/eat — съесть предложение; обязательны offer_id и building_id.
  • POST /city/miniapp/channels/{route}/services/{slug}/takeaway — купить предложение навынос.

Для совместимости POST .../showcase и POST .../buy остаются псевдонимами list и takeaway.

Миграция

Миграция 20260727120000_city_autonomous_economy.sql:

  • добавляет категорию предмета material;
  • переносит старые city_character_materials в общий инвентарь через идемпотентный migration ledger;
  • переносит объектные ресурсы и остатки старых объектных лотов в городской склад, а объектные кошельки — в казну;
  • возвращает персонажам результат завершённых этапов и сырьё незавершённых этапов активных старых смен, после чего останавливает эти смены;
  • добавляет escrow scopes, семидневные лоты, резервы смен и персональные доставки.

Миграцию необходимо применить до запуска новой версии API.