feat(vf): add GossipEntry and Tuning
This commit is contained in:
1 parent
24a8171dab
commit
59af42843d
1 file changed
+104
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace vf {
|
||||
|
||||
// What a village remembers about one player. Every kind accumulates its own
|
||||
// saturating counter; the signed sum of those counters weighted per kind is the
|
||||
// reputation that trade prices and iron golem hostility read.
|
||||
enum class GossipKind : uint8_t {
|
||||
MajorPositive = 0, // saved the village from a raid
|
||||
MinorPositive = 1, // helped a villager
|
||||
Trading = 2, // completed a trade
|
||||
MinorNegative = 3, // hit a villager
|
||||
MajorNegative = 4, // killed a villager
|
||||
Count,
|
||||
};
|
||||
|
||||
const char* gossipKindName(GossipKind kind);
|
||||
|
||||
// Value granted by one occurrence of each kind.
|
||||
constexpr int gossipMajorPositiveGain = 20;
|
||||
constexpr int gossipMinorPositiveGain = 25;
|
||||
constexpr int gossipTradingGain = 2;
|
||||
constexpr int gossipMinorNegativeGain = 25;
|
||||
constexpr int gossipMajorNegativeGain = 25;
|
||||
|
||||
// Reputation at or below which iron golems turn on the player.
|
||||
constexpr int golemHostileReputation = -100;
|
||||
|
||||
struct GossipEntry {
|
||||
// Per-kind rules: how much a point of this kind is worth, where it
|
||||
// saturates, how fast it fades per in-game day, and how far it travels when
|
||||
// two villagers meet. A zero sharePercent means the kind never spreads.
|
||||
struct Tuning {
|
||||
int weight = 1;
|
||||
int maxValue = 100;
|
||||
int decayPerDay = 10;
|
||||
int shareCap = 0;
|
||||
int sharePercent = 0;
|
||||
|
||||
bool shareable() const { return sharePercent > 0 && shareCap > 0; }
|
||||
};
|
||||
|
||||
GossipKind kind = GossipKind::Trading;
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
const GossipEntry::Tuning& gossipTuning(GossipKind kind);
|
||||
|
||||
// One villager's memory of the player. Values only ever saturate at their per
|
||||
// kind cap, so no single event source can dominate the sum without bound.
|
||||
class GossipLedger {
|
||||
public:
|
||||
// Adds `amount` points of `kind`, clamped into [0, maxValue]. Returns the
|
||||
// amount actually stored.
|
||||
int add(GossipKind kind, int amount);
|
||||
|
||||
int valueOf(GossipKind kind) const;
|
||||
|
||||
// Signed weighted sum across every kind.
|
||||
int reputation() const;
|
||||
|
||||
// Fades every kind by its own per-day rate. Returns true when anything moved.
|
||||
bool decayDays(int days);
|
||||
|
||||
// Spreads shareable kinds into `receiver`. The receiver can never be pushed
|
||||
// past the kind's share cap by gossip alone, so repeated meetings converge
|
||||
// instead of growing without limit. Returns true when the receiver changed.
|
||||
bool shareInto(GossipLedger& receiver) const;
|
||||
|
||||
// Non-zero entries in GossipKind order.
|
||||
std::vector<GossipEntry> entries() const;
|
||||
|
||||
int entryCount() const;
|
||||
bool empty() const;
|
||||
void forget(GossipKind kind);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
int values[static_cast<int>(GossipKind::Count)] = {};
|
||||
};
|
||||
|
||||
// Reputation resolved for one villager against the backdrop of its village:
|
||||
// `personal` drives that villager's prices, `village` drives golem hostility.
|
||||
struct ReputationView {
|
||||
int personal = 0;
|
||||
int village = 0;
|
||||
int villagerCount = 0;
|
||||
int majorNegative = 0;
|
||||
|
||||
// Positive lowers prices, negative raises them. Clamped to keep a single
|
||||
// extreme ledger from making goods free.
|
||||
int discountPercent() const;
|
||||
|
||||
bool golemHostile() const { return village <= golemHostileReputation; }
|
||||
bool friendly() const { return personal > 0; }
|
||||
};
|
||||
|
||||
ReputationView buildReputation(const GossipLedger& personal,
|
||||
const std::vector<const GossipLedger*>& village);
|
||||
|
||||
} // namespace vf
|
||||
Reference in new issue
Block a user