Allow selling items to the public merch chest
This commit is contained in:
parent
f79ea29f3a
commit
ccaa413137
@ -108,6 +108,73 @@ bool ClearMerchandise(RE::TESObjectREFR* merchant_shelf) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<float, float, float> CalculatePriceModifiers() {
|
||||||
|
// Calculate the actual barter price using the same formula Skyrim uses in the barter menu
|
||||||
|
// Formula from: http://en.uesp.net/wiki/Skyrim:Speech#Prices
|
||||||
|
// Allure perk is not counted because merchandise has no gender and is asexual
|
||||||
|
RE::GameSettingCollection* game_settings = RE::GameSettingCollection::GetSingleton();
|
||||||
|
float f_barter_min = game_settings->GetSetting("fBarterMin")->GetFloat();
|
||||||
|
float f_barter_max = game_settings->GetSetting("fBarterMax")->GetFloat();
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers fBarterMin: {:.2f}, fBarterMax: {:.2f}"), f_barter_min, f_barter_max);
|
||||||
|
|
||||||
|
RE::PlayerCharacter* player = RE::PlayerCharacter::GetSingleton();
|
||||||
|
float speech_skill = player->GetActorValue(RE::ActorValue::kSpeech);
|
||||||
|
float speech_skill_advance = player->GetActorValue(RE::ActorValue::kSpeechcraftSkillAdvance);
|
||||||
|
float speech_skill_modifier = player->GetActorValue(RE::ActorValue::kSpeechcraftModifier);
|
||||||
|
float speech_skill_power_modifier = player->GetActorValue(RE::ActorValue::kSpeechcraftPowerModifier);
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers speech_skill: {:.2f}, speech_skill_advance: {:.2f}, speech_skill_modifier: {:.2f}, speech_skill_power_modifier: {:.2f}"), speech_skill, speech_skill_advance, speech_skill_modifier, speech_skill_power_modifier);
|
||||||
|
|
||||||
|
float price_factor = f_barter_max - (f_barter_max - f_barter_min) * std::min(speech_skill, 100.f) / 100.f;
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers price_factor: {:.2f}"), price_factor);
|
||||||
|
|
||||||
|
float buy_haggle = 1;
|
||||||
|
float sell_haggle = 1;
|
||||||
|
if (player->HasPerkEntries(RE::BGSEntryPoint::ENTRY_POINTS::kModBuyPrices)) {
|
||||||
|
HaggleVisitor buy_visitor = HaggleVisitor(reinterpret_cast<RE::Actor*>(player));
|
||||||
|
player->ForEachPerkEntry(RE::BGSEntryPoint::ENTRY_POINTS::kModBuyPrices, buy_visitor);
|
||||||
|
buy_haggle = buy_visitor.GetResult();
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers buy_haggle: {:.2f}"), buy_haggle);
|
||||||
|
}
|
||||||
|
if (player->HasPerkEntries(RE::BGSEntryPoint::ENTRY_POINTS::kModSellPrices)) {
|
||||||
|
HaggleVisitor sell_visitor = HaggleVisitor(reinterpret_cast<RE::Actor*>(player));
|
||||||
|
player->ForEachPerkEntry(RE::BGSEntryPoint::ENTRY_POINTS::kModSellPrices, sell_visitor);
|
||||||
|
sell_haggle = sell_visitor.GetResult();
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers sell_haggle: {:.2f}"), sell_haggle);
|
||||||
|
}
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers 1 - speech_power_mod: {:.2f}"), (1.f - speech_skill_power_modifier / 100.f));
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers 1 - speech_mod: {:.2f}"), (1.f - speech_skill_modifier / 100.f));
|
||||||
|
float buy_price_modifier = buy_haggle * (1.f - speech_skill_power_modifier / 100.f) * (1.f - speech_skill_modifier / 100.f);
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers buy_price_modifier: {:.2f}"), buy_price_modifier);
|
||||||
|
float sell_price_modifier = sell_haggle * (1.f + speech_skill_power_modifier / 100.f) * (1.f + speech_skill_modifier / 100.f);
|
||||||
|
logger::info(FMT_STRING("CalculatePriceModifiers buy_price_modifier: {:.2f}"), sell_price_modifier);
|
||||||
|
|
||||||
|
std::tuple modifiers (price_factor, buy_price_modifier, sell_price_modifier);
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CalculateBuyPrice(RE::TESForm* form, float price_factor, float buy_price_modifier) {
|
||||||
|
int32_t buy_price = std::round(form->GetGoldValue() * buy_price_modifier * price_factor);
|
||||||
|
logger::info(FMT_STRING("CalculateBuyPrice buy_price: {:d}"), buy_price);
|
||||||
|
return buy_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CalculateSellPrice(RE::TESForm* form, float price_factor, float sell_price_modifier) {
|
||||||
|
int32_t sell_price = std::round(form->GetGoldValue() * sell_price_modifier / price_factor);
|
||||||
|
logger::info(FMT_STRING("CalculateSellPrice sell_price: {:d}"), sell_price);
|
||||||
|
return sell_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetMerchandiseSellPrice(RE::StaticFunctionTag*, RE::TESForm* form) {
|
||||||
|
if (!form) {
|
||||||
|
logger::error("GetMerchandiseSellPrice form is null!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::tuple modifiers = CalculatePriceModifiers();
|
||||||
|
float price_factor = std::get<0>(modifiers);
|
||||||
|
float sell_price_modifier = std::get<2>(modifiers);
|
||||||
|
CalculateSellPrice(form, price_factor, sell_price_modifier);
|
||||||
|
}
|
||||||
|
|
||||||
bool ClearAllMerchandise(RE::TESObjectCELL* cell) {
|
bool ClearAllMerchandise(RE::TESObjectCELL* cell) {
|
||||||
logger::info("Entered ClearAllMerchandise");
|
logger::info("Entered ClearAllMerchandise");
|
||||||
RE::TESDataHandler* data_handler = RE::TESDataHandler::GetSingleton();
|
RE::TESDataHandler* data_handler = RE::TESDataHandler::GetSingleton();
|
||||||
@ -237,44 +304,10 @@ void FillShelf(
|
|||||||
extra_page_num->count = load_page;
|
extra_page_num->count = load_page;
|
||||||
logger::info(FMT_STRING("FillShelf set shelf page to: {:d}"), merchant_shelf->extraList.GetCount());
|
logger::info(FMT_STRING("FillShelf set shelf page to: {:d}"), merchant_shelf->extraList.GetCount());
|
||||||
|
|
||||||
// Calculate the actual barter price using the same formula Skyrim uses in the barter menu
|
std::tuple modifiers = CalculatePriceModifiers();
|
||||||
// Formula from: http://en.uesp.net/wiki/Skyrim:Speech#Prices
|
float price_factor = std::get<0>(modifiers);
|
||||||
// Allure perk is not counted because merchandise has no gender and is asexual
|
float buy_price_modifier = std::get<1>(modifiers);
|
||||||
RE::GameSettingCollection* game_settings = RE::GameSettingCollection::GetSingleton();
|
float sell_price_modifier = std::get<2>(modifiers);
|
||||||
float f_barter_min = game_settings->GetSetting("fBarterMin")->GetFloat();
|
|
||||||
float f_barter_max = game_settings->GetSetting("fBarterMax")->GetFloat();
|
|
||||||
logger::info(FMT_STRING("FillShelf fBarterMin: {:.2f}, fBarterMax: {:.2f}"), f_barter_min, f_barter_max);
|
|
||||||
|
|
||||||
RE::PlayerCharacter* player = RE::PlayerCharacter::GetSingleton();
|
|
||||||
float speech_skill = player->GetActorValue(RE::ActorValue::kSpeech);
|
|
||||||
float speech_skill_advance = player->GetActorValue(RE::ActorValue::kSpeechcraftSkillAdvance);
|
|
||||||
float speech_skill_modifier = player->GetActorValue(RE::ActorValue::kSpeechcraftModifier);
|
|
||||||
float speech_skill_power_modifier = player->GetActorValue(RE::ActorValue::kSpeechcraftPowerModifier);
|
|
||||||
logger::info(FMT_STRING("FillShelf speech_skill: {:.2f}, speech_skill_advance: {:.2f}, speech_skill_modifier: {:.2f}, speech_skill_power_modifier: {:.2f}"), speech_skill, speech_skill_advance, speech_skill_modifier, speech_skill_power_modifier);
|
|
||||||
|
|
||||||
float price_factor = f_barter_max - (f_barter_max - f_barter_min) * std::min(speech_skill, 100.f) / 100.f;
|
|
||||||
logger::info(FMT_STRING("FillShelf price_factor: {:.2f}"), price_factor);
|
|
||||||
|
|
||||||
float buy_haggle = 1;
|
|
||||||
float sell_haggle = 1;
|
|
||||||
if (player->HasPerkEntries(RE::BGSEntryPoint::ENTRY_POINTS::kModBuyPrices)) {
|
|
||||||
HaggleVisitor buy_visitor = HaggleVisitor(reinterpret_cast<RE::Actor*>(player));
|
|
||||||
player->ForEachPerkEntry(RE::BGSEntryPoint::ENTRY_POINTS::kModBuyPrices, buy_visitor);
|
|
||||||
buy_haggle = buy_visitor.GetResult();
|
|
||||||
logger::info(FMT_STRING("FillShelf buy_haggle: {:.2f}"), buy_haggle);
|
|
||||||
}
|
|
||||||
if (player->HasPerkEntries(RE::BGSEntryPoint::ENTRY_POINTS::kModSellPrices)) {
|
|
||||||
HaggleVisitor sell_visitor = HaggleVisitor(reinterpret_cast<RE::Actor*>(player));
|
|
||||||
player->ForEachPerkEntry(RE::BGSEntryPoint::ENTRY_POINTS::kModSellPrices, sell_visitor);
|
|
||||||
sell_haggle = sell_visitor.GetResult();
|
|
||||||
logger::info(FMT_STRING("FillShelf sell_haggle: {:.2f}"), sell_haggle);
|
|
||||||
}
|
|
||||||
logger::info(FMT_STRING("FillShelf 1 - speech_power_mod: {:.2f}"), (1.f - speech_skill_power_modifier / 100.f));
|
|
||||||
logger::info(FMT_STRING("FillShelf 1 - speech_mod: {:.2f}"), (1.f - speech_skill_modifier / 100.f));
|
|
||||||
float buy_price_modifier = buy_haggle * (1.f - speech_skill_power_modifier / 100.f) * (1.f - speech_skill_modifier / 100.f);
|
|
||||||
logger::info(FMT_STRING("FillShelf buy_price_modifier: {:.2f}"), buy_price_modifier);
|
|
||||||
float sell_price_modifier = sell_haggle * (1.f + speech_skill_power_modifier / 100.f) * (1.f + speech_skill_modifier / 100.f);
|
|
||||||
logger::info(FMT_STRING("FillShelf buy_price_modifier: {:.2f}"), sell_price_modifier);
|
|
||||||
|
|
||||||
RE::NiPoint3 shelf_position = merchant_shelf->data.location;
|
RE::NiPoint3 shelf_position = merchant_shelf->data.location;
|
||||||
RE::NiPoint3 shelf_angle = merchant_shelf->data.angle;
|
RE::NiPoint3 shelf_angle = merchant_shelf->data.angle;
|
||||||
@ -370,7 +403,7 @@ void FillShelf(
|
|||||||
activator_extra_linked_ref->linkedRefs.push_back({item_keyword, ref});
|
activator_extra_linked_ref->linkedRefs.push_back({item_keyword, ref});
|
||||||
ref->extraList.Add(item_extra_linked_ref);
|
ref->extraList.Add(item_extra_linked_ref);
|
||||||
|
|
||||||
int32_t buy_price = std::round(ref->GetGoldValue() * buy_price_modifier * price_factor);
|
int32_t buy_price = CalculateBuyPrice(base, price_factor, buy_price_modifier);
|
||||||
logger::info(FMT_STRING("FillShelf buy_price: {:d}"), buy_price);
|
logger::info(FMT_STRING("FillShelf buy_price: {:d}"), buy_price);
|
||||||
|
|
||||||
// I'm abusing the ExtraCount ExtraData type for storing the quantity and price of the merchandise the activator_ref is linked to
|
// I'm abusing the ExtraCount ExtraData type for storing the quantity and price of the merchandise the activator_ref is linked to
|
||||||
@ -965,3 +998,4 @@ int GetMerchandisePrice(RE::StaticFunctionTag*, RE::TESObjectREFR* activator) {
|
|||||||
}
|
}
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,3 +44,4 @@ bool CreateMerchandiseList(
|
|||||||
);
|
);
|
||||||
int GetMerchandiseQuantity(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);
|
int GetMerchandiseQuantity(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);
|
||||||
int GetMerchandisePrice(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);
|
int GetMerchandisePrice(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);
|
||||||
|
int GetMerchandiseSellPrice(RE::StaticFunctionTag*, RE::TESForm* form);
|
||||||
|
@ -33,6 +33,7 @@ bool RegisterFuncs(RE::BSScript::IVirtualMachine* a_vm)
|
|||||||
a_vm->RegisterFunction("Create", "BRMerchandiseList", CreateMerchandiseList);
|
a_vm->RegisterFunction("Create", "BRMerchandiseList", CreateMerchandiseList);
|
||||||
a_vm->RegisterFunction("GetQuantity", "BRMerchandiseList", GetMerchandiseQuantity);
|
a_vm->RegisterFunction("GetQuantity", "BRMerchandiseList", GetMerchandiseQuantity);
|
||||||
a_vm->RegisterFunction("GetPrice", "BRMerchandiseList", GetMerchandisePrice);
|
a_vm->RegisterFunction("GetPrice", "BRMerchandiseList", GetMerchandisePrice);
|
||||||
|
a_vm->RegisterFunction("GetSellPrice", "BRMerchandiseList", GetMerchandiseSellPrice);
|
||||||
a_vm->RegisterFunction("Create", "BRTransaction", CreateTransaction);
|
a_vm->RegisterFunction("Create", "BRTransaction", CreateTransaction);
|
||||||
a_vm->RegisterFunction("CreateFromVendorSale", "BRTransaction", CreateTransactionFromVendorSale);
|
a_vm->RegisterFunction("CreateFromVendorSale", "BRTransaction", CreateTransactionFromVendorSale);
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user