188 lines
6.7 KiB
C++
188 lines
6.7 KiB
C++
#include "SelectionContentFactory.h"
|
|
|
|
#include "AutoProductionContent.h"
|
|
#include "BeltContent.h"
|
|
#include "DebrisContent.h"
|
|
#include "FactoryQueries.h"
|
|
#include "FieldMultiContent.h"
|
|
#include "HqContent.h"
|
|
#include "MultiBuildingContent.h"
|
|
#include "RecipeProductionContent.h"
|
|
#include "ShipContent.h"
|
|
#include "ShipIdentityComponent.h"
|
|
#include "ShipyardContent.h"
|
|
#include "SplitterContent.h"
|
|
#include "StationBodyComponent.h"
|
|
#include "StationContent.h"
|
|
#include "StorageContent.h"
|
|
#include "Simulation.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
// The catalog row a single building type belongs to (REQ-UI-SELECTION-CONTENT).
|
|
SelectionContentKind getKindForType(BuildingType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case BuildingType::Miner:
|
|
case BuildingType::Assembler:
|
|
return SelectionContentKind::RecipeProduction;
|
|
case BuildingType::Smelter:
|
|
case BuildingType::ReprocessingPlant:
|
|
return SelectionContentKind::AutoProduction;
|
|
case BuildingType::Shipyard:
|
|
return SelectionContentKind::Shipyard;
|
|
case BuildingType::SalvageBay:
|
|
return SelectionContentKind::Storage;
|
|
case BuildingType::Hq:
|
|
return SelectionContentKind::Hq;
|
|
case BuildingType::Belt:
|
|
case BuildingType::TunnelEntry:
|
|
case BuildingType::TunnelExit:
|
|
return SelectionContentKind::Belt;
|
|
case BuildingType::Splitter:
|
|
return SelectionContentKind::Splitter;
|
|
case BuildingType::PlayerDefenceStation:
|
|
case BuildingType::EnemyDefenceStation:
|
|
// Defence stations are field objects backed by entities; these two enum
|
|
// values exist only for cost and visuals lookup and never reach the panel as
|
|
// a building selection. The count summary is the harmless fallback.
|
|
return SelectionContentKind::MultiBuilding;
|
|
}
|
|
return SelectionContentKind::MultiBuilding;
|
|
}
|
|
|
|
// A belt, tunnel entry or tunnel exit -- the types whose card is the clear action alone
|
|
// and therefore aggregates (REQ-UI-SELECTION-AGGREGATE). The splitter is deliberately
|
|
// excluded: it carries per-object output filters, which have no aggregate.
|
|
bool isAggregatableBeltType(BuildingType type)
|
|
{
|
|
return type == BuildingType::Belt
|
|
|| type == BuildingType::TunnelEntry
|
|
|| type == BuildingType::TunnelExit;
|
|
}
|
|
|
|
ContentKey chooseBuildingContent(const SelectionRequest& request, Simulation& sim)
|
|
{
|
|
const FactoryState& state = sim.getFactoryState();
|
|
|
|
if (request.buildings.size() == 1)
|
|
{
|
|
const BuildingId id = request.buildings.front();
|
|
const Building* building = findBuilding(state, id);
|
|
if (building)
|
|
{
|
|
return { getKindForType(building->type), false };
|
|
}
|
|
const ConstructionSite* site = findSite(state, id);
|
|
if (site)
|
|
{
|
|
return { getKindForType(site->type), true };
|
|
}
|
|
// The building went away under the panel; the selection is stale and there is
|
|
// nothing to show (REQ-UI-EMPTY-SELECTION).
|
|
return {};
|
|
}
|
|
|
|
// Several buildings aggregate into one card only when every part of that card
|
|
// aggregates (REQ-UI-SELECTION-AGGREGATE). Construction sites are excluded from the
|
|
// belt case: a site's card is its own construction progress, which several sites
|
|
// cannot share.
|
|
bool allAggregatableBelts = true;
|
|
for (BuildingId id : request.buildings)
|
|
{
|
|
const Building* building = findBuilding(state, id);
|
|
if (!building || !isAggregatableBeltType(building->type))
|
|
{
|
|
allAggregatableBelts = false;
|
|
break;
|
|
}
|
|
}
|
|
if (allAggregatableBelts)
|
|
{
|
|
return { SelectionContentKind::Belt, false };
|
|
}
|
|
return { SelectionContentKind::MultiBuilding, false };
|
|
}
|
|
|
|
ContentKey chooseFieldContent(const SelectionRequest& request, Simulation& sim)
|
|
{
|
|
// A full single-object card is shown for a lone actor, and for debris whether one
|
|
// piece or several -- debris is the field category's other aggregating content
|
|
// (REQ-UI-FIELD-MULTI-SELECTION, REQ-UI-SELECTION-AGGREGATE).
|
|
if (request.actors.size() == 1 && request.debris.empty())
|
|
{
|
|
EntityAdmin& admin = sim.getAdmin();
|
|
const entt::entity actor = request.actors.front();
|
|
if (admin.isValid(actor) && admin.hasAll<ShipIdentityComponent>(actor))
|
|
{
|
|
return { SelectionContentKind::Ship, false };
|
|
}
|
|
if (admin.isValid(actor) && admin.hasAll<StationBodyComponent>(actor))
|
|
{
|
|
return { SelectionContentKind::Station, false };
|
|
}
|
|
return {};
|
|
}
|
|
|
|
if (request.actors.empty() && !request.debris.empty())
|
|
{
|
|
return { SelectionContentKind::Debris, false };
|
|
}
|
|
return { SelectionContentKind::FieldMulti, false };
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
ContentKey chooseContent(const SelectionRequest& request, Simulation& sim)
|
|
{
|
|
if (request.isEmpty())
|
|
{
|
|
return {};
|
|
}
|
|
// Buildings win, so a non-empty building selection is the whole selection
|
|
// (REQ-UI-SELECTION-CATEGORIES).
|
|
if (!request.buildings.empty())
|
|
{
|
|
return chooseBuildingContent(request, sim);
|
|
}
|
|
return chooseFieldContent(request, sim);
|
|
}
|
|
|
|
SelectionContent* createContent(const ContentKey& key, const SelectionRequest& request,
|
|
const SelectionContext& context, QWidget* parent)
|
|
{
|
|
switch (key.kind)
|
|
{
|
|
case SelectionContentKind::None:
|
|
return nullptr;
|
|
case SelectionContentKind::RecipeProduction:
|
|
return new RecipeProductionContent(context, request, parent);
|
|
case SelectionContentKind::AutoProduction:
|
|
return new AutoProductionContent(context, request, parent);
|
|
case SelectionContentKind::Shipyard:
|
|
return new ShipyardContent(context, request, parent);
|
|
case SelectionContentKind::Storage:
|
|
return new StorageContent(context, request, parent);
|
|
case SelectionContentKind::Hq:
|
|
return new HqContent(context, request, parent);
|
|
case SelectionContentKind::Belt:
|
|
return new BeltContent(context, request, parent);
|
|
case SelectionContentKind::Splitter:
|
|
return new SplitterContent(context, request, parent);
|
|
case SelectionContentKind::MultiBuilding:
|
|
return new MultiBuildingContent(context, request, parent);
|
|
case SelectionContentKind::Ship:
|
|
return new ShipContent(context, request, parent);
|
|
case SelectionContentKind::Station:
|
|
return new StationContent(context, request, parent);
|
|
case SelectionContentKind::Debris:
|
|
return new DebrisContent(context, request, parent);
|
|
case SelectionContentKind::FieldMulti:
|
|
return new FieldMultiContent(context, request, parent);
|
|
}
|
|
return nullptr;
|
|
}
|