Load shop keywords and gold, update shop gold

Gold is loaded into merchant chest after merchandise is loaded now. Gold is not saved to the merchandise list, but if owner takes or stores gold the change is saved to the shop separately. Gold refreshes after any transaction.
This commit is contained in:
Tyler Hallada 2021-02-13 17:50:19 -05:00
parent 289ec598d4
commit 17d428d385
5 changed files with 250 additions and 24 deletions

View File

@ -286,9 +286,6 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
RE::BGSKeyword* toggle_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_TOGGLE, MOD_NAME); RE::BGSKeyword* toggle_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_TOGGLE, MOD_NAME);
RE::BGSKeyword* next_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_NEXT, MOD_NAME); RE::BGSKeyword* next_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_NEXT, MOD_NAME);
RE::BGSKeyword* prev_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_PREV, MOD_NAME); RE::BGSKeyword* prev_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_PREV, MOD_NAME);
RE::BGSKeyword* vendor_item_armor_keyword = RE::TESForm::LookupByID<RE::BGSKeyword>(KEYWORD_VENDOR_ITEM_ARMOR);
RE::BGSListForm* vendor_items = data_handler->LookupForm<RE::BGSListForm>(FORM_LIST_VENDOR_ITEMS, MOD_NAME);
RE::TESFaction* vendor_services_faction = data_handler->LookupForm<RE::TESFaction>(FACTION_SERVICES_VENDOR, MOD_NAME);
SKSE::RegistrationMap<bool, std::vector<RE::TESObjectREFR*>> successReg = SKSE::RegistrationMap<bool, std::vector<RE::TESObjectREFR*>>(); SKSE::RegistrationMap<bool, std::vector<RE::TESObjectREFR*>> successReg = SKSE::RegistrationMap<bool, std::vector<RE::TESObjectREFR*>>();
successReg.Register(quest, RE::BSFixedString("OnLoadInteriorRefListSuccess")); successReg.Register(quest, RE::BSFixedString("OnLoadInteriorRefListSuccess"));
@ -462,11 +459,6 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
} }
// TODO: load shop vendor(s) // TODO: load shop vendor(s)
// TODO: load these values from shop config data
vendor_items->ClearData();
vendor_items->AddForm(vendor_item_armor_keyword);
vendor_services_faction->vendorData.vendorValues.notBuySell = false;
} else { } else {
const char * error = result.AsErr(); const char * error = result.AsErr();
logger::error(FMT_STRING("LoadInteriorRefList get_interior_ref_list error: {}"), error); logger::error(FMT_STRING("LoadInteriorRefList get_interior_ref_list error: {}"), error);

View File

@ -307,7 +307,6 @@ void FillShelf(
std::tuple modifiers = CalculatePriceModifiers(); std::tuple modifiers = CalculatePriceModifiers();
float price_factor = std::get<0>(modifiers); float price_factor = std::get<0>(modifiers);
float buy_price_modifier = std::get<1>(modifiers); float buy_price_modifier = std::get<1>(modifiers);
float sell_price_modifier = std::get<2>(modifiers);
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;
@ -981,7 +980,6 @@ void CreateMerchandiseListImpl(
RE::TESObjectREFR* merchant_chest RE::TESObjectREFR* merchant_chest
) { ) {
logger::info("Entered CreateMerchandiseListImpl"); logger::info("Entered CreateMerchandiseListImpl");
RE::TESDataHandler* data_handler = RE::TESDataHandler::GetSingleton();
std::vector<RawMerchandise> merch_records; std::vector<RawMerchandise> merch_records;
std::vector<std::vector<const char*>> keyword_strings; std::vector<std::vector<const char*>> keyword_strings;
@ -1015,6 +1013,10 @@ void CreateMerchandiseListImpl(
uint32_t form_type = (uint32_t)base->GetFormType(); uint32_t form_type = (uint32_t)base->GetFormType();
uint32_t quantity = entry_data->countDelta; uint32_t quantity = entry_data->countDelta;
RE::FormID form_id = base->GetFormID(); RE::FormID form_id = base->GetFormID();
if (form_id == 15) { // gold
logger::info("CreateMerchandiseList ignoring gold in merchant chest");
continue;
}
logger::info(FMT_STRING("CreateMerchandiseList quantity: {:d}"), quantity); logger::info(FMT_STRING("CreateMerchandiseList quantity: {:d}"), quantity);
logger::info(FMT_STRING("CreateMerchandiseList base form_id: {:x}, name: {}, type: {:x}"), (uint32_t)form_id, name, (uint32_t)form_type); logger::info(FMT_STRING("CreateMerchandiseList base form_id: {:x}, name: {}, type: {:x}"), (uint32_t)form_id, name, (uint32_t)form_type);

View File

@ -1,4 +1,5 @@
#include "bindings.h" #include "bindings.h"
#include "FormIds.h"
void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) { void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
logger::info("Entered CreateShopImpl"); logger::info("Entered CreateShopImpl");
@ -7,7 +8,8 @@ void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BS
return; return;
} }
SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString> successReg = SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString>(); SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString, int, RE::BSFixedString, std::vector<RE::BGSKeyword*>, bool> successReg =
SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString, int, RE::BSFixedString, std::vector<RE::BGSKeyword*>, bool>();
successReg.Register(quest, RE::BSFixedString("OnCreateShopSuccess")); successReg.Register(quest, RE::BSFixedString("OnCreateShopSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnCreateShopFail")); failReg.Register(quest, RE::BSFixedString("OnCreateShopFail"));
@ -17,7 +19,24 @@ void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BS
if (result.IsOk()) { if (result.IsOk()) {
RawShop shop = result.AsOk(); RawShop shop = result.AsOk();
logger::info(FMT_STRING("CreateShop success: {}"), shop.id); logger::info(FMT_STRING("CreateShop success: {}"), shop.id);
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description)); std::vector<RE::BGSKeyword*> keyword_forms;
for (int i = 0; i < shop.vendor_keywords_len; i++) {
RE::BSFixedString keyword = shop.vendor_keywords[i];
logger::info(FMT_STRING("GetShop keyword {:d}: {}"), i, keyword);
RE::TESForm* form = RE::TESForm::LookupByEditorID(keyword);
if (!form) { // form is not found, might be in an uninstalled mod
logger::warn(FMT_STRING("GetShop could not find keyword form for: {}"), keyword);
continue;
}
RE::BGSKeyword* keyword_form = static_cast<RE::BGSKeyword*>(form);
if (!keyword_form) {
logger::warn(FMT_STRING("GetShop could cast form to keyword with id {:x} for: {}"), (uint32_t)form->GetFormID(), keyword);
continue;
}
keyword_forms.push_back(keyword_form);
}
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description), shop.gold, RE::BSFixedString(shop.shop_type), keyword_forms, shop.vendor_keywords_exclude);
} else { } else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("CreateShop failure: {}"), error); logger::error(FMT_STRING("CreateShop failure: {}"), error);
@ -39,24 +58,58 @@ bool CreateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedSt
return true; return true;
} }
void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_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,
int gold,
RE::BSFixedString shop_type,
std::vector<RE::BGSKeyword*> keywords,
bool keywords_exclude,
RE::TESQuest* quest
) {
logger::info("Entered UpdateShopImpl"); logger::info("Entered UpdateShopImpl");
if (!quest) { if (!quest) {
logger::error("UpdateShopImpl quest is null!"); logger::error("UpdateShopImpl quest is null!");
return; return;
} }
SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString> successReg = SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString>(); SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString, int, RE::BSFixedString, std::vector<RE::BGSKeyword*>, bool> successReg =
SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString, int, RE::BSFixedString, std::vector<RE::BGSKeyword*>, bool>();
successReg.Register(quest, RE::BSFixedString("OnUpdateShopSuccess")); successReg.Register(quest, RE::BSFixedString("OnUpdateShopSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnUpdateShopFail")); failReg.Register(quest, RE::BSFixedString("OnUpdateShopFail"));
logger::info(FMT_STRING("UpdateShop api_url: {}, api_key: {}, name: {}, description: {}"), api_url, api_key, name, description); std::vector<const char*> keyword_strings;
FFIResult<RawShop> result = update_shop(api_url.c_str(), api_key.c_str(), id, name.c_str(), description.c_str()); for (auto keyword = keywords.begin(); keyword != keywords.end(); ++keyword) {
keyword_strings.push_back((*keyword)->GetFormEditorID());
}
logger::info(FMT_STRING("UpdateShop api_url: {}, api_key: {}, name: {}, description: {}, gold: {}, shop_type: {}, keywords.size(): {}, keywords_exclude: {}"), api_url, api_key, name, description, gold, shop_type, keywords.size(), keywords_exclude);
FFIResult<RawShop> result = update_shop(api_url.c_str(), api_key.c_str(), id, name.c_str(), description.c_str(), gold, shop_type.c_str(), &keyword_strings[0], keyword_strings.size(), keywords_exclude);
if (result.IsOk()) { if (result.IsOk()) {
RawShop shop = result.AsOk(); RawShop shop = result.AsOk();
logger::info(FMT_STRING("UpdateShop success: {}"), shop.id); logger::info(FMT_STRING("UpdateShop success: {}"), shop.id);
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description)); std::vector<RE::BGSKeyword*> keyword_forms;
for (int i = 0; i < shop.vendor_keywords_len; i++) {
RE::BSFixedString keyword = shop.vendor_keywords[i];
logger::info(FMT_STRING("GetShop keyword {:d}: {}"), i, keyword);
RE::TESForm* form = RE::TESForm::LookupByEditorID(keyword);
if (!form) { // form is not found, might be in an uninstalled mod
logger::warn(FMT_STRING("GetShop could not find keyword form for: {}"), keyword);
continue;
}
RE::BGSKeyword* keyword_form = static_cast<RE::BGSKeyword*>(form);
if (!keyword_form) {
logger::warn(FMT_STRING("GetShop could cast form to keyword with id {:x} for: {}"), (uint32_t)form->GetFormID(), keyword);
continue;
}
keyword_forms.push_back(keyword_form);
}
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description), shop.gold, RE::BSFixedString(shop.shop_type), keyword_forms, shop.vendor_keywords_exclude);
} else { } else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("UpdateShop failure: {}"), error); logger::error(FMT_STRING("UpdateShop failure: {}"), error);
@ -66,14 +119,26 @@ void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_
failReg.Unregister(quest); failReg.Unregister(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 UpdateShop(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
int32_t id,
RE::BSFixedString name,
RE::BSFixedString description,
int gold,
RE::BSFixedString shop_type,
std::vector<RE::BGSKeyword*> keywords,
bool keywords_exclude,
RE::TESQuest* quest
) {
logger::info("Entered UpdateShop"); logger::info("Entered UpdateShop");
if (!quest) { if (!quest) {
logger::error("UpdateShop quest is null!"); logger::error("UpdateShop quest is null!");
return false; return false;
} }
std::thread thread(UpdateShopImpl, api_url, api_key, id, name, description, quest); std::thread thread(UpdateShopImpl, api_url, api_key, id, name, description, gold, shop_type, keywords, keywords_exclude, quest);
thread.detach(); thread.detach();
return true; return true;
} }
@ -85,7 +150,8 @@ void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t i
return; return;
} }
SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString> successReg = SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString>(); SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString, int, RE::BSFixedString, std::vector<RE::BGSKeyword*>, bool> successReg =
SKSE::RegistrationMap<int, RE::BSFixedString, RE::BSFixedString, int, RE::BSFixedString, std::vector<RE::BGSKeyword*>, bool>();
successReg.Register(quest, RE::BSFixedString("OnGetShopSuccess")); successReg.Register(quest, RE::BSFixedString("OnGetShopSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnGetShopFail")); failReg.Register(quest, RE::BSFixedString("OnGetShopFail"));
@ -95,7 +161,24 @@ void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t i
if (result.IsOk()) { if (result.IsOk()) {
RawShop shop = result.AsOk(); RawShop shop = result.AsOk();
logger::info(FMT_STRING("GetShop success: {}"), shop.id); logger::info(FMT_STRING("GetShop success: {}"), shop.id);
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description)); std::vector<RE::BGSKeyword*> keyword_forms;
for (int i = 0; i < shop.vendor_keywords_len; i++) {
RE::BSFixedString keyword = shop.vendor_keywords[i];
logger::info(FMT_STRING("GetShop keyword {:d}: {}"), i, keyword);
RE::TESForm* form = RE::TESForm::LookupByEditorID(keyword);
if (!form) { // form is not found, might be in an uninstalled mod
logger::warn(FMT_STRING("GetShop could not find keyword form for: {}"), keyword);
continue;
}
RE::BGSKeyword* keyword_form = static_cast<RE::BGSKeyword*>(form);
if (!keyword_form) {
logger::warn(FMT_STRING("GetShop could cast form to keyword with id {:x} for: {}"), (uint32_t)form->GetFormID(), keyword);
continue;
}
keyword_forms.push_back(keyword_form);
}
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description), shop.gold, RE::BSFixedString(shop.shop_type), keyword_forms, shop.vendor_keywords_exclude);
} else { } else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("GetShop failure: {}"), error); logger::error(FMT_STRING("GetShop failure: {}"), error);
@ -125,7 +208,8 @@ void ListShopsImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TES
} }
// Since Papyrus arrays are single-type, the array of shops from the API needs to be decomposed into multiple arrays for each shop field // Since Papyrus arrays are single-type, the array of shops from the API needs to be decomposed into multiple arrays for each shop field
SKSE::RegistrationMap<std::vector<int>, std::vector<RE::BSFixedString>, std::vector<RE::BSFixedString>> successReg = SKSE::RegistrationMap<std::vector<int>, std::vector<RE::BSFixedString>, std::vector<RE::BSFixedString>>(); SKSE::RegistrationMap<std::vector<int>, std::vector<RE::BSFixedString>, std::vector<RE::BSFixedString>, std::vector<int>, std::vector<RE::BSFixedString>, std::vector<RE::BGSKeyword*>, std::vector<bool>> successReg =
SKSE::RegistrationMap<std::vector<int>, std::vector<RE::BSFixedString>, std::vector<RE::BSFixedString>, std::vector<int>, std::vector<RE::BSFixedString>, std::vector<RE::BGSKeyword*>, std::vector<bool>>();
successReg.Register(quest, RE::BSFixedString("OnListShopsSuccess")); successReg.Register(quest, RE::BSFixedString("OnListShopsSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnListShopsFail")); failReg.Register(quest, RE::BSFixedString("OnListShopsFail"));
@ -139,13 +223,41 @@ void ListShopsImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TES
std::vector<int> id_vec = std::vector<int>(); std::vector<int> id_vec = std::vector<int>();
std::vector<RE::BSFixedString> name_vec = std::vector<RE::BSFixedString>(); std::vector<RE::BSFixedString> name_vec = std::vector<RE::BSFixedString>();
std::vector<RE::BSFixedString> description_vec = std::vector<RE::BSFixedString>(); std::vector<RE::BSFixedString> description_vec = std::vector<RE::BSFixedString>();
std::vector<int> gold_vec = std::vector<int>();
std::vector<RE::BSFixedString> shop_type_vec = std::vector<RE::BSFixedString>();
std::vector<RE::BGSKeyword*> keywords_vec = std::vector<RE::BGSKeyword*>();
std::vector<bool> keywords_exclude_vec = std::vector<bool>();
for (int i = 0; i < vec.len; i++) { for (int i = 0; i < vec.len; i++) {
RawShop shop = vec.ptr[i]; RawShop shop = vec.ptr[i];
id_vec.push_back(shop.id); id_vec.push_back(shop.id);
name_vec.push_back(RE::BSFixedString(shop.name)); name_vec.push_back(RE::BSFixedString(shop.name));
description_vec.push_back(RE::BSFixedString(shop.description)); description_vec.push_back(RE::BSFixedString(shop.description));
gold_vec.push_back(shop.gold);
shop_type_vec.push_back(RE::BSFixedString(shop.shop_type));
std::vector<RE::BGSKeyword*> keyword_forms;
for (int j = 0; j < shop.vendor_keywords_len; j++) {
RE::BSFixedString keyword = shop.vendor_keywords[j];
logger::info(FMT_STRING("ListShop keyword {:d}: {}"), j, keyword);
RE::TESForm* form = RE::TESForm::LookupByEditorID(keyword);
if (!form) { // form is not found, might be in an uninstalled mod
logger::warn(FMT_STRING("ListShop could not find keyword form for: {}"), keyword);
continue;
}
RE::BGSKeyword* keyword_form = static_cast<RE::BGSKeyword*>(form);
if (!keyword_form) {
logger::warn(FMT_STRING("ListShop could cast form to keyword with id {:x} for: {}"), (uint32_t)form->GetFormID(), keyword);
continue;
}
keyword_forms.push_back(keyword_form);
}
// Since papyrus doesn't have multi-dimensional arrays, I have to fake it with one flat array with each keyword list separated by a nullptr
keywords_vec.insert(keywords_vec.end(), keyword_forms.begin(), keyword_forms.end());
keywords_vec.push_back(nullptr);
keywords_exclude_vec.push_back(shop.vendor_keywords_exclude);
} }
successReg.SendEvent(id_vec, name_vec, description_vec); successReg.SendEvent(id_vec, name_vec, description_vec, gold_vec, shop_type_vec, keywords_vec, keywords_exclude_vec);
} else { } else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("ListShops failure: {}"), error); logger::error(FMT_STRING("ListShops failure: {}"), error);
@ -155,6 +267,27 @@ void ListShopsImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TES
failReg.Unregister(quest); failReg.Unregister(quest);
} }
std::vector<RE::BGSKeyword*> GetKeywordsSubArray(RE::StaticFunctionTag*, std::vector<RE::BGSKeyword*> flat_keywords_array, int sub_array_index) {
int i = 0;
int current_sub_array = 0;
while (current_sub_array < sub_array_index) {
if (flat_keywords_array[i] == nullptr) {
current_sub_array += 1;
}
i += 1;
}
std::vector<RE::BGSKeyword*> sub_array = std::vector<RE::BGSKeyword*>();
while (true) {
if (flat_keywords_array[i] == nullptr) {
break;
} else {
sub_array.push_back(flat_keywords_array[i]);
}
i += 1;
}
return sub_array;
}
bool ListShops(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TESQuest* quest) { bool ListShops(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TESQuest* quest) {
logger::info("Entered ListShops"); logger::info("Entered ListShops");
if (!quest) { if (!quest) {
@ -166,3 +299,84 @@ bool ListShops(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedStr
thread.detach(); thread.detach();
return true; return true;
} }
bool SetVendorKeywords(RE::StaticFunctionTag*, std::vector<RE::BGSKeyword*> keywords, bool keywords_exclude) {
logger::info("Entered SetVendorKeywords");
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
RE::BGSListForm* vendor_items = data_handler->LookupForm<RE::BGSListForm>(FORM_LIST_VENDOR_ITEMS, MOD_NAME);
RE::TESFaction* vendor_services_faction = data_handler->LookupForm<RE::TESFaction>(FACTION_SERVICES_VENDOR, MOD_NAME);
if (!vendor_items) {
logger::error("SetVendorKeywords vendor_items could not be loaded!");
return false;
}
if (!vendor_services_faction) {
logger::error("SetVendorKeywords vendor_services_faction could not be loaded!");
return false;
}
vendor_items->ClearData();
for (auto keyword = keywords.begin(); keyword != keywords.end(); ++keyword) {
vendor_items->AddForm(*keyword);
}
vendor_services_faction->vendorData.vendorValues.notBuySell = keywords_exclude;
return true;
}
void RefreshShopGoldImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::TESObjectREFR* merchant_chest) {
logger::info("Entered RefreshShopGoldImpl");
if (!merchant_chest) {
logger::error("RefreshShopGoldImpl merch_chest is null!");
return;
}
SKSE::RegistrationMap<int> successReg = SKSE::RegistrationMap<int>();
successReg.Register(merchant_chest, RE::BSFixedString("OnRefreshShopGoldSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(merchant_chest, RE::BSFixedString("OnRefreshShopGoldFail"));
RE::TESForm* gold_form = RE::TESForm::LookupByID(15);
if (!gold_form) {
logger::error("RefreshShopGoldImpl failed to lookup gold form");
failReg.SendEvent(RE::BSFixedString("Failed to lookup gold form"));
successReg.Unregister(merchant_chest);
failReg.Unregister(merchant_chest);
return;
}
RE::TESBoundObject* gold = static_cast<RE::TESBoundObject*>(gold_form);
if (!gold) {
logger::error("RefreshShopGoldImpl failed to cast gold form to gold bound object");
failReg.SendEvent(RE::BSFixedString("Failed to cast gold form to gold bound object"));
successReg.Unregister(merchant_chest);
failReg.Unregister(merchant_chest);
return;
}
logger::info(FMT_STRING("RefreshShopGold api_url: {}, api_key: {}, id: {}"), api_url, api_key, id);
FFIResult<RawShop> result = get_shop(api_url.c_str(), api_key.c_str(), id);
if (result.IsOk()) {
RawShop shop = result.AsOk();
logger::info(FMT_STRING("RefreshShopGold success id: {} gold: {}"), shop.id, shop.gold);
if (shop.gold > 0) {
merchant_chest->AddObjectToContainer(gold, nullptr, shop.gold, merchant_chest);
}
successReg.SendEvent(shop.gold);
} else {
const char* error = result.AsErr();
logger::error(FMT_STRING("RefreshShopGold failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error));
}
successReg.Unregister(merchant_chest);
failReg.Unregister(merchant_chest);
}
bool RefreshShopGold(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::TESObjectREFR* merchant_chest) {
logger::info("Entered RefreshShopGold");
if (!merchant_chest) {
logger::error("RefreshShopGold merch_chest is null!");
return false;
}
std::thread thread(RefreshShopGoldImpl, api_url, api_key, id, merchant_chest);
thread.detach();
return true;
}

View File

@ -1,6 +1,21 @@
#pragma once #pragma once
bool CreateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest); 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, int32_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,
int gold,
RE::BSFixedString shop_type,
std::vector<RE::BGSKeyword*> keywords,
bool keywords_exclude,
RE::TESQuest* quest
);
bool GetShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, 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); bool ListShops(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::TESQuest* quest);
std::vector<RE::BGSKeyword*> GetKeywordsSubArray(RE::StaticFunctionTag*, std::vector<RE::BGSKeyword*> flat_keywords_array, int sub_array_index);
bool SetVendorKeywords(RE::StaticFunctionTag*, std::vector<RE::BGSKeyword*> keywords, bool keywords_exclude);
bool RefreshShopGold(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, int32_t id, RE::TESObjectREFR* merchant_chest);

View File

@ -19,6 +19,9 @@ bool RegisterFuncs(RE::BSScript::IVirtualMachine* a_vm)
a_vm->RegisterFunction("Update", "BRShop", UpdateShop); a_vm->RegisterFunction("Update", "BRShop", UpdateShop);
a_vm->RegisterFunction("Get", "BRShop", GetShop); a_vm->RegisterFunction("Get", "BRShop", GetShop);
a_vm->RegisterFunction("List", "BRShop", ListShops); a_vm->RegisterFunction("List", "BRShop", ListShops);
a_vm->RegisterFunction("GetKeywordsSubArray", "BRShop", GetKeywordsSubArray);
a_vm->RegisterFunction("SetVendorKeywords", "BRShop", SetVendorKeywords);
a_vm->RegisterFunction("RefreshGold", "BRShop", RefreshShopGold);
a_vm->RegisterFunction("Create", "BRInteriorRefList", CreateInteriorRefList); a_vm->RegisterFunction("Create", "BRInteriorRefList", CreateInteriorRefList);
a_vm->RegisterFunction("ClearCell", "BRInteriorRefList", ClearCell); a_vm->RegisterFunction("ClearCell", "BRInteriorRefList", ClearCell);
a_vm->RegisterFunction("Load", "BRInteriorRefList", LoadInteriorRefList); a_vm->RegisterFunction("Load", "BRInteriorRefList", LoadInteriorRefList);