updatebazaarprices.mac

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

updatebazaarprices.mac

Post by Sparr » Tue Aug 17, 2004 2:25 am

to use this macro you need a small patch to the MQ source because '/notify .. .. newvalue ..' is broken, see the end of the post

Code: Select all

 |Update Bazaar Prices
 |by Sparr
 |
 |this macro updates the prices on all your /trader items to compete
 | with other prices found via /bazaar
 |
 |rare items are priced 1 standard deviation below the average price, minus 1
 |common items are priced the median of the below avg prices, minus 1
 |
 |price is then upped to 1pp below the next higher price
 |
 |more price algorithms can be added, perhaps using average deviation,
 | quartile prices, etc
 |
 |has a few quirks, id love to hear feedback with specific data and desired outcome
 |
 |"| foo" indicates commented out code
 |" |foo" indicates a real comment

Sub Main
 /declare slot int local
 /declare dupecheck int local
 /declare itemname string local
 /declare result int local
 /declare stddev int local
 /declare itemsfound int local
 /declare pricetotal int local
 /declare avgprice int local
 /declare minprice int local
 /declare avgdev int local
 /declare devhigh int local
 /declare quartprice int local
 /declare maxprice int local
 /declare price int local
 /declare fairprice int local
 /declare targetprice int local
 /declare newtargetprice int local
 
 |open the trader window
 :OpenTraderAgain
 /trader
 /delay 10s ${Window[BazaarWnd].Open}
 /if (!${Window[BazaarWnd].Open}) /goto :OpenTraderAgain
 
 |open the bazaar search window
 :OpenBazaarAgain
 /bazaar
 /delay 10s ${Window[BazaarSearchWnd].Open}
 /if (!${Window[BazaarSearchWnd].Open}) /goto :OpenBazaarAgain
 
 |update traders
 /delay 1
 /notify BazaarSearchWnd BZR_UpdatePlayerButton leftmouseup
 /delay 5s

 |loop through all 80 slots
 /varset slot -1
 :nextslot
  /varcalc slot ${slot}+1
  /if (${slot}>79) /goto :donewithslots

  |click on the current slot
  /notify BZW_BazaarSlotsWnd BZR_BazaarSlot${slot} leftmouseup
  |skip the slot if its empty
  /if (!${Window[BazaarWnd].Child[BZW_SetPrice_Button].Enabled}) /goto :nextslot
  |skip the slot if it doesnt have a price
  /if (!${Window[BazaarWnd].Child[BZW_Clear_Button].Enabled}) /goto :nextslot
  |get the name of the item in the current slot
  /varset itemname ${Window[BZW_BazaarSlotsWnd].Child[BZR_BazaarSlot${slot}].Tooltip}

  |dont do the same item twice
  /if (${slot}) {
   /for dupecheck 0 to ${Math.Calc[${slot}-1]}
    /if (${itemname.Equal[${Window[BZW_BazaarSlotsWnd].Child[BZR_BazaarSlot${dupecheck}].Tooltip}]}) /goto :nextslot
   /next dupecheck
  }

  |search the bazaar for this item
  :SearchBazaarAgain
  /bzsrch race any class any stat any slot any type any price 0 9999999 ${itemname}
  /delay 5s ${Bazaar.Done}
  /if (!${Bazaar.Done}) /goto :SearchBazaarAgain

  |skip this item if its not in /bazaar
  /if (!${Bazaar.Count}) /goto :nextslot

  |find average, min, max price
  /varset itemsfound 0
  /varset pricetotal 0
  /varset minprice 9999999
  /varset maxprice 0
  /for result 1 to ${Bazaar.Count}
   |make sure this is the right item
   /if (${Bazaar.Item[${result}].Name.Equal[${itemname}]}&&!${Me.Name.Equal[${Bazaar.Item[${result}].Trader.Name}]}) {
    /varcalc itemsfound ${itemsfound}+${Bazaar.Item[${result}].Quantity}
    /varcalc pricetotal ${pricetotal}+${Bazaar.Item[${result}].Price}*${Bazaar.Item[${result}].Quantity}

    /if (${Bazaar.Item[${result}].Price}<${minprice}) /varset minprice ${Bazaar.Item[${result}].Price}
    /if (${Bazaar.Item[${result}].Price}>${maxprice}) /varset maxprice ${Bazaar.Item[${result}].Price}
 
   }
  /next result
  |skip this item if its not in /bazaar
  /if (!${itemsfound}) /goto :nextslot
  /varset avgprice ${Math.Calc[${pricetotal}/${itemsfound}/1000].Int}
  /varset minprice ${Math.Calc[${minprice}/1000].Int}
  /varset maxprice ${Math.Calc[${maxprice}/1000].Int}
  

  
  |find stddev and avgdev
  /varset stddev 0
  /varset avgdev 0
  /for result 1 to ${Bazaar.Count}
   /if (${Bazaar.Item[${result}].Name.Equal[${itemname}]}&&!${Me.Name.Equal[${Bazaar.Item[${result}].Trader.Name}]}) {
    /varcalc stddev ${stddev}+((${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}-${avgprice})^2)*${Bazaar.Item[${result}].Quantity}
    /varcalc avgdev ${avgdev}+${Math.Abs[${Bazaar.Item[${result}].Price}-${avgprice}*1000]}*${Bazaar.Item[${result}].Quantity}
   }
  /next result
  /varset stddev ${Math.Calc[(${stddev}/${itemsfound})^.5]}
  /varset avgdev ${Math.Calc[${avgdev}/${itemsfound}/1000].Int}
  
