(any addresses are from test server build Oct 27 2015)
Here is the normal run down of what happens when you cast a target ring spell.
Click gem, this will eventually call CastSpell where it will see it's got a target type of 45 and checks to see if pinstCEverQuest + 0x5c0 is null, if so it will create the TargetRing struct I posted above and return. You will have have your target ring on your screen. The TargetRing struct/class is created in the function at 0x551030 (which appears to be part of the CEverQuest class)
When you click (green or red reticle) it will call ProcessMouseEvents then CEverQuest::LMouseUp. In LMouseUp it checks if there is a target ring up at pinstCEverQuest + 0x5c0. If it is it will create another object (still need to decode this one, but the first 12 bytes are float X, float Y, float Z) in function at 0x5ffc90. This then calls the function at 0x585990 passing in the target ring object (so most likely part of this struct/class) and the newly created object that contains the location info. I haven't analyzed this function enough, but it will call CastSpell passing in the objected created in 0x5ffc90. CastSpell does do error checking and should safely return if we pass in a bad location, so we might be able to just create our own TargetRing object and place it in CEverQuest, create our own 0x5ffc90 object then call CastSpell without DBG knowing the difference, although it might be safest to emulate what a real person does to avoid any potential detection if they change stuff. Also worth noting that after returning from 0x585990 the client will delete the object at pinstCEverQuest + 0x5c0 and set it to null, so we will need to do this as well.
That's about all I've figured out so far.
Also this is what we have the RoF2 cast spell struct looking like on EQEmu (live looks the same, or mostly the same)
Rich (BB code):
struct CastSpell_Struct
{
/*00*/ uint32 slot;
/*04*/ uint32 spell_id;
/*08*/ ItemSlotStruct inventoryslot; // slot for clicky item, Seen unknown of 131 = normal cast
/*20*/ uint32 target_id;
/*24*/ uint32 cs_unknown[2];
/*32*/ float y_pos;
/*36*/ float x_pos;
/*40*/ float z_pos;
/*44*/
};
TL;DR we just really need to decode the struct created in 0x5ffc90 (test Oct 27 2015 client) or 0x5fe480 (live Oct 26 2015 client) and maybe fix up CastSpell.
Okay 0x5ffc90 is CTargetManager::Get()
EDIT:
Okay 0x600800 has something to do with making it red or green I think. -- it's the render method.
Here is the relevant stuff to target rings in CTargetManager
Rich (BB code):
//.text:005FFC99 push 1A4h ; size_t
//.text:005FFC9E call ??2@YAPAXI@Z ; operator new(uint)
struct CTargetManager {
/* 0x000 */ BYTE unknown[0x18c]; // other shit not used by target ring
/* 0x18c */ BYTE target_ring_in_foucs;
/* 0x18d */ BYTE padding[3];
/* 0x190 */ float target_ring_range; // squared for easier math
/* 0x194 */ float target_ring_x; // probably vec3 type class, this is whats passed to castspell
/* 0x198 */ float target_ring_y;
/* 0x19c */ float target_ring_z;
/* 0x1a0 */ BYTE target_ring_good; // red/green
/* 0x1a1 */ BYTE padding[3];
/* 0x1a4 */
};
- - - Updated - - -
Did some testing tonight, this appeared to work :P (ugly code is ugly)
Rich (BB code):
class CTargetRing {
public:
void Cast(int);
};
DWORD CTargetRing__Cast = FixOffset(0x585990);
FUNCTION_AT_ADDRESS(void CTargetRing::Cast(int), CTargetRing__Cast);
struct Vec3 { float Y; float X; float Z; };
VOID trcast(PSPAWNINFO pChar, PCHAR szLine)
{
if (!pTarget)
return;
//EzCommand("/cast 12");
CTargetRing *pTR = (CTargetRing *)((PEVERQUEST)pEverQuest)->TargetRing;
if (!pTR) {
WriteChatf("No Target Ring?");
return;
}
Vec3 test;
test.Y = ((PSPAWNINFO)pTarget)->Y;
test.X = ((PSPAWNINFO)pTarget)->X;
test.Z = ((PSPAWNINFO)pTarget)->Z;
pTR->Cast((int)&test);
// need to delete the target ring object here so it stops rendering
}
typing /trcast would cast the splash at my target

(I hit the spell gem first)