Skip to content

Commit

Permalink
feat: Rewrote ammo switching, mostly fixed decals.
Browse files Browse the repository at this point in the history
  • Loading branch information
FlenarnTemp committed Jan 29, 2025
1 parent 0c02939 commit 2c7fbf7
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 317 deletions.
165 changes: 14 additions & 151 deletions Plugin/src/Events/BSAnimationGraphEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,168 +23,31 @@ namespace RE
if (a_event.tag == ReloadComplete && AmmoSwitch::switchingAmmo == true)
{
DEBUG("'BSEventNotifyControl::ProcessEvent' - 'ReloadComplete'.");
BGSObjectInstance* equippedInstance = new BGSObjectInstance(nullptr, nullptr);
PlayerCharacter* playerCharacter = PlayerCharacter::GetSingleton();

playerCharacter->GetEquippedItem(equippedInstance, BGSEquipIndex{ 0 });
BGSObjectInstanceT<TESObjectWEAP>* weaponInstance = new BGSObjectInstanceT<TESObjectWEAP>{ static_cast<TESObjectWEAP*>(AmmoSwitch::equippedInstance->object), AmmoSwitch::equippedInstance->instanceData.get() };
TESObjectWEAP::InstanceData* instanceDataWEAP = (TESObjectWEAP::InstanceData*)(weaponInstance->instanceData.get());

if (equippedInstance->object && equippedInstance->object->formType == ENUM_FORM_ID::kWEAP && static_cast<TESObjectWEAP*>(equippedInstance->object)->weaponData.type == WEAPON_TYPE::kGun)
if (AmmoSwitch::ammoToSwitchTo)
{
BGSObjectInstanceT<TESObjectWEAP>* weaponInstance = new BGSObjectInstanceT<TESObjectWEAP>{ static_cast<TESObjectWEAP*>(equippedInstance->object), equippedInstance->instanceData.get() };
TESObjectWEAP::InstanceData* instanceDataWEAP = (TESObjectWEAP::InstanceData*)(weaponInstance->instanceData.get());
TESObjectWEAP* weapon = static_cast<TESObjectWEAP*>(equippedInstance->object);
const char* standardListPrefix = "CAS_AmmoSwitch_Standard_";
const char* uniqueListPrefix = "CAS_AmmoSwitch_Unique_";

TESAmmo* currentAmmo = instanceDataWEAP->ammo;

if (weapon->HasKeyword(AmmoSwitch::uniqueFormlistWEAP))
{
std::uint32_t keywordCount = weapon->GetNumKeywords();
if (keywordCount > 0)
{
bool weaponFoundKeyword = false;
for (std::uint32_t i = 0; i < keywordCount; ++i)
{
std::optional<BGSKeyword*> bgsKeyword = weapon->GetKeywordAt(i);
if (bgsKeyword.has_value())
{
const char* formEditorID = bgsKeyword.value()->GetFormEditorID();
if (strncmp(formEditorID, uniqueListPrefix, strlen(uniqueListPrefix)) == 0)
{
weaponFoundKeyword = true;
auto mapEntry = AmmoSwitch::keywordFormlistMap.find(bgsKeyword.value());
if (mapEntry != AmmoSwitch::keywordFormlistMap.end())
{
BGSListForm* formList = mapEntry->second;
std::uint32_t formListSize = formList->arrayOfForms.size();
std::uint32_t index = 0;
for (index; index < formListSize; ++index)
{
if (formList->arrayOfForms.begin()[index] == (TESForm*)currentAmmo)
{
break;
}
}

if (formListSize != 0)
{
bool hasAmmoInFormlist = false;
std::uint32_t firstFoundIndex = -1;
for (std::uint32_t i = 1; i < formListSize; i++)
{
std::uint32_t currentIndex = (index + i) % formListSize;
TESBoundObject* a_object = (TESBoundObject*)formList->arrayOfForms[currentIndex];
if (playerCharacter->GetInventoryObjectCount(a_object) != 0)
{
firstFoundIndex = currentIndex;
hasAmmoInFormlist = true;
}
}

if (hasAmmoInFormlist)
{
TESAmmo* ammoToSwitchTo = (TESAmmo*)formList->arrayOfForms[firstFoundIndex];

instanceDataWEAP->ammo = ammoToSwitchTo;

playerCharacter->currentProcess->SetCurrentAmmo(BGSEquipIndex{ 0 }, ammoToSwitchTo);
playerCharacter->SetCurrentAmmoCount(BGSEquipIndex{ 0 }, 0);
(Actor*)playerCharacter->ReloadWeapon(weaponInstance, BGSEquipIndex{ 0 });
PipboyDataManager::GetSingleton()->inventoryData.RepopulateItemCardsOnSection(ENUM_FORM_ID::kWEAP);
}
else
{
FATAL("'BSEventNotifyControl::ProcessEvent' - !hasAmmoInFormList");
AmmoSwitch::switchingAmmo = false;
FnProcessEvent fn = fnHash.at(*(uint64_t*)this);
return fn ? (this->*fn)(a_event, a_source) : BSEventNotifyControl::kContinue;
}
}
}
}
}
}
}
}
else
{
std::uint32_t keywordCount = currentAmmo->GetNumKeywords();
if (keywordCount > 0)
{
for (std::uint32_t i = 0; i < keywordCount; ++i)
{
std::optional<BGSKeyword*> bgsKeyword = currentAmmo->GetKeywordAt(i);
if (bgsKeyword.has_value())
{
const char* formEditorID = bgsKeyword.value()->GetFormEditorID();
if (strncmp(formEditorID, standardListPrefix, strlen(standardListPrefix)) == 0)
{
auto mapEntry = AmmoSwitch::keywordFormlistMap.find(bgsKeyword.value());
if (mapEntry != AmmoSwitch::keywordFormlistMap.end())
{
BGSListForm* formList = mapEntry->second;
std::uint32_t formListSize = formList->arrayOfForms.size();
std::uint32_t index = 0;
for (index = 0; index < formListSize; ++index)
{
if (formList->arrayOfForms.begin()[index] == (TESForm*)currentAmmo)
{
break;
}
}

if (formListSize != 0)
{
bool hasAmmoInFormlist = false;
std::uint32_t firstFoundIndex = -1;
for (std::uint32_t i = 1; i < formListSize; i++)
{
std::uint32_t currentIndex = (index + i) % formListSize;
TESBoundObject* a_object = (TESBoundObject*)formList->arrayOfForms[currentIndex];
if (playerCharacter->GetInventoryObjectCount(a_object) != 0)
{
firstFoundIndex = currentIndex;
hasAmmoInFormlist = true;
}
}

if (hasAmmoInFormlist)
{
TESAmmo* ammoToSwitchTo = (TESAmmo*)formList->arrayOfForms[firstFoundIndex];

instanceDataWEAP->ammo = ammoToSwitchTo;

playerCharacter->currentProcess->SetCurrentAmmo(BGSEquipIndex{ 0 }, ammoToSwitchTo);
playerCharacter->SetCurrentAmmoCount(BGSEquipIndex{ 0 }, 0);
(Actor*)playerCharacter->ReloadWeapon(weaponInstance, BGSEquipIndex{ 0 });
PipboyDataManager::GetSingleton()->inventoryData.RepopulateItemCardsOnSection(ENUM_FORM_ID::kWEAP);
}
else
{
FATAL("'BSEventNotifyControl::ProcessEvent' - !hasAmmoInFormList");
AmmoSwitch::switchingAmmo = false;
FnProcessEvent fn = fnHash.at(*(uint64_t*)this);
return fn ? (this->*fn)(a_event, a_source) : BSEventNotifyControl::kContinue;
}
}
}
}
}
}

}
}
instanceDataWEAP->ammo = AmmoSwitch::ammoToSwitchTo;
PlayerCharacter* playerCharacter = PlayerCharacter::GetSingleton();
playerCharacter->currentProcess->SetCurrentAmmo(BGSEquipIndex{ 0 }, AmmoSwitch::ammoToSwitchTo);
playerCharacter->SetCurrentAmmoCount(BGSEquipIndex{ 0 }, 0);
(Actor*)playerCharacter->ReloadWeapon(weaponInstance, BGSEquipIndex{ 0 });
PipboyDataManager::GetSingleton()->inventoryData.RepopulateItemCardsOnSection(ENUM_FORM_ID::kWEAP);
}

AmmoSwitch::switchingAmmo = false;
FnProcessEvent fn = fnHash.at(*(uint64_t*)this);
return fn ? (this->*fn)(a_event, a_source) : BSEventNotifyControl::kContinue;
AmmoSwitch::ammoToSwitchTo = nullptr;
AmmoSwitch::equippedInstance = nullptr;
}