|  |find 'fair price', the lowest price below the first quartile
|  |or 1pp below the lowest price if it IS the first quartile
|  /varset quartcount 0
|  /varset oldquartcount -1
|  /varset price ${minprice}
|  :fairpriceloop
|   /if (${quartcount}>${oldquartcount}) /varset quartprice ${Math.Calc[${price}-1]}
|   /varset oldquartcount ${quartcount}
|   /for result 1 to ${Bazaar.Count}
|    /if (${Bazaar.Item[${result}].Name.Equal[${itemname}]}&&!${Me.Name.Equal[${Bazaar.Item[${result}].Trader.Name}]}) {
|     /if (${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}==${price}) /varcalc quartcount ${quartcount}+${Bazaar.Item[${result}].Quantity}
|    }
|   /next result
|   /varcalc price ${price}+1
|  /if (${quartcount}<${Math.Calc[${itemsfound}/4]}&&${price}<=${avgprice}) /goto :fairpriceloop

  |find 'fair price'
  /varcalc quartprice (${avgprice}+${minprice})/2
  /varset fairprice 9999999
  /for result 1 to ${Bazaar.Count}
   /if (${Bazaar.Item[${result}].Name.Equal[${itemname}]}&&!${Me.Name.Equal[${Bazaar.Item[${result}].Trader.Name}]}) {
    /if (${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}>=${quartprice}&&${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}<${fairprice}) /varset fairprice ${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}
   }
  /next result
  
  |pick new price based on rarity, value, etc
  /if (${itemsfound}<15) {
   /varset targetprice ${Math.Calc[${avgprice}-${stddev}]}
   /varset targetprice ${If[${targetprice}<${minprice},${minprice},${targetprice}]}
  } else {
   /varset targetprice ${fairprice}
  }
  /varcalc targetprice ${targetprice}-1
  
  |check for underpriced item
  /if (${targetprice}<${Math.Calc[${SelectedItem.Value}/1050]}) {
     /echo Underpriced Goods!  ${itemname} for ${minprice}pp value:${Math.Calc[${SelectedItem.Value}/1050]} etc:(${avgprice},${targetprice},${stddev},${itemsfound})
     /varset targetprice ${Math.Calc[${SelectedItem.Value}/1000].Int}
  }

  |up the new price to 1pp below the next higher price
  /varset newtargetprice 9999999
  /for result 1 to ${Bazaar.Count}
   /if (${Bazaar.Item[${result}].Name.Equal[${itemname}]}&&!${Me.Name.Equal[${Bazaar.Item[${result}].Trader.Name}]}) {
    /if (${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}>${targetprice}&&${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}<${newtargetprice}) /varset newtargetprice ${Math.Calc[${Bazaar.Item[${result}].Price}/1000].Int}
   }
  /next result
  /varcalc targetprice ${newtargetprice}-1
   
|  /echo repricing ${itemname} from ${Window[BazaarWnd].Child[BZW_Money0].Text} to ${targetprice}

  |set new price in pp, only lamers use small coins in /trader
  :openqtywndagain
  /notify BazaarWnd BZW_Money0 leftmouseup
  /delay 5s ${Window[QuantityWnd].Open}
  /if (!${Window[QuantityWnd].Open}) /goto :openqtywndagain
  /delay 1
  /call NullSub ${Window[QuantityWnd].Child[QTYW_SliderInput].NewText[${targetprice}]}
  /delay 2
  /notify QuantityWnd QTYW_SliderInput enter
  /delay 1
  /notify BazaarWnd BZW_SetPrice_Button leftmouseup
  /delay 1
 /goto :nextslot
 :donewithslots
/return

Sub NullSub
/return
diff-ish patch for MQ2DataTypes.cpp:

Code: Select all

	case Text:
		GetCXStr(pWnd->WindowText,DataTypeTemp,MAX_STRING);
		Dest.Ptr=&DataTypeTemp[0];
		Dest.Type=pStringType;
		return true;
