feat: add kindIndex and clampInt
This commit is contained in:
1 parent
8ce02c1f47
commit
7ca8ae21c3
1 file changed
+142
@@ -0,0 +1,142 @@
|
|||||||
|
#include "vf/Gossip.h"
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int kindIndex(GossipKind kind) { return static_cast<int>(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<int>(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<int>(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<int>(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<int>(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<GossipEntry> GossipLedger::entries() const {
|
||||||
|
std::vector<GossipEntry> found;
|
||||||
|
for (int i = 0; i < static_cast<int>(GossipKind::Count); ++i) {
|
||||||
|
if (values[i] == 0) continue;
|
||||||
|
found.push_back({static_cast<GossipKind>(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<const GossipLedger*>& village) {
|
||||||
|
ReputationView view;
|
||||||
|
view.personal = personal.reputation();
|
||||||
|
view.majorNegative = personal.valueOf(GossipKind::MajorNegative);
|
||||||
|
view.villagerCount = static_cast<int>(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
|
||||||
Reference in new issue
Block a user