SpellsToBuy.mac [tells you what spells you need to buy]

Post your completed (working) macros here. Only for macros using MQ2Data syntax!

Moderator: MacroQuest Developers

Sparr
a hill giant
a hill giant
Posts: 159
Joined: Mon Jun 24, 2002 5:41 am

SpellsToBuy.mac [tells you what spells you need to buy]

Post by Sparr » Tue Jul 27, 2004 5:23 am

this macro lists all the spells you should have in your spellbook but dont. right now it makes a number of mistakes, but they arent fixable without access to more of the SPELL struct. the known problems:

no deity check, so youll see all the imbue spells for your class.
no 'real spell' check, so you will see a FEW item procs and NPC spells, although most of those are flagged level 255 so you shouldnt see many.
no expansion checks, so youll see all the LOY and LDON spells if you dont have those expansions.

I ran this for a character of mine with a mostly full pre-LOY spellbook for his level, only missing low level spells that have been added since he levelled up. It reported 27 missing spells. 2 were spells I actually needed to get, 1 was for another deity, 8 were non-PC spells, and the remaining 16 were LOY and LDON spells. Not the best signal:noise ratio, but definitely usable and useful.

Code: Select all

|Usage: 
| /macro spellstobuy
|  lists every spell to be bought
| /macro spellstobuy <level>
|  lists every level <level> spell to be bought
| /macro spellstobuy <minlevel> <maxlevel>
|  lists every level <minlevel> to level <maxlevel> spell to be bought

Sub Main(int LevelMin, int LevelMax)
 /declare x int local
 /for x 1 to 5499
  /if (!${Me.Book[${Spell[${x}]}]}&&${Spell[${x}].Level}<=${Me.Level}) {
   /if (${LevelMax}) {
    /if (${Spell[${x}].Level}<=${LevelMax}&&${Spell[${x}].Level}>=${LevelMin}) {
     /call SpellInfo ${x}
    }
   } else /if (${LevelMin}) {
    /if (${Spell[${x}].Level}==${LevelMin}) {
     /call SpellInfo ${x}
    }
   } else {
    /call SpellInfo ${x}
   }
  }
 /next x
/return

Sub SpellInfo(int SpellNum)
 /echo ${Spell[${SpellNum}]}   Level:${Spell[${SpellNum}].Level}  Type:${Spell[${SpellNum}].SpellType}  Target:${Spell[${SpellNum}].TargetType}
/return
 
UPDATE 2004.08.03: Added level restriction options
Last edited by Sparr on Tue Aug 03, 2004 2:31 am, edited 1 time in total.

Sparr
a hill giant
a hill giant
Posts: 159
Joined: Mon Jun 24, 2002 5:41 am

Post by Sparr » Sun Aug 01, 2004 4:37 pm

changed the name of the macro, since someone let me know the old name poorly indicated the purpose of the macro.

id appreciate feedback, especially regarding any mistakes it makes that I did not list above.

User avatar
Cr4zyb4rd
Plugins Czar
Posts: 1449
Joined: Tue Jul 20, 2004 11:46 am

Post by Cr4zyb4rd » Sun Aug 01, 2004 9:34 pm

This makes the exact same mistakes (the ones you'd expect, based on the issues you mentioned, like discs being included) as the "find needed spells" function that magelo provides, so you must have done it right :)

Could be cleaned up, but I don't really see the point, as it gives the information needed. It's not something anybody's likely to be using over and over again.

All it needs now is a GoGetMySpells that runs around to all the vendors, camps baz, and plows hard ldons until the spellbook is complete. :)

Onezero
a ghoul
a ghoul
Posts: 95
Joined: Thu Jan 01, 2004 1:19 pm
Location: Normal, IL
Contact:

Post by Onezero » Tue Aug 03, 2004 12:30 am

Sparr, you rule. This macro is great. Have tested it on 7 of my spell-using characters and it works perfectly. :)
.[b].[/b]:[b]:[/b] Onezero
"[i]Health is merely the slowest rate at which you can die.[/i]"

Sparr
a hill giant
a hill giant
Posts: 159
Joined: Mon Jun 24, 2002 5:41 am

Post by Sparr » Tue Aug 03, 2004 2:47 am

added level filter options

Tuna
a lesser mummy
a lesser mummy
Posts: 68
Joined: Mon Jul 21, 2003 4:10 pm

Post by Tuna » Tue Aug 03, 2004 11:23 am

Very useful, even for those of us who are anal retentive and have memorized every stat and spell for our toons. :)

BorealisSunbinder
orc pawn
orc pawn
Posts: 12
Joined: Thu Oct 17, 2002 6:28 pm

