Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarItem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarItem.cpp')
-rw-r--r--source/game/StarItem.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/source/game/StarItem.cpp b/source/game/StarItem.cpp
new file mode 100644
index 0000000..68590b5
--- /dev/null
+++ b/source/game/StarItem.cpp
@@ -0,0 +1,288 @@
+#include "StarItem.hpp"
+#include "StarRoot.hpp"
+#include "StarAssets.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarRandom.hpp"
+#include "StarLogging.hpp"
+#include "StarWorldLuaBindings.hpp"
+
+namespace Star {
+
+Item::Item(Json config, String directory, Json parameters) {
+ m_config = move(config);
+ m_directory = move(directory);
+ m_parameters = move(parameters);
+ m_name = m_config.getString("itemName");
+ m_count = 1;
+
+ m_maxStack = instanceValue("maxStack", Root::singleton().assets()->json("/items/defaultParameters.config:defaultMaxStack").toInt()).toInt();
+ m_shortDescription = instanceValue("shortdescription", "").toString();
+ m_description = instanceValue("description", "").toString();
+
+ m_rarity = RarityNames.getLeft(instanceValue("rarity").toString());
+
+ auto inventoryIcon = instanceValue("inventoryIcon", Root::singleton().assets()->json("/items/defaultParameters.config:missingIcon"));
+ if (inventoryIcon.type() == Json::Type::Array) {
+ List<Drawable> iconDrawables;
+ for (auto const& drawable : inventoryIcon.toArray()) {
+ auto image = AssetPath::relativeTo(m_directory, drawable.getString("image"));
+ Vec2F position = jsonToVec2F(drawable.getArray("position", {0, 0}));
+ iconDrawables.append(Drawable::makeImage(image, 1.0f, true, position));
+ }
+ setIconDrawables(move(iconDrawables));
+ } else {
+ auto image = AssetPath::relativeTo(m_directory, inventoryIcon.toString());
+ setIconDrawables({Drawable::makeImage(image, 1.0f, true, Vec2F())});
+ }
+
+ auto assets = Root::singleton().assets();
+ m_twoHanded = instanceValue("twoHanded", false).toBool();
+ m_price = instanceValue("price", assets->json("/items/defaultParameters.config:defaultPrice")).toInt();
+ m_tooltipKind = instanceValue("tooltipKind", "").toString();
+ auto largeImage = instanceValue("largeImage");
+ if (!largeImage.isNull())
+ m_largeImage = AssetPath::relativeTo(m_directory, largeImage.toString());
+
+ m_category = instanceValue("category", "").toString();
+ m_pickupSounds = jsonToStringSet(m_config.get("pickupSounds", JsonArray{}));
+ if (!m_pickupSounds.size())
+ m_pickupSounds = jsonToStringSet(assets->json("/items/defaultParameters.config:pickupSounds"));
+
+ m_timeToLive = instanceValue("timeToLive", Root::singleton().assets()->json("/items/defaultParameters.config:defaultTimeToLive").toFloat()).toFloat();
+
+ for (auto b : jsonToStringList(instanceValue("learnBlueprintsOnPickup", JsonArray{})))
+ m_learnBlueprintsOnPickup.append(ItemDescriptor(b));
+
+ for (auto pair : instanceValue("collectablesOnPickup", JsonObject{}).iterateObject())
+ m_collectablesOnPickup[pair.first] = pair.second.toString();
+}
+
+Item::~Item() {}
+
+String Item::name() const {
+ return m_name;
+}
+
+uint64_t Item::count() const {
+ return m_count;
+}
+
+uint64_t Item::setCount(uint64_t count, bool overfill) {
+ if (overfill)
+ m_count = count;
+ else
+ m_count = std::min(count, m_maxStack);
+ return count - m_count;
+}
+
+bool Item::stackableWith(ItemConstPtr const& item) const {
+ return item && name() == item->name() && parameters() == item->parameters();
+}
+
+uint64_t Item::maxStack() const {
+ return m_maxStack;
+}
+
+uint64_t Item::couldStack(ItemConstPtr const& item) const {
+ if (stackableWith(item) && m_count < m_maxStack) {
+ uint64_t take = m_maxStack - m_count;
+ return std::min(take, item->count());
+ } else {
+ return 0;
+ }
+}
+
+bool Item::stackWith(ItemPtr const& item) {
+ uint64_t take = couldStack(item);
+
+ if (take > 0 && item->consume(take)) {
+ m_count += take;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Item::matches(ItemDescriptor const& descriptor, bool exactMatch) const {
+ return descriptor.name() == m_name && (!exactMatch || descriptor.parameters() == m_parameters);
+}
+
+bool Item::matches(ItemConstPtr const& other, bool exactMatch) const {
+ return other->name() == m_name && (!exactMatch || other->parameters() == m_parameters);
+}
+
+bool Item::consume(uint64_t count) {
+ if (m_count >= count) {
+ m_count -= count;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+ItemPtr Item::take(uint64_t max) {
+ uint64_t takeCount = std::min(m_count, max);
+ if (takeCount != 0) {
+ if (auto newItems = clone()) {
+ m_count -= takeCount;
+ newItems->setCount(takeCount);
+ return newItems;
+ } else {
+ Logger::warn(strf("Could not clone %s, not moving %d items as requested.", friendlyName(), takeCount).c_str());
+ }
+ }
+
+ return {};
+}
+
+bool Item::empty() const {
+ return m_count == 0;
+}
+
+ItemDescriptor Item::descriptor() const {
+ return ItemDescriptor(m_name, m_count, m_parameters);
+}
+
+String Item::description() const {
+ return m_description;
+}
+
+String Item::friendlyName() const {
+ return m_shortDescription;
+}
+
+Rarity Item::rarity() const {
+ return m_rarity;
+}
+
+List<Drawable> Item::iconDrawables() const {
+ return m_iconDrawables;
+}
+
+List<Drawable> Item::dropDrawables() const {
+ auto drawables = iconDrawables();
+ Drawable::scaleAll(drawables, 1.0f / TilePixels);
+ return drawables;
+}
+
+bool Item::twoHanded() const {
+ return m_twoHanded;
+}
+
+float Item::timeToLive() const {
+ return m_timeToLive;
+}
+
+uint64_t Item::price() const {
+ return m_price * count();
+}
+
+String Item::tooltipKind() const {
+ return m_tooltipKind;
+}
+
+String Item::largeImage() const {
+ return m_largeImage;
+}
+
+String Item::category() const {
+ return m_category;
+}
+
+String Item::pickupSound() const {
+ return Random::randFrom(m_pickupSounds);
+}
+
+void Item::setMaxStack(uint64_t maxStack) {
+ m_maxStack = maxStack;
+}
+
+void Item::setDescription(String const& description) {
+ m_description = description;
+}
+
+void Item::setRarity(Rarity rarity) {
+ m_rarity = rarity;
+}
+
+void Item::setPrice(uint64_t price) {
+ m_price = price;
+}
+
+void Item::setIconDrawables(List<Drawable> drawables) {
+ m_iconDrawables = move(drawables);
+ auto boundBox = Drawable::boundBoxAll(m_iconDrawables, true);
+ if (!boundBox.isEmpty()) {
+ for (auto& drawable : m_iconDrawables)
+ drawable.translate(-boundBox.center());
+ // TODO: Why 16? Is this the size of the icon container? Shouldn't this
+ // be configurable?
+ float zoom = 16.0f / std::max(boundBox.width(), boundBox.height());
+ if (zoom < 1) {
+ for (auto& drawable : m_iconDrawables)
+ drawable.scale(zoom);
+ }
+ }
+}
+
+void Item::setTwoHanded(bool twoHanded) {
+ m_twoHanded = twoHanded;
+}
+
+void Item::setTimeToLive(float timeToLive) {
+ m_timeToLive = timeToLive;
+}
+
+List<QuestArcDescriptor> Item::pickupQuestTemplates() const {
+ return instanceValue("pickupQuestTemplates", JsonArray{}).toArray().transformed(&QuestArcDescriptor::fromJson);
+}
+
+StringSet Item::itemTags() const {
+ return jsonToStringSet(m_config.get("itemTags", JsonArray{}));
+}
+
+bool Item::hasItemTag(String const& itemTag) const {
+ return itemTags().contains(itemTag);
+}
+
+Json Item::instanceValue(String const& name, Json const& def) const {
+ return jsonMergeQueryDef(name, def, m_config, m_parameters);
+}
+
+Json Item::instanceValues() const {
+ return m_config.setAll(m_parameters.toObject());
+}
+
+Json Item::config() const {
+ return m_config;
+}
+
+Json Item::parameters() const {
+ return m_parameters;
+}
+
+void Item::setInstanceValue(String const& name, Json const& value) {
+ if (m_parameters.get(name, {}) != value)
+ m_parameters = m_parameters.setAll(JsonObject{{name, value}});
+}
+
+String const& Item::directory() const {
+ return m_directory;
+}
+
+List<ItemDescriptor> Item::learnBlueprintsOnPickup() const {
+ return m_learnBlueprintsOnPickup;
+}
+
+StringMap<String> Item::collectablesOnPickup() const {
+ return m_collectablesOnPickup;
+}
+
+GenericItem::GenericItem(Json const& config, String const& directory, Json const& parameters)
+ : Item(config, directory, parameters) {}
+
+ItemPtr GenericItem::clone() const {
+ return make_shared<GenericItem>(*this);
+}
+
+}