#include "trading.hpp" #include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "creaturestats.hpp" namespace MWMechanics { Trading::Trading() {} bool Trading::haggle(const MWWorld::Ptr& player, const MWWorld::Ptr& merchant, int playerOffer, int merchantOffer) { // accept if merchant offer is better than player offer if ( playerOffer <= merchantOffer ) { return true; } // reject if npc is a creature if ( merchant.getTypeName() != typeid(ESM::NPC).name() ) { return false; } const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); // Is the player buying? bool buying = (merchantOffer < 0); int a = std::abs(merchantOffer); int b = std::abs(playerOffer); int d = (buying) ? int(100 * (a - b) / a) : int(100 * (b - a) / b); int clampedDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(merchant); const MWMechanics::CreatureStats &merchantStats = merchant.getClass().getCreatureStats(merchant); const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); float a1 = static_cast(player.getClass().getSkill(player, ESM::Skill::Mercantile)); float b1 = 0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(); float c1 = 0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(); float d1 = static_cast(merchant.getClass().getSkill(merchant, ESM::Skill::Mercantile)); float e1 = 0.1f * merchantStats.getAttribute(ESM::Attribute::Luck).getModified(); float f1 = 0.2f * merchantStats.getAttribute(ESM::Attribute::Personality).getModified(); float dispositionTerm = gmst.find("fDispositionMod")->getFloat() * (clampedDisposition - 50); float pcTerm = (dispositionTerm + a1 + b1 + c1) * playerStats.getFatigueTerm(); float npcTerm = (d1 + e1 + f1) * merchantStats.getFatigueTerm(); float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat() + int(pcTerm - npcTerm); int roll = Misc::Rng::rollDice(100) + 1; // reject if roll fails // (or if player tries to buy things and get money) if ( roll > x || (merchantOffer < 0 && 0 < playerOffer) ) { return false; } // apply skill gain on successful barter float skillGain = 0.f; int finalPrice = std::abs(playerOffer); int initialMerchantOffer = std::abs(merchantOffer); if ( !buying && (finalPrice > initialMerchantOffer) ) { skillGain = floor(100.f * (finalPrice - initialMerchantOffer) / finalPrice); } else if ( buying && (finalPrice < initialMerchantOffer) ) { skillGain = floor(100.f * (initialMerchantOffer - finalPrice) / initialMerchantOffer); } player.getClass().skillUsageSucceeded(player, ESM::Skill::Mercantile, 0, skillGain); return true; } }