Thanks

Post by BorealisSunbinder » Sat Aug 07, 2004 11:29 am

Very useful snippet, once I saw this I ran it on all my spell casters. Who knew what I was missing? Thanks for making and posting.

JP5
a lesser mummy
a lesser mummy
Posts: 70
Joined: Tue Jul 06, 2004 10:32 pm

Post by JP5 » Tue Aug 17, 2004 9:52 pm

Works very nicely. One thing you could do to improve it is do /mqlog as well as /echo, so that you can "alphabetize" the list of spells you need by number.

Code: Select all

 /echo ${Spell[${SpellNum}]}   Level:${Spell[${SpellNum}].Level}
goes to

Code: Select all

 /echo ${Spell[${SpellNum}].Level]} ${Me.Class.ShortName} -- ${Spell[${SpellNum}]} 
/mqlog ${Spell[${SpellNum}].Level]} ${Me.Class.ShortName} -- ${Spell[${SpellNum}]}

User avatar
Night Hawk
a grimling bloodguard
a grimling bloodguard
Posts: 590
Joined: Fri Aug 13, 2004 4:56 pm

Post by Night Hawk » Thu Aug 19, 2004 4:35 am

I found changing the SpellInfo sub to this helps get rid of all that extra Unknown spell stuff :)

Code: Select all

Sub SpellInfo(int SpellNum)
   /if (${Spell[${SpellNum}].Level}!=0) {
      /echo ${Spell[${SpellNum}]}   Level:${Spell[${SpellNum}].Level}  Type:${Spell[${SpellNum}].SpellType}  Target:${Spell[${SpellNum}].TargetType}
   }
/return

Sparr
a hill giant
a hill giant
Posts: 159
Joined: Mon Jun 24, 2002 5:41 am

Post by Sparr » Thu Aug 19, 2004 4:41 am

ahh, most of those spells are level 255, didnt realize some of them were level 0. thanks for the fix.
[img]http://www.trifocus.net/~sparr/sparr_rotate_sig_16.gif[/img]

User avatar
Night Hawk
a grimling bloodguard
a grimling bloodguard
Posts: 590
Joined: Fri Aug 13, 2004 4:56 pm

Post by Night Hawk » Thu Aug 19, 2004 4:59 am

well just tested it on my char cuase I was bored, it returned the 4 GoD spells I don't have, some level 1 heal spell I don't have (I think it's in the tutorial), my discs, and 1 or 2 ldons spells. Everything else were Unknown Spells all labeled level 0

Chill
Contributing Member
Contributing Member
Posts: 435
Joined: Fri May 07, 2004 5:06 pm
Location: Erie, PA

Like it

Post by Chill » Thu Aug 19, 2004 8:57 am

Nice macro Sparr. I like the level options. My only suggestions are on the output:

1) First, I would clean up your output lines a little. I didnt like the repetitive "Level: Target: Type:" They made the lines longer and actually harder for me to read. I would suggest something like:

Code: Select all

Sub SpellInfo(int SpellNum) 
 /echo lvl ${Spell[${SpellNum}].Level}: ${Spell[${SpellNum}]}  (${Spell[${SpellNum}].SpellType})  ${Spell[${SpellNum}].TargetType}
/return
You can reformat to your taste of course, but I would definately suggest shorter.

2) The spells are displayed out of order. This is obviously because you're going through the spell ID's, but still it would be nice if they were listed by their level. My thought was that you could put the spell ID's into an array and put the display in a 1 to 65 loop at the end.

User avatar
blueninja
a grimling bloodguard
a grimling bloodguard
Posts: 541
Joined: Thu Aug 28, 2003 7:03 am
Location: Göteborg, Sweden

Post by blueninja » Thu Aug 19, 2004 9:09 am

A suggestion that I for one would like to see. Have it look through the bank and inventory for the spell scrolls. Should be fairly simple, just use ${FindItemCount[=Spell: ${SpellName}]} and ${FindItemBankCount[=Spell: ${SpellName}]} and if it's >0 you have it. I always like to stock up on spells a bit before I reach a new level, so I can scribe them right away, this would help me do that.

EDIT: Bah, was bored and did it myself. :) It now lets you see spells above your level if you specify a levelmax (it will say (Above level) in the output) and it will look through your inventory and bank and say (In Bag) or (In Bank) if you have the scroll.

Code: Select all

Removed. See updated code below.
Last edited by blueninja on Thu Aug 19, 2004 12:24 pm, edited 1 time in total.

User avatar
aChallenged1
a grimling bloodguard
a grimling bloodguard
Posts: 1804
Joined: Mon Jun 28, 2004 10:12 pm