+	case NewText:
+		strcpy(pWnd->WindowText->Text,Index);
+		GetCXStr(pWnd->WindowText,DataTypeTemp,MAX_STRING);
+		Dest.Ptr=&DataTypeTemp[0];
+		Dest.Type=pStringType;
+		return true;
	case Tooltip:
		GetCXStr(pWnd->Tooltip,DataTypeTemp,MAX_STRING);
		Dest.Ptr=&DataTypeTemp[0];
		Dest.Type=pStringType;
		return true;
diff-ish patch for MQ2DataTypes.h:

Code: Select all

-		Items=31
+		Items=31,
+		NewText=32
	};
...
		TypeMember(Items);
+		TypeMember(NewText);//32
 	}
[img]http://www.trifocus.net/~sparr/sparr_rotate_sig_16.gif[/img]

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

Post by Sparr » Tue Aug 17, 2004 4:17 am

also, if anyone has a way to modify the price slider/input without a patch, id appreciate being clued in.
[img]http://www.trifocus.net/~sparr/sparr_rotate_sig_16.gif[/img]

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

Post by Onezero » Tue Aug 17, 2004 12:49 pm

Btw.. your sig is awesome....
.[b].[/b]:[b]:[/b] Onezero
"[i]Health is merely the slowest rate at which you can die.[/i]"

Fabolous1
a ghoul
a ghoul
Posts: 134
Joined: Sun Jun 27, 2004 12:44 am

Post by Fabolous1 » Tue Aug 17, 2004 1:29 pm

Onezero wrote:Btw.. your sig is awesome....
/Agree lol

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

Post by Sparr » Tue Aug 17, 2004 1:29 pm

lol, thanks. ive been considering redoing it with twice as many frames, so the animation is smoother. and i thought about making every second circle rotate the opposite way, so they all turn like gears touching each other.
[img]http://www.trifocus.net/~sparr/sparr_rotate_sig_16.gif[/img]

missingfiles
a hill giant
a hill giant
Posts: 224
Joined: Wed Jun 09, 2004 1:15 pm

Post by missingfiles » Tue Aug 17, 2004 2:36 pm

Few quick questions.

I looked over the macro quickly (im at work)

1) Does this macro have the ability to set lowest price cap on items?

2) Are you scanning each item and not skipping dups that are for sale on you Like 30 stacks of grobbs you scan each and every stack?

3) How often does this macro check the price? If just once could this be set to auto check every 30 mins if a varable is set to 1 or something?

Flame away its a great macro.

Also do you believe your patch should be included in the next zip or is this something that wouldnt be needed by other macros?

A+ sig btw

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

Post by Sparr » Tue Aug 17, 2004 2:46 pm

1) what do you mean by lowest price cap? what it does now is pretty safe against 'one guy selling for 10% of the going price' syndrome, since it starts at a quartile-ish price for the base.

2) i skip dupes, it only scans for each item once

3) it checks once. if you want it to check every 30 minutes you could easily add ':startover' to the beginning and '/delay 1800s' '/goto :startover' to the end.

no, i dont believe this patch belongs in the zip. despite it being a workaround for a known problem with the 'normal' functioning of MQ, it does so in a 'bad' way. the MQ devs have made it pretty clear that they do NOT want to include ways to write to MQData objects, since that makes hacking far too easy (
{"/mqdataset Me.X warptoX" is a possibility opened up by the mqdataset command that i am working on).
[img]http://www.trifocus.net/~sparr/sparr_rotate_sig_16.gif[/img]

missingfiles
a hill giant
a hill giant
Posts: 224
Joined: Wed Jun 09, 2004 1:15 pm

Post by missingfiles » Tue Aug 17, 2004 3:00 pm

Lowest price cap goes like this:

I run this script and my price lowers to 5pp

You run the script and it drops to 4pp

Again
again
soon were at 1pp or lower

Setting the price cap drop for each item in a ini we can set grobb liquidized meat at lowest 4pp then no matter what the script cant drop you below profit.

Also A highest price cap might be good also for those times when no one else is selling and you want your price to be 35pp insted of 10pp.

If no price lower and no price higher then read ini set to high price

its just checks and balances.

Its a safty feature for people like me who want the script to run over and over to check prices for hours at a time (I know afk bah to you it will give the buyers the best price at all times)

Semper-Fi
orc pawn
orc pawn
Posts: 17
Joined: Sun Jun 13, 2004 4:35 pm

Post by Semper-Fi » Tue Aug 17, 2004 4:35 pm

if there are two people running this mac will the item eventually end up being 1pp for both?

Sorry i believe this has already been asked, Will it check every item, is there a way to leave out specified items?

Thank you, Im just worried i know some poeple on ym server run a few mac's here and would suck to be competitng with another bot to sell my Feirce Heraldric for 1 plat lol

missingfiles
a hill giant
a hill giant
Posts: 224
Joined: Wed Jun 09, 2004 1:15 pm

Post by missingfiles » Tue Aug 17, 2004 4:53 pm

Im asking thiat question above and asking for a fix at the same time please read all posts.

Im asking for a max price cap as well as a low price cap. ATM lowering the price 10% will eventually get the item down to 1c if ran continusly and put into a loop with another person macroing.

BUT

At its current form this macro only runs once to update your items price it doesnt loop. So you have no fear to use it atm and have your item drop to 1c.

Q) Here is another question for the dev. What happends when there is no one else selling your item (say rusty dagger) what does this macro do then? Im assuming it doesnt set a price and just leaves it as 0 causing it not to be sold.

