Calculate price from value, use ints for ids

This commit is contained in:
Tyler Hallada 2020-11-18 23:26:45 -05:00
parent a0eea948fe
commit 0f1b017158
11 changed files with 228 additions and 87 deletions

View File

@ -2,7 +2,7 @@
#include "NativeFunctions.h"
void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest) {
void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESQuest* quest) {
logger::info("Entered CreateInteriorRefListImpl");
if (!quest) {
@ -35,7 +35,7 @@ void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
if (base) {
RE::FormID base_form_id = base->GetFormID();
const RE::FormType form_type = base->GetFormType();
if (base_form_id == 0x7 || form_type == RE::FormType::ActorCharacter) {
if (base_form_id == 0x7 || form_type == RE::FormType::NPC || form_type == RE::FormType::LeveledNPC) {
// skip saving player ref or other companions
continue;
}
@ -107,7 +107,7 @@ void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
failReg.Unregister(quest);
}
bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest) {
bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESQuest* quest) {
logger::info("Entered CreateInteriorRefList");
if (!quest) {
@ -266,13 +266,13 @@ void LoadRefsTask(FFIResult<RawInteriorRefVec> result, RE::TESObjectREFR* target
});
}
void LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
void LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
logger::info("Entered LoadInteriorRefListImpl");
LoadRefsTask(get_interior_ref_list(api_url.c_str(), api_key.c_str(), interior_ref_list_id), target_ref, quest);
}
bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
logger::info("Entered LoadInteriorRefList");
if (!target_ref) {
@ -289,13 +289,13 @@ bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::
return true;
}
void LoadInteriorRefListByShopIdImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
void LoadInteriorRefListByShopIdImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
logger::info("Entered LoadInteriorRefListByShopIdImpl");
LoadRefsTask(get_interior_ref_list_by_shop_id(api_url.c_str(), api_key.c_str(), shop_id), target_ref, quest);
}
bool LoadInteriorRefListByShopId(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
bool LoadInteriorRefListByShopId(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
logger::info("Entered LoadInteriorRefListByShopId");
if (!target_ref) {

View File

@ -1,6 +1,6 @@
#pragma once
bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest);
bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESQuest* quest);
bool ClearCell(RE::StaticFunctionTag*);
bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest);
bool LoadInteriorRefListByShopId(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest);
bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest);
bool LoadInteriorRefListByShopId(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest);

View File