Post by aChallenged1 » Thu Aug 19, 2004 10:23 am

Nice initial work Sparr.

Great addition/changes blue. I do the same thing as you. I like to get spells before I ding so I can scribe them at the first opportunity.

Now all we need is a database (INI) with all normal spell vendors and which spells they sell. Unless someone is really bored, I don't see this happening.
Fuck writing MQ2 macros. Go with IS scripts; IS Rules!

User avatar
blueninja
a grimling bloodguard
a grimling bloodguard
Posts: 541
Joined: Thu Aug 28, 2003 7:03 am
Location: Göteborg, Sweden

Post by blueninja » Thu Aug 19, 2004 12:34 pm

Hope you don't mind me adding stuff to your macro. It's a great macro and I just thought of some features that would make it even better. Trying to make it the perfect script to use to fill up the spellbooks of my alts :). I've been rather bored today so I figured I might aswell add them myself instead of bugging you to do it.

Anyway, what I've done is that after it's searched it doesn't end, it waits for commands to be sent to it through /echo.
It will allow you to specify a maxlevel above your current level so you can see what spells you want to buy before you ding.
It will look for the scrolls in your bank and bags if the spell isn't in your spellbook and report that accordingly.

The commands availiable are:
Log
-writes the missing spells to a log file (/mqlog)

BuySpells
-if you have an open merchant window it will buy the spells you are missing that are in the merchant's inventory

Bazaar
-if you are in the bazaar it searches vendors for the spells you are missing and reports the lowest price

SearchVendor
-searches for spell merchants in inifiles made by Chill's macro

SearchVendorDump
-same as SearchVendor but it writes to logfile instead

SpellsToScribe
-lists the spells you have in your bags or bank that you are high enough to scribe but haven't yet

Might very well be a bug or two in there as I haven't tested it that much. Here's the code:

EDIT: Made it ask for confirmation before buying spells. Press shift+Y or shift+N to buy or pass.
EDIT: Added functionality to search for vendors in inifiles made by Chill's macro
EDIT: Made it work with bard songs too
EDIT: SpellsToScribe command added

Code: Select all

|Usage:
| /macro spellstobuy
|  lists every spell to be bought
| /macro spellstobuy <level>
|  lists every level <level> spell to be bought
| /macro spellstobuy <minlevel> <maxlevel>
|  lists every level <minlevel> to level <maxlevel> spell to be bought

#event Bazaar "[MQ2] Bazaar"
#event Merchant "[MQ2] BuySpells"
#event Log "[MQ2] Log"
#event SearchVendors "[MQ2] SearchVendors"
#event SearchVendorLog "[MQ2] SearchVendorDump"
#event SpellsToScribe "[MQ2] SpellsToScribe"

Sub Main(int LevelMin, int LevelMax)
 /declare x int local
 /declare MaxLevel int local
 /declare SpellsMissing int outer 0
 /declare SpellNames[256] string outer
 /declare SpellIDs[256] int outer
 /declare SpellLevels[256] int outer
 
 /if (!${Defined[STB_BuySpellStatus]}) /declare STB_BuySpellStatus int global

 /if (!${LevelMin}) {
 	/varset MaxLevel ${Me.Level}
 } else {
 	/varset MaxLevel ${LevelMax}
 }
 
 /for x 1 to 5499
  /if (!${Me.Book[${Spell[${x}]}]}) {
   /if (${MaxLevel}) {
    /if (${Spell[${x}].Level}<=${MaxLevel}&&${Spell[${x}].Level}>=${LevelMin}) {
     /call SpellInfo ${x}
    }
   } else /if (${LevelMin}) {
    /if (${Spell[${x}].Level}==${LevelMin}) {
     /call SpellInfo ${x}
    }
   } else {
    /call SpellInfo ${x}
   }
  }
 /next x
 
 /echo Search done, waiting for commands. Availiable commands are: Bazaar, BuySpells, SearchVendors, SearchVendorDump, SpellsToScribe and Log.
 
 :endlessloop
	/doevents
	/delay 1s
 /goto :endlessloop
 
/return

Sub Event_SpellsToScribe
	/declare Counter int local

	/for Counter 1 to ${SpellsMissing}
		/if (!${Me.Book[${Spell[${SpellIDs[${Counter}]}].Name}]} && ${Spell[${SpellIDs[${Counter}]}].Level}<=${Me.Level}) {
			/if (${FindItemCount[=${SpellNames[${Counter}]}]}) {
				/echo ${SpellNames[${Counter}]} is in inventory.
			}
			/if (${FindItemBankCount[=${SpellNames[${Counter}]}]}) {
				/echo ${SpellNames[${Counter}]} is in bank.
			}
		}
	/next Counter
		
	/echo Done looking for spells to scribe.
