squad-proto/src/sim/loot.h
z.kirill 7d6266aaf3 Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.

ДВИЖОК (engine/, цель tile2d)

  Каталог свой, и решение «это движок» принимается тем, куда положен файл.
  Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
  и карты уехали в engine/config.h, потолок населения этажа стал своим
  (MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
  центром карты вместо позиции отряда.

  engine/projection.*  единственное место, где движок знает про изометрию;
                       видов сразу два — абстракция с одной реализацией ничем
                       не проверена и обычно оказывается неправильной
  engine/project.*     манифест проекта: пути, вид, кривая глубины
  engine/app.*         окно, кадр, fixed timestep — вместо двух копий цикла
  engine/tilemap_draw  движок научился показывать свою карту

РЕДАКТОР (editor/, цель tile2d_editor)

  Открывает любой проект и ни одной игры по имени не знает.
  --tool  одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
          этажа, ASCII-карта, проверка набора. Правку делают файлами,
          последствия читают командой (docs/19-agent.md)
  терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
          открытый проект уходит потомкам через TILE2D_PROJECT

ПРИМЕР (samples/walk, цель tile2d_walk)

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

ИГРА (src/)

  Экстракшен: вес и два порога переноски, конечный боезапас, расходники
  применяются сами, общая сумка отряда, трата опыта на улучшения.

  Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
  вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
  боец с клинком не тратил найденные патроны при запасном стволе в сумке;
  массив виджетов экрана переполнился и молча съел хвост схрона; проверка
  улучшений сама ломала забег, вызывая NewRun посреди спуска.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 21:07:19 +03:00

56 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
// -----------------------------------------------------------------------------
// Предмет, лежащий на полу, и его подбор.
//
// Зачем отдельная сущность, а не «выдать предмет при убийстве»: в игре про
// спуск находка — это МЕСТО, до которого надо дойти. Лут, падающий в инвентарь
// сам, не заставляет никуда идти и превращает «лучше лут глубже» в строку в
// логе. Лежащий предмет виден в темноте плохо, лежит он там, куда отряд ещё не
// заходил, и за ним надо разомкнуть строй — это и есть цена находки.
//
// Подбор ПАССИВНЫЙ: боец, прошедший по предмету, поднимает его. Отдельной
// кнопки нет намеренно — игрок и так не нажимает «огонь» (спек 5), и заводить
// ради лута первое ручное действие в игре значило бы менять её жанр.
//
// FloorItem — компонент ECS в своём пуле, как Target и Bullet. Правила боя про
// него не знают вообще: ни решатель, ни LaneClear, ни клинок его не видят.
// -----------------------------------------------------------------------------
#include <vector>
#include "engine/math.h"
#include "ecs/ecs.h"
#include "sim/events.h"
#include "sim/items.h"
struct Agent;
struct FloorItem
{
ecs::Entity self = ecs::NO_ENTITY;
ItemId id = ItemId::NONE;
Vec2 pos{};
// Предмет не удаляется в момент подбора: пул перетасовывается swap-remove,
// а по нему в этот момент идёт цикл. Помеченные снимаются одним проходом
// после него.
bool taken = false;
// Сколько секунд предмет НЕ подбирается. Нужно ровно одному случаю: вещь,
// которую боец только что выбросил, лежит у него под ногами, и пассивный
// подбор поднял бы её тем же шагом. Выбросить стало бы невозможно.
float noPickup = 0.0f;
};
// pickupDelay > 0 — предмет полежит, прежде чем его снова можно подобрать.
void SpawnFloorItem(ecs::World& world, ItemId id, Vec2 pos, float pickupDelay = 0.0f);
// Подбор за шаг. Возвращает, сколько предметов поднято.
//
// Мёртвый боец ничего не подбирает, полная сумка — тоже: предмет остаётся
// лежать, и это правильно. «Некуда положить» обязано быть видно как лежащий
// под ногами предмет, а не как молча пропавшая находка.
// Подбирают В ОБЩУЮ СУМКУ: кто прошёл по предмету, тот его и поднял, но
// достанется он всему отряду. carriers — на скольких живых делится ноша.
int UpdateLootPickup(ecs::World& world, Agent* agents, int agentCount, SquadBag& bag,
int carriers, float carryBonus, CombatEventLog* events, float dt);