From 07a9cd7bcaa81f3773b8cdcc74c3c3b9bba2e54c Mon Sep 17 00:00:00 2001 From: WarStalkeR Date: Sat, 30 Sep 2023 20:34:45 +0300 Subject: [PATCH] craft slot min/max size implementation + code refactor --- src/Basescape/BaseView.cpp | 3 +- src/Basescape/CraftInfoState.cpp | 10 +- src/Basescape/CraftWeaponsState.cpp | 4 +- src/Mod/RuleBaseFacility.cpp | 10 +- src/Mod/RuleBaseFacility.h | 70 +++++++++++- src/Mod/RuleCraft.cpp | 23 +++- src/Mod/RuleCraft.h | 6 +- src/Savegame/Base.cpp | 119 +++++++++++++++------ src/Savegame/Base.h | 21 ++-- src/Ufopaedia/ArticleStateBaseFacility.cpp | 7 +- src/Ufopaedia/StatsForNerdsState.cpp | 13 ++- src/version.h | 2 +- 12 files changed, 217 insertions(+), 71 deletions(-) diff --git a/src/Basescape/BaseView.cpp b/src/Basescape/BaseView.cpp index f75f755331..3da40c0b3b 100644 --- a/src/Basescape/BaseView.cpp +++ b/src/Basescape/BaseView.cpp @@ -564,7 +564,8 @@ void BaseView::draw() Craft* slotCraft = craftSlotIt->craft; const RuleCraft* slotRules = slotCraft->getRules(); Surface* frame = _texture->getFrame(slotCraft->getSkinSprite() + 33); - frame->blitNShade(this, craftSlotIt->x + slotRules->getBigOffsetX(), craftSlotIt->y + slotRules->getBigOffsetY()); + frame->blitNShade(this, craftSlotIt->x + slotRules->getSizeOffsetX(), + craftSlotIt->y + slotRules->getSizeOffsetY()); fac->setCraftForDrawing(slotCraft); } ++craftSlotIt; diff --git a/src/Basescape/CraftInfoState.cpp b/src/Basescape/CraftInfoState.cpp index 3a3e2b9be1..3de5819f26 100644 --- a/src/Basescape/CraftInfoState.cpp +++ b/src/Basescape/CraftInfoState.cpp @@ -113,13 +113,13 @@ CraftInfoState::CraftInfoState(Base *base, size_t craftId) : _base(base), _craft _txtWAmmo[i] = new Text(75, 24, x, y + 16); } const RuleCraft* craftRule = _craft->getRules(); - if (craftRule->getBigOffsetX() != 0 || craftRule->getBigOffsetY() != 0) + if (craftRule->getSizeOffsetX() != 0 || craftRule->getSizeOffsetY() != 0) { _sprite = new InteractiveSurface( - 32 + std::abs(craftRule->getBigOffsetX()) * 2, - 40 + std::abs(craftRule->getBigOffsetY()) * 2, - 144 + craftRule->getBigOffsetX(), - 56 + craftRule->getBigOffsetY()); + 32 + std::abs(craftRule->getSizeOffsetX()) * 2, + 40 + std::abs(craftRule->getSizeOffsetY()) * 2, + 144 + craftRule->getSizeOffsetX(), + 56 + craftRule->getSizeOffsetY()); } else { diff --git a/src/Basescape/CraftWeaponsState.cpp b/src/Basescape/CraftWeaponsState.cpp index 642bb5fc0f..46770981cf 100644 --- a/src/Basescape/CraftWeaponsState.cpp +++ b/src/Basescape/CraftWeaponsState.cpp @@ -195,7 +195,9 @@ void CraftWeaponsState::lstWeaponsClick(Action *) return refSlot.craft == refCraft; }); if (!((craftSlotIt != _base->getCraftSlots()->end() && - (craftSlotIt->size == 0 || craftSlotIt->size >= newCraftSize)) || + ((craftSlotIt->min == 0 && craftSlotIt->max == 0) || + (newCraftSize >= craftSlotIt->min && + newCraftSize <= craftSlotIt->max))) || _base->getFreeCraftSlots(newCraftSize) > 0)) allowChange = false; if (classChanged && !classChangeAllowed) diff --git a/src/Mod/RuleBaseFacility.cpp b/src/Mod/RuleBaseFacility.cpp index de3d77ad3c..6cc681e734 100644 --- a/src/Mod/RuleBaseFacility.cpp +++ b/src/Mod/RuleBaseFacility.cpp @@ -41,7 +41,7 @@ RuleBaseFacility::RuleBaseFacility(const std::string &type, int listOrder) : _lift(false), _hyper(false), _mind(false), _grav(false), _mindPower(1), _size(1), _buildCost(0), _refundValue(0), _buildTime(0), _monthlyCost(0), _storage(0), _personnel(0), _aliens(0), _crafts(0), _labs(0), _workshops(0), _psiLabs(0), - _spriteEnabled(false), _craftsHidden(false), _craftOptions({Position(0, 0, 0)}), + _spriteEnabled(false), _craftsHidden(false), _craftOptions(), _sightRange(0), _sightChance(0), _radarRange(0), _radarChance(0), _defense(0), _hitRatio(0), _fireSound(0), _hitSound(0), _placeSound(-1), _ammoNeeded(1), _listOrder(listOrder), _trainingRooms(0), _maxAllowedPerBase(0), _sickBayAbsoluteBonus(0.0f), _sickBayRelativeBonus(0.0f), @@ -101,7 +101,7 @@ void RuleBaseFacility::load(const YAML::Node &node, Mod *mod) _spriteEnabled = node["spriteEnabled"].as(_spriteEnabled); _craftsHidden = node["craftsHidden"].as(_craftsHidden); - _craftOptions = node["craftOptions"].as>(_craftOptions); + _craftOptions = node["craftOptions"].as>(_craftOptions); _sightRange = node["sightRange"].as(_sightRange); _sightChance = node["sightChance"].as(_sightChance); @@ -475,11 +475,9 @@ bool RuleBaseFacility::getCraftsHidden() const /** * Gets the list of craft placement and limit options. - * X - horizontal render offset, Y - vertical render offset, - * Z - hangar slot craft size limit. If 0, size is ignored. - * @return the list of options as X/Y/Z positions. + * @return the list of CraftOption entries. */ -const std::vector &RuleBaseFacility::getCraftOptions() const +const std::vector &RuleBaseFacility::getCraftOptions() const { return _craftOptions; } diff --git a/src/Mod/RuleBaseFacility.h b/src/Mod/RuleBaseFacility.h index e9bd49660b..8ece6da67f 100644 --- a/src/Mod/RuleBaseFacility.h +++ b/src/Mod/RuleBaseFacility.h @@ -34,6 +34,38 @@ class RuleItem; struct VerticalLevel; enum BasePlacementErrors : int; +struct CraftOption +{ + /// Horizontal offset for rendering craft in the facility. + int x = 0; + /// Vertical offset for rendering craft in the facility. + int y = 0; + /// Minimum size of craft that can be housed in the slot. + int min = 0; + /// Maximum size of craft that can be housed in the slot. + int max = 0; + /// Is craft hidden or rendered in the base in the slot. + bool hide = false; + /// Constructor with default parameters. Needed for YAML. + CraftOption() + { + hide = false; + min = 0; + max = 0; + x = 0; + y = 0; + } + /// Constructor that allows to define facility craft slots. + CraftOption(int xOffset, int yOffset, int minSize, int maxSize, bool isHidden) + { + hide = isHidden; + min = minSize; + max = maxSize; + x = xOffset; + y = yOffset; + } +}; + /** * Represents a specific type of base facility. * Contains constant info about a facility like @@ -58,7 +90,7 @@ class RuleBaseFacility std::map > _buildCostItems; int _storage, _personnel, _aliens, _crafts, _labs, _workshops, _psiLabs; bool _spriteEnabled, _craftsHidden; - std::vector _craftOptions; + std::vector _craftOptions; int _sightRange, _sightChance; int _radarRange, _radarChance, _defense, _hitRatio, _fireSound, _hitSound, _placeSound; int _ammoNeeded; @@ -156,7 +188,7 @@ class RuleBaseFacility /// Gets if facility's crafts are hidden or not. bool getCraftsHidden() const; /// Gets a list of which tiles are used to place items stored in this facility - const std::vector& getCraftOptions() const; + const std::vector& getCraftOptions() const; /// Gets the facility's sight range. int getSightRange() const { return _sightRange; } /// Gets the facility's alien base detection chance. @@ -218,3 +250,37 @@ class RuleBaseFacility }; } + +namespace YAML +{ + template<> + struct convert + { + static Node encode(const OpenXcom::CraftOption& crOpt) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node.push_back(crOpt.x); + node.push_back(crOpt.y); + node.push_back(crOpt.min); + node.push_back(crOpt.max); + node.push_back(crOpt.hide); + return node; + } + + static bool decode(const Node& node, OpenXcom::CraftOption& crOpt) + { + if (!node.IsSequence() || node.size() != 5) + return false; + + crOpt.x = node[0].as(); + crOpt.y = node[1].as(); + crOpt.min = node[2].as(); + crOpt.max = node[3].as(); + crOpt.hide = node[4].as(); + + if (crOpt.min > crOpt.max) return false; + return true; + } + }; +} diff --git a/src/Mod/RuleCraft.cpp b/src/Mod/RuleCraft.cpp index c376e8fc5d..072015699d 100644 --- a/src/Mod/RuleCraft.cpp +++ b/src/Mod/RuleCraft.cpp @@ -38,7 +38,7 @@ RuleCraft::RuleCraft(const std::string &type, int listOrder) : _maxSmallSoldiers(-1), _maxLargeSoldiers(-1), _maxSmallVehicles(-1), _maxLargeVehicles(-1), _maxSmallUnits(-1), _maxLargeUnits(-1), _maxSoldiers(-1), _maxVehicles(-1), _maxUnitsLimit(-1), _monthlyBuyLimit(0), _costBuy(0), _costRent(0), _costSell(0), _repairRate(1), _refuelRate(1), - _transferTime(24), _score(0), _battlescapeTerrainData(0), _maxSkinIndex(0), _bigOffsetX(0), _bigOffsetY(0), + _transferTime(24), _score(0), _battlescapeTerrainData(0), _maxSkinIndex(0), _spriteSize(32, 40), _keepCraftAfterFailedMission(false), _allowLanding(true), _spacecraft(false), _notifyWhenRefueled(false), _autoPatrol(false), _undetectable(false), _listOrder(listOrder), _maxItems(0), _maxAltitude(-1), _maxStorageSpace(0.0), _stats(), _shieldRechargeAtBase(1000), @@ -139,8 +139,7 @@ void RuleCraft::load(const YAML::Node &node, Mod *mod, const ModScript &parsers) _craftInventoryTile = craftInventoryTile.as >(_craftInventoryTile); } _maxSkinIndex = node["maxSkinIndex"].as(_maxSkinIndex); - _bigOffsetX = node["bigOffsetX"].as(_bigOffsetX); - _bigOffsetY = node["bigOffsetY"].as(_bigOffsetY); + _spriteSize = node["spriteSize"].as>(_spriteSize); _deployment = node["deployment"].as< RuleCraftDeployment >(_deployment); _keepCraftAfterFailedMission = node["keepCraftAfterFailedMission"].as(_keepCraftAfterFailedMission); _allowLanding = node["allowLanding"].as(_allowLanding); @@ -273,6 +272,24 @@ int RuleCraft::getCraftSize() const return _stats.craftSize; } +/** + * Gets the craft's sprite horizontal offset. + * @return The offset in integer value. + */ +int RuleCraft::getSizeOffsetX() const +{ + return (32 - _spriteSize.first) / 2; +} + +/** + * Gets the craft's sprite vertical offset. + * @return The offset in integer value. + */ +int RuleCraft::getSizeOffsetY() const +{ + return (40 - _spriteSize.second) / 2; +} + /** * Gets the maximum fuel the craft can contain. * @return The fuel amount. diff --git a/src/Mod/RuleCraft.h b/src/Mod/RuleCraft.h index 11cf4e28b3..7f42d126d9 100644 --- a/src/Mod/RuleCraft.h +++ b/src/Mod/RuleCraft.h @@ -193,7 +193,7 @@ class RuleCraft int _repairRate, _refuelRate, _transferTime, _score; RuleTerrain *_battlescapeTerrainData; int _maxSkinIndex; - int _bigOffsetX, _bigOffsetY; + std::pair _spriteSize; bool _keepCraftAfterFailedMission, _allowLanding, _spacecraft, _notifyWhenRefueled, _autoPatrol, _undetectable; int _listOrder, _maxItems, _maxAltitude; double _maxStorageSpace; @@ -237,9 +237,9 @@ class RuleCraft /// Gets the craft's hull size. int getCraftSize() const; /// Gets the craft's sprite horizontal offset. - int getBigOffsetX() const { return _bigOffsetX; } + int getSizeOffsetX() const; /// Gets the craft's sprite vertical offset. - int getBigOffsetY() const { return _bigOffsetY; } + int getSizeOffsetY() const; /// Gets the craft's maximum fuel. int getMaxFuel() const; /// Gets the craft's maximum damage. diff --git a/src/Savegame/Base.cpp b/src/Savegame/Base.cpp index 5d43de34b8..69a8f0fa40 100644 --- a/src/Savegame/Base.cpp +++ b/src/Savegame/Base.cpp @@ -1008,14 +1008,13 @@ void Base::updateCraftSlots() if (size_t(i) < fac->getRules()->getCraftOptions().size()) { const auto& refOpts = fac->getRules()->getCraftOptions()[i]; - int trueSlotSize = refOpts.z >= 0 ? refOpts.z : std::abs(refOpts.z + 1); - _craftSlots.push_back(CraftSlot(nullptr, refOpts.z < 0 || hidesCrafts, trueSlotSize, + _craftSlots.push_back(CraftSlot(fac, nullptr, refOpts.hide || hidesCrafts, refOpts.min, refOpts.max, fac->getX() * GRID_SIZE + (fac->getRules()->getSize() - 1) * GRID_SIZE / 2 + refOpts.x, fac->getY() * GRID_SIZE + (fac->getRules()->getSize() - 1) * GRID_SIZE / 2 + refOpts.y)); } - else // Default craft offsets for a single slot hangar. + else // Default center offsets for hangars with undefined craft slots. { - _craftSlots.push_back(CraftSlot(nullptr, false, 0, + _craftSlots.push_back(CraftSlot(fac, nullptr, false, 0, 0, fac->getX() * GRID_SIZE + (fac->getRules()->getSize() - 1) * GRID_SIZE / 2 + 2, fac->getY() * GRID_SIZE + (fac->getRules()->getSize() - 1) * GRID_SIZE / 2 - 4)); } @@ -1023,11 +1022,12 @@ void Base::updateCraftSlots() } } - if (_craftSlots.size() > 0) + if (Options::debugLogging && _craftSlots.size() > 0) { for (size_t i = 0; i < _craftSlots.size(); ++i) - Log(LOG_DEBUG) << "Base: " << _name << ", Hangar Slot #" << i << ", Offset: [" - << _craftSlots[i].x << "," << _craftSlots[i].y << "], Size: " << _craftSlots[i].size; + Log(LOG_DEBUG) << "Base: " << _name << ", " << _craftSlots[i].parent->getRules()->getType() + << " Slot #" << i << ", Offset: [" << _craftSlots[i].x << "," << _craftSlots[i].y + << "], Size: " << _craftSlots[i].min << "~" << _craftSlots[i].max; } } @@ -1040,22 +1040,24 @@ void Base::syncCraftSlots() { slot.craft = nullptr; }); if (_crafts.size() <= 0) return; - std::vector slotSizes; std::vector craftSizes; - for (const Craft* refCraft : _crafts) + std::vector> slotSizes; + for (const Craft* refCraft : _crafts) // List of all craft sizes. { const int& refCraftSize = refCraft->getCraftSize(); - if (std::find(craftSizes.begin(), craftSizes.end(), refCraftSize) == craftSizes.end()) + if (std::find(craftSizes.begin(), craftSizes.end(), + refCraftSize) == craftSizes.end()) craftSizes.push_back(refCraftSize); } - for (const CraftSlot& refSlot : _craftSlots) + for (const CraftSlot& refSlot : _craftSlots) // List of all slot sizes. { - const int& refSlotSize = refSlot.size; - if (std::find(slotSizes.begin(), slotSizes.end(), refSlotSize) == slotSizes.end()) + const std::pair refSlotSize(refSlot.max, refSlot.min); + if (std::find(slotSizes.begin(), slotSizes.end(), + refSlotSize) == slotSizes.end()) slotSizes.push_back(refSlotSize); } std::sort(craftSizes.begin(), craftSizes.end(), std::greater()); // Bigger crafts first. - std::sort(slotSizes.begin(), slotSizes.end()); // Smallest slots first. + std::sort(slotSizes.begin(), slotSizes.end()); // Smallest by max size slots first. for (const int& craftSize : craftSizes) { @@ -1063,13 +1065,16 @@ void Base::syncCraftSlots() { bool gotPlace = false; if (_crafts[i]->getCraftSize() != craftSize) continue; // Mixing sizes works bad. - for (const int& slotSize : slotSizes) + for (const auto& slotSize : slotSizes) { - if (slotSize < craftSize) continue; // Ignore, if slot is smaller than craft. + if (craftSize > slotSize.first || craftSize < slotSize.second) + continue; // Ignore, if incompatible craft slot. for (size_t j = 0; j < _craftSlots.size(); ++j) // We need slot index. { - if (_craftSlots[j].size == 0 && craftSize > 0) continue; // Ignore zero size slots if craft has size. - if (_craftSlots[j].craft == nullptr && _craftSlots[j].size == slotSize) // Gradually check for bigger empty slots. + if ((_craftSlots[j].min == 0 && _craftSlots[j].max == 0) && craftSize > 0) + continue; // Ignore zero size slots if craft has size. + if (_craftSlots[j].craft == nullptr && _craftSlots[j].max == slotSize.first && + _craftSlots[j].min == slotSize.second) // Gradually check for bigger empty slots. { _craftSlots[j].craft = _crafts[i]; gotPlace = true; @@ -1081,7 +1086,8 @@ void Base::syncCraftSlots() if (gotPlace) continue; // No suitable slot size? Try to look for zero size one. for (size_t j = 0; j < _craftSlots.size(); ++j) { - if (_craftSlots[j].size != 0) continue; // Ignore non-zero size slots and disregard craft's size. + if (_craftSlots[j].min != 0 || _craftSlots[j].min != 0) + continue; // Ignore non-zero size slots and disregard craft's size. if (_craftSlots[j].craft == nullptr) { _craftSlots[j].craft = _crafts[i]; @@ -1090,7 +1096,8 @@ void Base::syncCraftSlots() } } if (gotPlace) continue; // Not found zero slot either? Just place craft anywhere. - Log(LOG_WARNING) << "Craft: " << _crafts[i]->getType() << ", ID: " << _crafts[i]->getId() << " - couldn't find compatible hangar slot. Using first available!"; + Log(LOG_WARNING) << "Craft: " << _crafts[i]->getType() << ", ID: " << _crafts[i]->getId() + << " - couldn't find compatible hangar slot. Using first available!"; for (size_t j = 0; j < _craftSlots.size(); ++j) { if (_craftSlots[j].craft == nullptr) @@ -1102,13 +1109,14 @@ void Base::syncCraftSlots() } } - if (_craftSlots.size() > 0) + if (Options::debugLogging && _craftSlots.size() > 0) { for (size_t i = 0; i < _craftSlots.size(); ++i) if (_craftSlots[i].craft != nullptr) - Log(LOG_DEBUG) << "Base: " << _name << ", Used Slot #" << i << ", Offset: [" - << _craftSlots[i].x << "," << _craftSlots[i].y << "], Size: " << _craftSlots[i].size - << ", Craft: " << _craftSlots[i].craft->getType() << "-" << _craftSlots[i].craft->getId(); + Log(LOG_DEBUG) << "Base: " << _name << ", " << _craftSlots[i].parent->getRules()->getType() + << ", Slot #" << i << ", Offset: [" << _craftSlots[i].x << "," << _craftSlots[i].y + << "], Size: " << _craftSlots[i].min << "~" << _craftSlots[i].max << ", Craft: " + << _craftSlots[i].craft->getType() << "-" << _craftSlots[i].craft->getId(); } } @@ -1128,23 +1136,66 @@ void Base::syncCraftChanges() */ int Base::getFreeCraftSlots(int craftSize) const { - int freeSlotsNum = 0; - + // Collect and sort all available craft slots. + std::vector> freeSlots; for (size_t i = 0; i < _craftSlots.size(); ++i) - if (_craftSlots[i].craft == nullptr && (craftSize <= 0 || _craftSlots[i].size == 0 || _craftSlots[i].size >= craftSize)) - freeSlotsNum++; + { + if (_craftSlots[i].craft == nullptr && (craftSize <= 0 || + (_craftSlots[i].min == 0 && _craftSlots[i].max == 0) || + (craftSize >= _craftSlots[i].min && craftSize <= _craftSlots[i].max))) + { + freeSlots.push_back(std::make_pair( + _craftSlots[i].max, _craftSlots[i].min)); + } + } + std::sort(freeSlots.begin(), freeSlots.end()); + // Reserve suitable slots for all incoming transfers. for (const auto* transfer : _transfers) - if (transfer->getType() == TRANSFER_CRAFT && transfer->getCraft()->getCraftSize() >= craftSize) - freeSlotsNum -= transfer->getQuantity(); + { + if (transfer->getType() == TRANSFER_CRAFT) + { + const auto& trSize = transfer->getCraft()->getCraftSize(); + for (int i = 0; i < transfer->getQuantity(); ++i) + { + for (auto fsIt = freeSlots.begin(); fsIt != freeSlots.end(); /* NOPE */) + { + if (trSize >= fsIt->second && trSize <= fsIt->first) + { + fsIt = freeSlots.erase(fsIt); + break; + } + else ++fsIt; + } + } + } + } + // Reserve suitable slots for all ongoing productions. for (const auto* prod : _productions) - if (prod->getRules()->getProducedCraft() && prod->getRules()->getProducedCraft()->getCraftSize() >= craftSize) - freeSlotsNum -= (prod->getAmountTotal() - prod->getAmountProduced()); + { + if (prod->getRules()->getProducedCraft()) + { + const auto& prSize = prod->getRules()->getProducedCraft()->getCraftSize(); + for (int i = 0; i < (prod->getAmountTotal() - prod->getAmountProduced()); ++i) + { + for (auto fsIt = freeSlots.begin(); fsIt != freeSlots.end(); /* NOPE */) + { + if (prSize >= fsIt->second && prSize <= fsIt->first) + { + fsIt = freeSlots.erase(fsIt); + break; + } + else ++fsIt; + } + } + } + } - Log(LOG_DEBUG) << "Base: " << _name << " requested number of free slots for size " << craftSize << ". Response: " << freeSlotsNum; + Log(LOG_DEBUG) << "Base: " << _name << " requested number of free slots for size " + << craftSize << ". Response: " << freeSlots.size(); - return freeSlotsNum; + return (int)freeSlots.size(); } /** diff --git a/src/Savegame/Base.h b/src/Savegame/Base.h index c0e8c8da29..5053a5275e 100644 --- a/src/Savegame/Base.h +++ b/src/Savegame/Base.h @@ -86,21 +86,28 @@ struct BaseSumDailyRecovery struct CraftSlot { + /// Pointer to the parent facility, where the slot belongs. + const BaseFacility* parent = nullptr; /// Pointer to the craft which is housed in the slot. Craft* craft = nullptr; - /// Flag if craft is hidden or rendered in the base at this position. + /// Is craft hidden or rendered in the base in the slot. bool hidden = false; - /// Size of the slot where the craft will be housed. - int size = 0; - /// Horizontal offset for rendering craft in the base. + /// Minimum size of craft that can be housed in the slot. + int min = 0; + /// Maximum size of craft that can be housed in the slot. + int max = 0; + /// Horizontal offset for rendering craft in the facility. int x = 0; - /// Vertical offset for rendering craft in the base. + /// Vertical offset for rendering craft in the facility. int y = 0; /// Constructor that allows to create new craft slots. - CraftSlot(Craft* craftPtr, bool isCraftHidden, int slotSize, int xOffset, int yOffset) { + CraftSlot(const BaseFacility* facPtr, Craft* craftPtr, bool isCraftHidden, + int minSize, int maxSize, int xOffset, int yOffset) { + parent = facPtr; craft = craftPtr; hidden = isCraftHidden; - size = slotSize; + min = minSize; + max = maxSize; x = xOffset; y = yOffset; } diff --git a/src/Ufopaedia/ArticleStateBaseFacility.cpp b/src/Ufopaedia/ArticleStateBaseFacility.cpp index 33558077da..6960de931b 100644 --- a/src/Ufopaedia/ArticleStateBaseFacility.cpp +++ b/src/Ufopaedia/ArticleStateBaseFacility.cpp @@ -146,9 +146,10 @@ namespace OpenXcom const auto& hangarOptions = facility->getCraftOptions(); for (const auto& refSlot : hangarOptions) { - int slotSize = refSlot.z >= 0 ? refSlot.z : std::abs(refSlot.z + 1); - const std::string craftClass = _game->getMod()->getCraftClassFromSize(slotSize); - const std::string slotClass = craftClass.empty() ? std::to_string(slotSize) : tr(craftClass + "_UC").c_str(); + const std::string craftClass = + _game->getMod()->getCraftClassFromSize(refSlot.max); + const std::string slotClass = craftClass.empty() ? + std::to_string(refSlot.max) : tr(craftClass + "_UC").c_str(); auto craftHangarIt = craftHangars.find(slotClass); if (craftHangarIt != craftHangars.end()) ++(craftHangarIt->second); else craftHangars.emplace(slotClass, 1); diff --git a/src/Ufopaedia/StatsForNerdsState.cpp b/src/Ufopaedia/StatsForNerdsState.cpp index 8875ced76c..f6ef945523 100644 --- a/src/Ufopaedia/StatsForNerdsState.cpp +++ b/src/Ufopaedia/StatsForNerdsState.cpp @@ -3089,16 +3089,19 @@ void StatsForNerdsState::initFacilityList() if (facilityRule->getCraftOptions().size() > 0) { - std::vector craftSlotSizes; + std::vector craftSlotSizes; for (size_t i = 0; i < facilityRule->getCraftOptions().size(); ++i) { if ((int)i > (facilityRule->getCrafts() - 1)) break; - int refSize = facilityRule->getCraftOptions().at(i).z; - int trueSlotSize = refSize >= 0 ? refSize : std::abs(refSize + 1); - craftSlotSizes.push_back(trueSlotSize); + std::ostringstream slotEntry; + const int& minSize = facilityRule->getCraftOptions().at(i).min; + const int& maxSize = facilityRule->getCraftOptions().at(i).max; + if (minSize == maxSize) slotEntry << "[" << maxSize << "]"; + else slotEntry << "[" << minSize << "~" << maxSize << "]"; + craftSlotSizes.push_back(slotEntry.str()); } std::sort(craftSlotSizes.begin(), craftSlotSizes.end()); - addVectorOfIntegers(ss, craftSlotSizes, "craftSlotSizes"); + addVectorOfStrings(ss, craftSlotSizes, "craftSlotSizes", false); } addInteger(ss, facilityRule->getLaboratories(), "labs"); diff --git a/src/version.h b/src/version.h index faa4533e3c..e038f9ae39 100644 --- a/src/version.h +++ b/src/version.h @@ -24,5 +24,5 @@ #define OPENXCOM_VERSION_NUMBER 7,9,8,0 #ifndef OPENXCOM_VERSION_GIT -#define OPENXCOM_VERSION_GIT " (v2023-09-29)" +#define OPENXCOM_VERSION_GIT " (v2023-09-30)" #endif