parent
4d80f064b5
commit
58890efc21
11 changed files with 257 additions and 43 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,144 @@ |
||||
#include "BookCheck.h" |
||||
|
||||
// Mostly borrowed from Fix Note icon for SkyUI by 0xC0000005
|
||||
namespace BookCheck |
||||
{ |
||||
std::vector<RE::TESObjectBOOK*> validBooks; |
||||
|
||||
void PreloadBookList() |
||||
{ |
||||
const auto dataHandler = RE::TESDataHandler::GetSingleton(); |
||||
|
||||
if (!dataHandler) { |
||||
return; |
||||
} |
||||
|
||||
RE::BGSKeyword* recipeKeyword = dataHandler->LookupForm<RE::BGSKeyword>(0xF5CB0, "Skyrim.esm"); // VendorItemRecipe
|
||||
|
||||
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectBOOK>()) { |
||||
if (!form || form->TeachesSpell()) { |
||||
continue; |
||||
} |
||||
if (form->HasKeyword(recipeKeyword) || IsBook(form)) { |
||||
validBooks.push_back(form); |
||||
} |
||||
} |
||||
} |
||||
|
||||
std::vector<RE::TESObjectBOOK*> GetBookList() |
||||
{ |
||||
return validBooks; |
||||
} |
||||
|
||||
const char* ExtractFileName(const char* const path, size_t& fileNameLength) |
||||
{ |
||||
if (!path) { |
||||
fileNameLength = 0; |
||||
return NULL; |
||||
} |
||||
|
||||
const char* ptr = path; |
||||
const char* fileNameStart = NULL; |
||||
|
||||
while (*ptr != 0) { |
||||
char value = *ptr; |
||||
|
||||
if (value == '\\' || value == '/') { |
||||
fileNameStart = ptr + 1; |
||||
} |
||||
|
||||
ptr++; |
||||
} |
||||
|
||||
const char* result = fileNameStart ? fileNameStart : path; |
||||
|
||||
fileNameLength = ptr - result; |
||||
|
||||
return result; |
||||
} |
||||
|
||||
// Performs a case-sensitive search for 'needle' in the specified string,
|
||||
// excluding any matches that are part of a larger word.
|
||||
bool ContainsWholeWord(const char* const haystack, const size_t haystackLength, |
||||
const char* const needle, const size_t needleLength) |
||||
{ |
||||
if (haystackLength >= needleLength) { |
||||
for (size_t i = 0; i < haystackLength; i++) { |
||||
if (haystack[i] != needle[0]) { |
||||
continue; |
||||
} |
||||
|
||||
size_t j = i + 1; |
||||
size_t k = 1; |
||||
|
||||
while (j < haystackLength && k < needleLength && haystack[j] == needle[k]) { |
||||
j++; |
||||
k++; |
||||
} |
||||
|
||||
if (k == needleLength) { |
||||
// Check that the match is not part of a larger word.
|
||||
|
||||
char next = haystack[j]; |
||||
|
||||
return !(next >= 'a' && next <= 'z'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool StartsWith(const char* haystack, size_t haystackLength, |
||||
const char* needle, size_t needleLength) |
||||
{ |
||||
return haystackLength >= needleLength && memcmp(haystack, needle, needleLength) == 0; |
||||
} |
||||
|
||||
bool IsNote(const char* const modelFileName, size_t modelFileNameLength) |
||||
{ |
||||
// Most items will use one of the note models from the base game, e.g. Note01.nif.
|
||||
if (ContainsWholeWord(modelFileName, modelFileNameLength, "Note", 4)) { |
||||
return true; |
||||
} |
||||
|
||||
// The Creation Club Fishing mod does not include 'Note' the inventory art model names for the
|
||||
// regional fishing maps, instead those items use the following format: FishMap<region>.
|
||||
if (StartsWith(modelFileName, modelFileNameLength, "FishMap", 7)) { |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool IsJournal(const char* const modelFileName, size_t modelFileNameLength) |
||||
{ |
||||
return ContainsWholeWord(modelFileName, modelFileNameLength, "Journal", 7); |
||||
} |
||||
|
||||
bool IsBook(RE::TESObjectBOOK* book) |
||||
{ |
||||
if (!book || !book->inventoryModel) { |
||||
return false; |
||||
} |
||||
|
||||
RE::BGSSoundDescriptorForm* pickupSound = book->As<RE::BGSPickupPutdownSounds>()->pickupSound; |
||||
|
||||
if (pickupSound && pickupSound->formID == 0xC7A54) { // ITMNoteUp
|
||||
return false; |
||||
} |
||||
|
||||
size_t modelFileNameLength; |
||||
const char* const modelFileName = BookCheck::ExtractFileName(book->inventoryModel->GetModel(), modelFileNameLength); |
||||
|
||||
if (modelFileNameLength == 0) { |
||||
return false; |
||||
} |
||||
|
||||
if (IsNote(modelFileName, modelFileNameLength) || IsJournal(modelFileName, modelFileNameLength)) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
#pragma once |
||||
|
||||
// Mostly borrowed from Fix Note icon for SkyUI by 0xC0000005
|
||||
namespace BookCheck |
||||
{ |
||||
void PreloadBookList(); |
||||
|
||||
std::vector<RE::TESObjectBOOK*> GetBookList(); |
||||
|
||||
const char* ExtractFileName(const char* const path, size_t& fileNameLength); |
||||
|
||||
// Performs a case-sensitive search for 'needle' in the specified string,
|
||||
// excluding any matches that are part of a larger word.
|
||||
bool ContainsWholeWord(const char* const haystack, const size_t haystackLength, const char* const needle, const size_t needleLength); |
||||
|
||||
bool StartsWith(const char* haystack, size_t haystackLength, const char* needle, size_t needleLength); |
||||
|
||||
bool IsNote(const char* const modelFileName, size_t modelFileNameLength); |
||||
|
||||
bool IsJournal(const char* const modelFileName, size_t modelFileNameLength); |
||||
|
||||
bool IsBook(RE::TESObjectBOOK* book); |
||||
} |
Loading…
Reference in new issue