Page 1 of 2

/MEMSPELL FIXED!

Posted: Tue Jul 08, 2003 6:26 pm
by EqMule
Ok a while ago, I set out to fix all the non working functions in mq that Plaz once had working, and it was actually thanks to him I was able to fix this good old one! So all say WB to /memspell it was surely missed!

More will come, Im still working on the merchantstuff...

NOTE! the cyan text is the section under which you paste the code, it doesnt mean you can paste it directly under that section, just a pointer to get you started, if you look in the section you will see lines that looks like the code you are going to insert, and you need to paste it under a similar line... also note that some lines might allready exist... just replace them, and you can replace the whole old memspell function in EQLib_Commands.cpp with this new one as well

ok here goes-> (DKAA will hang me for not learning the diff thing yet...)

in EQLib.h :
// ***************************************************************************
// EQ Addresses
// ***************************************************************************

Code: Select all

extern DWORD *EQADDR_SPELLBOOKWND;
//*******************************************************
// EQ Functions
// *******************************************************

Code: Select all

extern fEQMemSpell	      cmdMemSpell;

in EQLib_Commands.cpp :
// ***************************************************************************
// Function: MemSpell
// Description: Our '/MemSpell' command
// Usage: /MemSpell gem# "spell name"
// ***************************************************************************

Code: Select all

VOID MemSpell(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	bRunNextCommand = FALSE;
	DWORD SpellBookWnd = *EQADDR_SPELLBOOKWND; 
	CHAR szBuffer[MAX_STRING] = {0};
	CHAR szGem[MAX_STRING] = {0};
	WORD Gem = -1;
	CHAR SpellName[MAX_STRING] = {0};
	PCHARINFO pCharInfo = NULL;
	DWORD ID,GEMSLOT;

	if (!SpellBookWnd || !cmdMemSpell) return;
	if (NULL == (pCharInfo = GetCharInfo())) return;

	GetArg(szGem,szLine,1);
	GetArg(SpellName,szLine,2);
	Gem = atoi(szGem);
	if (Gem<1 || Gem>8) return;
	Gem--;
	if (pCharInfo->MemorizedSpells[Gem]!=0xFFFFFFFF) return; [color=green]//Im gonna put in dememcode here instead of returning, be patient...[/color]
	
	PSPELLLIST pSpell = GetSpellByName(SpellName);
	if (!pSpell) {
		sprintf(szBuffer,"Unable to find Spell '%s'",SpellName);
		WriteChatBuffer(szBuffer,CONCOLOR_RED);
		return;
	}
	if (pSpell->Level[pChar->Class-1]>pChar->Level) {
		sprintf(szBuffer,"You need to be level '%d' to memorize that spell ",pSpell->Level[pChar->Class-1]);
		WriteChatBuffer(szBuffer,CONCOLOR_RED);
		return;
	}
	ID = (DWORD)pSpell->ID;
	GEMSLOT = (DWORD)Gem;
	sprintf(szBuffer,"Memorizing spell '%d' in slot '%x' ",pSpell->ID, GEMSLOT+1); 
    WriteChatBuffer(szBuffer,USERCOLOR_DEFAULT);
	
	__asm {
	 push ecx; 
	 mov ecx, dword ptr [SpellBookWnd]; 
	 push GEMSLOT; 
	 push ID;
	 call dword ptr [cmdMemSpell]; 
	 pop ecx;
	}
	return;	
}
in EQLib_Interp.cpp :
// ***************************************************************************
// Function: TakeControlOfCommandList
// Description: Creates custom command list with our commands
// Points help/parsing at our list
// ***************************************************************************

Code: Select all

		{"/memspell",	"MemSpell"},
in EQLib_Main.cpp :
// EQ Address Initialization

Code: Select all

DWORD *EQADDR_SPELLBOOKWND;
// EQ Functions Initialization

Code: Select all

fEQMemSpell	      cmdMemSpell	 =  NULL;
// ***************************************************************************
// Function: ParseINIFile
// Description: Parse INI file for memory locations
// ***************************************************************************

Code: Select all

	GetPrivateProfileString("Function Locations","MemSpell","0",szBuffer,MAX_STRING,ClientINI);			cmdMemSpell = (fEQMemSpell)strtoul(szBuffer,NULL,16);

	GetPrivateProfileString("Class Locations","SpellBookWnd","0",szBuffer,MAX_STRING,ClientINI);		EQADDR_SPELLBOOKWND = (DWORD *)strtoul(szBuffer,NULL,16);
in MQ.h :
// ***************************************************************************
// Everquest function typedefs
// ***************************************************************************

Code: Select all

typedef VOID    (__cdecl *fEQMemSpell)(DWORD,DWORD);
// ***************************************************************************
// Exports
// ***************************************************************************

Code: Select all

extern "C" EQLIB_API VOID  MemSpell       (PSPAWNINFO, PCHAR);
in eqgame.ini :

Code: Select all

[Function Locations]
MemSpell=004F626C

[Class Locations]
SpellBookWnd=005FE258 
OK any feedback for making the code cleaner/better will be appreaciated, Im not a mastercoder by any means...

[edit] updated with new offsets for patch on july 10 2003

Posted: Tue Jul 08, 2003 6:33 pm
by BlueSkies
Wow, EqMule's on a roll!

Posted: Tue Jul 08, 2003 6:46 pm
by wassup
Added in and get the following errors:

