mirror of
https://github.com/brues-code/nampower.git
synced 2026-10-05 21:20:01 +00:00
add more item/spell dbc functions, improve flexibility of spell lua functions
This commit is contained in:
@@ -98,6 +98,25 @@ SET NP_TargetingQueueWindowMs "1000"
|
||||
|
||||
- `NP_NameplateDistance` - The distance in yards to display nameplates. Defaults to whatever was set by the game or vanilla tweaks.
|
||||
|
||||
### Existing Lua Changes
|
||||
|
||||
#### Improved flexibility on spellbook Lua functions
|
||||
These built-in Lua spell APIs now accept any of the following as their first argument: 1) spell slot (original behavior), 2) spell name, or 3) `spellId:number`.
|
||||
|
||||
Name and spellId lookups are cached internally and validated against current spellbook contents before reuse so you don't have to worry about performance implications or issues after respec'ing.
|
||||
|
||||
See examples below for differences in how BOOKTYPE works.
|
||||
|
||||
Functions: `GetSpellTexture`, `GetSpellName`, `GetSpellCooldown`, `GetSpellAutocast`, `ToggleSpellAutocast`, `PickupSpell`, `CastSpell`, `IsCurrentCast`, `IsSpellPassive`.
|
||||
|
||||
Examples:
|
||||
```
|
||||
/run print(GetSpellTexture(1, "spell")) -- booktype required
|
||||
/run print(GetSpellTexture("spellId:25978")) -- defaults to BOOKTYPE_SPELL
|
||||
/run print(GetSpellTexture("spellId:6268", "pet")) -- "pet" needed for pet spells
|
||||
/run print(GetSpellTexture("Fireball")) -- name search
|
||||
```
|
||||
|
||||
### Custom Lua Functions
|
||||
|
||||
#### QueueSpellByName(spellName)
|
||||
@@ -209,6 +228,20 @@ Examples:
|
||||
/run local slot, bookType, spellId=GetSpellSlotTypeIdForName("Frostbolt");print(slot);print(bookType);print(spellId)
|
||||
```
|
||||
|
||||
#### GetItemStats(itemId)
|
||||
Returns a Lua table containing all fields for the item’s `ItemStats_C` record (including localized `displayName` and `description`). Returns 0 if the item cannot be found or loaded.
|
||||
|
||||
#### GetItemStatsField(itemId, fieldName)
|
||||
Fast lookup for a single field on an item. Returns the requested field value or raises a Lua error if the item or field is not found.
|
||||
|
||||
#### GetSpellRec(spellId)
|
||||
Returns a Lua table containing all fields for the spell’s `SpellRec` record (including localized `name` and `rank`). Returns 0 if the spell cannot be found.
|
||||
|
||||
#### GetSpellRecField(spellId, fieldName)
|
||||
Fast lookup for a single field on a spell. Returns the requested field value or raises a Lua error if the spell or field is not found.
|
||||
|
||||
Struct references (see `nampower/game.hpp` for full details):
|
||||
|
||||
#### GetNampowerVersion()
|
||||
Returns the current version of Nampower split into major, minor and patch numbers.
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ set(SOURCE_FILES
|
||||
spellevents.cpp
|
||||
scripts.hpp
|
||||
scripts.cpp
|
||||
items.hpp
|
||||
items.cpp
|
||||
dbc_fields.hpp
|
||||
dbc_fields.cpp
|
||||
)
|
||||
|
||||
add_library(${DLL_NAME} SHARED ${SOURCE_FILES})
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Created by pmacc on 1/8/2025.
|
||||
//
|
||||
|
||||
#include "dbc_fields.hpp"
|
||||
#include "offsets.hpp"
|
||||
|
||||
namespace Nampower {
|
||||
// Hash tables for O(1) field lookups
|
||||
std::unordered_map<std::string, size_t> itemStatsFieldMap;
|
||||
std::unordered_map<std::string, size_t> itemStatsArrayFieldMap;
|
||||
std::unordered_map<std::string, size_t> spellRecFieldMap;
|
||||
std::unordered_map<std::string, size_t> spellRecArrayFieldMap;
|
||||
static bool fieldMapsInitialized = false;
|
||||
|
||||
// ItemStats_C field descriptors
|
||||
const FieldDescriptor itemStatsFields[] = {
|
||||
{"class", offsetof(game::ItemStats_C, m_class), FieldType::INT32},
|
||||
{"subclass", offsetof(game::ItemStats_C, m_subclass), FieldType::INT32},
|
||||
{"displayInfoID", offsetof(game::ItemStats_C, m_displayInfoID), FieldType::INT32},
|
||||
{"quality", offsetof(game::ItemStats_C, m_quality), FieldType::INT32},
|
||||
{"flags", offsetof(game::ItemStats_C, m_flags), FieldType::INT32},
|
||||
{"buyPrice", offsetof(game::ItemStats_C, m_buyPrice), FieldType::INT32},
|
||||
{"sellPrice", offsetof(game::ItemStats_C, m_sellPrice), FieldType::INT32},
|
||||
{"inventoryType", offsetof(game::ItemStats_C, m_inventoryType), FieldType::INT32},
|
||||
{"allowableClass", offsetof(game::ItemStats_C, m_allowableClass), FieldType::INT32},
|
||||
{"allowableRace", offsetof(game::ItemStats_C, m_allowableRace), FieldType::INT32},
|
||||
{"itemLevel", offsetof(game::ItemStats_C, m_itemLevel), FieldType::INT32},
|
||||
{"requiredLevel", offsetof(game::ItemStats_C, m_requiredLevel), FieldType::INT32},
|
||||
{"requiredSkill", offsetof(game::ItemStats_C, m_requiredSkill), FieldType::INT32},
|
||||
{"requiredSkillRank", offsetof(game::ItemStats_C, m_requiredSkillRank), FieldType::INT32},
|
||||
{"requiredSpell", offsetof(game::ItemStats_C, m_requiredSpell), FieldType::INT32},
|
||||
{"requiredHonorRank", offsetof(game::ItemStats_C, m_requiredHonorRank), FieldType::INT32},
|
||||
{"requiredCityRank", offsetof(game::ItemStats_C, m_requiredCityRank), FieldType::INT32},
|
||||
{"requiredRep", offsetof(game::ItemStats_C, m_requiredRep), FieldType::INT32},
|
||||
{"requiredRepRank", offsetof(game::ItemStats_C, m_requiredRepRank), FieldType::INT32},
|
||||
{"maxCount", offsetof(game::ItemStats_C, m_maxCount), FieldType::INT32},
|
||||
{"stackable", offsetof(game::ItemStats_C, m_stackable), FieldType::INT32},
|
||||
{"containerSlots", offsetof(game::ItemStats_C, m_containerSlots), FieldType::INT32},
|
||||
{"delay", offsetof(game::ItemStats_C, m_delay), FieldType::INT32},
|
||||
{"ammoType", offsetof(game::ItemStats_C, m_ammoType), FieldType::INT32},
|
||||
{"rangedModRange", offsetof(game::ItemStats_C, m_rangedModRange), FieldType::INT32},
|
||||
{"bonding", offsetof(game::ItemStats_C, m_bonding), FieldType::INT32},
|
||||
{"pageText", offsetof(game::ItemStats_C, m_pageText), FieldType::INT32},
|
||||
{"languageID", offsetof(game::ItemStats_C, m_languageID), FieldType::INT32},
|
||||
{"pageMaterial", offsetof(game::ItemStats_C, m_pageMaterial), FieldType::INT32},
|
||||
{"startQuestID", offsetof(game::ItemStats_C, m_startQuestID), FieldType::INT32},
|
||||
{"lockID", offsetof(game::ItemStats_C, m_lockID), FieldType::INT32},
|
||||
{"material", offsetof(game::ItemStats_C, m_material), FieldType::INT32},
|
||||
{"sheatheType", offsetof(game::ItemStats_C, m_sheatheType), FieldType::INT32},
|
||||
{"randomProperty", offsetof(game::ItemStats_C, m_randomProperty), FieldType::INT32},
|
||||
{"block", offsetof(game::ItemStats_C, m_block), FieldType::INT32},
|
||||
{"itemSet", offsetof(game::ItemStats_C, m_itemSet), FieldType::INT32},
|
||||
{"maxDurability", offsetof(game::ItemStats_C, m_maxDurability), FieldType::INT32},
|
||||
{"area", offsetof(game::ItemStats_C, m_area), FieldType::INT32},
|
||||
{"map", offsetof(game::ItemStats_C, m_map), FieldType::INT32},
|
||||
{"duration", offsetof(game::ItemStats_C, m_duration), FieldType::INT32},
|
||||
{"bagFamily", offsetof(game::ItemStats_C, m_bagFamily), FieldType::INT32},
|
||||
};
|
||||
const size_t itemStatsFieldsCount = sizeof(itemStatsFields) / sizeof(itemStatsFields[0]);
|
||||
|
||||
const ArrayFieldDescriptor itemStatsArrayFields[] = {
|
||||
{"bonusStat", offsetof(game::ItemStats_C, m_bonusStat), FieldType::INT32, 10},
|
||||
{"bonusAmount", offsetof(game::ItemStats_C, m_bonusAmount), FieldType::INT32, 10},
|
||||
{"minDamage", offsetof(game::ItemStats_C, m_minDamage), FieldType::FLOAT, 5},
|
||||
{"maxDamage", offsetof(game::ItemStats_C, m_maxDamage), FieldType::FLOAT, 5},
|
||||
{"damageType", offsetof(game::ItemStats_C, m_damageType), FieldType::INT32, 5},
|
||||
{"resistances", offsetof(game::ItemStats_C, m_resistances), FieldType::INT32, 7},
|
||||
{"spellID", offsetof(game::ItemStats_C, m_spellID), FieldType::INT32, 5},
|
||||
{"spellTrigger", offsetof(game::ItemStats_C, m_spellTrigger), FieldType::INT32, 5},
|
||||
{"spellCharges", offsetof(game::ItemStats_C, m_spellCharges), FieldType::INT32, 5},
|
||||
{"spellCooldown", offsetof(game::ItemStats_C, m_spellCooldown), FieldType::INT32, 5},
|
||||
{"spellCategory", offsetof(game::ItemStats_C, m_spellCategory), FieldType::INT32, 5},
|
||||
{"spellCategoryCooldown", offsetof(game::ItemStats_C, m_spellCategoryCooldown), FieldType::INT32, 5},
|
||||
};
|
||||
const size_t itemStatsArrayFieldsCount = sizeof(itemStatsArrayFields) / sizeof(itemStatsArrayFields[0]);
|
||||
|
||||
// SpellRec field descriptors
|
||||
const FieldDescriptor spellRecFields[] = {
|
||||
{"id", offsetof(game::SpellRec, Id), FieldType::UINT32},
|
||||
{"school", offsetof(game::SpellRec, School), FieldType::UINT32},
|
||||
{"category", offsetof(game::SpellRec, Category), FieldType::UINT32},
|
||||
{"castUI", offsetof(game::SpellRec, castUI), FieldType::UINT32},
|
||||
{"dispel", offsetof(game::SpellRec, Dispel), FieldType::UINT32},
|
||||
{"mechanic", offsetof(game::SpellRec, Mechanic), FieldType::UINT32},
|
||||
{"attributes", offsetof(game::SpellRec, Attributes), FieldType::UINT32},
|
||||
{"attributesEx", offsetof(game::SpellRec, AttributesEx), FieldType::UINT32},
|
||||
{"attributesEx2", offsetof(game::SpellRec, AttributesEx2), FieldType::UINT32},
|
||||
{"attributesEx3", offsetof(game::SpellRec, AttributesEx3), FieldType::UINT32},
|
||||
{"attributesEx4", offsetof(game::SpellRec, AttributesEx4), FieldType::UINT32},
|
||||
{"stances", offsetof(game::SpellRec, Stances), FieldType::UINT32},
|
||||
{"stancesNot", offsetof(game::SpellRec, StancesNot), FieldType::UINT32},
|
||||
{"targets", offsetof(game::SpellRec, Targets), FieldType::UINT32},
|
||||
{"targetCreatureType", offsetof(game::SpellRec, TargetCreatureType), FieldType::UINT32},
|
||||
{"requiresSpellFocus", offsetof(game::SpellRec, RequiresSpellFocus), FieldType::UINT32},
|
||||
{"casterAuraState", offsetof(game::SpellRec, CasterAuraState), FieldType::UINT32},
|
||||
{"targetAuraState", offsetof(game::SpellRec, TargetAuraState), FieldType::UINT32},
|
||||
{"castingTimeIndex", offsetof(game::SpellRec, CastingTimeIndex), FieldType::UINT32},
|
||||
{"recoveryTime", offsetof(game::SpellRec, RecoveryTime), FieldType::UINT32},
|
||||
{"categoryRecoveryTime", offsetof(game::SpellRec, CategoryRecoveryTime), FieldType::UINT32},
|
||||
{"interruptFlags", offsetof(game::SpellRec, InterruptFlags), FieldType::UINT32},
|
||||
{"auraInterruptFlags", offsetof(game::SpellRec, AuraInterruptFlags), FieldType::UINT32},
|
||||
{"channelInterruptFlags", offsetof(game::SpellRec, ChannelInterruptFlags), FieldType::UINT32},
|
||||
{"procFlags", offsetof(game::SpellRec, procFlags), FieldType::UINT32},
|
||||
{"procChance", offsetof(game::SpellRec, procChance), FieldType::UINT32},
|
||||
{"procCharges", offsetof(game::SpellRec, procCharges), FieldType::UINT32},
|
||||
{"maxLevel", offsetof(game::SpellRec, maxLevel), FieldType::UINT32},
|
||||
{"baseLevel", offsetof(game::SpellRec, baseLevel), FieldType::UINT32},
|
||||
{"spellLevel", offsetof(game::SpellRec, spellLevel), FieldType::UINT32},
|
||||
{"durationIndex", offsetof(game::SpellRec, DurationIndex), FieldType::UINT32},
|
||||
{"powerType", offsetof(game::SpellRec, powerType), FieldType::UINT32},
|
||||
{"manaCost", offsetof(game::SpellRec, manaCost), FieldType::UINT32},
|
||||
{"manaCostPerlevel", offsetof(game::SpellRec, manaCostPerlevel), FieldType::UINT32},
|
||||
{"manaPerSecond", offsetof(game::SpellRec, manaPerSecond), FieldType::UINT32},
|
||||
{"manaPerSecondPerLevel", offsetof(game::SpellRec, manaPerSecondPerLevel), FieldType::UINT32},
|
||||
{"rangeIndex", offsetof(game::SpellRec, rangeIndex), FieldType::UINT32},
|
||||
{"speed", offsetof(game::SpellRec, speed), FieldType::FLOAT},
|
||||
{"modalNextSpell", offsetof(game::SpellRec, modalNextSpell), FieldType::UINT32},
|
||||
{"stackAmount", offsetof(game::SpellRec, StackAmount), FieldType::UINT32},
|
||||
{"equippedItemClass", offsetof(game::SpellRec, EquippedItemClass), FieldType::INT32},
|
||||
{"equippedItemSubClassMask", offsetof(game::SpellRec, EquippedItemSubClassMask), FieldType::INT32},
|
||||
{"equippedItemInventoryTypeMask", offsetof(game::SpellRec, EquippedItemInventoryTypeMask), FieldType::INT32},
|
||||
{"spellVisual", offsetof(game::SpellRec, SpellVisual), FieldType::UINT32},
|
||||
{"spellVisual2", offsetof(game::SpellRec, SpellVisual2), FieldType::UINT32},
|
||||
{"spellIconID", offsetof(game::SpellRec, SpellIconID), FieldType::UINT32},
|
||||
{"activeIconID", offsetof(game::SpellRec, activeIconID), FieldType::UINT32},
|
||||
{"spellPriority", offsetof(game::SpellRec, spellPriority), FieldType::UINT32},
|
||||
{"manaCostPercentage", offsetof(game::SpellRec, ManaCostPercentage), FieldType::UINT32},
|
||||
{"startRecoveryCategory", offsetof(game::SpellRec, StartRecoveryCategory), FieldType::UINT32},
|
||||
{"startRecoveryTime", offsetof(game::SpellRec, StartRecoveryTime), FieldType::UINT32},
|
||||
{"maxTargetLevel", offsetof(game::SpellRec, MaxTargetLevel), FieldType::UINT32},
|
||||
{"spellFamilyName", offsetof(game::SpellRec, SpellFamilyName), FieldType::UINT32},
|
||||
{"spellFamilyFlags", offsetof(game::SpellRec, SpellFamilyFlags), FieldType::UINT64},
|
||||
{"maxAffectedTargets", offsetof(game::SpellRec, MaxAffectedTargets), FieldType::UINT32},
|
||||
{"dmgClass", offsetof(game::SpellRec, DmgClass), FieldType::UINT32},
|
||||
{"preventionType", offsetof(game::SpellRec, PreventionType), FieldType::UINT32},
|
||||
{"stanceBarOrder", offsetof(game::SpellRec, StanceBarOrder), FieldType::UINT32},
|
||||
{"minFactionId", offsetof(game::SpellRec, MinFactionId), FieldType::UINT32},
|
||||
{"minReputation", offsetof(game::SpellRec, MinReputation), FieldType::UINT32},
|
||||
{"requiredAuraVision", offsetof(game::SpellRec, RequiredAuraVision), FieldType::UINT32},
|
||||
};
|
||||
const size_t spellRecFieldsCount = sizeof(spellRecFields) / sizeof(spellRecFields[0]);
|
||||
|
||||
const ArrayFieldDescriptor spellRecArrayFields[] = {
|
||||
{"totem", offsetof(game::SpellRec, Totem), FieldType::UINT32, 2},
|
||||
{"reagent", offsetof(game::SpellRec, Reagent), FieldType::INT32, 8},
|
||||
{"reagentCount", offsetof(game::SpellRec, ReagentCount), FieldType::UINT32, 8},
|
||||
{"effect", offsetof(game::SpellRec, Effect), FieldType::UINT32, 3},
|
||||
{"effectDieSides", offsetof(game::SpellRec, EffectDieSides), FieldType::INT32, 3},
|
||||
{"effectBaseDice", offsetof(game::SpellRec, EffectBaseDice), FieldType::UINT32, 3},
|
||||
{"effectDicePerLevel", offsetof(game::SpellRec, EffectDicePerLevel), FieldType::FLOAT, 3},
|
||||
{"effectRealPointsPerLevel", offsetof(game::SpellRec, EffectRealPointsPerLevel), FieldType::FLOAT, 3},
|
||||
{"effectBasePoints", offsetof(game::SpellRec, EffectBasePoints), FieldType::INT32, 3},
|
||||
{"effectMechanic", offsetof(game::SpellRec, EffectMechanic), FieldType::UINT32, 3},
|
||||
{"effectImplicitTargetA", offsetof(game::SpellRec, EffectImplicitTargetA), FieldType::UINT32, 3},
|
||||
{"effectImplicitTargetB", offsetof(game::SpellRec, EffectImplicitTargetB), FieldType::UINT32, 3},
|
||||
{"effectRadiusIndex", offsetof(game::SpellRec, EffectRadiusIndex), FieldType::UINT32, 3},
|
||||
{"effectApplyAuraName", offsetof(game::SpellRec, EffectApplyAuraName), FieldType::UINT32, 3},
|
||||
{"effectAmplitude", offsetof(game::SpellRec, EffectAmplitude), FieldType::UINT32, 3},
|
||||
{"effectMultipleValue", offsetof(game::SpellRec, EffectMultipleValue), FieldType::FLOAT, 3},
|
||||
{"effectChainTarget", offsetof(game::SpellRec, EffectChainTarget), FieldType::UINT32, 3},
|
||||
{"effectItemType", offsetof(game::SpellRec, EffectItemType), FieldType::UINT32, 3},
|
||||
{"effectMiscValue", offsetof(game::SpellRec, EffectMiscValue), FieldType::INT32, 3},
|
||||
{"effectTriggerSpell", offsetof(game::SpellRec, EffectTriggerSpell), FieldType::UINT32, 3},
|
||||
{"effectPointsPerComboPoint", offsetof(game::SpellRec, EffectPointsPerComboPoint), FieldType::FLOAT, 3},
|
||||
{"dmgMultiplier", offsetof(game::SpellRec, DmgMultiplier), FieldType::FLOAT, 3},
|
||||
};
|
||||
const size_t spellRecArrayFieldsCount = sizeof(spellRecArrayFields) / sizeof(spellRecArrayFields[0]);
|
||||
|
||||
void InitializeFieldMaps() {
|
||||
if (fieldMapsInitialized) return;
|
||||
|
||||
// Build hash maps for O(1) lookups
|
||||
for (size_t i = 0; i < itemStatsFieldsCount; ++i) {
|
||||
itemStatsFieldMap[itemStatsFields[i].name] = i;
|
||||
}
|
||||
for (size_t i = 0; i < itemStatsArrayFieldsCount; ++i) {
|
||||
itemStatsArrayFieldMap[itemStatsArrayFields[i].name] = i;
|
||||
}
|
||||
for (size_t i = 0; i < spellRecFieldsCount; ++i) {
|
||||
spellRecFieldMap[spellRecFields[i].name] = i;
|
||||
}
|
||||
for (size_t i = 0; i < spellRecArrayFieldsCount; ++i) {
|
||||
spellRecArrayFieldMap[spellRecArrayFields[i].name] = i;
|
||||
}
|
||||
|
||||
fieldMapsInitialized = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Created by pmacc on 1/8/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "main.hpp"
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Nampower {
|
||||
// Field type enumeration
|
||||
enum class FieldType {
|
||||
INT32,
|
||||
UINT32,
|
||||
FLOAT,
|
||||
STRING,
|
||||
UINT64
|
||||
};
|
||||
|
||||
// Field descriptor for simple fields
|
||||
struct FieldDescriptor {
|
||||
const char* name;
|
||||
size_t offset;
|
||||
FieldType type;
|
||||
};
|
||||
|
||||
// Field descriptor for array fields
|
||||
struct ArrayFieldDescriptor {
|
||||
const char* name;
|
||||
size_t offset;
|
||||
FieldType type;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
// ItemStats_C field descriptors
|
||||
extern const FieldDescriptor itemStatsFields[];
|
||||
extern const size_t itemStatsFieldsCount;
|
||||
extern const ArrayFieldDescriptor itemStatsArrayFields[];
|
||||
extern const size_t itemStatsArrayFieldsCount;
|
||||
|
||||
// SpellRec field descriptors
|
||||
extern const FieldDescriptor spellRecFields[];
|
||||
extern const size_t spellRecFieldsCount;
|
||||
extern const ArrayFieldDescriptor spellRecArrayFields[];
|
||||
extern const size_t spellRecArrayFieldsCount;
|
||||
|
||||
// Hash tables for O(1) field lookups
|
||||
extern std::unordered_map<std::string, size_t> itemStatsFieldMap;
|
||||
extern std::unordered_map<std::string, size_t> itemStatsArrayFieldMap;
|
||||
extern std::unordered_map<std::string, size_t> spellRecFieldMap;
|
||||
extern std::unordered_map<std::string, size_t> spellRecArrayFieldMap;
|
||||
|
||||
// Initialize field maps (call once before using field lookups)
|
||||
void InitializeFieldMaps();
|
||||
|
||||
// Forward declarations for Lua functions (defined in offsets.hpp/scripts.cpp)
|
||||
using lua_pushnumberT = void (__fastcall *)(uintptr_t *, double);
|
||||
using lua_pushstringT = void (__fastcall *)(uintptr_t *, char *);
|
||||
using lua_newtableT = void (__fastcall *)(uintptr_t *);
|
||||
using lua_settableT = void (__fastcall *)(uintptr_t *, int);
|
||||
|
||||
extern lua_pushnumberT lua_pushnumber;
|
||||
extern lua_pushstringT lua_pushstring;
|
||||
extern lua_newtableT lua_newtable;
|
||||
extern lua_settableT lua_settable;
|
||||
|
||||
// Helper template functions to push fields to Lua (inline for performance)
|
||||
template<typename T>
|
||||
inline void PushFieldsToLua(uintptr_t* luaState, const T* obj, const FieldDescriptor* fields, size_t fieldCount) {
|
||||
for (size_t i = 0; i < fieldCount; ++i) {
|
||||
const auto& field = fields[i];
|
||||
lua_pushstring(luaState, const_cast<char*>(field.name));
|
||||
|
||||
const char* fieldPtr = reinterpret_cast<const char*>(obj) + field.offset;
|
||||
|
||||
switch (field.type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const int32_t*>(fieldPtr));
|
||||
break;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const uint32_t*>(fieldPtr));
|
||||
break;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const float*>(fieldPtr));
|
||||
break;
|
||||
case FieldType::UINT64:
|
||||
lua_pushnumber(luaState, static_cast<double>(*reinterpret_cast<const uint64_t*>(fieldPtr)));
|
||||
break;
|
||||
case FieldType::STRING: {
|
||||
const char* str = *reinterpret_cast<const char* const*>(fieldPtr);
|
||||
lua_pushstring(luaState, str ? const_cast<char*>(str) : const_cast<char*>(""));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void PushArrayFieldsToLua(uintptr_t* luaState, const T* obj, const ArrayFieldDescriptor* fields, size_t fieldCount) {
|
||||
for (size_t i = 0; i < fieldCount; ++i) {
|
||||
const auto& field = fields[i];
|
||||
lua_pushstring(luaState, const_cast<char*>(field.name));
|
||||
lua_newtable(luaState);
|
||||
|
||||
const char* fieldPtr = reinterpret_cast<const char*>(obj) + field.offset;
|
||||
|
||||
for (size_t j = 0; j < field.count; ++j) {
|
||||
lua_pushnumber(luaState, j + 1); // Lua is 1-indexed
|
||||
|
||||
switch (field.type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const int32_t*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const uint32_t*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const float*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::UINT64:
|
||||
lua_pushnumber(luaState, static_cast<double>(reinterpret_cast<const uint64_t*>(fieldPtr)[j]));
|
||||
break;
|
||||
case FieldType::STRING: {
|
||||
const char* str = reinterpret_cast<const char* const*>(fieldPtr)[j];
|
||||
lua_pushstring(luaState, str ? const_cast<char*>(str) : const_cast<char*>(""));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -30,6 +30,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace game {
|
||||
#pragma pack(push, 1)
|
||||
@@ -209,7 +210,7 @@ namespace game {
|
||||
int m_containerSlots;
|
||||
int m_bonusStat[10];
|
||||
int m_bonusAmount[10];
|
||||
int m_minDamage[5];
|
||||
float m_minDamage[5];
|
||||
float m_maxDamage[5];
|
||||
int m_damageType[5];
|
||||
int m_resistances[7];
|
||||
@@ -229,7 +230,7 @@ namespace game {
|
||||
int m_pageMaterial;
|
||||
int m_startQuestID;
|
||||
int m_lockID;
|
||||
char *m_material;
|
||||
int m_material;
|
||||
int m_sheatheType;
|
||||
int m_randomProperty;
|
||||
int m_block;
|
||||
|
||||
+148
-1
@@ -5,8 +5,155 @@
|
||||
#include "helper.hpp"
|
||||
#include "offsets.hpp"
|
||||
#include "main.hpp"
|
||||
#include "dbc_fields.hpp"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
namespace Nampower {
|
||||
|
||||
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType) {
|
||||
struct CachedEntry {
|
||||
uint32_t slot;
|
||||
uint32_t type;
|
||||
std::string cachedNameLower;
|
||||
};
|
||||
static std::unordered_map<std::string, CachedEntry> spellSlotCache;
|
||||
|
||||
auto const normalize = [](const char *name) -> std::string {
|
||||
std::string out = name ? name : "";
|
||||
std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) { return char(std::tolower(c)); });
|
||||
return out;
|
||||
};
|
||||
|
||||
const std::string key = normalize(spellName);
|
||||
|
||||
auto const spellNameMatchesAtSlot = [&normalize](const char *requestedLower, uint32_t slot, uint32_t type) -> bool {
|
||||
if (!requestedLower) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t spellId = 0;
|
||||
if (type == 0) {
|
||||
spellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownSpells) + slot * 4);
|
||||
} else if (type == 1) {
|
||||
spellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownPetSpells) + slot * 4);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellId == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const spell = game::GetSpellInfo(spellId);
|
||||
if (!spell) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
|
||||
auto const actualName = reinterpret_cast<const char *>(spell->SpellName[language]);
|
||||
if (!actualName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const actualLower = normalize(actualName);
|
||||
return _stricmp(actualLower.c_str(), requestedLower) == 0;
|
||||
};
|
||||
|
||||
if (!key.empty()) {
|
||||
auto cacheIt = spellSlotCache.find(key);
|
||||
if (cacheIt != spellSlotCache.end()) {
|
||||
auto const &entry = cacheIt->second;
|
||||
if (entry.slot < 1024 && spellNameMatchesAtSlot(key.c_str(), entry.slot, entry.type)) {
|
||||
if (spellType) {
|
||||
*spellType = entry.type;
|
||||
}
|
||||
return entry.slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto const getSpellSlotAndType = reinterpret_cast<GetSpellSlotAndTypeT>(Offsets::GetSpellSlotAndType);
|
||||
auto const slot = getSpellSlotAndType(spellName, spellType);
|
||||
|
||||
if (slot < 1024 && spellType && !key.empty()) {
|
||||
spellSlotCache[key] = {slot, *spellType, key};
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
uint32_t GetSpellIdFromSpellName(const char *spellName) {
|
||||
uint32_t bookType;
|
||||
uint32_t spellSlot = GetSpellSlotAndTypeForName(spellName, &bookType);
|
||||
|
||||
uint32_t spellId = 0;
|
||||
if (spellSlot < 1024) {
|
||||
if (bookType == 0) {
|
||||
spellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownSpells) +
|
||||
spellSlot * 4);
|
||||
} else {
|
||||
spellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownPetSpells) +
|
||||
spellSlot * 4);
|
||||
}
|
||||
}
|
||||
|
||||
return spellId;
|
||||
}
|
||||
|
||||
uint32_t ConvertSpellIdToSpellSlot(uint32_t spellId, uint32_t bookType) {
|
||||
static std::unordered_map<uint64_t, uint32_t> spellIdToSlotCache;
|
||||
auto const cacheKey = (uint64_t(spellId) << 1) | (bookType & 0x1);
|
||||
|
||||
auto const slotHasSpellId = [bookType](uint32_t slot, uint32_t expectedId) -> bool {
|
||||
if (slot >= 1024) {
|
||||
return false;
|
||||
}
|
||||
uint32_t slotSpellId = 0;
|
||||
if (bookType == 0) {
|
||||
slotSpellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownSpells) + slot * 4);
|
||||
} else {
|
||||
slotSpellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownPetSpells) + slot * 4);
|
||||
}
|
||||
return slotSpellId == expectedId;
|
||||
};
|
||||
|
||||
auto cacheIt = spellIdToSlotCache.find(cacheKey);
|
||||
if (cacheIt != spellIdToSlotCache.end()) {
|
||||
if (slotHasSpellId(cacheIt->second, spellId)) {
|
||||
return cacheIt->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Search through player spellbook
|
||||
if (bookType == 0) {
|
||||
for (uint32_t spellSlot = 0; spellSlot < 1024; spellSlot++) {
|
||||
uint32_t slotSpellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownSpells) +
|
||||
spellSlot * 4);
|
||||
if (slotSpellId == spellId) {
|
||||
spellIdToSlotCache[cacheKey] = spellSlot;
|
||||
return spellSlot;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Search through pet spellbook
|
||||
for (uint32_t spellSlot = 0; spellSlot < 1024; spellSlot++) {
|
||||
uint32_t slotSpellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownPetSpells) +
|
||||
spellSlot * 4);
|
||||
if (slotSpellId == spellId) {
|
||||
spellIdToSlotCache[cacheKey] = spellSlot;
|
||||
return spellSlot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool SpellIsOnGcd(const game::SpellRec *spell) {
|
||||
if (spell->Id == 51714) {
|
||||
// power overwhelming gcd removed but client not updated
|
||||
@@ -122,4 +269,4 @@ namespace Nampower {
|
||||
void SetNameplateDistance(float distance) {
|
||||
*reinterpret_cast<float *>(Offsets::NameplateDistance) = distance * distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
#include "game.hpp"
|
||||
|
||||
namespace Nampower {
|
||||
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType);
|
||||
|
||||
uint32_t GetSpellIdFromSpellName(const char *spellName);
|
||||
|
||||
uint32_t ConvertSpellIdToSpellSlot(uint32_t spellId, uint32_t bookType);
|
||||
|
||||
bool SpellIsOnGcd(const game::SpellRec *spell);
|
||||
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Created by pmacc on 9/21/2024.
|
||||
//
|
||||
|
||||
#include "items.hpp"
|
||||
#include "offsets.hpp"
|
||||
#include "logging.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nampower {
|
||||
// Global dictionary to store itemId -> ItemStats_C mappings
|
||||
static std::unordered_map<uint32_t, game::ItemStats_C *> itemStatsCache;
|
||||
|
||||
auto const getRow = reinterpret_cast<DBCache_ItemCacheDBGetRowT>(Offsets::DBCache_ItemCacheDBGetRow);
|
||||
auto const itemCache = reinterpret_cast<void *>(Offsets::ItemDBCache);
|
||||
|
||||
// Callback function for DBCache
|
||||
void __stdcall ItemStatsCallback(uintptr_t *tooltip, char param_2) {
|
||||
if (tooltip != nullptr) {
|
||||
auto itemId = *reinterpret_cast<uint32_t *>(tooltip + 0xE6);
|
||||
|
||||
int ptr;
|
||||
auto itemStats = getRow(itemCache, nullptr, itemId, &ptr, &ItemStatsCallback, nullptr, 0);
|
||||
if (itemStats) {
|
||||
DEBUG_LOG("Queried itemId " << itemId << " -> " << itemStats);
|
||||
// Store in cache
|
||||
itemStatsCache[itemId] = reinterpret_cast<game::ItemStats_C *>(itemStats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoadItem(uint32_t itemId) {
|
||||
// Check if already in cache
|
||||
auto it = itemStatsCache.find(itemId);
|
||||
if (it != itemStatsCache.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!itemCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
int ptr;
|
||||
auto itemStats = getRow(itemCache, nullptr, itemId, &ptr, &ItemStatsCallback, nullptr, 0);
|
||||
if (itemStats) {
|
||||
// Store in cache
|
||||
itemStatsCache[itemId] = reinterpret_cast<game::ItemStats_C *>(itemStats);
|
||||
} else {
|
||||
// wait for .005 sec
|
||||
Sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
game::ItemStats_C* GetItemStats(uint32_t itemId) {
|
||||
auto it = itemStatsCache.find(itemId);
|
||||
if (it != itemStatsCache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string escapeJsonString(const char *str) {
|
||||
if (!str) return "null";
|
||||
|
||||
std::string result = "\"";
|
||||
for (const char *p = str; *p; ++p) {
|
||||
switch (*p) {
|
||||
case '"':
|
||||
result += "\\\"";
|
||||
break;
|
||||
case '\\':
|
||||
result += "\\\\";
|
||||
break;
|
||||
case '\b':
|
||||
result += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
result += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
result += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
result += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
result += "\\t";
|
||||
break;
|
||||
default:
|
||||
if (static_cast<unsigned char>(*p) < 0x20) {
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), "\\u%04x", static_cast<unsigned char>(*p));
|
||||
result += buf;
|
||||
} else {
|
||||
result += *p;
|
||||
}
|
||||
}
|
||||
}
|
||||
result += "\"";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Register a function if you want to use this
|
||||
// Don't want everyone scraping all items.
|
||||
void ExportAllItems() {
|
||||
DEBUG_LOG("Starting getAllItems - fetching items 1 to 100000");
|
||||
|
||||
// Loop through all item IDs
|
||||
for (uint32_t itemId = 1; itemId <= 100000; ++itemId) {
|
||||
LoadItem(itemId);
|
||||
|
||||
// Log progress every 1000 items
|
||||
if (itemId % 1000 == 0) {
|
||||
DEBUG_LOG("Progress: " << itemId << " / 100000 items processed");
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("Finished fetching items, found " << itemStatsCache.size() << " valid items");
|
||||
DEBUG_LOG("Writing items to items.json");
|
||||
|
||||
// Write all cached items to JSON file (overwrite mode)
|
||||
try {
|
||||
std::ofstream jsonFile("items.json", std::ios::trunc);
|
||||
if (!jsonFile.is_open()) {
|
||||
DEBUG_LOG("Failed to open items.json for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
jsonFile << "[\n";
|
||||
|
||||
bool first = true;
|
||||
for (const auto &pair: itemStatsCache) {
|
||||
if (!first) {
|
||||
jsonFile << ",\n";
|
||||
}
|
||||
first = false;
|
||||
|
||||
uint32_t itemId = pair.first;
|
||||
game::ItemStats_C *item = pair.second;
|
||||
|
||||
if (!item) continue;
|
||||
|
||||
std::ostringstream json;
|
||||
json << " {\n";
|
||||
json << " \"id\": " << itemId << ",\n";
|
||||
json << " \"class\": " << item->m_class << ",\n";
|
||||
json << " \"subclass\": " << item->m_subclass << ",\n";
|
||||
json << " \"displayName\": " << escapeJsonString(item->m_displayName[0]) << ",\n";
|
||||
json << " \"displayInfoID\": " << item->m_displayInfoID << ",\n";
|
||||
json << " \"quality\": " << item->m_quality << ",\n";
|
||||
json << " \"flags\": " << static_cast<int>(item->m_flags) << ",\n";
|
||||
json << " \"buyPrice\": " << item->m_buyPrice << ",\n";
|
||||
json << " \"sellPrice\": " << item->m_sellPrice << ",\n";
|
||||
json << " \"inventoryType\": " << item->m_inventoryType << ",\n";
|
||||
json << " \"allowableClass\": " << item->m_allowableClass << ",\n";
|
||||
json << " \"allowableRace\": " << item->m_allowableRace << ",\n";
|
||||
json << " \"itemLevel\": " << item->m_itemLevel << ",\n";
|
||||
json << " \"requiredLevel\": " << item->m_requiredLevel << ",\n";
|
||||
json << " \"requiredSkill\": " << item->m_requiredSkill << ",\n";
|
||||
json << " \"requiredSkillRank\": " << item->m_requiredSkillRank << ",\n";
|
||||
json << " \"requiredSpell\": " << item->m_requiredSpell << ",\n";
|
||||
json << " \"requiredHonorRank\": " << item->m_requiredHonorRank << ",\n";
|
||||
json << " \"requiredCityRank\": " << item->m_requiredCityRank << ",\n";
|
||||
json << " \"requiredRep\": " << item->m_requiredRep << ",\n";
|
||||
json << " \"requiredRepRank\": " << item->m_requiredRepRank << ",\n";
|
||||
json << " \"maxCount\": " << item->m_maxCount << ",\n";
|
||||
json << " \"stackable\": " << item->m_stackable << ",\n";
|
||||
json << " \"containerSlots\": " << item->m_containerSlots << ",\n";
|
||||
|
||||
// Arrays
|
||||
json << " \"bonusStat\": [";
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
json << item->m_bonusStat[i];
|
||||
if (i < 9) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"bonusAmount\": [";
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
json << item->m_bonusAmount[i];
|
||||
if (i < 9) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"minDamage\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_minDamage[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"maxDamage\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_maxDamage[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"damageType\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_damageType[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"resistances\": [";
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
json << item->m_resistances[i];
|
||||
if (i < 6) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"delay\": " << item->m_delay << ",\n";
|
||||
json << " \"ammoType\": " << item->m_ammoType << ",\n";
|
||||
json << " \"rangedModRange\": " << item->m_rangedModRange << ",\n";
|
||||
|
||||
json << " \"spellID\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_spellID[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"spellTrigger\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_spellTrigger[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"spellCharges\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_spellCharges[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"spellCooldown\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_spellCooldown[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"spellCategory\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_spellCategory[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"spellCategoryCooldown\": [";
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
json << item->m_spellCategoryCooldown[i];
|
||||
if (i < 4) json << ", ";
|
||||
}
|
||||
json << "],\n";
|
||||
|
||||
json << " \"bonding\": " << item->m_bonding << ",\n";
|
||||
json << " \"description\": " << escapeJsonString(item->m_description) << ",\n";
|
||||
json << " \"pageText\": " << item->m_pageText << ",\n";
|
||||
json << " \"languageID\": " << item->m_languageID << ",\n";
|
||||
json << " \"pageMaterial\": " << item->m_pageMaterial << ",\n";
|
||||
json << " \"startQuestID\": " << item->m_startQuestID << ",\n";
|
||||
json << " \"lockID\": " << item->m_lockID << ",\n";
|
||||
json << " \"material\": " << item->m_material << ",\n";
|
||||
json << " \"sheatheType\": " << item->m_sheatheType << ",\n";
|
||||
json << " \"randomProperty\": " << item->m_randomProperty << ",\n";
|
||||
json << " \"block\": " << item->m_block << ",\n";
|
||||
json << " \"itemSet\": " << item->m_itemSet << ",\n";
|
||||
json << " \"maxDurability\": " << item->m_maxDurability << ",\n";
|
||||
json << " \"area\": " << item->m_area << ",\n";
|
||||
json << " \"map\": " << item->m_map << ",\n";
|
||||
json << " \"duration\": " << item->m_duration << ",\n";
|
||||
json << " \"bagFamily\": " << item->m_bagFamily << "\n";
|
||||
json << " }";
|
||||
|
||||
jsonFile << json.str();
|
||||
}
|
||||
|
||||
jsonFile << "\n]\n";
|
||||
jsonFile.close();
|
||||
|
||||
DEBUG_LOG("Successfully wrote " << itemStatsCache.size() << " items to items.json");
|
||||
} catch (const std::exception &e) {
|
||||
DEBUG_LOG("Exception writing to items.json: " << e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by pmacc on 9/21/2024.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "main.hpp"
|
||||
|
||||
namespace Nampower {
|
||||
using TooltipItemStatsCallbackT = void (__stdcall *)(uintptr_t *tooltip, char param_2);
|
||||
|
||||
using DBCache_ItemCacheDBGetRowT = uint32_t * (__fastcall *)(void *this_ptr, void *dummy_edx, uint32_t itemId, int *param_2, TooltipItemStatsCallbackT callback, int *param_4, char param_5);
|
||||
|
||||
void ExportAllItems();
|
||||
void LoadItem(uint32_t itemId);
|
||||
game::ItemStats_C* GetItemStats(uint32_t itemId);
|
||||
}
|
||||
+37
-51
@@ -36,6 +36,7 @@
|
||||
#include "scripts.hpp"
|
||||
#include "spellchannel.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "items.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@@ -99,23 +100,10 @@ namespace Nampower {
|
||||
std::unique_ptr<hadesmem::PatchDetour<SpellGoT>> gSpellGoDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gSpellTargetUnitDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gSpellStopCastingDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gCastSpellByNameNoQueueDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gQueueSpellByNameDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> qQueueScriptDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gIsSpellInRangeDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gIsSpellUsableDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gGetCurrentCastingInfoDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gGetSpellIdForNameDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gGetSpellNameAndRankForIdDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gGetSpellSlotAndTypeForNameDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gChannelStopCastingNextTickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<OnSpriteRightClickT>> gOnSpriteRightClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleSpriteClickT>> gSpell_C_HandleSpriteClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_TargetSpellT>> gSpell_C_TargetSpellDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gGetNampowerVersionDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gGetItemLevelDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellCooldownDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellDelayedDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gCastResultHandlerDetour;
|
||||
@@ -130,6 +118,10 @@ namespace Nampower {
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGPlayer_C_OnAttackIconPressedT>> gCGPlayer_C_OnAttackIconPressedDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<InvalidFunctionPtrCheckT>> gInvalidFunctionPtrCheckDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<GetSpellSlotFromLuaT>> gGetSpellSlotFromLuaDetour;
|
||||
|
||||
uint32_t GetTime() {
|
||||
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count()) - gStartTime;
|
||||
@@ -543,6 +535,10 @@ namespace Nampower {
|
||||
return iSceneEnd(ptr);
|
||||
}
|
||||
|
||||
void InvalidFunctionPtrCheckHook(hadesmem::PatchDetourBase *detour, uint32_t param_1) {
|
||||
// remove original call to allow registering lua functions at any address range
|
||||
}
|
||||
|
||||
void updateFromCvar(const char *cvar, const char *value) {
|
||||
if (strcmp(cvar, "NP_QueueCastTimeSpells") == 0) {
|
||||
gUserSettings.queueCastTimeSpells = atoi(value) != 0;
|
||||
@@ -1116,29 +1112,13 @@ namespace Nampower {
|
||||
&Script_SpellStopCastingHook);
|
||||
gSpell_C_TargetSpellDetour = createHook<Spell_C_TargetSpellT>(process, Offsets::Spell_C_TargetSpell,
|
||||
&Spell_C_TargetSpellHook);
|
||||
gCastSpellByNameNoQueueDetour = createHook<LuaScriptT>(process, Offsets::Script_CastSpellByNameNoQueue,
|
||||
Script_CastSpellByNameNoQueue);
|
||||
gQueueSpellByNameDetour = createHook<LuaScriptT>(process, Offsets::Script_QueueSpellByName,
|
||||
Script_QueueSpellByName);
|
||||
qQueueScriptDetour = createHook<LuaScriptT>(process, Offsets::Script_QueueScript, Script_QueueScript);
|
||||
gIsSpellInRangeDetour = createHook<LuaScriptT>(process, Offsets::Script_IsSpellInRange, Script_IsSpellInRange);
|
||||
gIsSpellUsableDetour = createHook<LuaScriptT>(process, Offsets::Script_IsSpellUsable, Script_IsSpellUsable);
|
||||
gGetCurrentCastingInfoDetour = createHook<LuaScriptT>(process, Offsets::Script_GetCurrentCastingInfo,
|
||||
Script_GetCurrentCastingInfo);
|
||||
gGetSpellIdForNameDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellIdForName,
|
||||
Script_GetSpellIdForName);
|
||||
gGetSpellNameAndRankForIdDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellNameAndRankForId,
|
||||
Script_GetSpellNameAndRankForId);
|
||||
gGetSpellSlotAndTypeForNameDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellSlotTypeIdForName,
|
||||
Script_GetSpellSlotTypeIdForName);
|
||||
gOnSpriteRightClickDetour = createHook<OnSpriteRightClickT>(process, Offsets::OnSpriteRightClick,
|
||||
OnSpriteRightClickHook);
|
||||
gChannelStopCastingNextTickDetour = createHook<LuaScriptT>(process, Offsets::Script_ChannelStopCastingNextTick,
|
||||
Script_ChannelStopCastingNextTick);
|
||||
gGetNampowerVersionDetour = createHook<LuaScriptT>(process, Offsets::Script_GetNampowerVersion,
|
||||
Script_GetNampowerVersion);
|
||||
gGetItemLevelDetour = createHook<LuaScriptT>(process, Offsets::Script_GetItemLevel, Script_GetItemLevel);
|
||||
gIEndSceneDetour = createHook<ISceneEndT>(process, Offsets::ISceneEndPtr, &ISceneEndHook);
|
||||
gInvalidFunctionPtrCheckDetour = createHook<InvalidFunctionPtrCheckT>(process, Offsets::InvalidFunctionPtrCheck,
|
||||
&InvalidFunctionPtrCheckHook);
|
||||
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
|
||||
&GetSpellSlotFromLuaHook);
|
||||
|
||||
// gCGPlayer_C_OnAttackIconPressedDetour = createHook<CGPlayer_C_OnAttackIconPressedT>(process,
|
||||
// Offsets::CGPlayer_C_OnAttackIconPressed,
|
||||
@@ -1169,46 +1149,52 @@ namespace Nampower {
|
||||
// register our own lua functions
|
||||
DEBUG_LOG("Registering Custom Lua functions");
|
||||
char queueSpellByName[] = "QueueSpellByName";
|
||||
RegisterLuaFunction(queueSpellByName, reinterpret_cast<uintptr_t *>(Offsets::Script_QueueSpellByName));
|
||||
RegisterLuaFunction(queueSpellByName, reinterpret_cast<uintptr_t *>(Script_QueueSpellByName));
|
||||
|
||||
char castSpellByNameNoQueue[] = "CastSpellByNameNoQueue";
|
||||
RegisterLuaFunction(castSpellByNameNoQueue,
|
||||
reinterpret_cast<uintptr_t *>(Offsets::Script_CastSpellByNameNoQueue));
|
||||
RegisterLuaFunction(castSpellByNameNoQueue, reinterpret_cast<uintptr_t *>(Script_CastSpellByNameNoQueue));
|
||||
|
||||
char queueScript[] = "QueueScript";
|
||||
RegisterLuaFunction(queueScript, reinterpret_cast<uintptr_t *>(Offsets::Script_QueueScript));
|
||||
RegisterLuaFunction(queueScript, reinterpret_cast<uintptr_t *>(Script_QueueScript));
|
||||
|
||||
char isSpellInRange[] = "IsSpellInRange";
|
||||
RegisterLuaFunction(isSpellInRange, reinterpret_cast<uintptr_t *>(Offsets::Script_IsSpellInRange));
|
||||
RegisterLuaFunction(isSpellInRange, reinterpret_cast<uintptr_t *>(Script_IsSpellInRange));
|
||||
|
||||
char isSpellUsable[] = "IsSpellUsable";
|
||||
RegisterLuaFunction(isSpellUsable, reinterpret_cast<uintptr_t *>(Offsets::Script_IsSpellUsable));
|
||||
RegisterLuaFunction(isSpellUsable, reinterpret_cast<uintptr_t *>(Script_IsSpellUsable));
|
||||
|
||||
char getCurrentCastingInfo[] = "GetCurrentCastingInfo";
|
||||
RegisterLuaFunction(getCurrentCastingInfo,
|
||||
reinterpret_cast<uintptr_t *>(Offsets::Script_GetCurrentCastingInfo));
|
||||
RegisterLuaFunction(getCurrentCastingInfo, reinterpret_cast<uintptr_t *>(Script_GetCurrentCastingInfo));
|
||||
|
||||
char getSpellIdForName[] = "GetSpellIdForName";
|
||||
RegisterLuaFunction(getSpellIdForName,
|
||||
reinterpret_cast<uintptr_t *>(Offsets::Script_GetSpellIdForName));
|
||||
RegisterLuaFunction(getSpellIdForName, reinterpret_cast<uintptr_t *>(Script_GetSpellIdForName));
|
||||
|
||||
char getSpellNameAndRankForId[] = "GetSpellNameAndRankForId";
|
||||
RegisterLuaFunction(getSpellNameAndRankForId,
|
||||
reinterpret_cast<uintptr_t *>(Offsets::Script_GetSpellNameAndRankForId));
|
||||
RegisterLuaFunction(getSpellNameAndRankForId, reinterpret_cast<uintptr_t *>(Script_GetSpellNameAndRankForId));
|
||||
|
||||
char getSpellSlotTypeIdForName[] = "GetSpellSlotTypeIdForName";
|
||||
RegisterLuaFunction(getSpellSlotTypeIdForName,
|
||||
reinterpret_cast<uintptr_t *>(Offsets::Script_GetSpellSlotTypeIdForName));
|
||||
RegisterLuaFunction(getSpellSlotTypeIdForName, reinterpret_cast<uintptr_t *>(Script_GetSpellSlotTypeIdForName));
|
||||
|
||||
char channelStopCastingNextTick[] = "ChannelStopCastingNextTick";
|
||||
RegisterLuaFunction(channelStopCastingNextTick,
|
||||
reinterpret_cast<uintptr_t *>(Offsets::Script_ChannelStopCastingNextTick));
|
||||
RegisterLuaFunction(channelStopCastingNextTick, reinterpret_cast<uintptr_t *>(Script_ChannelStopCastingNextTick));
|
||||
|
||||
char getNampowerVersion[] = "GetNampowerVersion";
|
||||
RegisterLuaFunction(getNampowerVersion, reinterpret_cast<uintptr_t *>(Offsets::Script_GetNampowerVersion));
|
||||
RegisterLuaFunction(getNampowerVersion, reinterpret_cast<uintptr_t *>(Script_GetNampowerVersion));
|
||||
|
||||
char getItemILevel[] = "GetItemLevel";
|
||||
RegisterLuaFunction(getItemILevel, reinterpret_cast<uintptr_t *>(Offsets::Script_GetItemLevel));
|
||||
RegisterLuaFunction(getItemILevel, reinterpret_cast<uintptr_t *>(Script_GetItemLevel));
|
||||
|
||||
char getItemStats[] = "GetItemStats";
|
||||
RegisterLuaFunction(getItemStats, reinterpret_cast<uintptr_t *>(Script_GetItemStats));
|
||||
|
||||
char getSpellRec[] = "GetSpellRec";
|
||||
RegisterLuaFunction(getSpellRec, reinterpret_cast<uintptr_t *>(Script_GetSpellRec));
|
||||
|
||||
char getItemStatsField[] = "GetItemStatsField";
|
||||
RegisterLuaFunction(getItemStatsField, reinterpret_cast<uintptr_t *>(Script_GetItemStatsField));
|
||||
|
||||
char getSpellRecField[] = "GetSpellRecField";
|
||||
RegisterLuaFunction(getSpellRecField, reinterpret_cast<uintptr_t *>(Script_GetSpellRecField));
|
||||
}
|
||||
|
||||
std::once_flag loadFlag;
|
||||
|
||||
+8
-3
@@ -30,8 +30,8 @@ namespace Nampower {
|
||||
constexpr uint32_t BUFFER_DECREASE_FREQUENCY = 10000; // time in ms between changes to lower buffer
|
||||
|
||||
constexpr uint32_t MAJOR_VERSION = 2;
|
||||
constexpr uint32_t MINOR_VERSION = 11;
|
||||
constexpr uint32_t PATCH_VERSION = 2;
|
||||
constexpr uint32_t MINOR_VERSION = 12;
|
||||
constexpr uint32_t PATCH_VERSION = 0;
|
||||
|
||||
constexpr int32_t LUA_REGISTRYINDEX = -10000;
|
||||
constexpr int32_t LUA_GLOBALSINDEX = -10001;
|
||||
@@ -96,7 +96,8 @@ namespace Nampower {
|
||||
|
||||
using CGPlayer_C_OnAttackIconPressedT = int (__fastcall *)(uintptr_t *this_ptr, void *dummy_edx, uint64_t guid);
|
||||
|
||||
using GetSpellSlotAndTypeT = int (__fastcall *)(const char *, uint32_t *);
|
||||
using GetSpellSlotAndTypeT = uint32_t (__fastcall *)(const char *, uint32_t *);
|
||||
using GetSpellSlotFromLuaT = uint32_t (__fastcall *)(int param_1, uint32_t *slot, uint32_t *type);
|
||||
using GetTimeMsT = uint64_t (__stdcall *)();
|
||||
|
||||
using GetClientConnectionT = uintptr_t *(__stdcall *)();
|
||||
@@ -124,6 +125,8 @@ namespace Nampower {
|
||||
using lua_pushnilT = void (__fastcall *)(uintptr_t *);
|
||||
using lua_errorT = void (__cdecl *)(uintptr_t *, const char *);
|
||||
using lua_settopT = void (__fastcall *)(uintptr_t *, int);
|
||||
using lua_newtableT = void (__fastcall *)(uintptr_t *);
|
||||
using lua_settableT = void (__fastcall *)(uintptr_t *, int);
|
||||
|
||||
using Spell_C_CooldownEventTriggeredT = void (__fastcall *)(uint32_t spellId,
|
||||
uint64_t *targetGUID,
|
||||
@@ -147,6 +150,8 @@ namespace Nampower {
|
||||
void *callbackPtr,
|
||||
int category, char unk2, int unk3);
|
||||
|
||||
using InvalidFunctionPtrCheckT = void (__fastcall *)(uint32_t param_1);
|
||||
|
||||
void RegisterLuaFunction(char *, uintptr_t *func);
|
||||
|
||||
void LuaCall(const char *code);
|
||||
|
||||
+10
-14
@@ -49,6 +49,7 @@ enum class Offsets : std::uint32_t {
|
||||
AutoRepeatingSpellId = 0xCEAC30,
|
||||
VisualSpellId = 0X00CEAC58,
|
||||
GetSpellSlotAndType = 0X004B3950,
|
||||
GetSpellSlotFromLua = 0X004B3EC0,
|
||||
OsGetAsyncTimeMs = 0X0042B790,
|
||||
ChannelTargetGuid = 0xC4D980,
|
||||
NameplateDistance = 0xC4D988, // float containing the distance squared ready to be pythagorean'd
|
||||
@@ -124,20 +125,6 @@ enum class Offsets : std::uint32_t {
|
||||
Script_RunScript = 0x0048B980,
|
||||
Script_SpellStopCasting = 0x006E6E80,
|
||||
|
||||
// Added script functions
|
||||
Script_QueueSpellByName = 0x004B4B38, // unused address at the end of Script_CastSpellByName. Need to be < 0x7FEDAC to avoid Invalid Function Pointer
|
||||
Script_CastSpellByNameNoQueue = 0X004B4B64,
|
||||
Script_QueueScript = 0X0048B968, // unused address at the end of Script_StopCinematic
|
||||
Script_IsSpellInRange = 0x004E76D8,
|
||||
Script_IsSpellUsable = 0X004E77A4,
|
||||
Script_GetCurrentCastingInfo = 0X004E77F8,
|
||||
Script_GetSpellIdForName = 0X004E7828,
|
||||
Script_GetSpellNameAndRankForId = 0X004E7844,
|
||||
Script_GetSpellSlotTypeIdForName = 0X004E784A,
|
||||
Script_ChannelStopCastingNextTick = 0X004E7858,
|
||||
Script_GetNampowerVersion = 0X004E7874,
|
||||
Script_GetItemLevel = 0X004E787A,
|
||||
|
||||
lua_state_ptr = 0x7040D0,
|
||||
|
||||
lua_isstring = 0x006F3510,
|
||||
@@ -152,6 +139,11 @@ enum class Offsets : std::uint32_t {
|
||||
lua_pcall = 0x006F41A0,
|
||||
lua_error = 0X006F4940,
|
||||
lua_settop = 0X006F3080,
|
||||
lua_newtable = 0x006F3C90,
|
||||
lua_settable = 0x006F3E20,
|
||||
lua_pushboolean = 0x006F39F0,
|
||||
lua_rawseti = 0x006F3EA0,
|
||||
lua_gettop = 0x006F3070,
|
||||
|
||||
|
||||
CGInputControlGetActive = 0XBE1148,
|
||||
@@ -177,4 +169,8 @@ enum class Offsets : std::uint32_t {
|
||||
CGUnit_C_ClearSpellEffect = 0x00614150,
|
||||
|
||||
CGPlayer_C_OnAttackIconPressed = 0X006131A0,
|
||||
|
||||
DBCache_ItemCacheDBGetRow = 0x0055BA30,
|
||||
|
||||
InvalidFunctionPtrCheck = 0x0042A320,
|
||||
};
|
||||
|
||||
+364
-41
@@ -4,6 +4,10 @@
|
||||
|
||||
#include "scripts.hpp"
|
||||
#include "offsets.hpp"
|
||||
#include "items.hpp"
|
||||
#include "dbc_fields.hpp"
|
||||
#include "helper.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace Nampower {
|
||||
auto const lua_error = reinterpret_cast<lua_errorT>(Offsets::lua_error);
|
||||
@@ -14,38 +18,17 @@ namespace Nampower {
|
||||
auto const lua_tostring = reinterpret_cast<lua_tostringT>(Offsets::lua_tostring);
|
||||
auto const lua_tonumber = reinterpret_cast<lua_tonumberT>(Offsets::lua_tonumber);
|
||||
|
||||
auto const lua_pushnumber = reinterpret_cast<lua_pushnumberT>(Offsets::lua_pushnumber);
|
||||
auto const lua_pushstring = reinterpret_cast<lua_pushstringT>(Offsets::lua_pushstring);
|
||||
// Export Lua functions for dbc_fields.hpp templates
|
||||
lua_pushnumberT lua_pushnumber = reinterpret_cast<lua_pushnumberT>(Offsets::lua_pushnumber);
|
||||
lua_pushstringT lua_pushstring = reinterpret_cast<lua_pushstringT>(Offsets::lua_pushstring);
|
||||
lua_newtableT lua_newtable = reinterpret_cast<lua_newtableT>(Offsets::lua_newtable);
|
||||
lua_settableT lua_settable = reinterpret_cast<lua_settableT>(Offsets::lua_settable);
|
||||
|
||||
bool gScriptQueued;
|
||||
int gScriptPriority = 1;
|
||||
char *queuedScript;
|
||||
|
||||
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType) {
|
||||
auto const getSpellSlotAndType = reinterpret_cast<GetSpellSlotAndTypeT>(Offsets::GetSpellSlotAndType);
|
||||
return getSpellSlotAndType(spellName, spellType);
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetSpellIdFromSpellName(const char *spellName) {
|
||||
uint32_t bookType;
|
||||
uint32_t spellSlot = GetSpellSlotAndTypeForName(spellName, &bookType);
|
||||
|
||||
uint32_t spellId = 0;
|
||||
if (spellSlot < 1024) {
|
||||
if (bookType == 0) {
|
||||
spellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownSpells) +
|
||||
spellSlot * 4);
|
||||
} else {
|
||||
spellId = *reinterpret_cast<uint32_t *>(uint32_t(Offsets::CGSpellBook_mKnownPetSpells) +
|
||||
spellSlot * 4);
|
||||
}
|
||||
}
|
||||
|
||||
return spellId;
|
||||
}
|
||||
|
||||
uint32_t Script_CastSpellByNameNoQueue(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_CastSpellByNameNoQueue(uintptr_t *luaState) {
|
||||
DEBUG_LOG("Casting next spell without queuing");
|
||||
// turn on forceQueue and then call regular CastSpellByName
|
||||
gNoQueueCast = true;
|
||||
@@ -56,7 +39,7 @@ namespace Nampower {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Script_QueueSpellByName(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_QueueSpellByName(uintptr_t *luaState) {
|
||||
DEBUG_LOG("Force queuing next cast spell");
|
||||
// turn on forceQueue and then call regular CastSpellByName
|
||||
gForceQueueCast = true;
|
||||
@@ -78,7 +61,7 @@ namespace Nampower {
|
||||
return spellStopCasting(luaState);
|
||||
}
|
||||
|
||||
uint32_t Script_IsSpellInRange(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_IsSpellInRange(uintptr_t *luaState) {
|
||||
auto param1IsString = lua_isstring(luaState, 1);
|
||||
auto param1IsNumber = lua_isnumber(luaState, 1);
|
||||
if (param1IsString || param1IsNumber) {
|
||||
@@ -150,7 +133,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_IsSpellUsable(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_IsSpellUsable(uintptr_t *luaState) {
|
||||
auto param1IsString = lua_isstring(luaState, 1);
|
||||
auto param1IsNumber = lua_isnumber(luaState, 1);
|
||||
if (param1IsString || param1IsNumber) {
|
||||
@@ -204,7 +187,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_GetCurrentCastingInfo(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_GetCurrentCastingInfo(uintptr_t *luaState) {
|
||||
auto const castingSpellId = reinterpret_cast<uint32_t *>(Offsets::CastingSpellId);
|
||||
lua_pushnumber(luaState, *castingSpellId);
|
||||
|
||||
@@ -246,7 +229,7 @@ namespace Nampower {
|
||||
return 7;
|
||||
}
|
||||
|
||||
uint32_t Script_GetSpellIdForName(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_GetSpellIdForName(uintptr_t *luaState) {
|
||||
if (lua_isstring(luaState, 1)) {
|
||||
auto const spellName = lua_tostring(luaState, 1);
|
||||
auto const spellId = GetSpellIdFromSpellName(spellName);
|
||||
@@ -259,7 +242,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_GetSpellNameAndRankForId(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_GetSpellNameAndRankForId(uintptr_t *luaState) {
|
||||
if (lua_isnumber(luaState, 1)) {
|
||||
auto const spellId = uint32_t(lua_tonumber(luaState, 1));
|
||||
auto const spell = game::GetSpellInfo(spellId);
|
||||
@@ -271,7 +254,7 @@ namespace Nampower {
|
||||
return 2;
|
||||
} else {
|
||||
DEBUG_LOG("Spell not found for id: " << spellId);
|
||||
lua_error(luaState, "Spell not found");
|
||||
lua_error(luaState, "Spell not found");
|
||||
}
|
||||
} else {
|
||||
lua_error(luaState, "Usage: GetSpellNameAndRankForId(spellId)");
|
||||
@@ -280,7 +263,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_GetSpellSlotTypeIdForName(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_GetSpellSlotTypeIdForName(uintptr_t *luaState) {
|
||||
if (lua_isstring(luaState, 1)) {
|
||||
auto const spellName = lua_tostring(luaState, 1);
|
||||
uint32_t bookType;
|
||||
@@ -330,7 +313,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_ChannelStopCastingNextTick(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_ChannelStopCastingNextTick(uintptr_t *luaState) {
|
||||
if (gCastData.channeling) {
|
||||
DEBUG_LOG("ChannelStopCastingNextTick activated, canceling next tick");
|
||||
gCastData.cancelChannelNextTick = true;
|
||||
@@ -339,7 +322,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_GetNampowerVersion(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_GetNampowerVersion(uintptr_t *luaState) {
|
||||
lua_pushnumber(luaState, MAJOR_VERSION);
|
||||
lua_pushnumber(luaState, MINOR_VERSION);
|
||||
lua_pushnumber(luaState, PATCH_VERSION);
|
||||
@@ -347,7 +330,7 @@ namespace Nampower {
|
||||
return 3;
|
||||
}
|
||||
|
||||
uint32_t Script_GetItemLevel(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_GetItemLevel(uintptr_t *luaState) {
|
||||
if (lua_isnumber(luaState, 1)) {
|
||||
auto const itemId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
|
||||
@@ -380,7 +363,7 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Script_QueueScript(hadesmem::PatchDetourBase *detour, uintptr_t *luaState) {
|
||||
uint32_t Script_QueueScript(uintptr_t *luaState) {
|
||||
DEBUG_LOG("Trying to queue script");
|
||||
|
||||
auto const currentTime = GetTime();
|
||||
@@ -418,7 +401,7 @@ namespace Nampower {
|
||||
return runScript(luaState);
|
||||
}
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RunQueuedScript(int priority) {
|
||||
@@ -440,4 +423,344 @@ namespace Nampower {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Script_GetItemStats(uintptr_t *luaState) {
|
||||
if (!lua_isnumber(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: GetItemStats(itemId)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t itemId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
|
||||
// Load item if not cached
|
||||
LoadItem(itemId);
|
||||
|
||||
// Get from cache
|
||||
game::ItemStats_C *item = GetItemStats(itemId);
|
||||
if (!item) {
|
||||
lua_error(luaState, "Item not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create new table
|
||||
lua_newtable(luaState);
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
PushFieldsToLua(luaState, item, itemStatsFields, itemStatsFieldsCount);
|
||||
|
||||
// Push string fields manually (require language)
|
||||
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
|
||||
lua_pushstring(luaState, const_cast<char *>("displayName"));
|
||||
lua_pushstring(luaState,
|
||||
item->m_displayName[language] ? item->m_displayName[language] : const_cast<char *>(""));
|
||||
lua_settable(luaState, -3);
|
||||
|
||||
lua_pushstring(luaState, const_cast<char *>("description"));
|
||||
lua_pushstring(luaState, item->m_description ? item->m_description : const_cast<char *>(""));
|
||||
lua_settable(luaState, -3);
|
||||
|
||||
// Push all array fields using descriptors
|
||||
PushArrayFieldsToLua(luaState, item, itemStatsArrayFields, itemStatsArrayFieldsCount);
|
||||
|
||||
return 1; // Return the table
|
||||
}
|
||||
|
||||
uint32_t Script_GetSpellRec(uintptr_t *luaState) {
|
||||
if (!lua_isnumber(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: GetSpellRec(spellId)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t spellId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
|
||||
// Get spell info
|
||||
auto spell = game::GetSpellInfo(spellId);
|
||||
if (!spell) {
|
||||
lua_error(luaState, "Spell not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create new table
|
||||
lua_newtable(luaState);
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
PushFieldsToLua(luaState, spell, spellRecFields, spellRecFieldsCount);
|
||||
|
||||
// Push string fields manually (require language)
|
||||
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
|
||||
lua_pushstring(luaState, const_cast<char *>("name"));
|
||||
lua_pushstring(luaState, spell->SpellName[language] ? const_cast<char *>(spell->SpellName[language])
|
||||
: const_cast<char *>(""));
|
||||
lua_settable(luaState, -3);
|
||||
|
||||
lua_pushstring(luaState, const_cast<char *>("rank"));
|
||||
lua_pushstring(luaState, reinterpret_cast<const char *>(spell->Rank[language])
|
||||
? const_cast<char *>(reinterpret_cast<const char *>(spell->Rank[language]))
|
||||
: const_cast<char *>(""));
|
||||
lua_settable(luaState, -3);
|
||||
|
||||
// Push all array fields using descriptors
|
||||
PushArrayFieldsToLua(luaState, spell, spellRecArrayFields, spellRecArrayFieldsCount);
|
||||
|
||||
return 1; // Return the table
|
||||
}
|
||||
|
||||
uint32_t Script_GetItemStatsField(uintptr_t *luaState) {
|
||||
if (!lua_isnumber(luaState, 1) || !lua_isstring(luaState, 2)) {
|
||||
lua_error(luaState, "Usage: GetItemStatsField(itemId, fieldName)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
InitializeFieldMaps();
|
||||
|
||||
uint32_t itemId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
const char *fieldName = lua_tostring(luaState, 2);
|
||||
|
||||
// Load item if not cached
|
||||
LoadItem(itemId);
|
||||
|
||||
// Get from cache
|
||||
game::ItemStats_C *item = GetItemStats(itemId);
|
||||
if (!item) {
|
||||
lua_pushnumber(luaState, 0); // Return nil/false to indicate not found
|
||||
return 1;
|
||||
}
|
||||
|
||||
// O(1) hash table lookup for simple fields
|
||||
auto simpleIt = itemStatsFieldMap.find(fieldName);
|
||||
if (simpleIt != itemStatsFieldMap.end()) {
|
||||
size_t i = simpleIt->second;
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(item) + itemStatsFields[i].offset;
|
||||
|
||||
switch (itemStatsFields[i].type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const int32_t *>(fieldPtr));
|
||||
return 1;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const uint32_t *>(fieldPtr));
|
||||
return 1;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const float *>(fieldPtr));
|
||||
return 1;
|
||||
case FieldType::STRING: {
|
||||
const char *str = *reinterpret_cast<const char *const *>(fieldPtr);
|
||||
lua_pushstring(luaState, str ? const_cast<char *>(str) : const_cast<char *>(""));
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// O(1) hash table lookup for array fields
|
||||
auto arrayIt = itemStatsArrayFieldMap.find(fieldName);
|
||||
if (arrayIt != itemStatsArrayFieldMap.end()) {
|
||||
size_t i = arrayIt->second;
|
||||
const auto &field = itemStatsArrayFields[i];
|
||||
lua_newtable(luaState);
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(item) + field.offset;
|
||||
|
||||
for (size_t j = 0; j < field.count; ++j) {
|
||||
lua_pushnumber(luaState, j + 1);
|
||||
|
||||
switch (field.type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const int32_t *>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const uint32_t *>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const float *>(fieldPtr)[j]);
|
||||
break;
|
||||
default:
|
||||
lua_pushnumber(luaState, 0);
|
||||
break;
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check for special string fields
|
||||
if (strcmp(fieldName, "displayName") == 0) {
|
||||
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
|
||||
lua_pushstring(luaState,
|
||||
item->m_displayName[language] ? item->m_displayName[language] : const_cast<char *>(""));
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(fieldName, "description") == 0) {
|
||||
lua_pushstring(luaState, item->m_description ? item->m_description : const_cast<char *>(""));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Field not found
|
||||
lua_error(luaState, "Unknown field name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_GetSpellRecField(uintptr_t *luaState) {
|
||||
if (!lua_isnumber(luaState, 1) || !lua_isstring(luaState, 2)) {
|
||||
lua_error(luaState, "Usage: GetSpellRecField(spellId, fieldName)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
InitializeFieldMaps();
|
||||
|
||||
uint32_t spellId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
const char *fieldName = lua_tostring(luaState, 2);
|
||||
|
||||
// Get spell info
|
||||
auto spell = game::GetSpellInfo(spellId);
|
||||
if (!spell) {
|
||||
lua_pushnumber(luaState, 0); // Return nil/false to indicate not found
|
||||
return 1;
|
||||
}
|
||||
|
||||
// O(1) hash table lookup for simple fields
|
||||
auto simpleIt = spellRecFieldMap.find(fieldName);
|
||||
if (simpleIt != spellRecFieldMap.end()) {
|
||||
size_t i = simpleIt->second;
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(spell) + spellRecFields[i].offset;
|
||||
|
||||
switch (spellRecFields[i].type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const int32_t *>(fieldPtr));
|
||||
return 1;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const uint32_t *>(fieldPtr));
|
||||
return 1;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, *reinterpret_cast<const float *>(fieldPtr));
|
||||
return 1;
|
||||
case FieldType::UINT64:
|
||||
lua_pushnumber(luaState, static_cast<double>(*reinterpret_cast<const uint64_t *>(fieldPtr)));
|
||||
return 1;
|
||||
case FieldType::STRING: {
|
||||
const char *str = *reinterpret_cast<const char *const *>(fieldPtr);
|
||||
lua_pushstring(luaState, str ? const_cast<char *>(str) : const_cast<char *>(""));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// O(1) hash table lookup for array fields
|
||||
auto arrayIt = spellRecArrayFieldMap.find(fieldName);
|
||||
if (arrayIt != spellRecArrayFieldMap.end()) {
|
||||
size_t i = arrayIt->second;
|
||||
const auto &field = spellRecArrayFields[i];
|
||||
lua_newtable(luaState);
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(spell) + field.offset;
|
||||
|
||||
for (size_t j = 0; j < field.count; ++j) {
|
||||
lua_pushnumber(luaState, j + 1);
|
||||
|
||||
switch (field.type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const int32_t *>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const uint32_t *>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const float *>(fieldPtr)[j]);
|
||||
break;
|
||||
default:
|
||||
lua_pushnumber(luaState, 0);
|
||||
break;
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check for special string fields
|
||||
if (strcmp(fieldName, "name") == 0) {
|
||||
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
|
||||
lua_pushstring(luaState, spell->SpellName[language] ? const_cast<char *>(spell->SpellName[language])
|
||||
: const_cast<char *>(""));
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(fieldName, "rank") == 0) {
|
||||
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
|
||||
lua_pushstring(luaState, reinterpret_cast<const char *>(spell->Rank[language])
|
||||
? const_cast<char *>(reinterpret_cast<const char *>(spell->Rank[language]))
|
||||
: const_cast<char *>(""));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Field not found
|
||||
lua_error(luaState, "Unknown field name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetSpellSlotFromLuaHook(hadesmem::PatchDetourBase *detour, int param_1, uint32_t *slot, uint32_t *type) {
|
||||
// Get Lua state pointer
|
||||
uintptr_t *luaState = GetLuaStatePtr();
|
||||
|
||||
// Check if first parameter is not a number
|
||||
if (lua_isnumber(luaState, 1) == 0) {
|
||||
const char *spellStr = lua_tostring(luaState, 1);
|
||||
|
||||
// Check if string starts with "spellId:" (case-insensitive)
|
||||
if (_strnicmp(spellStr, "spellId:", 8) == 0) {
|
||||
// Extract spell ID from string
|
||||
uint32_t spellId = atoi(spellStr + 8);
|
||||
|
||||
if (spellId > 0) {
|
||||
// Check if second parameter has "pet"
|
||||
uint32_t bookType = 0;
|
||||
if (lua_isstring(luaState, 2)) {
|
||||
const char *bookTypeStr = lua_tostring(luaState, 2);
|
||||
if (_strcmpi(bookTypeStr, "pet") == 0) {
|
||||
bookType = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t spellSlot = ConvertSpellIdToSpellSlot(spellId, bookType);
|
||||
if(!spellSlot){
|
||||
lua_error(luaState, "Unable convert spell id to spell slot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (slot) {
|
||||
*slot = spellSlot;
|
||||
}
|
||||
if (type) {
|
||||
*type = bookType; // Use the requested bookType
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
lua_error(luaState, "Unable parse spell id. Format is spellId:123.");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
uint32_t bookType;
|
||||
auto spellSlot = GetSpellSlotAndTypeForName(spellStr, &bookType);
|
||||
// returns large number if spell not found
|
||||
if (spellSlot == 0 || spellSlot > 100000) {
|
||||
lua_error(luaState, "Unable to find spell slot for spell name.");
|
||||
return 0;
|
||||
} else {
|
||||
if (slot) {
|
||||
*slot = spellSlot;
|
||||
}
|
||||
if (type) {
|
||||
*type = bookType;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
auto const getSpellSlotFromLua = detour->GetTrampolineT<GetSpellSlotFromLuaT>();
|
||||
// Fall back to original function
|
||||
return getSpellSlotFromLua(param_1, slot, type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-12
@@ -8,31 +8,41 @@
|
||||
#include "main.hpp"
|
||||
|
||||
namespace Nampower {
|
||||
uint32_t Script_CastSpellByNameNoQueue(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_CastSpellByNameNoQueue(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_QueueSpellByName(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_QueueSpellByName(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_IsSpellInRange(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_IsSpellInRange(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_IsSpellUsable(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_IsSpellUsable(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_SpellStopCastingHook(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetCurrentCastingInfo(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_GetCurrentCastingInfo(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetSpellIdForName(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_GetSpellIdForName(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetSpellNameAndRankForId(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_GetSpellNameAndRankForId(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetSpellSlotTypeIdForName(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_GetSpellSlotTypeIdForName(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_ChannelStopCastingNextTick(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_ChannelStopCastingNextTick(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetNampowerVersion(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_GetNampowerVersion(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetItemLevel(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_GetItemLevel(uintptr_t *luaState);
|
||||
|
||||
bool Script_QueueScript(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint32_t Script_QueueScript(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetItemStats(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetSpellRec(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetItemStatsField(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_GetSpellRecField(uintptr_t *luaState);
|
||||
|
||||
uint32_t GetSpellSlotFromLuaHook(hadesmem::PatchDetourBase *detour, int param_1, uint32_t *slot, uint32_t *type);
|
||||
|
||||
bool RunQueuedScript(int priority);
|
||||
}
|
||||
@@ -704,13 +704,4 @@ namespace Nampower {
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CGPlayer_C_OnAttackIconPressedHook(hadesmem::PatchDetourBase *detour, uintptr_t *this_ptr, void *dummy_edx,
|
||||
uint64_t guid) {
|
||||
auto const onAttackIconPressed = detour->GetTrampolineT<CGPlayer_C_OnAttackIconPressedT>();
|
||||
|
||||
DEBUG_LOG("Attack icon pressed for guid " << guid);
|
||||
|
||||
return onAttackIconPressed(this_ptr, dummy_edx, 0);
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,4 @@ namespace Nampower {
|
||||
CDataStore *packet);
|
||||
|
||||
int PlaySpellVisualHandlerHook(hadesmem::PatchDetourBase *detour, uint32_t *opCode, CDataStore *packet);
|
||||
|
||||
int CGPlayer_C_OnAttackIconPressedHook(hadesmem::PatchDetourBase *detour, uintptr_t *this_ptr, void *dummy_edx,
|
||||
uint64_t guid);
|
||||
}
|
||||
Reference in New Issue
Block a user