This exploit worked in several cities across Norrath and Luclin. Need to make the macro work in another city? It's simple! Just write up a simple INI file, and off it goes to make you thousands of platinum!
It combines very fast, buys and sells when it needs to, and supports random pathing. (There are 3 forges in the Bazaar.. you wouldn't want to look like you were macroing by going to the same one over and over again would you?)
Credits, in no particular:
-cronic for help starting the project and writing the original macro until I overhauled it.
-Dont_Know_At_All for the original tradeskill code. Got the idea from your code.
-Kaitain and Diggler for the great recipes.ini.
-Kint for his GoToLoc macro.
Here's the code, commented for your reading pleasure.. Enjoy!
Also included a few INI files I used. :)
Synaxt: /macro makesheets <inifile> [starting path]
makesheets.mac
Code: Select all
| MakeSheets.
#turbo
#event Full "There was no place to put that"
#event Error "You cannot combine these items in this container type!"
#event Failure "You lacked the skills"
#event Success "You have fashioned the items together to create something new"
Sub Main
| - Declare global variables.
/declare cursor global
/declare phase array
/declare count1 global
/declare count2 global
/declare inifile global
/declare recipefile global
/declare path global
/varset cursor FALSE
| - Define INI filename.
/if $defined(Param0)==FALSE /call EndMacro "You must specify an INI file."
/varset inifile @Param0
/varset recipefile $ini(@inifile,Settings,RecipeINI)
| - Check random pathing settings.
/if $ini(@inifile,Settings,RandomPathing)==FALSE {
/if $defined(Param1)==FALSE {
/echo Starting path not defined, using default.
/varset path 0
}
} else {
/varset path @Param1
}
/if $ini(@inifile,Settings,RandomPathing)==TRUE {
/if $defined(Param1)==FALSE {
/echo Starting path not defined, using default.
/varset path 0
}
} else {
/varset path 0
}
| - Checks for recipe list in INI file.
/if $ini(@inifile,Recipes)~~NOTFOUND /call EndMacro "Recipes list not defined in INI file."
| - Opens your bags.
/if $ini(@inifile,Settings,OpenPacks)==TRUE /call Packs
| - Main Loop
:Loop
/if $envopen=="ENVIRO_NOT_OPEN" /call OpenEnviro "Forge" "$ini(@inifile,Settings,ContainerInUse)"
/if $return=="INUSE" /goto :BuySell
/call DoRecipes
/echo Finished making sheets... returning to merchant.
/click left enviro done
:BuySell
/call BuySell
/goto :Loop
/return
| - This is the order in which the main functions of the macro are executed.
Sub BuySell
/if n $count("Water Flask")<$ini(@inifile,Settings,WaterLow) {
/call WalkPath "ForgeToWater" "FALSE"
/call OpenMerchant "$ini(@inifile,Settings,WaterMerchant)"
/call Barter "buy" "Water Flask" "$ini(@inifile,Settings,WaterMax)"
/if "$ini(@inifile,Settings,WaterMerchant)"!="$ini(@inifile,Settings,OreMerchant)" {
/click left merchant done
/call WalkPath "WaterToOre" "FALSE"
}
/goto :Skip
}
/call WalkPath "ForgeToOre" "FALSE"
/if "$ini(@inifile,Settings,WaterMerchant)"=="$ini(@inifile,Settings,OreMerchant)" /call WalkPath "ForgeToWater" "FALSE"
:Skip
/call OpenMerchant "$ini(@inifile,Settings,OreMerchant)"
/call Barter "sell" "Medium Quality Folded Sheet Metal"
/delay 5
/call Barter "buy" "Small Brick of Medium Quality Ore"
/echo Finished buying and selling.. returning to forge.
/call WalkPath "OreToForge" "$ini(@inifile,Settings,RandomPathing)"
/return
| - This sub grabs the recipes from your recipes.ini file.
Sub DoRecipes
/varset phase(1) 1
:Loop
/if "$ini(@inifile,Recipes,Recipe$int(@phase(1)))"==NOTFOUND /return
/varset phase(0) "$ini(@inifile,Recipes,Recipe$int(@phase(1)))"
/echo Excuting recipe $ini(@inifile,Recipes,Recipe$int(@phase(1)))...
/call TradeSkills "$ini(@inifile,Recipes,Recipe$int(@phase(1)))"
/varadd phase(1) 1
/goto :Loop
/return
| - This sub goes through the recipe entry and puts each item into the forge.
Sub TradeSkills(recipe)
/if "$ini(@recipefile,@recipe))"~~NOTFOUND /Call EndMacro "Could not find @recipe in Recipe INI file."
:Begin
/call CleanPack
/call ClearCursor "FALSE"
/doevents
/call Pause
/varset count1 0
:Loop
/if "$ini(@recipefile,@recipe,Comp$int(@count1))"==NOTFOUND /goto :Combine
/if n $count("$ini(@recipefile,@recipe,Comp$int(@count1))")==0 /goto :End
/call AddComponent "$ini(@recipefile,@recipe,Comp$int(@count1))" "@count1"
/varadd count1 1
/goto :Loop
:Combine
/call DoCombine
:CheckProduct
/doevents
/if @cursor==FALSE /goto :CheckProduct
/varset cursor FALSE
/goto :Begin
:End
/call CleanPack
/call ClearCursor "FALSE"
/return
| - Adds items to an enviromental container given itemname and slot.
Sub AddComponent(item,slot)
/sendkey down ctrl
:Loop
/finditem "@item"
/if $cursor()==NULL /goto :Loop
/click left enviro @slot
/sendkey up ctrl
/if $cursor()!=NULL /call ClearCursor "FALSE"
/return
| - Clicks combine button until combine registers.
sub DoCombine
:Loop
/varset count1 0
/click left enviro combine
/doevents
:Check
/if $pack(e,empty)==FALSE {
/if @count1>5 /goto :Loop
/varadd count1 1
/delay 1
/goto :Check
}
/delay 1
/return
| - Opens the enviromental container given itemname.
Sub OpenEnviro(item,action)
/varset count1 0
:Loop
/if $envopen=="@item" /return
/itemtarget forge
/face fast nolook
/click left item
:Check
/varadd count1 1
/delay 10
/if $envopen=="@item" /return
/if n @count1==5 {
/if @action==WAIT /varset count1 0
/goto :Loop
}
/if n @count1==10 /goto :Loop
/if n @count1>=15 {
/echo Screw it..
/return INUSE
}
/goto :Check
/return
| - Opens a merchant given merchantname.
Sub OpenMerchant(merchant)
:Check
/target @merchant
/call GoToLoc "$target(y),$target(x)" "5"
/face fast nolook
/click right target
/delay 10
/if $merchant(open)==FALSE /goto :Check
/if $merchant("@merchant")==FALSE {
/click left merchant done
/goto :Check
}
/return
| - This sub will buy or sell any amount of any given item.
Sub Barter(action,item,amount)
/echo $if(@action==sell,Sell,Buy)ing @item...
/if @action==sell /goto :Sell
:Check
/delay 10
/selectitem "@item" merchant
/delay 3
/if "$selecteditem()"!="@item" {
/if @action==buy /echo Cannot find @item...
/return
}
/if @action==buy /goto :Buy
:Sell
/if n $count("@item")<=0 /return
/delay 1
/finditem "@item"
/delay 1
/if "$selecteditem()"!="@item" /return
/sellitem $if($selecteditem(count)>=1,$selecteditem(count),1)
/delay 3
/goto :Sell
:Buy
/if $defined(amount)==FALSE /goto :FillUp
/if n $count("@item")>=@amount /return
:StackLoop
/if n $calc(@amount-$count("@item"))<=20 /goto :RegLoop
/buyitem $if($selecteditem(count)==1,20,1)
/delay 3
/goto :StackLoop
:FillUp
/if n $freeinv(space)<2 /return
/buyitem $if($selecteditem(count)==1,20,1)
/delay 3
/goto :FillUp
:RegLoop
/if n $calc(@amount-$count("@item"))<=0 /return
/buyitem $if($selecteditem(count)==1,$calc(@amount-$count("@item")),1)
/delay 3
/goto :RegLoop
/return
| - Will walk a path listed in the INI file, given pathname. Random is used when randomize pathing is enabled.
Sub WalkPath(pathname,random)
/call PickPath "@pathname" "@random"
/varset count1 1
/echo Excuting path $ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Name)
:Loop
/if $ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))==NOTFOUND /return
/if $left(4,$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1)))==DOOR /goto :Door
/call GoToLoc "$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))" "2"
/delay 1
/varadd count1 1
/goto :Loop
:Door
/call OpenDoor "$mid(5,$calc($instr(;,"$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))")-5),"$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))")" "$right($calc($strlen("$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))")-$calc($instr(;,"$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))")+1)),"$ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path),Loc$int(@count1))")"
/delay 1
/varadd count1 1
/goto :Loop
/return
| - Picks a random path from any listed in the INI file with the same name ending in a number.
Sub PickPath(pathname,random)
/if @random==FALSE /return
/varset path 0
:Loop
/if $ini(@inifile,$left($strlen("@pathname"),"@pathname")$int(@path))~~NOTFOUND /goto :Random
/delay 1
/varadd path 1
/goto :Loop
:Random
/if @path==0 /call EndMacro "Path not found."
/varset path $rand(@path)
/echo RANDOM @path
/return
| - Opens a door given a location behind the door and the door keyword.
Sub OpenDoor(location,keyword,check)
/face fast nolook loc @location
/doortarget @keyword
:Check
/press u
/delay 5
/if $door(open)==TRUE /return
/if "@check"=="nocheck" /goto :End
/delay 5
/goto :Check
:End
/delay 5
/return
| - Used in the WalkPath sub, will go to a location given location(x,y) and distance to ending point.
Sub GoToLoc(location,distance)
:Start
/if n $distance(@location)<=@distance /goto :End
/face nolook loc @location
/if n $distance(@location)>=@distance /sendkey down up
:Move
/delay 0
/if n $distance(@location)<=@distance /goto :End
/face fast nolook loc @location
/if n $distance(@location)>=@distance /goto :Move
:End
/sendkey up up
/return
| - Opens or closes all of the bags in your inventory.
Sub Packs(action)
/varset count1 0
:Loop
/if @count1>=8 {
/press i
/return
}
/if $pack(@count1,open)==NULL {
/varadd count1 1
/goto :Loop
}
/if @action==CLOSE /goto :Close
:Open
/if $pack(@count1,open)==FALSE {
/if $invpanel==FALSE /windowstate inventory open
/click right inv @count1
/goto :Open
}
/varadd count1 1
/goto :Loop
:Close
/if $pack(@count1,open)==TRUE {
/if $invpanel==FALSE /windowstate inventory open
/click right inv @count1
/goto :Close
}
/varadd count1 1
/goto :Loop
/return
| - Cleans on the enviromental container incase there is an error in a combine attempt.
Sub CleanPack
/if $pack(e,empty)==TRUE /return
/varset count1 0
/press ctrl
/sendkey down shift
/delay 1
:Loop
/if n @count1==10 /goto :End
/if $item(e,@count1)==TRUE {
/echo $int(@count1) slot
/delay 1
/click left enviro $int(@count1)
/call ClearCursor "FALSE"
}
/varadd count1 1
/goto :Loop
:End
/sendkey up shift
/press shift
/return
| - Clears your cursor of items by dropping them into your inventory or destroying them.
Sub ClearCursor(clear)
/if @clear==TRUE /varset cursor @clear
:Loop
/if $ini(@inifile,Settings,DestroyItems)==TRUE /call DestroyItem
/autoinv
/if $cursor()!=NULL {
/delay 1
/goto :Loop
}
/return
| - Destroys an item on your cursor if not listed in the INI file.
Sub DestroyItem
/varset count2 1
:Loop
/if "$ini(@inifile,NoDestroy,Item$int(@count2))"==NOTFOUND /goto :Destroy
/if "$ini(@inifile,NoDestroy,Item$int(@count2))"=="$cursor(name)" /return
/varadd count2 1
/goto :Loop
:Destroy
/if n @count2==1 /call EndMacro "Must define a list of items no destory if DestroyItems is on."
/if "$cursor(name)"==NULL /return
/echo Destroying $cursor(name)...
/destroy
/return
Sub Event_Full
/call CleanPack
/Call EndMacro "Your inventory is full."
/endmacro
/return
Sub Event_Error
/delay 1
/call ClearCursor "TRUE"
/call CleanPack
/return
Sub Event_Success
:Loop
/if $cursor()==NULL /goto :Loop
/call ClearCursor "TRUE"
/varset cursor TRUE
/return
Sub Event_Failure
:Loop
/if @phase(0)==MQFoldedSheet {
/if $cursor()==NULL /goto :Loop
}
/call ClearCursor "TRUE"
/delay 1
/varset cursor TRUE
/return
| - Pause sub routine.
Sub Pause
/if "$target(name,clean)"!="$char(name)" /return
/echo Pausing!! To resume, type /target clear or target something else.
:HoldingPattern
/delay 20
/if "$target(name,clean)"=="$char(name)" /goto :HoldingPattern
/return
| - Error reporting.
Sub EndMacro(error)
/echo @error
/echo An error has occured.. ending macro.
/endmacro
/return
template.ini
Code: Select all
| MakeSheets INI Template.
[Settings]
| - Name of your recipe INi file.
RecipeINI=recipes
| - Open all bags when you start the macro?
OpenPacks=TRUE
| - Use randomized pathing?
RandomPathing=FALSE
| - Destroy items not listed on your NoDestroy list?
DestroyItems=TRUE
| - What would you like to do if your enviromental container is in use?
ContainerInUse=WAIT
| - Name of water merchant.
WaterMerchant=WaterMerchant_01
| - How low should your water supply get before you return to the merchant to get more?
WaterLow=0
| - Amount of water to buy.
WaterMax=0
| - Name of ore merchant.
OreMerchant=OreMerchant_01
| - List of recipes to execute.
[Recipes]
Recipe1=MQLargeBrick
Recipe2=MQBlock
Recipe3=MQFoldedSheet
| - Items not to destory.
[NoDestroy]
Item1=Smithy Hammer
Item2=Water Flask
Item3=Small Brick of Medium Quality Ore
Item4=Large Brick of Medium Quality Ore
item5=Medium Quality Folded Sheet Metal
Item6=Block of Medium Quality Ore
| - In pathing, you must specify each x and y in the format x,y.
| - Doors are in the following format: DOOR:x,y,;keyword .
|
| - If you wish to use random paths you will need a different
| path with the same name and a different ending number.
| In this example we have OreToForge0 and OreToForge1. When
| the macro chooses a random path, it will pick between 0 or 1.
| - 0 is the default path, thus it must exsist. 1,2,3 etc are for
| randomized pathing.
| - Path from the ore merchant to the forge
[OreToForge0]
Name=OreToForge
Loc1=00,00
Loc2=DOOR:00,00;door1
Loc3=00,00
[OreToForge1]
Name=OreToForge
Loc1=00,00
Loc2=DOOR:00,00;door1
Loc3=00,00
| - Path from the forge to the ore merchant.
| If the ore and water are on the same merchant, such
| as in the Bazaar or in Kaladim, you do not need a
| ForgeToOre or WaterToOre path.
[ForgeToOre0]
Name=ForgeToOre
Loc1=00,00
Loc2=DOOR:00,00;door1
Loc3=00,00
[ForgeToOre1]
Name=ForgeToOre
Loc1=00,00
Loc2=DOOR:00,00;door1
Loc3=00,00
| - Path from the forge to the water merchant.
[ForgeToWater0]
Name=ForgeToWater
Loc1=00,00
Loc2=DOOR:68,-867;door1
Loc3=00,00
[ForgeToWater1]
Name=ForgeToWater
Loc1=00,00
Loc2=DOOR:68,-867;door1
Loc3=00,00
| - Path from water merchant to forge.
[WaterToOre0]
Name=WaterToOre
Loc1=00,00
Loc2=DOOR:00,00;door1
Loc3=00,00
[WaterToOre1]
Name=WaterToOre
Loc1=00,00
Loc2=DOOR:00,00;door1
Loc3=00,00
neriak.ini
Code: Select all
| Settings for Neriak - Commons.
[Settings]
RecipeINI=recipes
OpenPacks=TRUE
RandomPathing=FALSE
DestroyItems=TRUE
ContainerInUse=WAIT
WaterMerchant=Dunred M`Trik
WaterLow=40
WaterMax=200
OreMerchant=Treven Ru`Soe
[Recipes]
Recipe1=MQLargeBrick
Recipe2=MQBlock
Recipe3=MQFoldedSheet
[NoDestroy]
Item1=Smithy Hammer
Item2=Water Flask
Item3=Small Brick of Medium Quality Ore
Item4=Large Brick of Medium Quality Ore
item5=Medium Quality Folded Sheet Metal
Item6=Block of Medium Quality Ore
[OreToForge0]
Name=OreToForge
Loc1=35,-902
Loc2=DOOR:34,-890;door1
Loc3=34,-890
Loc4=20,-877
[ForgeToOre0]
Name=ForgeToOre
Loc1=34,-890
Loc2=DOOR:35,-902;door1
Loc3=35,-902
Loc4=49,-907
[ForgeToWater0]
Name=ForgeToWater
Loc1=35,-867
Loc2=DOOR:68,-867;door1
Loc3=68,-867
[WaterToOre0]
Name=WaterToOre
Loc1=47,-867
Loc2=DOOR:35,-867;door1
Loc3=35,-867
Loc4=34,-890
Loc5=DOOR:35,-902;door1
Loc6=35,-902
Loc7=49,-907
bazaar.ini
Code: Select all
| Settings for The Bazaar
[Settings]
RecipeINI=recipes
OpenPacks=TRUE
RandomPathing=TRUE
DestroyItems=FALSE
ContainerInUse=LEAVE
WaterMerchant=Gliblixl Rocktok
WaterLow=40
WaterMax=60
OreMerchant=Gliblixl Rocktok
[Recipes]
Recipe1=MQLargeBrick
Recipe2=MQBlock
Recipe3=MQFoldedSheet
[NoDestroy]
Item1=Smithy Hammer
Item2=Water Flask
Item3=Small Brick of Medium Quality Ore
Item4=Large Brick of Medium Quality Ore
item5=Medium Quality Folded Sheet Metal
Item6=Block of Medium Quality Ore
[OreToForge0]
Name=Stable forge
Loc1=-681,-28
Loc2=-569,-6
Loc3=-568,89
Loc4=-539,177
Loc5=-519,208
[ForgeToWater0]
Name=Stable forge
Loc1=-519,208
Loc2=-539,177
Loc3=-568,89
Loc4=-569,-6
Loc5=-681,-28
[OreToForge1]
Name=Arena forge
Loc1=-683,-29
Loc2=-569,-7
Loc3=-573,-126
Loc4=-373,-138
Loc5=-349,-111
[ForgeToWater1]
Name=Arena forge
Loc1=-349,-111
Loc2=-373,-138
Loc3=-573,-126
Loc4=-569,-7
Loc5=-683,-29
katta.ini
Code: Select all
| Settings for Katta Castellum.
[Settings]
RecipeINI=recipes
OpenPacks=TRUE
RandomPathing=FALSE
DestroyItems=FALSE
ContainerInUse=WAIT
WaterMerchant=Kitty Barleou
WaterLow=40
WaterMax=200
OreMerchant=Bole Bricktop
[Recipes]
Recipe1=MQLargeBrick
Recipe2=MQBlock
Recipe3=MQFoldedSheet
[NoDestroy]
Item1=Smithy Hammer
Item2=Water Flask
Item3=Small Brick of Medium Quality Ore
Item4=Large Brick of Medium Quality Ore
item5=Medium Quality Folded Sheet Metal
Item6=Block of Medium Quality Ore
[OreToForge0]
Name=OreToForge
Loc1=40,-1526
Loc2=18,-1535
[ForgeToOre0]
Name=ForgeToOre
Loc1=40,-1526
Loc2=54,-1535
[ForgeToWater0]
Name=ForgeToWater
Loc1=-13,-1530
Loc2=DOOR:-13,-1577;kat
Loc3=-13,-1577
Loc4=199,-1601
Loc5=351,-1444
Loc6=329,-1243
Loc7=DOOR:276,-1248;kat
Loc8=276,-1248
Loc9=225,-1117
[WaterToOre0]
Name=WaterToOre
Loc1=276,-1248
Loc2=DOOR:329,-1243;kat
Loc3=329,-1243
Loc4=351,-1444
Loc5=199,-1601
Loc6=-13,-1577
Loc7=DOOR:-13,-1530;kat
Loc8=-13,-1530
Loc9=40,-1526
Loc10=54,-1535
recipes.ini Entries:
Code: Select all
[MQLargeBrick]
Cont=Enviro
Comp0=Small Brick Of Medium Quality Ore
Comp1=Small Brick Of Medium Quality Ore
Comp2=Small Brick Of Medium Quality Ore
Comp3=Water Flask
[MQBlock]
cont=Enviro
Comp0=Large Brick of Medium Quality Ore
Comp1=Large Brick of Medium Quality Ore
Comp2=Large Brick of Medium Quality Ore
comp3=Water Flask
[MQFoldedSheet]
Cont=Enviro
Comp0=Block Of Medium Quality Ore
Comp1=Smithy Hammer
Comp2=Water Flask
Go ahead, give it a try. :)
Cheers,
Lestor




