From 7ca8ae21c30879f9cfbcf8cebe4937d1aa3d3d41 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 7 Sep 2026 19:40:51 +0200 Subject: [PATCH] feat: add kindIndex and clampInt --- core/src/Gossip.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 core/src/Gossip.cpp diff --git a/core/src/Gossip.cpp b/core/src/Gossip.cpp new file mode 100644 index 0000000..a8aaadd --- /dev/null +++ b/core/src/Gossip.cpp @@ -0,0 +1,142 @@ +#include "vf/Gossip.h" + +namespace vf { + +namespace { + +int kindIndex(GossipKind kind) { return static_cast(kind); } + +int clampInt(int value, int low, int high) { + if (value < low) return low; + if (value > high) return high; + return value; +} + +const GossipEntry::Tuning tuningTable[static_cast(GossipKind::Count)] = { + // weight, maxValue, decayPerDay, shareCap, sharePercent + {5, 100, 10, 0, 0}, + {5, 200, 20, 100, 50}, + {1, 25, 2, 20, 50}, + {-5, 200, 20, 100, 50}, + {-5, 100, 2, 0, 0}, +}; + +} // namespace + +const char* gossipKindName(GossipKind kind) { + switch (kind) { + case GossipKind::MajorPositive: return "majorPositive"; + case GossipKind::MinorPositive: return "minorPositive"; + case GossipKind::Trading: return "trading"; + case GossipKind::MinorNegative: return "minorNegative"; + case GossipKind::MajorNegative: return "majorNegative"; + case GossipKind::Count: break; + } + return "unknown"; +} + +const GossipEntry::Tuning& gossipTuning(GossipKind kind) { + return tuningTable[kindIndex(kind)]; +} + +int GossipLedger::add(GossipKind kind, int amount) { + if (amount == 0) return 0; + const GossipEntry::Tuning& tuning = gossipTuning(kind); + int& slot = values[kindIndex(kind)]; + int before = slot; + slot = clampInt(slot + amount, 0, tuning.maxValue); + return slot - before; +} + +int GossipLedger::valueOf(GossipKind kind) const { return values[kindIndex(kind)]; } + +int GossipLedger::reputation() const { + int total = 0; + for (int i = 0; i < static_cast(GossipKind::Count); ++i) + total += values[i] * tuningTable[i].weight; + return total; +} + +bool GossipLedger::decayDays(int days) { + if (days <= 0) return false; + bool changed = false; + for (int i = 0; i < static_cast(GossipKind::Count); ++i) { + if (values[i] == 0) continue; + int faded = clampInt(values[i] - tuningTable[i].decayPerDay * days, 0, tuningTable[i].maxValue); + if (faded != values[i]) { + values[i] = faded; + changed = true; + } + } + return changed; +} + +bool GossipLedger::shareInto(GossipLedger& receiver) const { + bool changed = false; + for (int i = 0; i < static_cast(GossipKind::Count); ++i) { + const GossipEntry::Tuning& tuning = tuningTable[i]; + if (!tuning.shareable() || values[i] <= 0) continue; + int& target = receiver.values[i]; + if (target >= tuning.shareCap) continue; + int transferred = values[i] * tuning.sharePercent / 100; + if (transferred <= 0) continue; + int raised = clampInt(target + transferred, 0, tuning.shareCap); + if (raised != target) { + target = raised; + changed = true; + } + } + return changed; +} + +std::vector GossipLedger::entries() const { + std::vector found; + for (int i = 0; i < static_cast(GossipKind::Count); ++i) { + if (values[i] == 0) continue; + found.push_back({static_cast(i), values[i]}); + } + return found; +} + +int GossipLedger::entryCount() const { + int count = 0; + for (int value : values) + if (value != 0) ++count; + return count; +} + +bool GossipLedger::empty() const { return entryCount() == 0; } + +void GossipLedger::forget(GossipKind kind) { values[kindIndex(kind)] = 0; } + +void GossipLedger::clear() { + for (int& value : values) value = 0; +} + +int ReputationView::discountPercent() const { + return clampInt(personal / 10, -60, 60); +} + +ReputationView buildReputation(const GossipLedger& personal, + const std::vector& village) { + ReputationView view; + view.personal = personal.reputation(); + view.majorNegative = personal.valueOf(GossipKind::MajorNegative); + view.villagerCount = static_cast(village.size()); + + if (village.empty()) { + view.village = view.personal; + return view; + } + + int sum = 0; + for (const GossipLedger* ledger : village) { + sum += ledger->reputation(); + int major = ledger->valueOf(GossipKind::MajorNegative); + if (major > view.majorNegative) view.majorNegative = major; + } + view.village = sum / view.villagerCount; + return view; +} + +} // namespace vf