56 lines
2.8 KiB
C++
56 lines
2.8 KiB
C++
#pragma once
|
|
// The contents of a flask or barrel: MaterialInventoryComponent holds how much of each material it has (count_per_material_type). A flask keeps its materials
|
|
// apart (no reactions inside: do_reactions is 0 for potions), they react when they are poured out or spilled into the world.
|
|
// Representation on the component: count_per_material_type.mix = "water:700;radioactive_liquid:300", plus the main material (the largest part) and the total count
|
|
// under count_per_material_type.Material.material / .count (what scripts and the HUD read).
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "lua/entity_api.h"
|
|
|
|
namespace ng {
|
|
|
|
struct MixPart { std::string mat; double n = 0; };
|
|
|
|
inline std::vector<MixPart> mix_get(IEntityWorld& w, int comp) {
|
|
std::vector<MixPart> parts;
|
|
const LVal mix = w.get_value(comp, "count_per_material_type.mix", false);
|
|
if (mix.t == LVal::T::Str && !mix.s.empty()) {
|
|
size_t pos = 0;
|
|
while (pos < mix.s.size()) {
|
|
size_t end = mix.s.find(';', pos);
|
|
if (end == std::string::npos) end = mix.s.size();
|
|
const std::string item = mix.s.substr(pos, end - pos);
|
|
const size_t c = item.rfind(':');
|
|
if (c != std::string::npos) parts.push_back({item.substr(0, c), std::atof(item.c_str() + c + 1)});
|
|
pos = end + 1;
|
|
}
|
|
return parts;
|
|
}
|
|
const LVal m = w.get_value(comp, "count_per_material_type.Material.material", false), n = w.get_value(comp, "count_per_material_type.Material.count", false);
|
|
if (m.t == LVal::T::Str && !m.s.empty() && n.t == LVal::T::Str && std::atof(n.s.c_str()) > 0) parts.push_back({m.s, std::atof(n.s.c_str())});
|
|
return parts;
|
|
}
|
|
|
|
inline double mix_total(const std::vector<MixPart>& p) { double t = 0; for (const MixPart& x : p) t += x.n; return t; }
|
|
|
|
inline void mix_set(IEntityWorld& w, int comp, std::vector<MixPart> parts) {
|
|
parts.erase(std::remove_if(parts.begin(), parts.end(), [](const MixPart& x) { return x.n < 0.5; }), parts.end());
|
|
std::stable_sort(parts.begin(), parts.end(), [](const MixPart& a, const MixPart& b) { return a.n > b.n; });
|
|
std::string s;
|
|
for (const MixPart& x : parts) s += (s.empty() ? "" : ";") + x.mat + ":" + std::to_string((long long)std::llround(x.n));
|
|
w.set_value(comp, "count_per_material_type.mix", LVal::string(s));
|
|
w.set_value(comp, "count_per_material_type.Material.material", LVal::string(parts.empty() ? std::string() : parts.front().mat));
|
|
w.set_value(comp, "count_per_material_type.Material.count", LVal::string(std::to_string((long long)std::llround(mix_total(parts)))));
|
|
}
|
|
|
|
inline void mix_add(std::vector<MixPart>& parts, const std::string& mat, double n) {
|
|
for (MixPart& x : parts) if (x.mat == mat) { x.n += n; return; }
|
|
parts.push_back({mat, n});
|
|
}
|
|
|
|
} // namespace ng
|