Semi-working refactor of merch for multiple shelves

Code is now capable of loading merch onto multiple store shelves during load shop.

Still need to fix refresh, loading merch after creating merch and making transactions, the shelf buttons, as well as saving the state of the shelves to the server.
This commit is contained in:
Tyler Hallada 2020-11-28 23:44:48 -05:00
parent e673ac4642
commit d1849735b2
8 changed files with 649 additions and 614 deletions

View File

@ -76,6 +76,7 @@ void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnCreateInteriorRefListFail")); failReg.Register(quest, RE::BSFixedString("OnCreateInteriorRefListFail"));
// TODO: may need to dynamically pass shop cell into this function
RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty"); RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty");
logger::info(FMT_STRING("CreateInteriorRefListImpl lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID()); logger::info(FMT_STRING("CreateInteriorRefListImpl lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID());
if (!cell) { if (!cell) {
@ -92,8 +93,13 @@ void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
for (auto entry = cell->references.begin(); entry != cell->references.end(); ++entry) { for (auto entry = cell->references.begin(); entry != cell->references.end(); ++entry) {
RE::TESObjectREFR * ref = (*entry).get(); RE::TESObjectREFR * ref = (*entry).get();
const char * name = ref->GetName(); const char * name = ref->GetName();
logger::info(FMT_STRING("CreateInteriorRefList ref: {}"), name); RE::FormID ref_form_id = ref->GetFormID();
const RE::TESBoundObject * base = ref->GetBaseObject(); logger::info(FMT_STRING("CreateInteriorRefList ref: {}, form_id: {:x}"), name, (uint32_t)ref_form_id);
if (ref->IsDisabled()) {
logger::info("CreateInteriorRefList skipping ref since it is disabled");
continue;
}
RE::TESBoundObject * base = ref->GetBaseObject();
if (base) { if (base) {
RE::FormID base_form_id = base->GetFormID(); RE::FormID base_form_id = base->GetFormID();
const RE::FormType form_type = base->GetFormType(); const RE::FormType form_type = base->GetFormType();
@ -113,11 +119,9 @@ void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
logger::info(FMT_STRING("CreateInteriorRefList position: {:.2f}, {:.2f}, {:.2f} angle: {:.2f}, {:.2f}, {:.2f} scale: {:d}"), position_x, position_y, position_z, angle_x, angle_y, angle_z, scale); logger::info(FMT_STRING("CreateInteriorRefList position: {:.2f}, {:.2f}, {:.2f} angle: {:.2f}, {:.2f}, {:.2f} scale: {:d}"), position_x, position_y, position_z, angle_x, angle_y, angle_z, scale);
logger::info(FMT_STRING("CreateInteriorRefList deleted: {:d}, wants delete: {:d}"), ref->IsMarkedForDeletion(), ref->inGameFormFlags.all(RE::TESObjectREFR::InGameFormFlag::kWantsDelete)); logger::info(FMT_STRING("CreateInteriorRefList deleted: {:d}, wants delete: {:d}"), ref->IsMarkedForDeletion(), ref->inGameFormFlags.all(RE::TESObjectREFR::InGameFormFlag::kWantsDelete));
RE::TESFile * base_file = base->GetFile(0); std::pair<uint32_t, const char*> id_parts = get_local_form_id_and_mod_name(base);
char * base_file_name = base_file->fileName; uint32_t base_local_form_id = id_parts.first;
bool is_light = base_file->recordFlags.all(RE::TESFile::RecordFlag::kSmallFile); const char * base_file_name = id_parts.second;
uint32_t base_local_form_id = is_light ? base_form_id & 0xfff : base_form_id & 0xFFFFFF;
RE::FormID ref_form_id = ref->GetFormID();
uint16_t ref_mod_index = ref_form_id >> 24; uint16_t ref_mod_index = ref_form_id >> 24;
char * ref_file_name = nullptr; char * ref_file_name = nullptr;
uint32_t ref_local_form_id = ref_form_id & 0xFFFFFF; uint32_t ref_local_form_id = ref_form_id & 0xFFFFFF;
@ -133,7 +137,7 @@ void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_
} }
} }
logger::info(FMT_STRING("CreateInteriorRefList ref_file_name: {}, base_file_name: {}"), ref_file_name, base_file_name); logger::info(FMT_STRING("CreateInteriorRefList ref_file_name: {}, base_file_name: {}"), ref_file_name, base_file_name);
if (strcmp("Bazaar Realm.esp", base_file_name) == 0) { if (strcmp(base_file_name, MOD_NAME) == 0) {
logger::info(FMT_STRING("CreateInteriorRefList ref base is in Bazaar Ream.esp: {:x}"), base_local_form_id); logger::info(FMT_STRING("CreateInteriorRefList ref base is in Bazaar Ream.esp: {:x}"), base_local_form_id);
if (ignored_shelf_related_form_ids.find(base_local_form_id) != ignored_shelf_related_form_ids.end()) { if (ignored_shelf_related_form_ids.find(base_local_form_id) != ignored_shelf_related_form_ids.end()) {
logger::info("CreateInteriorRefList ref is an ignored shelf related form"); logger::info("CreateInteriorRefList ref is an ignored shelf related form");
@ -218,8 +222,8 @@ bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE
bool ClearCell(RE::StaticFunctionTag*) { bool ClearCell(RE::StaticFunctionTag*) {
logger::info("Entered ClearCell"); logger::info("Entered ClearCell");
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
using func_t = bool(RE::TESObjectREFR* a_thisObj, void* a_param1, void* a_param2, double& a_result); using func_t = bool(RE::TESObjectREFR* a_thisObj, void* a_param1, void* a_param2, double& a_result);
// TODO: the cell will need to be dynamically passed in
RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty"); RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty");
logger::info(FMT_STRING("ClearCell lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID()); logger::info(FMT_STRING("ClearCell lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID());
if (!cell) { if (!cell) {
@ -235,18 +239,7 @@ bool ClearCell(RE::StaticFunctionTag*) {
int mod_index = form_id >> 24; int mod_index = form_id >> 24;
if (mod_index != 255) { if (mod_index != 255) {
RE::TESFile * file = ref->GetDescriptionOwnerFile(); // TODO: recognize somehow that this ref was a pre-placed initially disabled furnature upgrade piece and disable it now if so
if (file) {
bool is_light = file->recordFlags.all(RE::TESFile::RecordFlag::kSmallFile);
uint32_t local_form_id = is_light ? ref->GetFormID() & 0xfff : form_id & 0xFFFFFF;
if (!data_handler->LookupForm<RE::TESObjectREFR>(local_form_id, file->fileName)) {
logger::info(FMT_STRING("ClearCell ref was not in mod file! {:x} {}"), local_form_id, ref->GetName());
} else {
logger::info(FMT_STRING("ClearCell ref in mod file {:x} {}"), local_form_id, ref->GetName());
}
} else {
logger::info(FMT_STRING("ClearCell ref not in ANY file! {:x} {}"), (uint32_t)form_id, ref->GetName());
}
++entry; ++entry;
} else { } else {
logger::info(FMT_STRING("ClearCell ref is a temp ref, deleting {:x} {}"), (uint32_t)form_id, ref->GetName()); logger::info(FMT_STRING("ClearCell ref is a temp ref, deleting {:x} {}"), (uint32_t)form_id, ref->GetName());
@ -267,6 +260,14 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
return; return;
} }
// Testing to see what ExtraLinkedRefChildren stores
RE::ExtraLinkedRefChildren* linkedChildren = (RE::ExtraLinkedRefChildren*)public_chest->extraList.GetByType(RE::ExtraDataType::kLinkedRefChildren);
if (linkedChildren) {
logger::info(FMT_STRING("CreateMerchandiseList public_chest has linkedChildren: size: {}"), linkedChildren->linkedChildren.size());
} else {
logger::info("CreateMerchandiseList public_chest has no linkedChildren");
}
// Placing the refs must be done on the main thread otherwise calling MoveTo causes a crash // Placing the refs must be done on the main thread otherwise calling MoveTo causes a crash
auto task = SKSE::GetTaskInterface(); auto task = SKSE::GetTaskInterface();
task->AddTask([result, target_ref, private_chest, public_chest, quest]() { task->AddTask([result, target_ref, private_chest, public_chest, quest]() {
@ -277,6 +278,7 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
using func_t2 = decltype(&MoveTo); using func_t2 = decltype(&MoveTo);
REL::Relocation<func_t2> MoveTo_Native(RE::Offset::TESObjectREFR::MoveTo); REL::Relocation<func_t2> MoveTo_Native(RE::Offset::TESObjectREFR::MoveTo);
REL::ID extra_linked_ref_vtbl(static_cast<std::uint64_t>(229564)); REL::ID extra_linked_ref_vtbl(static_cast<std::uint64_t>(229564));
std::vector<RE::TESObjectREFR*> shelves;
RE::BGSKeyword* shelf_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_SHELF, MOD_NAME); RE::BGSKeyword* shelf_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_SHELF, MOD_NAME);
RE::BGSKeyword* chest_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_CHEST, MOD_NAME); RE::BGSKeyword* chest_keyword = data_handler->LookupForm<RE::BGSKeyword>(KEYWORD_CHEST, MOD_NAME);
@ -285,7 +287,7 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
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);
SKSE::RegistrationMap<bool> successReg = SKSE::RegistrationMap<bool>(); 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"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnLoadInteriorRefListFail")); failReg.Register(quest, RE::BSFixedString("OnLoadInteriorRefListFail"));
@ -344,6 +346,10 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
game_ref = data_handler->LookupForm<RE::TESObjectREFR>(ref.ref_local_form_id, ref.ref_mod_name); game_ref = data_handler->LookupForm<RE::TESObjectREFR>(ref.ref_local_form_id, ref.ref_mod_name);
if (game_ref) { if (game_ref) {
logger::info(FMT_STRING("LoadInteriorRefList lookup ref name: {}, form_id: {:x}"), game_ref->GetName(), (uint32_t)game_ref->GetFormID()); logger::info(FMT_STRING("LoadInteriorRefList lookup ref name: {}, form_id: {:x}"), game_ref->GetName(), (uint32_t)game_ref->GetFormID());
if (game_ref->IsDisabled()) {
logger::info("LoadInteriorRefList lookup ref is disabled, enabling");
game_ref->formFlags &= ~RE::TESObjectREFR::RecordFlags::kInitiallyDisabled;
}
} else { } else {
logger::info(FMT_STRING("LoadInteriorRefList lookup ref not found, ref_mod_name: {}, ref_local_form_id: {:x}"), ref.ref_mod_name, ref.ref_local_form_id); logger::info(FMT_STRING("LoadInteriorRefList lookup ref not found, ref_mod_name: {}, ref_local_form_id: {:x}"), ref.ref_mod_name, ref.ref_local_form_id);
} }
@ -392,7 +398,8 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
RE::TESObjectREFR* shelf_ref = PlaceAtMe_Native(a_vm, 0, target_ref, form, 1, false, false); RE::TESObjectREFR* shelf_ref = PlaceAtMe_Native(a_vm, 0, target_ref, form, 1, false, false);
MoveTo_Native(shelf_ref, shelf_ref->CreateRefHandle(), cell, cell->worldSpace, position, angle); MoveTo_Native(shelf_ref, shelf_ref->CreateRefHandle(), cell, cell->worldSpace, position, angle);
shelf_ref->data.angle = angle; // set angle directly to fix bug with MoveTo in an unloaded target cell shelf_ref->data.angle = angle; // set angle directly to fix bug with MoveTo in an unloaded target cell
RE::ExtraLinkedRef* shelf_extra_linked_ref = (RE::ExtraLinkedRef*)RE::BSExtraData::Create(sizeof(RE::ExtraLinkedRef), extra_linked_ref_vtbl.address()); shelves.push_back(shelf_ref);
RE::ExtraLinkedRef* shelf_extra_linked_ref = RE::BSExtraData::Create<RE::ExtraLinkedRef>(extra_linked_ref_vtbl.address());
shelf_extra_linked_ref->linkedRefs.push_back({public_chest_keyword, public_chest}); shelf_extra_linked_ref->linkedRefs.push_back({public_chest_keyword, public_chest});
shelf_extra_linked_ref->linkedRefs.push_back({chest_keyword, private_chest}); shelf_extra_linked_ref->linkedRefs.push_back({chest_keyword, private_chest});
shelf_ref->extraList.Add(shelf_extra_linked_ref); shelf_ref->extraList.Add(shelf_extra_linked_ref);
@ -429,7 +436,7 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
button_ref->data.angle = button_angle; // set angle directly to fix bug with MoveTo in an unloaded target cell button_ref->data.angle = button_angle; // set angle directly to fix bug with MoveTo in an unloaded target cell
button_ref->refScale = button.position.scale; button_ref->refScale = button.position.scale;
RE::ExtraLinkedRef* button_extra_linked_ref = (RE::ExtraLinkedRef*)RE::BSExtraData::Create(sizeof(RE::ExtraLinkedRef), extra_linked_ref_vtbl.address()); RE::ExtraLinkedRef* button_extra_linked_ref = RE::BSExtraData::Create<RE::ExtraLinkedRef>(extra_linked_ref_vtbl.address());
button_extra_linked_ref->linkedRefs.push_back({shelf_keyword, shelf_ref}); button_extra_linked_ref->linkedRefs.push_back({shelf_keyword, shelf_ref});
button_ref->extraList.Add(button_extra_linked_ref); button_ref->extraList.Add(button_extra_linked_ref);
@ -459,7 +466,7 @@ void LoadRefsTask(FFIResult<RawInteriorRefData> result, RE::TESObjectREFR* targe
return; return;
} }
successReg.SendEvent(true); successReg.SendEvent(true, shelves);
successReg.Unregister(quest); successReg.Unregister(quest);
failReg.Unregister(quest); failReg.Unregister(quest);
}); });

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +1,44 @@
#pragma once #pragma once
bool ToggleMerchandise( //bool ToggleMerchandise(
RE::StaticFunctionTag*, // RE::StaticFunctionTag*,
RE::BSFixedString api_url, // RE::BSFixedString api_url,
RE::BSFixedString api_key, // RE::BSFixedString api_key,
int32_t shop_id, // int32_t shop_id,
RE::TESObjectREFR* merchant_shelf, // RE::TESObjectREFR* merchant_shelf
RE::TESForm* activator_static, //);
RE::BGSKeyword* shelf_keyword, //bool LoadNextMerchandise(
RE::BGSKeyword* chest_keyword, // RE::StaticFunctionTag*,
RE::BGSKeyword* item_keyword, // RE::BSFixedString api_url,
RE::BGSKeyword* activator_keyword, // RE::BSFixedString api_key,
RE::BGSKeyword* toggle_keyword, // int32_t shop_id,
RE::BGSKeyword* next_keyword, // RE::TESObjectREFR* merchant_shelf
RE::BGSKeyword* prev_keyword //);
); //bool LoadPrevMerchandise(
bool LoadNextMerchandise( // RE::StaticFunctionTag*,
RE::StaticFunctionTag*, // RE::BSFixedString api_url,
RE::BSFixedString api_url, // RE::BSFixedString api_key,
RE::BSFixedString api_key, // int32_t shop_id,
int32_t shop_id, // RE::TESObjectREFR* merchant_shelf
RE::TESObjectREFR* merchant_shelf, //);
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
RE::BGSKeyword* chest_keyword,
RE::BGSKeyword* item_keyword,
RE::BGSKeyword* activator_keyword,
RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword
);
bool LoadPrevMerchandise(
RE::StaticFunctionTag*,
RE::BSFixedString api_url,
RE::BSFixedString api_key,
int32_t shop_id,
RE::TESObjectREFR* merchant_shelf,
RE::TESForm* activator_static,
RE::BGSKeyword* shelf_keyword,
RE::BGSKeyword* chest_keyword,
RE::BGSKeyword* item_keyword,
RE::BGSKeyword* activator_keyword,
RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword
);
bool LoadMerchandiseByShopId( bool LoadMerchandiseByShopId(
RE::StaticFunctionTag*, RE::StaticFunctionTag*,
RE::BSFixedString api_url, RE::BSFixedString api_url,
RE::BSFixedString api_key, RE::BSFixedString api_key,
int32_t shop_id, int32_t shop_id,
RE::TESObjectREFR* merchant_shelf, RE::TESObjectCELL* cell,
RE::TESForm* activator_static, std::vector<RE::TESObjectREFR*> merchant_shelves,
RE::BGSKeyword* shelf_keyword, RE::TESObjectREFR* merchant_chest
RE::BGSKeyword* chest_keyword,
RE::BGSKeyword* item_keyword,
RE::BGSKeyword* activator_keyword,
RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword
); );
bool RefreshMerchandise( //bool RefreshMerchandise(
RE::StaticFunctionTag*, // RE::StaticFunctionTag*,
RE::BSFixedString api_url, // RE::BSFixedString api_url,
RE::BSFixedString api_key, // RE::BSFixedString api_key,
int32_t shop_id, // int32_t shop_id,
RE::TESObjectREFR* merchant_shelf, // RE::TESObjectREFR* merchant_shelf
RE::TESForm* activator_static, //);
RE::BGSKeyword* shelf_keyword, bool ReplaceMerch3D(RE::StaticFunctionTag*, RE::TESObjectREFR* merchant_shelf);
RE::BGSKeyword* chest_keyword, bool ReplaceAllMerch3D(RE::StaticFunctionTag*, RE::TESObjectCELL* cell);
RE::BGSKeyword* item_keyword,
RE::BGSKeyword* activator_keyword,
RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword,
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, int32_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 GetMerchandiseQuantity(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);
int GetMerchandisePrice(RE::StaticFunctionTag*, RE::TESObjectREFR* activator); int GetMerchandisePrice(RE::StaticFunctionTag*, RE::TESObjectREFR* activator);

View File

@ -1,4 +1,5 @@
#include "bindings.h" #include "bindings.h"
#include "utils.h"
void CreateTransactionImpl( void CreateTransactionImpl(
RE::BSFixedString api_url, RE::BSFixedString api_url,
@ -33,10 +34,9 @@ void CreateTransactionImpl(
RE::FormID form_id = merch_base->GetFormID(); 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); logger::info(FMT_STRING("CreateTransactionImpl merch_base form_id: {:x}, name: {}, type: {:x}"), (uint32_t)form_id, name, (uint32_t)form_type);
RE::TESFile * file = merch_base->GetFile(0); std::pair<uint32_t, const char*> id_parts = get_local_form_id_and_mod_name(merch_base);
const char * mod_name = file->fileName; uint32_t local_form_id = id_parts.first;
bool is_light = file->recordFlags.all(RE::TESFile::RecordFlag::kSmallFile); const char* mod_name = id_parts.second;
uint32_t local_form_id = is_light ? form_id & 0xfff : form_id & 0xFFFFFF;
logger::info(FMT_STRING("CreateTransactionImpl merch_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 // TODO: implement is_food

View File

@ -1,10 +1,12 @@
#pragma once #pragma once
const char* MOD_NAME = "Bazaar Realm.esp"; constexpr const char* MOD_NAME = "Bazaar Realm.esp";
const uint32_t KEYWORD_SHELF = 0x002fb1; constexpr uint32_t KEYWORD_SHELF = 0x002fb1;
const uint32_t KEYWORD_CHEST = 0x002fb2; constexpr uint32_t KEYWORD_CHEST = 0x002fb2;
const uint32_t KEYWORD_PUBLIC_CHEST = 0x00603e; constexpr uint32_t KEYWORD_PUBLIC_CHEST = 0x00603e;
const uint32_t KEYWORD_TOGGLE = 0x00351b; constexpr uint32_t KEYWORD_TOGGLE = 0x00351b;
const uint32_t KEYWORD_NEXT = 0x00351c; constexpr uint32_t KEYWORD_NEXT = 0x00351c;
const uint32_t KEYWORD_PREV = 0x00351d; constexpr uint32_t KEYWORD_PREV = 0x00351d;
const uint32_t KEYWORD_ITEM = 0x003517; constexpr uint32_t KEYWORD_ITEM = 0x003517;
const uint32_t KEYWORD_ACTIVATOR = 0x004AA8; constexpr uint32_t KEYWORD_ACTIVATOR = 0x004AA8;
constexpr uint32_t ACTIVATOR_STATIC = 0x002a3b;

View File

@ -23,12 +23,13 @@ bool RegisterFuncs(RE::BSScript::IVirtualMachine* a_vm)
a_vm->RegisterFunction("ClearCell", "BRInteriorRefList", ClearCell); a_vm->RegisterFunction("ClearCell", "BRInteriorRefList", ClearCell);
a_vm->RegisterFunction("Load", "BRInteriorRefList", LoadInteriorRefList); a_vm->RegisterFunction("Load", "BRInteriorRefList", LoadInteriorRefList);
a_vm->RegisterFunction("LoadByShopId", "BRInteriorRefList", LoadInteriorRefListByShopId); a_vm->RegisterFunction("LoadByShopId", "BRInteriorRefList", LoadInteriorRefListByShopId);
a_vm->RegisterFunction("Toggle", "BRMerchandiseList", ToggleMerchandise); //a_vm->RegisterFunction("Toggle", "BRMerchandiseList", ToggleMerchandise);
a_vm->RegisterFunction("NextPage", "BRMerchandiseList", LoadNextMerchandise); //a_vm->RegisterFunction("NextPage", "BRMerchandiseList", LoadNextMerchandise);
a_vm->RegisterFunction("PrevPage", "BRMerchandiseList", LoadPrevMerchandise); //a_vm->RegisterFunction("PrevPage", "BRMerchandiseList", LoadPrevMerchandise);
a_vm->RegisterFunction("Load", "BRMerchandiseList", LoadMerchandiseByShopId); a_vm->RegisterFunction("Load", "BRMerchandiseList", LoadMerchandiseByShopId);
a_vm->RegisterFunction("Refresh", "BRMerchandiseList", RefreshMerchandise); //a_vm->RegisterFunction("Refresh", "BRMerchandiseList", RefreshMerchandise);
a_vm->RegisterFunction("Replace3D", "BRMerchandiseList", ReplaceMerch3D); a_vm->RegisterFunction("Replace3D", "BRMerchandiseList", ReplaceMerch3D);
a_vm->RegisterFunction("ReplaceAll3D", "BRMerchandiseList", ReplaceAllMerch3D);
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);

View File

@ -19,3 +19,11 @@ RE::NiPoint3 rotate_point(RE::NiPoint3 point, RE::NiMatrix3 rotation_matrix) {
(point.x * rotation_matrix.entry[0][2]) + (point.y * rotation_matrix.entry[1][2]) + (point.z * rotation_matrix.entry[2][2]) (point.x * rotation_matrix.entry[0][2]) + (point.y * rotation_matrix.entry[1][2]) + (point.z * rotation_matrix.entry[2][2])
); );
} }
std::pair<uint32_t, const char*> get_local_form_id_and_mod_name(RE::TESForm* form) {
RE::FormID form_id = form->GetFormID();
RE::TESFile* file = form->GetFile(0);
const char* mod_name = file->fileName;
bool is_light = file->recordFlags.all(RE::TESFile::RecordFlag::kSmallFile);
return std::pair(is_light ? form_id & 0xfff : form_id & 0xFFFFFF, mod_name);
}

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
RE::NiMatrix3 get_rotation_matrix(RE::NiPoint3 rotation); RE::NiMatrix3 get_rotation_matrix(RE::NiPoint3 rotation);
RE::NiPoint3 rotate_point(RE::NiPoint3 point, RE::NiMatrix3 rotation_matrix); RE::NiPoint3 rotate_point(RE::NiPoint3 point, RE::NiMatrix3 rotation_matrix);
std::pair<uint32_t, const char*> get_local_form_id_and_mod_name(RE::TESForm* form);