\Compile\macroquest\Release\EQLib.res
Creating library ..\Release/EQLib.lib and object ..\Release/EQLib.exp
EQLib_Commands.obj : error LNK2001: unresolved external symbol "unsigned long * EQADDR_SPELLBOOKWND" (?EQADDR_SPELLBOOKWND@@3PAKA)
EQLib_Main.obj : error LNK2001: unresolved external symbol "unsigned long * EQADDR_SPELLBOOKWND" (?EQADDR_SPELLBOOKWND@@3PAKA)
..\Release/EQLib.dll : fatal error LNK1120: 1 unresolved externals

Tried it 3 times and get the same errors.

Any ideas?

Posted: Tue Jul 08, 2003 7:26 pm
by BlueSkies
Are you sure you put everything where he said it should go?

Don't mean to be rude -- but I had very similar problems, and it was because I had misread the text. Once I pulled my eyes back into focus (I really think I need glasses or something), I moved the code to where it needed to go and it compiled fine, and works great! :)

Try it again, and pay very special attention to where you put everything. I was successful by adding the additions to the ends of all the sections he mentioned, not the tops. Give that a try, and see how it goes for you.

Good luck with it. Let us know how it goes.

Posted: Tue Jul 08, 2003 7:42 pm
by dont_know_at_all
I'm pretty sure a

Code: Select all

DWORD *EQADDR_SPELLBOOKWND;
is missing from eqlib_main.cpp

Posted: Tue Jul 08, 2003 8:16 pm
by BlueSkies
Doesn't

extern DWORD *EQADDR_SPELLBOOKWND;

take care of that though?

Or am I mistaken? Probably am... :P

Posted: Tue Jul 08, 2003 8:31 pm
by EqMule
dont_know_at_all wrote:I'm pretty sure a

Code: Select all

DWORD *EQADDR_SPELLBOOKWND;
is missing from eqlib_main.cpp
yeah you are correct, I missed that... damn!, original post updated now...

Posted: Tue Jul 08, 2003 9:00 pm
by BlueSkies
Oh I know why it worked for me, then... I had already updated my source with Plaz's, and that must have been in there somewhere. :)

Posted: Tue Jul 08, 2003 9:08 pm
by dont_know_at_all
Updated in CVS and on the downloads page.

Untested, since I don't have my EQ machine available at the moment.

Posted: Tue Jul 08, 2003 9:09 pm
by wassup
Thank you, that did the trick :)

This is a great fix and many thanks...

Posted: Tue Jul 08, 2003 9:40 pm
by EqMule
dont_know_at_all wrote:Updated in CVS and on the downloads page.
Appreciate that, many thanks! :D

Posted: Tue Jul 08, 2003 10:07 pm
by Plazmic
Aww man, I can't post while at work, so i couldn't mention this until now..

The favorite function can be faked, and you can auto-mem a spell using it (fixes unmemming issue)... and it only uses the offsets from my other post ;)

Code: Select all

SPELLFAVORITE MemSpellFavorite;
VOID MemSpell(PSPAWNINFO pChar, PCHAR szLine)
{
	if (!EQADDR_SPELLBOOKWND || !cmdLoadSpells) return;
	DWORD Favorite = (DWORD)&MemSpellFavorite;
	CHAR szGem[MAX_STRING] = {0};
	DWORD sp;
	WORD Gem = -1;
	CHAR SpellName[MAX_STRING] = {0};
	PCHARINFO pCharInfo = NULL;
	DWORD SpellBookWnd = *EQADDR_SPELLBOOKWND;
	if (!SpellBookWnd) return;
	if (NULL == (pCharInfo = GetCharInfo())) return;

	GetArg(szGem,szLine,1);
	GetArg(SpellName,szLine,2);
	Gem = atoi(szGem);
	if (Gem<1 || Gem>8) return;
	Gem--;

	PSPELLLIST pSpell = GetSpellByName(SpellName); 
	if (!pSpell) return;
	if (pSpell->Level[pChar->Class-1]>pChar->Level) return;

	ZeroMemory(&MemSpellFavorite,sizeof(MemSpellFavorite));
	strcpy(MemSpellFavorite.Name,"Mem a Spell");
	MemSpellFavorite.Byte_3A=1;
	for (sp=0;sp<8;sp++) MemSpellFavorite.SpellId[sp]=0xFFFFFFFF;
	MemSpellFavorite.SpellId[Gem] = pSpell->ID;

	__asm {
		push ecx;
		mov ecx, dword ptr [SpellBookWnd];
		push 8;
		push dword ptr [Favorite];
		call dword ptr [cmdLoadSpells];
		pop ecx;
	}
}

Posted: Tue Jul 08, 2003 10:36 pm
by macrotoon
OH MY GOD!

I was coming to this forum to ask how you track things like this in EQ. Meaning how can you find what commands and such are given to the server when you memorize a spell. Im such a newbie when it comes to this kind of stuff, but this little project was gonna keep me busy. DAMN YOU EQ MULE! hehe

Good work!

Posted: Tue Jul 08, 2003 11:35 pm
by fwiggles
wow GJ Plaz and EQMule...i don't play a caster, but if i did this would be somethin i would definately use :D

Posted: Wed Jul 09, 2003 3:11 am
by wassup
Both of these functions do the same thing?

If so which is going to be permanent in the CVS?