Lol, no, I'm trying to take it out of the hands of our players, to sink gold, by selling some of our random loot in a shop. The notion is to get the prices to adjust automatically, to inject some more information into the player market. The discussion on our boards stretched to 9 pages of varying technicality, which you can look at here if you're feeling sadomasochistic:
Market Pricing MusingsThe code that's resulted so far is as follows. The comments at the bottom are mostly correct, but outdated - I decided to see the fake history with average rate of sale meeting desired rate of sale, so prices will drop slowly to start. The core concept is to peg prices with a minimum of disruption to the market, by increasing supply by a fixed amount, by pegging price change and price change speed to rates of purchase. The commented out CREATE TABLES at top are far from final as well - I can't index them until I've seen all the calls, and they'll likely have additional columns, like playername in the history table.
void LoadAugShop();
void LoadAugDisplay();
void AdjustPricesAfterSale();
/*
mshop_aug_inv
mi_aug, mi_price, mi_avail, mi_sold
mshop_aug_his
mh_id (autoinc), mh_aug, mh_date, mh_price (price only in case we want to use in the future)
tracks current price, avail, sold, aug#
join aug tables for rarity on aug #
CREATE TABLE mshop_aug_his (mh_id INT(11) default NULL auto_increment primary key, mh_aug INT UNSIGNED default NULL, mh_price BIGINT(20) default NULL, mh_date DATETIME default NULL);
CREATE TABLE mshop_aug_inv (mi_aug INT UNSIGNED NOT NULL primary key, mi_price BIGINT(20) default NULL, mi_avail TINYINT UNSIGNED default NULL, mi_sold TINYINT UNSIGNED default NULL);
*/
void LoadAugShop() {
if (GetLocalString(GetModule(), "ServerNumber") != "111")
return;
object oOwnerWay = GetWaypointByTag("wp_aug_shop_own");
object oCaseWay = GetWaypointByTag("wp_aug_shop_case");
object oCase = CreateObject(OBJECT_TYPE_PLACEABLE, "aug_shop_display", GetLocation(oCaseWay));
/*
calc ARoS/DRoS by rarity (Actual and Desired Rate of Sale) - DRoS is pegged, ARoS is measured using
history, with fake sales meeting ARoS calculated in for first 90 day period
*/
float fARoSUR, fDRoSUR = 0.1666;//1 per 6 resets
float fARoSR, fDRoSR = 0.25; //1 per 4
float fARoSUC, fDRoSUC = 0.5; //1 per 2
float fARoSC, fDRoSC = 1.0; //1 per 1
//purge old records? Not for now, sales data potentially useful
//Get Actual Rate of Sale for the 4 rarities in last 90 days
string sSQL = "SELECT FLOOR(ra_rarity/1000000) AS a, COUNT(*) FROM rip_augments, mshop_aug_his " +
"WHERE ra_id = mh_aug AND DATEDIFF(NOW(), mh_date) < 90 AND FLOOR(ra_rarity/1000000) < 5 " +
"GROUP BY a ORDER BY a ASC";
int nRarity, nSales, nSaleCountUR, nSaleCountR, nSalecountUC, nSaleCountC;
object oModule = GetModule();
SQLExecDirect(sSQL);
while (SQLFetch() != SQL_ERROR) {
nRarity = StringToInt(SQLGetData(1));
nSales = StringToInt(SQLGetData(2));
switch (nRarity) {
case 1: nSaleCountC = nSales; break;
case 2: nSalecountUC = nSales; break;
case 3: nSaleCountR = nSales; break;
case 4: nSaleCountUR = nSales; break;
default: break;
}
}
//seed virtual fake sells for first 90 days via math - keeps real history clean and
//gives low RoD/RoI to start (prices will begin high)
sSQL = "SELECT DATEDIFF(NOW(), '2013-02-08 23:59:59')";
int nDays;
SQLExecDirect(sSQL);
if (SQLFetch() != SQL_ERROR) {
nDays = StringToInt(SQLGetData(1));
}
//calc current Actual Rates of Sale for rarities adjusted for fake sales
//90 days is roughly 180 resets, give or take, fDRoS's are per reset
fARoSC = (nSaleCountC/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSC) : 0.0);
fARoSUC = (nSalecountUC/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSUC) : 0.0);
fARoSR = (nSaleCountR/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSR) : 0.0);
fARoSUR = (nSaleCountUR/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSUR) : 0.0);
//calc price drops from last sales period RoD = .19*x^2 – 0.38*x +.02; x = AROS/DROS
float fSalesRatioC = fARoSC/fDRoSC;
float fSalesRatioUC = fARoSUC/fDRoSUC;
float fSalesRatioR = fARoSR/fDRoSR;
float fSalesRatioUR = fARoSUR/fDRoSUR;
float fRoDC = (0.19 * pow(fSalesRatioC, 2.0)) - (0.38 * fSalesRatioC) + 0.02;
float fRoDUC = (0.19 * pow(fSalesRatioUC, 2.0)) - (0.38 * fSalesRatioUC) + 0.02;
float fRoDR = (0.19 * pow(fSalesRatioR, 2.0)) - (0.38 * fSalesRatioR) + 0.02;
float fRoDUR = (0.19 * pow(fSalesRatioUR, 2.0)) - (0.38 * fSalesRatioUR) + 0.02;
//select rarity, aug from table where mi_avail - set
mshop_aug_inv
mi_aug, mi_price, mi_avail, mi_sold
//for each, decrement price for that aug by RoD*.7
//for each, decrement price of each of that type by RoD*.25
//for each, decrement price of each of that rarity by*.05
}
/*
Price is adjusted on each sale, increasing by the current RoI for that rarity, based on the current rate of sale
for that rarity. This adjustment on point of sale allows us to make multiples of the augs in the shop each reset
available, because it increases price to prevent runs. Moreover, it increasingly increases price if they buy another.
The net effect of this is to increase liquidity, and thereby the accuracy of market information for players. The
only catch is that we'll have to seed a fake history (which is easy) to simulate current rate of sale > desired rate
of sale to start, so that the starting elasticity will be high, and will not decrease after the first sale (as it
would if the history showed zero sales in the last 90 days - 1/90 is closer to desired rate of sale than 0/90).
Price is also adjusted on shop load, after server load. We check the database to see which items were available last
reset, and which of those were sold.
For available items:
If sold, we increase price on all items of that rarity by a percentage of the current RoI for that rarity. That
percentage is based on the number of items of that rarity, let's call that NIoR. If we have 150 items of that rarity,
we would adjust the prices of all items of that rarity up by (1/150*RoI), or RoI/NIoR.
If not sold, we decrease price on all items of that rarity by a percentage of the current RoD: RoD/NIoR.
further:
If sold, we increase price on all items of that type (a smaller subset than rarity) by a percentage based on the
number of items of that type (NIoT), or RoI/NIoT.
If not sold, we decrease price on all items of that type by RoD/NIoT.
We peg changing elasticities to DRoS by rarity rather than type because assigning a desired rate of sale to types would cause more distortions in pricing.
*/
Funky