/return

Sub Event_SearchVendors
	/call SearchVendors 0
/return

Sub Event_SearchVendorLog
	/call SearchVendors 1
/return

Sub SearchVendors(bool Logging)
	/declare Counter int local
	/declare KeyList string local
	/declare KeyTemp string local
	/declare KeyCount int local
	/declare ZoneTemp string local
	/declare FoundSpells bool local 0
	
	/if (${Logging}) /mqlog ---------------------- Merchants with missing spells for ${Me.Name} --------------------------	
	/for Counter 1 to ${SpellsMissing}
		/if (!${FindItemCount[=${SpellNames[${Counter}]}]} && !${FindItemBankCount[=${SpellNames[${Counter}]}]}) {
			/varset KeyList ${Ini[SpellVendors.ini,${SpellIDs[${Counter}]}]}
			/if (${String[${KeyList}].NotEqual[NULL]}) {
				/varset KeyCount 1
				:MoreKeys
				/varset KeyTemp ${KeyList.Arg[${KeyCount},|]}
				/if (${String[${KeyTemp}].Equal[Null]}) /goto :NoMoreKeys
				/varset ZoneTemp ${Ini[SpellVendors.ini,${SpellIDs[${Counter}]},${KeyTemp},]}
				/varset FoundSpells 1
				/if (${Logging}) {
					/mqlog ${SpellNames[${Counter}]} available from ${KeyTemp} in ${ZoneTemp} at loc ${Ini[SpellVendorList.ini,${ZoneTemp},${KeyTemp}]}
				} else {
					/echo ${SpellNames[${Counter}]} available from ${KeyTemp} in ${ZoneTemp} at loc ${Ini[SpellVendorList.ini,${ZoneTemp},${KeyTemp}]}
				}
				/varcalc KeyCount ${KeyCount}+1
				/goto :MoreKeys
				:NoMoreKeys
			}
		}
	/next Counter
	/if (${Logging}) /mqlog ---------------------- End of merchants for ${Me.Name} ---------------------------------------
	/if (${Logging}) /echo Logging of merchants to ${Macro.Name}.log done.
	/echo Vendor search done. ${If[${FoundSpells},,No matches found.]}
/return

Sub Event_Merchant
	/if (!${Merchant.Open}) {
		/echo You need to open a merchant window.
		/return
	}
	/call BuySpells
/return

Sub BuySpells
	/if (!${Merchant.Open}) /return
	/squelch /custombind add BUYSPELLYES
	/squelch /custombind set BUYSPELLYES-up /varset STB_BuySpellStatus 1
	/squelch /bind BUYSPELLYES shift+y

	/squelch /custombind add BUYSPELLNO
	/squelch /custombind set BUYSPELLNO-up /varset STB_BuySpellStatus 0
	/squelch /bind BUYSPELLNO shift+n

	/if (!${Defined[STB_BuySpellStatus]}) /declare STB_BuySpellStatus int global

	/declare Counter int local
	/declare ItemCounter int local
	/declare ItemSlotNumber int local
	
	/for Counter 1 to ${SpellsMissing}
		/varset ItemSlotNumber 0
		/varset STB_BuySpellStatus 2
		/if (${Merchant.Item[=${SpellNames[${Counter}]}].ID} && !${FindItemCount[${SpellNames[${Counter}]}]} && !${FindItemBankCount[${SpellNames[${Counter}]}]}) {
			/for ItemCounter 1 to ${Merchant.Items}
				/if (${Merchant.Item[${ItemCounter}].Name.Equal[${SpellNames[${Counter}]}]}) /varset ItemSlotNumber ${ItemCounter}
			/next ItemCounter
			/if (${ItemSlotNumber}) {
				/echo Buy ${Merchant.Item[${ItemSlotNumber}].Name} for ${Math.Calc[${Merchant.Item[${ItemSlotNumber}].BuyPrice}\1000].Int}p ${Math.Calc[(${Merchant.Item[${ItemSlotNumber}].BuyPrice}\100)%10].Int}g ${Math.Calc[(${Merchant.Item[${ItemSlotNumber}].BuyPrice}\10)%10].Int}s ${Math.Calc[${Merchant.Item[${ItemSlotNumber}].BuyPrice}%10].Int}c? (Shift-Y / Shift-N)
				:WaitForSpellBuyResponse
				/if (${STB_BuySpellStatus}==2) {
					/delay 1
					/goto :WaitForSpellBuyResponse
				}
				/if (${STB_BuySpellStatus}==1) {
					/itemnotify merchant${ItemSlotNumber} leftmouseup
					/buyitem 1
					/delay 2s
				}
			}
		}
	/next Counter
	/echo Finished buying spells.
	/squelch /custombind delete BUYSPELLYES
	/squelch /custombind delete BUYSPELLNO
	/squelch /bind shift+y clear
	/squelch /bind shift+n clear
	/squelch /deletevar STB_BuySpellStatus