List of things that would be nice to add (IMO)
--------------------------------------------------------
1) Price Caps (Set [Name Of Item] [Low Price] [High price] in an ini file that is checked every update to make sure your current price is with in allowed range)
2) Loop ability (can be manually added in by user but would be nice at top of macro let user set a varable eather 0 or 1)
Last edited by missingfiles on Tue Aug 17, 2004 5:17 pm, 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 » Tue Aug 17, 2004 5:03 pm

this macro will only get into a 'death loop' if you and someone else are both running it, AND no one else is selling the item. if someone else is selling it then youd both end up cycling in an interesting pattern between (thirdguysprice) and (thirdguysprice)/2, because eventually one of you would fall below the 'too cheap' threshold and the other would get bumped back up to (thirdguysprice)-1, starting the loop over again.

and, as a last resort, it will never sell an item for less than you can get from a vendor for it (notice it even /echo's a notice if the chosen price is that low, possibility for profit if you go BUY those items from other people and dump em on a vendor).
[img]http://www.trifocus.net/~sparr/sparr_rotate_sig_16.gif[/img]

missingfiles
a hill giant
a hill giant
Posts: 224
Joined: Wed Jun 09, 2004 1:15 pm

Post by missingfiles » Tue Aug 17, 2004 5:34 pm

The likly hood of a death loop is very slim and the check vs sellable twards a merchant is a good idea only problem is that with tradskill made items the price can get well below profit thats why a ini file with low cap would be awsome ( Hard lock is alwase good)

Sparr dont take what im saying as your macro sucks etc, honestly its well written and im sorry if im nit picking. If I want the changes done ill make them my self was just putting some ideas your way in the chance you might agree they were good.

Process
a lesser mummy
a lesser mummy
Posts: 73
Joined: Fri Jun 25, 2004 5:30 pm

Post by Process » Wed Aug 25, 2004 1:20 pm

Sorry for being a n00b, but I have a question...To run this macro, do I have to recompile using a new MQ2DataTypes.cpp file and a new MQ2DataTypes.h file? How do I go about doing that? Do I just replace the sourcecode's files with the files you posted above, or am I supposed to edit the pre-compiled MQ2DataTypes.cpp and MQ2DataTypes.h files somehow with what you posted, then compile? I'm not sure how to go about editting the MQ2DataTypes.cpp and MQ2DataTypes.h files.

I'd LOVE a bazaar updating macro. I spend A LOT of time making sure I have the lowest price in the bazaar on my 80 items up for sale. It's very time consuming. If I can get this macro to work, I will be very appreciative.

Thank you,

Process

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

Post by aChallenged1 » Wed Aug 25, 2004 1:25 pm

Anytime you update .h and other .cpp files you need to recompile the whole kit. Easy enough to do, you won't have to change anything. Just open up MacroQuest.dsw, rebuild vs F7 (make sure you're not running MQ2) so that the old gets deleted first befor it's rebuilt, when that's done do batch build. I personally rebuild all when I rebuild. Takes a little longer, but makes me feel better, and seems to prevent troubles I've had at times.
Fuck writing MQ2 macros. Go with IS scripts; IS Rules!

Process
a lesser mummy
a lesser mummy
Posts: 73
Joined: Fri Jun 25, 2004 5:30 pm

Post by Process » Wed Aug 25, 2004 1:57 pm

Thanks for the reply. I guess what I'm asking is how exactly I go about updating the MQ2DataTypes.cpp and MQ2DataTypes.h files?

I tried editing them in VS, but when I recompiled I had all kinds of errors. Is there a method of editting these files that I'm missing? I can't seem to figure out the exact method and sytax to use when editting these two files. For instance, am I supposed to edit out all the "+'s" and "-'s"? Am I supposed to leave them in? Am I supposed to just copy the code exactly how it's posted? I've tried all of that and had no luck, but perhaps I'm missing something.

Thanks again,

Process