Skip to content

Commit

Permalink
Fixes issue with assigning hotkey to equipped items
Browse files Browse the repository at this point in the history
  • Loading branch information
DudeMcDude committed Apr 17, 2016
1 parent 047371a commit a80ec02
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 19 deletions.
96 changes: 88 additions & 8 deletions TemplePlus/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ class GenericCallbacks

} genericCallbacks;


class ItemCallbacks
{
public:
static int __cdecl SkillBonus(DispatcherCallbackArgs args);

static int __cdecl UseableItemRadialEntry(DispatcherCallbackArgs args);
} itemCallbacks;


class ConditionFunctionReplacement : public TempleFix {
public:
const char* name() override {
Expand Down Expand Up @@ -205,18 +215,14 @@ class ConditionFunctionReplacement : public TempleFix {

// power attack damage bonus
replaceFunction<int(DispatcherCallbackArgs)>(0x100F8540, genericCallbacks.PowerAttackDamageBonus);

replaceFunction<int(DispatcherCallbackArgs)>(0x10100840, itemCallbacks.UseableItemRadialEntry);

}
} condFuncReplacement;



class ItemCallbacks
{
public:
static int __cdecl SkillBonus(DispatcherCallbackArgs args);
} itemCallbacks;

class ClassAbilityCallbacks
{
#define FeatFunc(fname) static int __cdecl Feat ## fname ## (DispatcherCallbackArgs args)
Expand Down Expand Up @@ -1995,7 +2001,7 @@ int* ConditionSystem::CondNodeGetArgPtr(CondNode* condNode, int argIdx)
radEntry.minArg = 0;
radEntry.type = RadialMenuEntryType::Toggle;
radEntry.actualArg = (int)conds.CondNodeGetArgPtr(args.subDispNode->condNode, 0);
radEntry.callback = (void (__cdecl*)(objHndl, RadialMenuEntry*))temple::GetPointer(0x100F0200);
radEntry.callback = (BOOL (__cdecl*)(objHndl, RadialMenuEntry*))temple::GetPointer(0x100F0200);
MesLine mesLine;
mesLine.key = 5105; //disable AoOs
if (!mesFuncs.GetLine(*combatSys.combatMesfileIdx, &mesLine) )
Expand Down Expand Up @@ -2154,7 +2160,7 @@ int __cdecl RecklessOffenseRadialMenuInit(DispatcherCallbackArgs args)
radEntry.minArg = 0;
radEntry.type = RadialMenuEntryType::Toggle;
radEntry.actualArg = (int)conds.CondNodeGetArgPtr(args.subDispNode->condNode, 0);
radEntry.callback = (void(__cdecl*)(objHndl, RadialMenuEntry*))temple::GetPointer(0x100F0200);
radEntry.callback = (BOOL(__cdecl*)(objHndl, RadialMenuEntry*))temple::GetPointer(0x100F0200);
MesLine mesLine;
mesLine.key = 5107; // reckless offense
if (!mesFuncs.GetLine(*combatSys.combatMesfileIdx, &mesLine))
Expand Down Expand Up @@ -2994,6 +3000,80 @@ int ItemCallbacks::SkillBonus(DispatcherCallbackArgs args)
return 0;
}

int ItemCallbacks::UseableItemRadialEntry(DispatcherCallbackArgs args)
{
auto invIdx = args.GetCondArg(2);
auto itemHandle = inventory.GetItemAtInvIdx(args.objHndCaller, invIdx);
auto itemObj = gameSystems->GetObj().GetObject(itemHandle);
auto objType = itemObj->type;
int useMagicDeviceSkillBase = critterSys.SkillBaseGet(args.objHndCaller, skill_use_magic_device);

if (objType != obj_t_food && !inventory.IsIdentified(itemHandle))
return 0;

auto charges = itemObj->GetInt32(obj_f_item_spell_charges_idx);
if (charges == 0)
return 0;

auto itemFlags = itemObj->GetItemFlags();

auto spIdx = args.GetCondArg(0);

auto spData = itemObj->GetSpell(obj_f_item_spell_idx, spIdx);

if ( (objType == obj_t_scroll || (itemFlags & OIF_NEEDS_SPELL) && (itemObj->type == obj_t_generic || itemObj->type == obj_t_weapon) )
&& !useMagicDeviceSkillBase && !critterSys.HashMatchingClassForSpell(args.objHndCaller, spData.spellEnum))
return 0;

if (objType == obj_t_scroll && !spellSys.CheckAbilityScoreReqForSpell(args.objHndCaller, spData.spellEnum, -1) && !useMagicDeviceSkillBase)
return 0;

RadialMenuEntry radEntry;
if (objType == obj_t_food){
if (inventory.IsMagicItem(itemHandle))
radEntry.d20ActionType = D20A_USE_POTION;
else
radEntry.d20ActionType = D20A_USE_ITEM;
}
else{
radEntry.d20ActionType = D20A_USE_ITEM;
}

radEntry.d20ActionData1 = invIdx;
radEntry.d20SpellData.Set(spData.spellEnum, spData.classCode, spData.spellLevel, invIdx, (MetaMagicData)0);
radEntry.text = const_cast<char*>(description.getDisplayName(itemHandle, args.objHndCaller));

RadialMenuStandardNode parentType;
switch(objType)
{
case obj_t_scroll:
parentType = RadialMenuStandardNode ::Scrolls;
break;
case obj_t_food:
parentType = RadialMenuStandardNode::Potions;
break;
default:
parentType = args.GetCondArg(1) != 3 ? RadialMenuStandardNode::Items : RadialMenuStandardNode::Wands;
break;
}

radEntry.helpId = ElfHash::Hash(spellSys.GetSpellEnumTAG(spData.spellEnum));

radEntry.AddChildToStandard(args.objHndCaller, parentType);

// add to Copy Scroll
if (objType == obj_t_scroll && objects.StatLevelGet(args.objHndCaller, stat_level_wizard) >= 1
&& critterSys.HashMatchingClassForSpell(args.objHndCaller, spData.spellEnum)
&& spellSys.IsArcaneSpellClass(spData.classCode)
&& !spellSys.spellKnownQueryGetData(args.objHndCaller, spData.spellEnum, nullptr, nullptr, nullptr))
{
radEntry.d20ActionType = D20A_COPY_SCROLL;
radEntry.d20ActionData1 = inventory.GetInventoryLocation(itemHandle);
radEntry.AddChildToStandard(args.objHndCaller, RadialMenuStandardNode::CopyScroll);
}

return 0;
}
#pragma endregion


Expand Down
12 changes: 12 additions & 0 deletions TemplePlus/critter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,18 @@ int LegacyCritterSystem::PlayCritterVoiceLine(objHndl obj, objHndl fellow, char*
return addresses.PlayCritterVoiceLine(obj, fellow, text, soundId);
}

bool LegacyCritterSystem::HashMatchingClassForSpell(objHndl handle, uint32_t spellEnum) const
{
return temple::GetRef<BOOL(__cdecl)(objHndl, uint32_t)>(0x10075DA0)(handle, spellEnum);
}

int LegacyCritterSystem::SkillBaseGet(objHndl handle, SkillEnum skill)
{
if (!handle)
return 0;
return gameSystems->GetObj().GetObject(handle)->GetInt32Array(obj_f_critter_skill_idx)[ skill] / 2;
}

int LegacyCritterSystem::SpellNumByFieldAndClass(objHndl obj, obj_f field, uint32_t spellClassCode)
{
auto objBody = gameSystems->GetObj().GetObject(obj);
Expand Down
4 changes: 4 additions & 0 deletions TemplePlus/critter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <memory>
#include <temple/dll.h>

enum SkillEnum:uint32_t;

namespace gfx {
enum class WeaponAnim;
class EncodedAnimId;
Expand Down Expand Up @@ -310,6 +312,8 @@ struct LegacyCritterSystem : temple::AddressTable
bool IsWieldingRangedWeapon(objHndl performer);
void GetCritterVoiceLine(objHndl obj, objHndl fellow, char *str, int* soundId);
int PlayCritterVoiceLine(objHndl obj, objHndl fellow, char* text, int soundId);
bool HashMatchingClassForSpell(objHndl handle, uint32_t spellEnum) const; // checks if obj has a matching spell in their list
static int SkillBaseGet(objHndl handle, SkillEnum skill);
static int SpellNumByFieldAndClass(objHndl obj, obj_f field, uint32_t spellClassCode);
int DomainSpellNumByField(objHndl obj, obj_f field);
static int GetNumFollowers(objHndl obj, int excludeForcedFollowers);
Expand Down
101 changes: 97 additions & 4 deletions TemplePlus/hotkeys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "tio\tio.h"
#include "gamesystems/legacy.h"
#include "util/fixes.h"
#include "obj.h"
#include "critter.h"
#include "action_sequence.h"

HotkeySystem hotkeys;

Expand Down Expand Up @@ -50,16 +53,102 @@ class HotkeyReplacements : TempleFix
{
public:
const char* name() override { return "Hotkey Function Replacements";}

static BOOL HotkeyCompare(RadialMenuEntry& first, RadialMenuEntry & second);
static BOOL HotkeyActivate(objHndl obj);
void apply() override
{
replaceFunction(0x100F3B80, HotkeyInit);
replaceFunction(0x100F3BC0, HotkeyExit);
replaceFunction(0x100F3BD0, SaveHotkeys);
replaceFunction(0x100F3C80, LoadHotkeys);
replaceFunction(0x100F4030, HotkeyAssignCallback);
replaceFunction(0x100F0380, HotkeyCompare);
replaceFunction(0x100F0B80, HotkeyActivate);
}
} hotkeyReplacements;

BOOL HotkeyReplacements::HotkeyCompare(RadialMenuEntry& first, RadialMenuEntry& second)
{
auto actionType = first.d20ActionType;

if (actionType != second.d20ActionType) {
return FALSE;
}

if (actionType == D20A_ACTIVATE_DEVICE_FREE
|| actionType == D20A_ACTIVATE_DEVICE_STANDARD
|| actionType == D20A_ACTIVATE_DEVICE_SPELL)
return first.textHash == second.textHash;

if (first.d20ActionData1 != second.d20ActionData1)
return FALSE;

if (first.d20SpellData.spellEnumOrg != second.d20SpellData.spellEnumOrg)
return FALSE;

if (first.d20SpellData.metaMagicData != second.d20SpellData.metaMagicData)
return FALSE;

if (first.d20ActionType == D20A_NONE &&first.textHash != second.textHash)
return FALSE;

return TRUE;
}

BOOL HotkeyReplacements::HotkeyActivate(objHndl obj)
{
auto radMenuForHK = temple::GetRef<RadialMenu*>(0x115B2050);

if (!radMenuForHK)
return FALSE;

auto radMenuNodeCount = temple::GetRef<int>(0x118676C0);
if (radMenuNodeCount > radMenuForHK->nodeCount)
return FALSE;

auto& activeRadialMenu = temple::GetRef<const RadialMenu*>(0x115B2048);
activeRadialMenu = radialMenus.GetForObj(obj);

auto& radEntry = radMenuForHK->nodes[radMenuNodeCount -1].entry;

auto& activeRadialMenuNode = temple::GetRef<int>(0x115B204C);
activeRadialMenuNode = radMenuNodeCount - 1;

if (radEntry.d20ActionType == D20A_CAST_SPELL)
actSeqSys.ActSeqSpellReset();
else if (radEntry.d20ActionType == D20A_USE_ITEM && radEntry.d20SpellData.spellEnumOrg != 0){
actSeqSys.ActSeqSpellReset();
}

auto nodeType = radEntry.type;
auto result = FALSE;
if (nodeType == RadialMenuEntryType::Action)
{
if (radEntry.callback){
result = radEntry.callback(obj, &radEntry);
}
}
else if (nodeType == RadialMenuEntryType::Slider)// will toggle between min/max values
{
temple::GetRef<void(__cdecl)(objHndl, RadialMenuEntry&)>(0x100F05C0)(obj, radEntry); // toggle value to min/max
temple::GetRef<void(__cdecl)(objHndl, RadialMenuEntry&)>(0x100F05F0)(obj, radEntry); // activate / deactivate float line
result = FALSE;
}
else if (nodeType == RadialMenuEntryType::Toggle)
{
if (radEntry.callback) {
result = radEntry.callback(obj, &radEntry);
}
temple::GetRef<void(__cdecl)(objHndl, RadialMenuEntry&)>(0x100F05F0)(obj, radEntry); // activate / deactivate float line
}


activeRadialMenu = nullptr;
activeRadialMenuNode = -1;
return result;

}

int HotkeySystem::SaveHotkeys(TioFile* file)
{
Expand Down Expand Up @@ -143,12 +232,16 @@ void HotkeySystem::HotkeyAssignCallback(int cancelFlag)
{
if (!cancelFlag)
{
auto hotkeyTable = addresses.hotkeyTable;
auto hkIdx = *addresses.keyIdxToBind;

int radMenuIdx = addresses.HotkeyTableSearch(*addresses.radMenuEntryToBind);
if (radMenuIdx != -1)
addresses.hotkeyTable[radMenuIdx].d20ActionType = D20A_UNASSIGNED;
memcpy(&addresses.hotkeyTable[*addresses.keyIdxToBind], *addresses.radMenuEntryToBind, sizeof(RadialMenuEntry));
strncpy(&addresses.hotkeyTexts[128 * (*addresses.keyIdxToBind)], (*addresses.radMenuEntryToBind)->text, 127);
addresses.hotkeyTable[*addresses.keyIdxToBind].text = &addresses.hotkeyTexts[128 * (*addresses.keyIdxToBind)];
hotkeyTable[radMenuIdx].d20ActionType = D20A_UNASSIGNED;

hotkeyTable[hkIdx] = **addresses.radMenuEntryToBind;
strncpy(&addresses.hotkeyTexts[128 * hkIdx], (*addresses.radMenuEntryToBind)->text, 127);
hotkeyTable[hkIdx].text = &addresses.hotkeyTexts[128 * hkIdx];

auto file = fopen("hotkeys.sco", "wb");
SaveHotkeys(file);
Expand Down
20 changes: 20 additions & 0 deletions TemplePlus/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,26 @@ const char* InventorySystem::GetItemErrorString(ItemErrorCode itemErrorCode)
return line.value;
}

bool InventorySystem::IsMagicItem(objHndl itemHandle)
{
return gameSystems->GetObj().GetObject(itemHandle)->GetItemFlags() & OIF_IS_MAGICAL;
}

bool InventorySystem::IsIdentified(objHndl itemHandle)
{
if (!itemHandle)
return false;
auto obj = gameSystems->GetObj().GetObject(itemHandle);

if (!obj->IsItem())
return false;

if (obj->GetItemFlags() & ItemFlag::OIF_IS_MAGICAL)
return (obj->GetItemFlags() & ItemFlag::OIF_IDENTIFIED);

return true;
}

bool InventorySystem::IsBuckler(objHndl shield)
{
if (!shield)
Expand Down
2 changes: 2 additions & 0 deletions TemplePlus/inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ struct InventorySystem : temple::AddressTable
bool IsProficientWithArmor(objHndl obj, objHndl armor) const;
void GetItemMesLine(MesLine* line);
const char* GetItemErrorString(ItemErrorCode itemErrorCode);
static bool IsMagicItem(objHndl itemHandle);
static bool IsIdentified(objHndl itemHandle);
static bool IsBuckler(objHndl shield);
void(__cdecl*_ForceRemove)(objHndl, objHndl);
void ItemRemove(objHndl item); // pretty much same as ForceRemove, but also send a d20 signal for inventory update, and checks for parent first
Expand Down
10 changes: 5 additions & 5 deletions TemplePlus/radialmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static struct RadialMenuAddresses : temple::AddressTable {
int(__cdecl *SetSpontaneousCastingAltNode)(objHndl handle, int parentIdx, SpellStoreData * spellData);
int(__cdecl *AddSpell)(objHndl handle, SpellStoreData * spellData, int * idxOut, const RadialMenuEntry & entry); //adds a spell to the Radial Menu
int(__cdecl * RadialMenuCheckboxSthgSub_100F0200)(objHndl objHnd, RadialMenuEntry* radialMenuEntry);
void(__cdecl * CopyEntryToSelected)(objHndl obj, RadialMenuEntry* entry);
BOOL(__cdecl * CopyEntryToSelected)(objHndl obj, RadialMenuEntry* entry);
RadialMenu ** activeRadialMenu;
int * activeRadialMenuNode;

Expand Down Expand Up @@ -235,7 +235,7 @@ int RadialMenus::AddParentChildNode(objHndl objHnd, RadialMenuEntry* radialMenuE
node->entry.d20ActionType = D20A_NONE;
node->parent = parentIdx;
node->childCount = 0;
node->entry.callback = (void ( __cdecl*)(objHndl, RadialMenuEntry*) )return0;
node->entry.callback = (int ( __cdecl*)(objHndl, RadialMenuEntry*) )return0;
node->entry.type = RadialMenuEntryType::Parent;
node->morphsTo = -1;
node->entry.textHash = conds.hashmethods.StringHash(radialMenuEntry->text);
Expand Down Expand Up @@ -294,7 +294,7 @@ int RadialMenus::AddRootParentNode(objHndl obj, RadialMenuEntry* entry){

node->entry.d20ActionType = D20A_NONE;
node->childCount = 0;
node->entry.callback = (void(__cdecl*)(objHndl, RadialMenuEntry*))return0;
node->entry.callback = (int(__cdecl*)(objHndl, RadialMenuEntry*))return0;
node->entry.type = RadialMenuEntryType::Parent;
node->morphsTo = -1;
node->entry.textHash = ElfHash::Hash(entry->text);
Expand Down Expand Up @@ -463,7 +463,7 @@ RadialMenuEntrySlider::RadialMenuEntrySlider(int combatMesLine, int _minArg, int
if (combatMesHeaderText != -1)
field4 = reinterpret_cast<int>(combatSys.GetCombatMesLine(combatMesHeaderText)); // the popup title
helpId = _helpId;
callback = (void(__cdecl*)(objHndl, RadialMenuEntry*))temple::GetPointer(0x100F0200);
callback = (BOOL(__cdecl*)(objHndl, RadialMenuEntry*))temple::GetPointer(0x100F0200);
}

RadialMenuEntryAction::RadialMenuEntryAction(int combatMesLine, D20ActionType d20aType, int data1, uint32_t HelpId) : RadialMenuEntry() {
Expand All @@ -484,7 +484,7 @@ RadialMenuEntryToggle::RadialMenuEntryToggle(int combatMesLine, void* ActualArg,
type = RadialMenuEntryType::Toggle;
text = combatSys.GetCombatMesLine(combatMesLine);
helpId = ElfHash::Hash(HelpId);
callback = temple::GetRef<void(__cdecl)(objHndl, RadialMenuEntry*)>(0x100F0200);
callback = temple::GetRef<BOOL(__cdecl)(objHndl, RadialMenuEntry*)>(0x100F0200);
minArg = 0;
maxArg = 1;
actualArg = reinterpret_cast<int>(ActualArg);
Expand Down
2 changes: 1 addition & 1 deletion TemplePlus/radialmenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct RadialMenuEntry {
//int spellEnumOrg;
//uint32_t spellMetaMagic;
int dispKey;
void (__cdecl *callback)(objHndl a1, RadialMenuEntry *entry);
BOOL (__cdecl *callback)(objHndl a1, RadialMenuEntry *entry);
int flags;
int helpId; // String hash for the help topic associated with this entry
int field44;
Expand Down
Loading

0 comments on commit a80ec02

Please sign in to comment.