@ -2,6 +2,45 @@
#include "NativeFunctions.h"
class HaggleVisitor : public RE::PerkEntryVisitor {
public:
HaggleVisitor(RE::Actor *a_actor) {
actor = a_actor;
result = 1;
}
virtual RE::PerkEntryVisitor::ReturnType Visit(RE::BGSPerkEntry *perkEntry) override {
RE::BGSEntryPointPerkEntry *entryPoint = (RE::BGSEntryPointPerkEntry *)perkEntry;
RE::BGSPerk *perk = entryPoint->perk;
logger::info(FMT_STRING("HaggleVisitor perk: {} ({:x})"), perk->GetFullName(), (uint32_t)perk->GetFormID());
RE::BGSPerk *next_perk = perk->nextPerk;
if (next_perk) {
logger::info(FMT_STRING("HaggleVisitor next_perk: {} ({:x})"), next_perk->GetFullName(), (uint32_t)next_perk->GetFormID());
if (actor->HasPerk(next_perk)) {
logger::info("HaggleVisitor actor has next_perk, skipping this perk");
return RE::PerkEntryVisitor::ReturnType::kContinue;
}
} else {
logger::info("HaggleVisitor next_perk is null");
}
if (entryPoint->functionData && entryPoint->entryData.function == RE::BGSEntryPointPerkEntry::EntryData::Function::kMultiplyValue) {
RE::BGSEntryPointFunctionDataOneValue *oneValue = (RE::BGSEntryPointFunctionDataOneValue*)entryPoint->functionData;
logger::info(FMT_STRING("HaggleVisitor setting oneValue data to result: {:.2f}"), oneValue->data);
result = oneValue->data;
}
return RE::PerkEntryVisitor::ReturnType::kContinue;
}
float GetResult() const {
return result;
}
protected:
RE::Actor* actor;
float result;
};
bool ClearMerchandiseImpl(RE::TESObjectREFR* merchant_chest, RE::TESObjectREFR* merchant_shelf, RE::TESForm* activator_static, RE::BGSKeyword* shelf_keyword, RE::BGSKeyword* item_keyword, RE::BGSKeyword* activator_keyword)
{
logger::info("Entered ClearMerchandiseImpl");
@ -92,7 +131,7 @@ void LoadMerchTask(
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword,
int page,
bool loadMaxPageIfOver
bool load_max_page_if_over
) {
if (!merchant_shelf) {
logger::error("LoadMerchTask merchant_shelf is null!");
@ -107,7 +146,7 @@ void LoadMerchTask(
// Placing the refs must be done on the main thread otherwise disabling & deleting refs in ClearMerchandiseImpl causes a crash
auto task = SKSE::GetTaskInterface();
task->AddTask([result, merchant_shelf, activator_static, shelf_keyword, chest_keyword, item_keyword, activator_keyword, prev_keyword, next_keyword, page, loadMaxPageIfOver, toggle_ref]() {
task->AddTask([result, merchant_shelf, activator_static, shelf_keyword, chest_keyword, item_keyword, activator_keyword, prev_keyword, next_keyword, page, load_max_page_if_over, toggle_ref]() {
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
RE::BSScript::Internal::VirtualMachine * a_vm = RE::BSScript::Internal::VirtualMachine::GetSingleton();
using func_t = decltype(&PlaceAtMe);
@ -139,8 +178,47 @@ void LoadMerchTask(
int max_page = std::ceil((float)(vec.len) / (float)9);
int load_page = page;
// 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("LoadMerchandise 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("LoadMerchandise 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("LoadMerchandise 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("LoadMerchandise 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("LoadMerchandise sell_haggle: {:.2f}"), sell_haggle);
}
logger::info(FMT_STRING("LoadMerchandise 1 - speech_power_mod: {:.2f}"), (1.f - speech_skill_power_modifier / 100.f));
logger::info(FMT_STRING("LoadMerchandise 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("LoadMerchandise 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("LoadMerchandise buy_price_modifier: {:.2f}"), sell_price_modifier);
if (vec.len > 0 && page > max_page) {
if (loadMaxPageIfOver) {
if (load_max_page_if_over) {
load_page = max_page;
} else {
logger::info(FMT_STRING("LoadMerchandise page {:d} is greater than max_page {:d}, doing nothing"), page, max_page);
@ -163,6 +241,8 @@ void LoadMerchTask(
RE::NiPoint3 shelf_angle = merchant_shelf->data.angle;
RE::NiMatrix3 rotation_matrix = get_rotation_matrix(shelf_angle);
merchant_chest->ResetInventory(false);
logger::info(FMT_STRING("LoadMerchandise current shelf page is: {:d}"), merchant_shelf->extraList.GetCount());
for (int i = 0; i < vec.len; i++) {
RawMerchandise merch = vec.ptr[i];
@ -249,16 +329,18 @@ void LoadMerchTask(
}
logger::info(FMT_STRING("LoadMerchandise relative position x: {:.2f}, y: {:.2f}, z: {:.2f}"), ref_position.x, ref_position.y, ref_position.z);
ref_position = rotate_point(ref_position, rotation_matrix);
logger::info(FMT_STRING("LoadMerchandise relative rotated position x: {:.2f}, y: {:.2f}, z: {:.2f}"), ref_position.x, ref_position.y, ref_position.z);
ref_position = RE::NiPoint3(shelf_position.x + ref_position.x, shelf_position.y + ref_position.y, shelf_position.z + ref_position.z);
logger::info(FMT_STRING("LoadMerchandise absolute rotated position x: {:.2f}, y: {:.2f}, z: {:.2f}"), ref_position.x, ref_position.y, ref_position.z);
MoveTo_Native(ref, ref->CreateRefHandle(), cell, cell->worldSpace, ref_position - RE::NiPoint3(10000, 10000, 10000), ref_angle);
MoveTo_Native(activator_ref, activator_ref->CreateRefHandle(), cell, cell->worldSpace, ref_position, ref_angle);
RE::BSFixedString name = RE::BSFixedString::BSFixedString(fmt::format(FMT_STRING("{} for {:d}g ({:d})"), ref->GetName(), merch.price, merch.quantity));
activator_ref->SetDisplayName(name, true);
activator_extra_linked_ref->linkedRefs.push_back({item_keyword, ref});
item_extra_linked_ref->linkedRefs.push_back({activator_keyword, activator_ref});
int32_t buy_price = std::round(merch.price * buy_price_modifier * price_factor);
logger::info(FMT_STRING("LoadMerchandise 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
RE::ExtraCount * extra_quantity_price = activator_ref->extraList.GetByType<RE::ExtraCount>();
if (!extra_quantity_price) {
@ -266,7 +348,12 @@ void LoadMerchTask(
activator_ref->extraList.Add(extra_quantity_price);
}
extra_quantity_price->count = merch.quantity;
extra_quantity_price->pad14 = merch.price;
extra_quantity_price->pad14 = buy_price;
RE::BSFixedString name = RE::BSFixedString::BSFixedString(fmt::format(FMT_STRING("{} for {:d}g ({:d})"), ref->GetName(), buy_price, merch.quantity));
activator_ref->SetDisplayName(name, true);
merchant_chest->AddObjectToContainer(base, nullptr, merch.quantity, merchant_chest);
}
// I'm abusing the ExtraCount ExtraData type for storing the current page number state of the shelf
@ -332,7 +419,7 @@ void LoadMerchTask(
void LoadMerchandiseImpl(
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t merchandise_list_id,
int32_t merchandise_list_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -343,18 +430,18 @@ void LoadMerchandiseImpl(
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword,
int page,
bool loadMaxPageIfOver
bool load_max_page_if_over
) {
logger::info("Entered LoadMerchandiseImpl");
logger::info(FMT_STRING("LoadMerchandise page: {:d}"), page);
LoadMerchTask(get_merchandise_list(api_url.c_str(), api_key.c_str(), merchandise_list_id), merchant_shelf, activator_static, shelf_keyword, chest_keyword, item_keyword, activator_keyword, toggle_keyword, next_keyword, prev_keyword, page, loadMaxPageIfOver);
LoadMerchTask(get_merchandise_list(api_url.c_str(), api_key.c_str(), merchandise_list_id), merchant_shelf, activator_static, shelf_keyword, chest_keyword, item_keyword, activator_keyword, toggle_keyword, next_keyword, prev_keyword, page, load_max_page_if_over);
}
void LoadMerchandiseByShopIdImpl(
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -365,19 +452,19 @@ void LoadMerchandiseByShopIdImpl(
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword,
int page,
bool loadMaxPageIfOver
bool load_max_page_if_over
) {
logger::info("Entered LoadMerchandiseByShopIdImpl");
logger::info(FMT_STRING("LoadMerchandiseByShopIdImpl page: {:d}"), page);
LoadMerchTask(get_merchandise_list_by_shop_id(api_url.c_str(), api_key.c_str(), shop_id), merchant_shelf, activator_static, shelf_keyword, chest_keyword, item_keyword, activator_keyword, toggle_keyword, next_keyword, prev_keyword, page, loadMaxPageIfOver);
LoadMerchTask(get_merchandise_list_by_shop_id(api_url.c_str(), api_key.c_str(), shop_id), merchant_shelf, activator_static, shelf_keyword, chest_keyword, item_keyword, activator_keyword, toggle_keyword, next_keyword, prev_keyword, page, load_max_page_if_over);
}
bool ToggleMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -439,7 +526,7 @@ bool LoadNextMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -471,7 +558,7 @@ bool LoadPrevMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -507,7 +594,7 @@ bool LoadMerchandiseByShopId(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -541,7 +628,7 @@ bool RefreshMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -552,11 +639,15 @@ bool RefreshMerchandise(
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword
) {
logger::info("Entered ClearMerchandise");
logger::info("Entered RefreshMerchandise");
RE::TESObjectREFR * merchant_chest = merchant_shelf->GetLinkedRef(chest_keyword);
if (!merchant_chest) {
logger::error("ClearMerchandise could not find merchant_chest linked from merchant_shelf!");
logger::error("RefreshMerchandise could not find merchant_chest linked from merchant_shelf!");
return false;
}
if (!merchant_shelf) {
logger::error("RefreshMerchandise merchant_shelf is null!");
return false;
}
int page = merchant_shelf->extraList.GetCount();
@ -607,7 +698,7 @@ bool ReplaceMerch3D(RE::StaticFunctionTag*, RE::TESObjectREFR* merchant_shelf, R
return true;
}
void CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest) {
void CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESObjectREFR* merchant_chest) {
logger::info("Entered CreateMerchandiseListImpl");
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
std::vector<RawMerchandise> merch_records;
@ -710,7 +801,7 @@ void CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
failReg.Unregister(merchant_chest);
}
bool CreateMerchandiseList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest) {
bool CreateMerchandiseList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESObjectREFR* merchant_chest) {
logger::info("Entered CreateMerchandiseList");
if (!merchant_chest) {

View File

@ -4,7 +4,7 @@ bool ToggleMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -19,7 +19,7 @@ bool LoadNextMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -34,7 +34,7 @@ bool LoadPrevMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -49,7 +49,7 @@ bool LoadMerchandiseByShopId(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -64,7 +64,7 @@ bool RefreshMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
@ -76,6 +76,6 @@ bool RefreshMerchandise(
RE::BGSKeyword* prev_keyword
);
bool ReplaceMerch3D(RE::StaticFunctionTag*, RE::TESObjectREFR* merchant_shelf, RE::TESForm* activator_static, RE::BGSKeyword* shelf_keyword, RE::BGSKeyword* item_keyword);
bool CreateMerchandiseList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest);
bool CreateMerchandiseList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t shop_id, RE::TESObjectREFR* merchant_chest);
int GetMerchandiseQuantity(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);
int GetMerchandisePrice(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);

View File

@ -1,6 +1,6 @@
#include "bindings.h"
void CreateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
void CreateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, int32_t mod_version, RE::TESQuest* quest) {
logger::info("Entered CreateOwnerImpl");
if (!quest) {
logger::error("CreateOwnerImpl quest is null!");
@ -27,7 +27,7 @@ void CreateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::B
failReg.Unregister(quest);
}
bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, int32_t mod_version, RE::TESQuest* quest) {
logger::info("Entered CreateOwner");
if (!quest) {
logger::error("CreateOwner quest is null!");
@ -39,7 +39,7 @@ bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedS
return true;
}
void UpdateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
void UpdateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::BSFixedString name, int32_t mod_version, RE::TESQuest* quest) {
logger::info("Entered UpdateOwnerImpl");
if (!quest) {
logger::error("UpdateOwnerImpl quest is null!");
@ -66,7 +66,7 @@ void UpdateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint3
failReg.Unregister(quest);
}
bool UpdateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
bool UpdateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::BSFixedString name, int32_t mod_version, RE::TESQuest* quest) {
logger::info("Entered UpdateOwner");
if (!quest) {
logger::error("UpdateOwner quest is null!");

View File

@ -1,4 +1,4 @@
#pragma once
bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest);
bool UpdateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest);
bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, int32_t mod_version, RE::TESQuest* quest);
bool UpdateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::BSFixedString name, int32_t mod_version, RE::TESQuest* quest);

View File

@ -39,7 +39,7 @@ bool CreateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedSt
return true;
}
void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
logger::info("Entered UpdateShopImpl");
if (!quest) {
logger::error("UpdateShopImpl quest is null!");
@ -66,7 +66,7 @@ void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32
failReg.Unregister(quest);
}
bool UpdateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
bool UpdateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
logger::info("Entered UpdateShop");
if (!quest) {
logger::error("UpdateShop quest is null!");
@ -78,7 +78,7 @@ bool UpdateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedSt
return true;
}
void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::TESQuest* quest) {
void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::TESQuest* quest) {
logger::info("Entered GetShopImpl");
if (!quest) {
logger::error("GetShopImpl quest is null!");
@ -105,7 +105,7 @@ void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t
failReg.Unregister(quest);
}
bool GetShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::TESQuest* quest) {
bool GetShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::TESQuest* quest) {
logger::info("Entered GetShop");
if (!quest) {
logger::error("GetShop quest is null!");

View File

@ -1,6 +1,6 @@
#pragma once
bool CreateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest);
bool UpdateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest);
bool GetShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::TESQuest* quest);
bool UpdateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest);
bool GetShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::TESQuest* quest);
bool ListShops(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TESQuest* quest);

View File

@ -3,53 +3,49 @@
void CreateTransactionImpl(
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
bool is_sell,
uint32_t quantity,
uint32_t amount,
RE::BGSKeyword* item_keyword,
RE::TESObjectREFR* activator
int32_t quantity,
int32_t amount,
RE::TESForm* merch_base,
RE::TESObjectREFR* result_handler
) {
logger::info("Entered CreateTransactionImpl");
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
if (!activator) {
logger::error("CreateTransactionImpl activator is null!");
if (!result_handler) {
logger::error("CreateTransactionImpl result_handler is null!");
return;
}
if (!merch_base) {
logger::error("CreateTransactionImpl merch_base is null!");
return;
}
SKSE::RegistrationMap<int, int, int> successReg = SKSE::RegistrationMap<int, int, int>();
successReg.Register(activator, RE::BSFixedString("OnCreateTransactionSuccess"));
successReg.Register(result_handler, RE::BSFixedString("OnCreateTransactionSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(activator, RE::BSFixedString("OnCreateTransactionFail"));
failReg.Register(result_handler, RE::BSFixedString("OnCreateTransactionFail"));
const char * name = merch_base->GetName();
uint32_t form_type = (uint32_t)merch_base->GetFormType();
RE::FormID form_id = merch_base->GetFormID();
logger::info(FMT_STRING("CreateTransactionImpl merch_base form_id: {:x}, name: {}, type: {:x}"), (uint32_t)form_id, name, (uint32_t)form_type);
RE::TESObjectREFR * merch_ref = activator->GetLinkedRef(item_keyword);
RE::TESBoundObject * base = merch_ref->GetBaseObject();
if (!base) {
logger::error("CreateTransactionImpl merchandise item base is null!");
failReg.SendEvent(RE::BSFixedString("Could not find the merchandise for the activator"));
successReg.Unregister(activator);
failReg.Unregister(activator);
}
const char * name = base->GetName();
uint32_t form_type = (uint32_t)base->GetFormType();
RE::FormID form_id = base->GetFormID();
logger::info(FMT_STRING("CreateTransactionImpl base form_id: {:x}, name: {}, type: {:x}"), (uint32_t)form_id, name, (uint32_t)form_type);
RE::TESFile * file = base->GetFile(0);
RE::TESFile * file = merch_base->GetFile(0);
const char * mod_name = file->fileName;
bool is_light = file->recordFlags.all(RE::TESFile::RecordFlag::kSmallFile);
uint32_t local_form_id = is_light ? form_id & 0xfff : form_id & 0xFFFFFF;
logger::info(FMT_STRING("CreateTransactionImpl base form file_name: {}, local_form_id: {:x}"), mod_name, local_form_id);
logger::info(FMT_STRING("CreateTransactionImpl merch_base form file_name: {}, local_form_id: {:x}"), mod_name, local_form_id);
// TODO: implement is_food
bool is_food = false;
uint32_t price = 0;
RE::ExtraCount * extra_quantity_price = activator->extraList.GetByType<RE::ExtraCount>();
if (extra_quantity_price) {
price = extra_quantity_price->pad14;
}
uint32_t price = amount / quantity;
// RE::ExtraCount * extra_quantity_price = activator->extraList.GetByType<RE::ExtraCount>();
// if (extra_quantity_price) {
// price = extra_quantity_price->pad14;
// }
RawTransaction input_transaction = { 0, shop_id, mod_name, local_form_id, name, form_type, is_food, price, is_sell, quantity, amount };
FFIResult<RawTransaction> result = create_transaction(api_url.c_str(), api_key.c_str(), input_transaction);
@ -62,17 +58,18 @@ void CreateTransactionImpl(
logger::error(FMT_STRING("CreateTransaction failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error));
}
successReg.Unregister(activator);
failReg.Unregister(activator);
successReg.Unregister(result_handler);
failReg.Unregister(result_handler);
}
bool CreateTransaction(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
bool is_sell,
uint32_t quantity,
uint32_t amount,
int32_t quantity,
int32_t amount,
RE::BGSKeyword* item_keyword,
RE::TESObjectREFR* activator
) {
@ -83,7 +80,47 @@ bool CreateTransaction(
return false;
}
std::thread thread(CreateTransactionImpl, api_url, api_key, shop_id, is_sell, quantity, amount, item_keyword, activator);
RE::TESObjectREFR * merch_ref = activator->GetLinkedRef(item_keyword);
if (!merch_ref) {
logger::error("CreateTransaction merch_ref is null!");
return false;
}
RE::TESBoundObject * merch_base = merch_ref->GetBaseObject();
if (!merch_base) {
logger::error("CreateTransaction merch_base is null!");
return false;
}
std::thread thread(CreateTransactionImpl, api_url, api_key, shop_id, is_sell, quantity, amount, merch_base, activator);
thread.detach();
return true;
}
bool CreateTransactionFromVendorSale(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
int32_t shop_id,
bool is_sell,
int32_t quantity,
int32_t amount,
RE::TESForm* merch_base,
RE::TESObjectREFR* merch_chest
) {
logger::info("Entered CreateTransactionFromVendorSale");
if (!merch_chest) {
logger::error("CreateTransactionFromVendorSale activator is null!");
return false;
}
if (!merch_base) {
logger::error("CreateTransactionFromVendorSale merch_base is null!");
return false;
}
std::thread thread(CreateTransactionImpl, api_url, api_key, shop_id, is_sell, quantity, amount, merch_base, merch_chest);
thread.detach();
return true;
}

View File

@ -4,10 +4,22 @@ bool CreateTransaction(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
uint32_t shop_id,
int32_t shop_id,
bool is_sell,
uint32_t quantity,
uint32_t amount,
int32_t quantity,
int32_t amount,
RE::BGSKeyword* item_keyword,
RE::TESObjectREFR* activator
);
bool CreateTransactionFromVendorSale(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
int32_t shop_id,
bool is_sell,
int32_t quantity,
int32_t amount,
RE::TESForm* merch_base,
RE::TESObjectREFR* merch_chest
);

View File

@ -33,6 +33,7 @@ bool RegisterFuncs(RE::BSScript::IVirtualMachine* a_vm)
a_vm->RegisterFunction("GetQuantity", "BRMerchandiseList", GetMerchandiseQuantity);
a_vm->RegisterFunction("GetPrice", "BRMerchandiseList", GetMerchandisePrice);
a_vm->RegisterFunction("Create", "BRTransaction", CreateTransaction);
a_vm->RegisterFunction("CreateFromVendorSale", "BRTransaction", CreateTransactionFromVendorSale);
return true;
}