/return

Sub Event_Log
	/declare Counter int local
	/mqlog ------------------------ Missing Spells for ${Me.Name} ------------------------
	/for Counter 1 to ${SpellsMissing}
		/if (!${FindItemCount[=${SpellNames[${Counter}]}]} && !${FindItemBankCount[=${SpellNames[${Counter}]}]}) /mqlog ${Me.Name} is missing level ${SpellLevels[${Counter}]} ${SpellNames[${Counter}]}
	/next Counter
	/mqlog ------------------------ End of Spells for ${Me.Name} -------------------------
	/echo Logging to ${Macro.Name}.log done.
/return

Sub Event_Bazaar
	/if (${Zone.Name.NotEqual[The Bazaar]}) {
		/echo You need to be in The Bazaar to search.
		/return
	}
	/if (${String[${Plugin[MQ2Bzsrch]}].Equal[NULL]}) {
		/echo You need to load the mq2bzsrch plugin to search.
		/return
	}
	/call BazaarSearch
/return

Sub BazaarSearch
 /declare Counter int local
 /declare ItemCounter int local
 /declare CheapestPrice int local
 /declare CheapestVendor string local
 /declare FoundSpells bool local 0
 /echo Searching the bazaar for missing spells.
 
 /for Counter 1 to ${SpellsMissing}
	/if (!${FindItemCount[=${SpellNames[${Counter}]}]} && !${FindItemBankCount[=${SpellNames[${Counter}]}]}) {
		/varset CheapestPrice 0
	  :KeepSearching
	  /bzsrch race any class any stat any slot any type scroll price 0 9999999 "${SpellNames[${Counter}]}"
	  /delay 3s ${Bazaar.Done}
	  /if (!${Bazaar.Done}) /goto :KeepSearching
		/if (${Bazaar.Count}) {
			/for ItemCounter 1 to ${Bazaar.Count}
				/varset FoundSpells 1
				/if (!${CheapestPrice} || ${CheapestPrice}>${Bazaar.Item[${ItemCounter}].Price} && ${Bazaar.Item[${ItemCounter}].Name.Equal[${SpellNames[${Counter}]}]}) {
					/varset CheapestPrice ${Bazaar.Item[${ItemCounter}].Price}
					/varset CheapestVendor ${Bazaar.Item[${ItemCounter}].Trader.Name}
				}
			/next ItemCounter
			/echo ${SpellNames[${Counter}]} is sold by ${CheapestVendor} for ${Math.Calc[${CheapestPrice}\1000].Int}p ${Math.Calc[(${CheapestPrice}\100)%10].Int}g ${Math.Calc[(${CheapestPrice}\10)%10].Int}s ${Math.Calc[${CheapestPrice}%10].Int}c.
		}
	}
 /next Counter
 /echo Bazaar search done. ${If[${FoundSpells},,No matches found.]}
/return


Sub SpellInfo(int SpellNum)
 /declare SpellText string local
 /if (${Me.Class.Name.Equal[Bard]}) {
	/varset SpellText Song:
 } else {
	/varset SpellText Spell:
 }
 /declare InBank bool local ${FindItemBankCount[=${SpellText} ${Spell[${SpellNum}].Name}]}
 /declare InBag bool local ${FindItemCount[=${SpellText} ${Spell[${SpellNum}].Name}]}

| /if (!${InBank} && !${InBag}) {
	 /varcalc SpellsMissing ${SpellsMissing}+1
	 /varset SpellNames[${SpellsMissing}] ${SpellText} ${Spell[${SpellNum}].Name}
	 /varset SpellLevels[${SpellsMissing}] ${Spell[${SpellNum}].Level}
	 /varset SpellIDs[${SpellsMissing}] ${Spell[${SpellNum}].ID}
| }
 /echo ${Spell[${SpellNum}]} ${If[${Spell[${SpellNum}].Level}>${Me.Level},(Above level) ,]}${If[${InBag},(In Bag) ,]}${If[${InBank},(In Bank) ,]}Level:${Spell[${SpellNum}].Level}  Type:${Spell[${SpellNum}].SpellType}  Target:${Spell[${SpellNum}].TargetType}

/return 
Last edited by blueninja on Fri Aug 20, 2004 3:45 pm, edited 3 times in total.