[Merchants] Add New Classic Greed/Faction/Charisma Prices Rule (#4301)

* [Merchants] Add New Classic Greed/Faction/Charisma Prices Rule

* Fix size of greed field.

* Fix { formatting and add {} to one liners

* Fix return type of GetGreedPercent

* Remove code that slipped in from another patch

* Fix greed to be unsigned

* Update client.cpp

* Update client_packet.cpp

* Update client.cpp

Fix bad name in extra log message added manually from merge.

* Update client_packet.cpp

Spacing.

* Update client.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
This commit is contained in:
Paul Coene
2024-05-17 11:16:02 -04:00
committed by GitHub
parent a80ab75260
commit c0a8fd097e
11 changed files with 605 additions and 457 deletions
+89 -2
View File
@@ -3761,7 +3761,83 @@ void Client::Escape()
MessageString(Chat::Skills, ESCAPE);
}
float Client::CalcPriceMod(Mob* other, bool reverse)
float Client::CalcClassicPriceMod(Mob* other, bool reverse) {
float price_multiplier = 0.8f;
if (other && other->IsNPC()) {
FACTION_VALUE faction_level = GetFactionLevel(CharacterID(), other->CastToNPC()->GetNPCTypeID(), GetRace(), GetClass(), GetDeity(), other->CastToNPC()->GetPrimaryFaction(), other);
int32 cha = GetCHA();
if (faction_level <= FACTION_AMIABLY) {
cha += 11; // amiable faction grants a defacto 11 charisma bonus
}
uint8 greed = other->CastToNPC()->GetGreedPercent();
// Sony's precise algorithm is unknown, but this produces output that is virtually identical
if (faction_level <= FACTION_INDIFFERENTLY) {
if (cha > 75) {
if (greed) {
// this is derived from curve fitting to a lot of price data
price_multiplier = -0.2487768 + (1.599635 - -0.2487768) / (1 + pow((cha / 135.1495), 1.001983));
price_multiplier += (greed + 25u) / 100.0f; // default vendor markup is 25%; anything above that is 'greedy'
price_multiplier = 1.0f / price_multiplier;
}
else {
// non-greedy merchants use a linear scale
price_multiplier = 1.0f - ((115.0f - cha) * 0.004f);
}
}
else if (cha > 60) {
price_multiplier = 1.0f / (1.25f + (greed / 100.0f));
}
else {
price_multiplier = 1.0f / ((1.0f - (cha - 120.0f) / 220.0f) + (greed / 100.0f));
}
}
else { // apprehensive
if (cha > 75) {
if (greed) {
// this is derived from curve fitting to a lot of price data
price_multiplier = -0.25f + (1.823662 - -0.25f) / (1 + (cha / 135.0f));
price_multiplier += (greed + 25u) / 100.0f; // default vendor markup is 25%; anything above that is 'greedy'
price_multiplier = 1.0f / price_multiplier;
}
else {
price_multiplier = (100.0f - (145.0f - cha) / 2.8f) / 100.0f;
}
}
else if (cha > 60) {
price_multiplier = 1.0f / (1.4f + greed / 100.0f);
}
else {
price_multiplier = 1.0f / ((1.0f + (143.574 - cha) / 196.434) + (greed / 100.0f));
}
}
float maxResult = 1.0f / 1.05; // price reduction caps at this amount
if (price_multiplier > maxResult) {
price_multiplier = maxResult;
}
if (!reverse) {
price_multiplier = 1.0f / price_multiplier;
}
}
LogMerchants(
"[{}] [{}] items at [{}] price multiplier [{}] [{}]",
other->GetName(),
reverse ? "buys" : "sells",
price_multiplier,
reverse ? "from" : "to",
GetName()
);
return price_multiplier;
}
float Client::CalcNewPriceMod(Mob* other, bool reverse)
{
float chaformula = 0;
if (other)
@@ -3807,6 +3883,17 @@ float Client::CalcPriceMod(Mob* other, bool reverse)
return chaformula; //Returns 1.10, expensive stuff!
}
float Client::CalcPriceMod(Mob* other, bool reverse)
{
float price_mod = CalcNewPriceMod(other, reverse);
if (RuleB(Merchant, UseClassicPriceMod)) {
price_mod = CalcClassicPriceMod(other, reverse);
}
return price_mod;
}
void Client::GetGroupAAs(GroupLeadershipAA_Struct *into) const {
memcpy(into, &m_pp.leader_abilities.group, sizeof(GroupLeadershipAA_Struct));
}
@@ -12474,4 +12561,4 @@ void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
}
}
}
}
}