Files
Noita-GPU-Vulkan/src/entity/material_mix.h
T
2026-10-19 20:59:15 +02:00

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