- add sell feature

- add basic pricing mechanism
This commit is contained in:
Lorenc Pekaj 2018-10-31 18:19:18 +11:00
parent c616c94359
commit ae01993db4

View File

@ -16,23 +16,24 @@
#define STOCK_REPORTING_PERIODS ( 30 ) // last 30 periods (days) #define STOCK_REPORTING_PERIODS ( 30 ) // last 30 periods (days)
#define DIALOG_STOCK_MARKET 8923 #define DIALOG_STOCK_MARKET 8923
#define DIALOG_PLAYER_STOCKS 8924
#define DIALOG_STOCK_MARKET_BUY 8925 #define DIALOG_STOCK_MARKET_BUY 8925
#define DIALOG_STOCK_MARKET_SELL 8926
#define STOCK_MM_USER_ID ( 0 ) #define STOCK_MM_USER_ID ( 0 )
/* ** Variables ** */ /* ** Variables ** */
enum E_STOCK_MARKET_DATA enum E_STOCK_MARKET_DATA
{ {
E_NAME[ 64 ], E_SYMBOL[ 4 ], Float: E_MAX_SHARES, E_NAME[ 64 ], E_SYMBOL[ 4 ], Float: E_MAX_SHARES,
// market maker // market maker
Float: E_IPO_SHARES, Float: E_IPO_PRICE Float: E_IPO_SHARES, Float: E_IPO_PRICE, Float: E_MAX_PRICE
}; };
enum E_STOCK_MARKET_PRICE_DATA enum E_STOCK_MARKET_PRICE_DATA
{ {
E_SQL_ID, Float: E_PRICE, E_SQL_ID, Float: E_PRICE, Float: E_POOL
Float: E_POOL
}; };
enum enum
@ -40,10 +41,15 @@ enum
E_STOCK_MINING_COMPANY E_STOCK_MINING_COMPANY
}; };
static const Float: STOCK_MARKET_POOL_FACTOR = 100000.0; // for every STOCK_MARKET_POOL_FACTOR ... STOCK_MARKET_PRICE_FACTOR added to the price
static const Float: STOCK_MARKET_PRICE_FACTOR = 5.0;
static stock static stock
g_stockMarketData [ MAX_STOCKS ] [ E_STOCK_MARKET_DATA ], g_stockMarketData [ MAX_STOCKS ] [ E_STOCK_MARKET_DATA ],
g_stockMarketReportData [ MAX_STOCKS ] [ STOCK_REPORTING_PERIODS ] [ E_STOCK_MARKET_PRICE_DATA ], g_stockMarketReportData [ MAX_STOCKS ] [ STOCK_REPORTING_PERIODS ] [ E_STOCK_MARKET_PRICE_DATA ],
Iterator: stockmarkets < MAX_STOCKS > Iterator: stockmarkets < MAX_STOCKS >,
Float: p_PlayerShares [ MAX_PLAYERS ] [ MAX_STOCKS ]
; ;
/* ** Forwards / Getters ** */ /* ** Forwards / Getters ** */
@ -58,7 +64,7 @@ hook OnScriptInit( )
AddServerVariable( "stock_report_time", "0", GLOBAL_VARTYPE_INT ); AddServerVariable( "stock_report_time", "0", GLOBAL_VARTYPE_INT );
// create markets // create markets
CreateStockMarket( 0, "The Mining Company", "MC", 1000000, 100 ); CreateStockMarket( 0, "The Mining Company", "MC", 100000.0, 25.0, 250.0 ); // 25m mcap max
return 1; return 1;
} }
@ -97,11 +103,64 @@ hook OnDialogResponse( playerid, dialogid, response, listitem, inputtext[ ] )
{ {
SetPVarInt( playerid, "stockmarket_selection", s ); SetPVarInt( playerid, "stockmarket_selection", s );
StockMarket_ShowBuySlip( playerid, s ); StockMarket_ShowBuySlip( playerid, s );
break;
} }
x ++; x ++;
} }
return 1; return 1;
} }
else if ( dialogid == DIALOG_PLAYER_STOCKS && response )
{
new
x = 0;
foreach ( new stockid : stockmarkets ) if ( p_PlayerShares[ playerid ] [ stockid ] )
{
if ( x == listitem )
{
SetPVarInt( playerid, "stockmarket_selling_stock", stockid );
StockMarket_ShowSellSlip( playerid, stockid );
break;
}
x ++;
}
return 1;
}
else if ( dialogid == DIALOG_STOCK_MARKET_SELL )
{
if ( ! response ) {
return cmd_shares( playerid, "" ), 1;
}
new
stockid = GetPVarInt( playerid, "stockmarket_selling_stock" );
if ( ! Iter_Contains( stockmarkets, stockid ) ) {
return SendError( playerid, "There was an error processing your sell order, please try again." );
}
new
input_shares;
if ( sscanf( inputtext, "d", input_shares ) ) SendError( playerid, "You must use a valid value." );
else if ( input_shares > floatround( p_PlayerShares[ playerid ] [ stockid ], floatround_floor ) ) SendError( playerid, "You do not have this many shares available to sell." );
else if ( input_shares <= 1 ) SendError( playerid, "The minimum number of shares you can sell is 1." );
else
{
new
Float: shares = float( input_shares );
if ( ( p_PlayerShares[ playerid ] [ stockid ] -= shares ) < 0.1 ) {
mysql_single_query( sprintf( "DELETE FROM `STOCK_OWNERS` WHERE `USER_ID`=%d AND `STOCK_ID`=%d", GetPlayerAccountID( playerid ), stockid ) );
} else {
StockMarket_GiveShares( stockid, GetPlayerAccountID( playerid ), -shares );
}
StockMarket_UpdateSellOrder( stockid, GetPlayerAccountID( playerid ), shares );
SendServerMessage( playerid, "You have placed a sell order for %s shares at %s each. "COL_ORANGE"To cancel your sell order, /shares cancel", number_format( shares, .decimals = 3 ), cash_format( g_stockMarketReportData[ stockid ] [ 1 ] [ E_PRICE ], .decimals = 2 ) );
return 1;
}
return StockMarket_ShowSellSlip( playerid, stockid );
}
else if ( dialogid == DIALOG_STOCK_MARKET_BUY ) else if ( dialogid == DIALOG_STOCK_MARKET_BUY )
{ {
new new
@ -110,13 +169,13 @@ hook OnDialogResponse( playerid, dialogid, response, listitem, inputtext[ ] )
if ( response ) if ( response )
{ {
new new
Float: shares; shares;
if ( sscanf( inputtext, "f", shares ) ) SendError( playerid, "You must use a valid value." ); if ( sscanf( inputtext, "d", shares ) ) SendError( playerid, "You must use a valid value." );
else if ( shares <= 10.0 ) SendError( playerid, "The minimum number of shares you can buy is 10." ); else if ( shares < 10 ) SendError( playerid, "The minimum number of shares you can buy is 10." );
else else
{ {
mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_OWNERS` WHERE `STOCK_ID` = %d AND `USER_ID` = %d", stockid, STOCK_MM_USER_ID ), "StockMarket_OnPurchaseOrder", "ddf", playerid, stockid, shares ); mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_SELL_ORDERS` WHERE `STOCK_ID`=%d ORDER BY `LIST_DATE` ASC", stockid ), "StockMarket_OnPurchaseOrder", "ddf", playerid, stockid, float( shares ) );
return 1; return 1;
} }
return StockMarket_ShowBuySlip( playerid, stockid ); return StockMarket_ShowBuySlip( playerid, stockid );
@ -141,18 +200,19 @@ thread Stock_UpdateReportingPeriods( stockid )
{ {
g_stockMarketReportData[ stockid ] [ row ] [ E_SQL_ID ] = cache_get_field_content_int( row, "ID" ); g_stockMarketReportData[ stockid ] [ row ] [ E_SQL_ID ] = cache_get_field_content_int( row, "ID" );
g_stockMarketReportData[ stockid ] [ row ] [ E_POOL ] = cache_get_field_content_float( row, "POOL" ); g_stockMarketReportData[ stockid ] [ row ] [ E_POOL ] = cache_get_field_content_float( row, "POOL" );
g_stockMarketReportData[ stockid ] [ row ] [ E_PRICE ] = cache_get_field_content_float( row, "PRICE" );
} }
} }
else // no historical reporting data, restock the market maker else // no historical reporting data, restock the market maker
{ {
// set current stock market prices to IPO // set current stock market prices to IPO
//g_stockMarketReportData[ stockid ] [ 1 ] [ E_PRICE ] = g_stockMarketData[ stockid ] [ E_IPO_PRICE ]; g_stockMarketReportData[ stockid ] [ 0 ] [ E_PRICE ] = g_stockMarketData[ stockid ] [ E_IPO_PRICE ];
// create report for the company using the IPO price // create report for the company using the IPO price
//StockMarket_ReleaseDividends( stockid ); StockMarket_ReleaseDividends( stockid );
// give market maker shares // put market maker shares on the market
StockMarket_GiveShares( stockid, STOCK_MM_USER_ID, g_stockMarketData[ stockid ] [ E_IPO_SHARES ] ); // , g_stockMarketData[ stockid ] [ E_IPO_PRICE ] StockMarket_UpdateSellOrder( stockid, STOCK_MM_USER_ID, g_stockMarketData[ stockid ] [ E_IPO_SHARES ] );
} }
return 1; return 1;
} }
@ -172,6 +232,18 @@ thread StockMarket_OnPurchaseOrder( playerid, stockid, Float: shares )
return SendError( playerid, "This stock has no available shares for sale." ); return SendError( playerid, "This stock has no available shares for sale." );
} }
// check if quantity is valid
new
Float: available_quantity = 0.0;
for ( new r = 0; r < rows; r ++ ) {
available_quantity += cache_get_field_content_float( r, "SHARES" );
}
if ( shares > available_quantity ) {
return SendError( playerid, "There are not that many shares available for sale." ), StockMarket_ShowBuySlip( playerid, stockid ), 1;
}
// check if the player has the money for the purchase // check if the player has the money for the purchase
new Float: ask_price = g_stockMarketReportData[ stockid ] [ 1 ] [ E_PRICE ]; new Float: ask_price = g_stockMarketReportData[ stockid ] [ 1 ] [ E_PRICE ];
new purchase_cost = floatround( ask_price * shares ); new purchase_cost = floatround( ask_price * shares );
@ -180,16 +252,51 @@ thread StockMarket_OnPurchaseOrder( playerid, stockid, Float: shares )
return SendError( playerid, "You need at least %s to purchase this many shares.", cash_format( purchase_cost ) ), StockMarket_ShowBuySlip( playerid, stockid ), 1; return SendError( playerid, "You need at least %s to purchase this many shares.", cash_format( purchase_cost ) ), StockMarket_ShowBuySlip( playerid, stockid ), 1;
} }
// check if quantity is valid new
new Float: available_quantity = cache_get_field_content_float( 0, "SHARES" ); Float: amount_remaining = shares;
if ( shares > available_quantity ) { for ( new row = 0; row < rows; row ++ )
return SendError( playerid, "There are not that many shares available for sale." ), StockMarket_ShowBuySlip( playerid, stockid ), 1; {
new sell_order_user_id = cache_get_field_content_int( row, "USER_ID" );
new Float: sell_order_shares = cache_get_field_content_float( row, "SHARES" );
// check if seller is online
new
sellerid;
foreach ( sellerid : Player ) if ( GetPlayerAccountID( sellerid ) == sell_order_user_id ) {
break;
}
new Float: sold_shares = amount_remaining > sell_order_shares ? sell_order_shares : amount_remaining;
new sold_amount = floatround( sold_shares * ask_price );
if ( 0 <= sellerid < MAX_PLAYERS && Iter_Contains( Player, sellerid ) ) {
GivePlayerBankMoney( sellerid, sold_amount ), Beep( sellerid );
SendServerMessage( sellerid, "You have sold %s %s shares to %s(%d) for "COL_GOLD"%s"COL_WHITE"!", number_format( sold_shares, .decimals = 3 ), g_stockMarketData[ stockid ] [ E_NAME ], ReturnPlayerName( playerid ), playerid, cash_format( sold_amount ) );
} else {
mysql_single_query( sprintf( "UPDATE `USERS` SET `BANKMONEY` = `BANKMONEY` + %d WHERE `ID` = %d", sold_amount, sell_order_user_id ) );
}
// remove the sell order if there is little to no shares available
if ( sell_order_shares - amount_remaining < 1.0 )
{
// get rid of this sell order
mysql_single_query( sprintf( "DELETE FROM `STOCK_SELL_ORDERS` WHERE `USER_ID`=%d and `STOCK_ID`=%d", sell_order_user_id, stockid ) );
// deduct the sell order amount from amount remaining
amount_remaining -= sell_order_shares;
}
else
{
// reduce sell order quantity
StockMarket_UpdateSellOrder( stockid, sell_order_user_id, -amount_remaining );
// the player's buy order was filled in the single sell order ... prevent updating
break;
}
} }
// reduce the market makers shares
StockMarket_GiveShares( stockid, STOCK_MM_USER_ID, -shares );
// increment the players shares // increment the players shares
StockMarket_GiveShares( stockid, GetPlayerAccountID( playerid ), shares ); StockMarket_GiveShares( stockid, GetPlayerAccountID( playerid ), shares );
@ -205,11 +312,11 @@ thread StockMarket_OnShowBuySlip( playerid, stockid )
rows = cache_get_row_count( ); rows = cache_get_row_count( );
if ( ! rows ) { if ( ! rows ) {
return SendError( playerid, "This stock does now have any shares available to buy." ); return SendError( playerid, "This stock does not currently have any shares available to buy." );
} }
new new
Float: available_quantity = cache_get_field_content_float( 0, "SHARES" ); Float: available_quantity = cache_get_field_content_float( 0, "SALE_SHARES" );
format( format(
szBigString, sizeof ( szBigString ), szBigString, sizeof ( szBigString ),
@ -228,7 +335,7 @@ thread StockMarket_OnShowShares( playerid )
rows = cache_get_row_count( ); rows = cache_get_row_count( );
if ( ! rows ) { if ( ! rows ) {
return SendError( playerid, "This stock does now have any shares available to buy." ); return SendError( playerid, "You are not holding any shares of any company." );
} }
szLargeString = ""COL_WHITE"Stock\t"COL_WHITE"Total Shares\t"COL_WHITE"Current Price ($)\t"COL_GREEN"Value ($)\n"; szLargeString = ""COL_WHITE"Stock\t"COL_WHITE"Total Shares\t"COL_WHITE"Current Price ($)\t"COL_GREEN"Value ($)\n";
@ -243,6 +350,7 @@ thread StockMarket_OnShowShares( playerid )
new Float: current_price = StockMarket_GetCurrentPrice( stockid ); new Float: current_price = StockMarket_GetCurrentPrice( stockid );
new Float: shares = cache_get_field_content_float( row, "SHARES" ); new Float: shares = cache_get_field_content_float( row, "SHARES" );
format( format(
szLargeString, sizeof( szLargeString ), szLargeString, sizeof( szLargeString ),
"%s%s (%s)\t%s\t%s\t"COL_GREEN"%s\n", "%s%s (%s)\t%s\t%s\t"COL_GREEN"%s\n",
@ -253,9 +361,12 @@ thread StockMarket_OnShowShares( playerid )
cash_format( current_price, .decimals = 2 ), cash_format( current_price, .decimals = 2 ),
cash_format( floatround( shares * current_price ) ) cash_format( floatround( shares * current_price ) )
); );
// store player stocks in a variable for reference
p_PlayerShares[ playerid ] [ stockid ] = shares;
} }
} }
return ShowPlayerDialog( playerid, DIALOG_STOCK_MARKET, DIALOG_STYLE_TABLIST_HEADERS, ""COL_WHITE"Stock Market", szLargeString, "Sell", "Close" ), 1; return ShowPlayerDialog( playerid, DIALOG_PLAYER_STOCKS, DIALOG_STYLE_TABLIST_HEADERS, ""COL_WHITE"Stock Market", szLargeString, "Sell", "Close" ), 1;
} }
thread Stock_OnDividendPayout( stockid ) thread Stock_OnDividendPayout( stockid )
@ -293,20 +404,35 @@ thread Stock_OnDividendPayout( stockid )
} }
} }
// set the new price of the company
new // TODO: use parabola for factor difficulty?
Float: new_price = ( g_stockMarketReportData[ stockid ] [ 0 ] [ E_POOL ] / STOCK_MARKET_POOL_FACTOR) * STOCK_MARKET_PRICE_FACTOR + g_stockMarketData[ stockid ] [ E_IPO_PRICE ];
if ( new_price > g_stockMarketData[ stockid ] [ E_MAX_PRICE ] ) { // dont want wild market caps
new_price = g_stockMarketData[ stockid ] [ E_MAX_PRICE ];
}
else if ( new_price < g_stockMarketData[ stockid ] [ E_IPO_PRICE ] ) { // force a minimum of IPO price
new_price = g_stockMarketData[ stockid ] [ E_IPO_PRICE ];
}
g_stockMarketReportData[ stockid ] [ 0 ] [ E_PRICE ] = new_price;
// store temporary stock info // store temporary stock info
new temp_stock_price_data[ MAX_STOCKS ] [ STOCK_REPORTING_PERIODS ] [ E_STOCK_MARKET_PRICE_DATA ]; new temp_stock_price_data[ MAX_STOCKS ] [ STOCK_REPORTING_PERIODS ] [ E_STOCK_MARKET_PRICE_DATA ];
temp_stock_price_data = g_stockMarketReportData; temp_stock_price_data = g_stockMarketReportData;
// shift all earnings by one // shift all report data by one
for ( new r = 0; r < sizeof( g_stockMarketReportData[ ] ) - 2; r ++ ) { for ( new r = 0; r < sizeof( g_stockMarketReportData[ ] ) - 2; r ++ ) {
g_stockMarketReportData[ stockid ] [ r + 1 ] [ E_POOL ] = temp_stock_price_data[ stockid ] [ r ] [ E_POOL ]; g_stockMarketReportData[ stockid ] [ r + 1 ] [ E_POOL ] = temp_stock_price_data[ stockid ] [ r ] [ E_POOL ];
g_stockMarketReportData[ stockid ] [ r + 1 ] [ E_PRICE ] = temp_stock_price_data[ stockid ] [ r ] [ E_PRICE ];
} }
// reset earnings // reset earnings
g_stockMarketReportData[ stockid ] [ 0 ] [ E_POOL ] = 1.0; // set to 1 instead of 0 to prevent errors g_stockMarketReportData[ stockid ] [ 0 ] [ E_POOL ] = 0.0; // set to 1 instead of 0 to prevent errors
g_stockMarketReportData[ stockid ] [ 0 ] [ E_PRICE ] = 0.0; // set to 0, it will be determined next day
// insert to database the old information // insert to database the old information
mysql_format( dbHandle, szBigString, sizeof ( szBigString ), "INSERT INTO `STOCK_REPORTS` (`STOCK_ID`, `POOL`) VALUES (%d, %f)", stockid, g_stockMarketReportData[ stockid ] [ 0 ] [ E_POOL ] ); mysql_format( dbHandle, szBigString, sizeof ( szBigString ), "INSERT INTO `STOCK_REPORTS` (`STOCK_ID`, `POOL`, `PRICE`) VALUES (%d, %f, %f)", stockid, g_stockMarketReportData[ stockid ] [ 0 ] [ E_POOL ], g_stockMarketReportData[ stockid ] [ 1 ] [ E_PRICE ] );
mysql_tquery( dbHandle, szBigString, "StockMarket_InsertReport", "d", stockid ); mysql_tquery( dbHandle, szBigString, "StockMarket_InsertReport", "d", stockid );
return 1; return 1;
} }
@ -317,13 +443,40 @@ thread Stock_UpdateMaximumShares( stockid )
rows = cache_get_row_count( ); rows = cache_get_row_count( );
if ( rows ) { if ( rows ) {
g_stockMarketData[ stockid ] [ E_MAX_SHARES ] = cache_get_field_content_float( 0, "TOTAL_SHARES" ); g_stockMarketData[ stockid ] [ E_MAX_SHARES ] = cache_get_field_content_float( 0, "SHARES_OWNED" ) + cache_get_field_content_float( 0, "SHARES_HELD" );
printf("%f shares", g_stockMarketData[ stockid ] [ E_MAX_SHARES ]);
} else { } else {
g_stockMarketData[ stockid ] [ E_MAX_SHARES ] = g_stockMarketData[ stockid ] [ E_IPO_SHARES ]; g_stockMarketData[ stockid ] [ E_MAX_SHARES ] = g_stockMarketData[ stockid ] [ E_IPO_SHARES ];
} }
return 1; return 1;
} }
thread StockMarket_OnCancelOrder( playerid )
{
new
rows = cache_get_row_count( );
if ( rows )
{
new
player_account = GetPlayerAccountID( playerid );
for ( new row = 0; row < rows; row ++ )
{
new stockid = cache_get_field_content_int( row, "STOCK_ID" );
new Float: shares = cache_get_field_content_float( row, "SHARES" );
mysql_single_query( sprintf( "DELETE FROM `STOCK_SELL_ORDERS` WHERE `STOCK_ID`=%d AND `USER_ID`=%d", stockid, player_account ) );
StockMarket_GiveShares( stockid, player_account, shares );
}
return 1;
}
else
{
return SendError( playerid, "You have no stock market sell orders to cancel." ), 1;
}
}
/* ** Command ** */ /* ** Command ** */
CMD:increase( playerid, params[ ] ) { CMD:increase( playerid, params[ ] ) {
StockMarket_UpdateEarnings( 0, strval( params ) ); StockMarket_UpdateEarnings( 0, strval( params ) );
@ -338,7 +491,7 @@ CMD:newreport( playerid, params[ ] ) {
CMD:stocks( playerid, params[ ] ) return cmd_stockmarkets( playerid, params ); CMD:stocks( playerid, params[ ] ) return cmd_stockmarkets( playerid, params );
CMD:stockmarkets( playerid, params[ ] ) CMD:stockmarkets( playerid, params[ ] )
{ {
szLargeString = ""COL_WHITE"Stock\t"COL_WHITE"Max Shares\t"COL_WHITE"Dividend Per Share ($)\n"; szLargeString = ""COL_WHITE"Stock\t"COL_WHITE"Max Shares\t"COL_WHITE"Dividend Per Share ($)\t"COL_WHITE"Price ($)\n";
foreach ( new s : stockmarkets ) foreach ( new s : stockmarkets )
{ {
@ -347,12 +500,13 @@ CMD:stockmarkets( playerid, params[ ] )
format( format(
szLargeString, sizeof( szLargeString ), szLargeString, sizeof( szLargeString ),
"%s%s (%s)\t%s\t"COL_GREEN"%s\n", "%s%s (%s)\t%s\t"COL_GREEN"%s\t"COL_GREEN"%s\n",
szLargeString, szLargeString,
g_stockMarketData[ s ] [ E_NAME ], g_stockMarketData[ s ] [ E_NAME ],
g_stockMarketData[ s ] [ E_SYMBOL ], g_stockMarketData[ s ] [ E_SYMBOL ],
number_format( g_stockMarketData[ s ] [ E_MAX_SHARES ], .decimals = 0 ), number_format( g_stockMarketData[ s ] [ E_MAX_SHARES ], .decimals = 0 ),
cash_format( payout, .decimals = 2 ) cash_format( payout, .decimals = 2 ),
cash_format( g_stockMarketReportData[ s ] [ 1 ] [ E_PRICE ], .decimals = 2 )
); );
} }
@ -362,12 +516,17 @@ CMD:stockmarkets( playerid, params[ ] )
CMD:shares( playerid, params[ ] ) CMD:shares( playerid, params[ ] )
{ {
if ( strmatch( params, "cancel" ) ) {
// todo: work with dialogs
mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_SELL_ORDERS` WHERE `USER_ID` = %d", GetPlayerAccountID( playerid ) ), "StockMarket_OnCancelOrder", "d", playerid );
return 1;
}
mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_OWNERS` WHERE `USER_ID` = %d", GetPlayerAccountID( playerid ) ), "StockMarket_OnShowShares", "d", playerid ); mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_OWNERS` WHERE `USER_ID` = %d", GetPlayerAccountID( playerid ) ), "StockMarket_OnShowShares", "d", playerid );
return 1; return 1;
} }
/* ** Functions ** */ /* ** Functions ** */
stock CreateStockMarket( stockid, const name[ 64 ], const symbol[ 4 ], Float: ipo_shares, Float: ipo_price ) stock CreateStockMarket( stockid, const name[ 64 ], const symbol[ 4 ], Float: ipo_shares, Float: ipo_price, Float: max_price )
{ {
if ( ! Iter_Contains( stockmarkets, stockid ) ) if ( ! Iter_Contains( stockmarkets, stockid ) )
{ {
@ -376,17 +535,18 @@ stock CreateStockMarket( stockid, const name[ 64 ], const symbol[ 4 ], Float: ip
g_stockMarketData[ stockid ] [ E_IPO_SHARES ] = ipo_shares; g_stockMarketData[ stockid ] [ E_IPO_SHARES ] = ipo_shares;
g_stockMarketData[ stockid ] [ E_IPO_PRICE ] = ipo_price; g_stockMarketData[ stockid ] [ E_IPO_PRICE ] = ipo_price;
g_stockMarketData[ stockid ] [ E_MAX_PRICE ] = max_price;
// reset stock price information // reset stock price information
for ( new r = 0; r < sizeof( g_stockMarketReportData[ ] ); r ++ ) { for ( new r = 0; r < sizeof( g_stockMarketReportData[ ] ); r ++ ) {
g_stockMarketReportData[ stockid ] [ r ] [ E_POOL ] = 1.0; g_stockMarketReportData[ stockid ] [ r ] [ E_POOL ] = 0.0;
} }
// load price information if there is // load price information if there is
mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_REPORTS` WHERE `STOCK_ID`=%d ORDER BY `REPORTING_TIME` DESC LIMIT %d", stockid, sizeof( g_stockMarketReportData[ ] ) ), "Stock_UpdateReportingPeriods", "d", stockid ); mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_REPORTS` WHERE `STOCK_ID`=%d ORDER BY `REPORTING_TIME` DESC LIMIT %d", stockid, sizeof( g_stockMarketReportData[ ] ) ), "Stock_UpdateReportingPeriods", "d", stockid );
// load the maximum number of shares // load the maximum number of shares
mysql_tquery( dbHandle, sprintf( "SELECT SUM(`SHARES`) AS TOTAL_SHARES FROM `STOCK_OWNERS` WHERE `STOCK_ID`=0", stockid ), "Stock_UpdateMaximumShares", "d", stockid ); mysql_tquery( dbHandle, sprintf( "SELECT (SELECT SUM(`SHARES`) FROM `STOCK_OWNERS` WHERE `STOCK_ID`=%d) AS `SHARES_OWNED`, (SELECT SUM(`SHARES`) FROM `STOCK_SELL_ORDERS` WHERE `STOCK_ID`=%d) AS `SHARES_HELD`", stockid, stockid ), "Stock_UpdateMaximumShares", "d", stockid );
// add to iterator // add to iterator
Iter_Add( stockmarkets, stockid ); Iter_Add( stockmarkets, stockid );
@ -396,7 +556,7 @@ stock CreateStockMarket( stockid, const name[ 64 ], const symbol[ 4 ], Float: ip
static stock StockMarket_ReleaseDividends( stockid ) static stock StockMarket_ReleaseDividends( stockid )
{ {
mysql_format( dbHandle, szBigString, sizeof ( szBigString ), "SELECT * as `TOTAL_SHARES` FROM `STOCK_OWNERS` WHERE `STOCK_ID`=%d", stockid, stockid ); mysql_format( dbHandle, szBigString, sizeof ( szBigString ), "SELECT * FROM `STOCK_OWNERS` WHERE `STOCK_ID`=%d", stockid );
mysql_tquery( dbHandle, szBigString, "Stock_OnDividendPayout", "d", stockid ); mysql_tquery( dbHandle, szBigString, "Stock_OnDividendPayout", "d", stockid );
return 1; return 1;
} }
@ -422,20 +582,46 @@ stock StockMarket_GiveShares( stockid, accountid, Float: shares )
mysql_single_query( szBigString ); mysql_single_query( szBigString );
} }
stock StockMarket_UpdateSellOrder( stockid, accountid, Float: shares )
{
mysql_format(
dbHandle, szBigString, sizeof ( szBigString ),
"INSERT INTO `STOCK_SELL_ORDERS` (`STOCK_ID`, `USER_ID`, `SHARES`) VALUES (%d, %d, %f) ON DUPLICATE KEY UPDATE `SHARES` = `SHARES` + %f",
stockid, accountid, shares, shares
);
mysql_single_query( szBigString );
}
static stock StockMarket_ShowBuySlip( playerid, stockid ) static stock StockMarket_ShowBuySlip( playerid, stockid )
{ {
mysql_tquery( dbHandle, sprintf( "SELECT * FROM `STOCK_OWNERS` WHERE `STOCK_ID` = %d AND `USER_ID` = %d", stockid, STOCK_MM_USER_ID ), "StockMarket_OnShowBuySlip", "dd", playerid, stockid ); mysql_tquery( dbHandle, sprintf( "SELECT SUM(`SHARES`) AS `SALE_SHARES` FROM `STOCK_SELL_ORDERS` WHERE `STOCK_ID`=%d", stockid ), "StockMarket_OnShowBuySlip", "dd", playerid, stockid );
return 1;
}
static stock StockMarket_ShowSellSlip( playerid, stockid )
{
format(
szLargeString, sizeof ( szLargeString ),
""COL_WHITE"You can sell shares of %s for "COL_GREEN"%s"COL_WHITE" each.\n\nThough, you will have to wait until a person buys them.\n\nYou have %s available shares to sell.",
g_stockMarketData[ stockid ] [ E_NAME ],
cash_format( g_stockMarketReportData[ stockid ] [ 1 ] [ E_PRICE ], .decimals = 2 ),
number_format( p_PlayerShares[ playerid ] [ stockid ], .decimals = 3 )
);
ShowPlayerDialog( playerid, DIALOG_STOCK_MARKET_SELL, DIALOG_STYLE_INPUT, ""COL_WHITE"Stock Market", szLargeString, "Sell", "Close" );
return 1; return 1;
} }
/* /*
DROP TABLE `STOCK_REPORTS`;
CREATE TABLE IF NOT EXISTS `STOCK_REPORTS` ( CREATE TABLE IF NOT EXISTS `STOCK_REPORTS` (
`ID` int(11) primary key auto_increment, `ID` int(11) primary key auto_increment,
`STOCK_ID` int(11), `STOCK_ID` int(11),
`POOL` float, `POOL` float,
`PRICE` float,
`REPORTING_TIME` TIMESTAMP default CURRENT_TIMESTAMP `REPORTING_TIME` TIMESTAMP default CURRENT_TIMESTAMP
); );
DROP TABLE `STOCK_OWNERS`;
CREATE TABLE IF NOT EXISTS `STOCK_OWNERS` ( CREATE TABLE IF NOT EXISTS `STOCK_OWNERS` (
`USER_ID` int(11), `USER_ID` int(11),
`STOCK_ID` int(11), `STOCK_ID` int(11),
@ -443,10 +629,12 @@ static stock StockMarket_ShowBuySlip( playerid, stockid )
PRIMARY KEY (USER_ID, STOCK_ID) PRIMARY KEY (USER_ID, STOCK_ID)
); );
CREATE TABLE IF NOT EXISTS `STOCK_TRADE_LOG` ( DROP TABLE `STOCK_SELL_ORDERS`;
`ID` int(11) primary key auto_increment, CREATE TABLE IF NOT EXISTS `STOCK_SELL_ORDERS` (
`USER_ID` int(11),
`STOCK_ID` int(11), `STOCK_ID` int(11),
`USER_ID` int(11),
`SHARES` float, `SHARES` float,
) `LIST_DATE` TIMESTAMP default CURRENT_TIMESTAMP,
PRIMARY KEY (STOCK_ID, USER_ID)
);
*/ */