if (a_event.tag == reloadStateExit && AmmoSwitch::switchingAmmo == true)
{
DEBUG("'BSEventNotifyControl::ProcessEvent' - 'reloadStateExit'.");
AmmoSwitch::switchingAmmo = false;
AmmoSwitch::ammoToSwitchTo = nullptr;
AmmoSwitch::equippedInstance = nullptr;
}

FnProcessEvent fn = fnHash.at(*(uint64_t*)this);
Expand Down
35 changes: 35 additions & 0 deletions Plugin/src/Events/TESCellFullyLoadedEvent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

namespace RE
{
namespace Cascadia
{
class CellFullyLoadedListener : public BSTEventSink<TESCellFullyLoadedEvent>
{
public:
static CellFullyLoadedListener* GetSingleton()
{
static CellFullyLoadedListener instance;
return &instance;
}

virtual BSEventNotifyControl ProcessEvent(const TESCellFullyLoadedEvent& a_event, BSTEventSource<TESCellFullyLoadedEvent>*) override
{
DEBUG("EVENT FIRED");

if (a_event.cell)
{
a_event.cell->UpdateAllDecals();
}

return BSEventNotifyControl::kContinue;
}
};

void RegisterForCellFullyLoaded(BSTEventSink<TESCellFullyLoadedEvent>* a_sink) {
using func_t = decltype(&RegisterForCellFullyLoaded);
REL::Relocation<func_t> func{ REL::ID(2201571) };
return func(a_sink);
}
}
}
13 changes: 12 additions & 1 deletion Plugin/src/Shared/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@ namespace RE
// TODO - list available components.
}

for (std::uint32_t i = 0; i < size; ++i)
{
auto test = requiredItems->at(i);

TESForm* temp1 = test.first;
BGSTypedFormValuePair::SharedVal temp2 = test.second;
DEBUG("temp1 edid: {}", temp1->GetFormEditorID());
DEBUG("temp2 'i' value: {}", temp2.i);

}

examineMenu->ShowConfirmMenu(initDataRepair, repairFailureCallback);
}

Expand Down Expand Up @@ -521,7 +532,7 @@ namespace RE

TESObjectWEAPFireOriginal(a_weapon, a_source, a_equipIndex, a_ammo, a_poison);

BGSInventoryItem* inventoryItem = nullptr;
BGSInventoryItem* inventoryItem = nullptr;;
TESFormID weaponFormID = a_weapon->object->GetFormID();
for (BGSInventoryItem& item : playerCharacter->inventoryList->data)
{
Expand Down
Loading

0 comments on commit 2c7fbf7

Please sign in to comment.