diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm index 24ab2eb3303..55c6d496e0c 100644 --- a/code/__DEFINES/construction/material.dm +++ b/code/__DEFINES/construction/material.dm @@ -68,13 +68,13 @@ //Stock market stock values. /// How much quantity of a material stock exists for common materials like iron & glass. -#define MATERIAL_QUANTITY_COMMON 25000 +#define MATERIAL_QUANTITY_COMMON 5000 /// How much quantity of a material stock exists for uncommon materials like silver & titanium. -#define MATERIAL_QUANTITY_UNCOMMON 10000 +#define MATERIAL_QUANTITY_UNCOMMON 1000 /// How much quantity of a material stock exists for rare materials like gold, uranium, & diamond. -#define MATERIAL_QUANTITY_RARE 2500 +#define MATERIAL_QUANTITY_RARE 200 /// How much quantity of a material stock exists for exotic materials like diamond & bluespace crystals. -#define MATERIAL_QUANTITY_EXOTIC 500 +#define MATERIAL_QUANTITY_EXOTIC 50 // The number of ore vents that will spawn boulders with this material. /// Is this material going to spawn often in ore vents? (80% of vents on lavaland) diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm index 93b0678581a..7b619b274f5 100644 --- a/code/__DEFINES/economy.dm +++ b/code/__DEFINES/economy.dm @@ -75,7 +75,7 @@ #define MARKET_TREND_DOWNWARD -1 #define MARKET_TREND_STABLE 0 -#define MARKET_EVENT_PROBABILITY 1 //Probability of a market event firing, in percent. Fires once per material, every 20 seconds. +#define MARKET_EVENT_PROBABILITY 8 //Probability of a market event firing, in percent. Fires once per material, every stock market tick. #define MARKET_PROFIT_MODIFIER 0.8 //We don't make every sale a 1-1 of the actual buy price value, like with real life taxes and to encourage more smart trades diff --git a/code/controllers/subsystem/stock_market.dm b/code/controllers/subsystem/stock_market.dm index c9f632c7faf..6c4341adc8d 100644 --- a/code/controllers/subsystem/stock_market.dm +++ b/code/controllers/subsystem/stock_market.dm @@ -1,7 +1,7 @@ SUBSYSTEM_DEF(stock_market) name = "Stock Market" - wait = 20 SECONDS + wait = 60 SECONDS init_order = INIT_ORDER_DEFAULT runlevels = RUNLEVEL_GAME @@ -28,7 +28,7 @@ SUBSYSTEM_DEF(stock_market) materials_trends[possible_market] = rand(MARKET_TREND_DOWNWARD,MARKET_TREND_UPWARD) //aka -1 to 1 materials_trend_life += possible_market - materials_trend_life[possible_market] = rand(1,10) + materials_trend_life[possible_market] = rand(1,3) materials_quantity += possible_market materials_quantity[possible_market] = possible_market.tradable_base_quantity + (rand(-(possible_market.tradable_base_quantity) * 0.5, possible_market.tradable_base_quantity * 0.5)) @@ -80,7 +80,7 @@ SUBSYSTEM_DEF(stock_market) materials_trends[mat] = MARKET_TREND_DOWNWARD else materials_trends[mat] = MARKET_TREND_STABLE - materials_trend_life[mat] = rand(3,10) // Change our trend life for x number of fires of the subsystem + materials_trend_life[mat] = rand(1,3) // Change our trend life for x number of fires of the subsystem else materials_trend_life[mat] -= 1 @@ -88,14 +88,14 @@ SUBSYSTEM_DEF(stock_market) var/quantity_change = 0 switch(trend) if(MARKET_TREND_UPWARD) - price_change = ROUND_UP(gaussian(price_units * 0.1, price_baseline * 0.05)) //If we don't ceil, small numbers will get trapped at low values - quantity_change = -round(gaussian(quantity_baseline * 0.05, quantity_baseline * 0.05)) + price_change = ROUND_UP(gaussian(price_units * 0.30, price_baseline * 0.15)) //If we don't ceil, small numbers will get trapped at low values + quantity_change = -round(gaussian(quantity_baseline * 0.15, quantity_baseline * 0.15)) if(MARKET_TREND_STABLE) price_change = round(gaussian(0, price_baseline * 0.01)) - quantity_change = round(gaussian(0, quantity_baseline * 0.01)) + quantity_change = round(gaussian(0, quantity_baseline * 0.5)) if(MARKET_TREND_DOWNWARD) - price_change = -ROUND_UP(gaussian(price_units * 0.1, price_baseline * 0.05)) - quantity_change = round(gaussian(quantity_baseline * 0.05, quantity_baseline * 0.05)) + price_change = -ROUND_UP(gaussian(price_units * 0.3, price_baseline * 0.15)) + quantity_change = round(gaussian(quantity_baseline * 0.15, quantity_baseline * 0.15)) materials_prices[mat] = round(clamp(price_units + price_change, price_minimum, price_maximum)) materials_quantity[mat] = round(clamp(stock_quantity + quantity_change, 0, quantity_baseline * 2)) diff --git a/code/datums/stock_market_events.dm b/code/datums/stock_market_events.dm index 81142d23002..4907bf784f6 100644 --- a/code/datums/stock_market_events.dm +++ b/code/datums/stock_market_events.dm @@ -83,7 +83,7 @@ /datum/stock_market_event/large_boost name = "Large Boost!" trend_value = MARKET_TREND_UPWARD - trend_duration = 3 + trend_duration = 4 circumstance = list( "has just released a new product that raised the price of ", "discovered a new valuable use for ", @@ -93,14 +93,14 @@ /datum/stock_market_event/large_boost/start_event() . = ..() var/price_units = SSstock_market.materials_prices[mat] - SSstock_market.materials_prices[mat] += round(gaussian(price_units * 0.5, price_units * 0.1)) + SSstock_market.materials_prices[mat] += round(gaussian(price_units, price_units * 0.15)) SSstock_market.materials_prices[mat] = clamp(SSstock_market.materials_prices[mat], price_minimum * mat.value_per_unit, price_maximum * mat.value_per_unit) create_news() /datum/stock_market_event/large_drop name = "Large Drop!" trend_value = MARKET_TREND_DOWNWARD - trend_duration = 5 + trend_duration = 4 circumstance = list( "'s latest product has seen major controversy, and resulted in a price drop for ", "has been hit with a major lawsuit, resulting in a price drop for ", @@ -110,6 +110,42 @@ /datum/stock_market_event/large_drop/start_event() . = ..() var/price_units = SSstock_market.materials_prices[mat] - SSstock_market.materials_prices[mat] -= round(gaussian(price_units * 1.5, price_units * 0.1)) + SSstock_market.materials_prices[mat] -= round(gaussian(price_units * 1.5, price_units * 0.15)) SSstock_market.materials_prices[mat] = clamp(SSstock_market.materials_prices[mat], price_minimum * mat.value_per_unit, price_maximum * mat.value_per_unit) create_news() + +/datum/stock_market_event/hotcakes + name = "Selling like Hotcakes!" + trend_value = MARKET_TREND_UPWARD + trend_duration = 1 + circumstance = list( + "has just released a new product that is dominating the market for ", + "is hitting it big! Dramatically stocking and raising the price of ", + ", in a surprise move, monopolized supply and has raised the price of ", + ) + +/datum/stock_market_event/hotcakes/start_event() + . = ..() + SSstock_market.materials_prices[mat] = round(price_maximum * mat.value_per_unit) + create_news() + +/datum/stock_market_event/lockdown + name = "Lockdown!" + trend_value = MARKET_TREND_DOWNWARD + trend_duration = 2 + circumstance = list( + "is being investigated by the Galactic Trade Commission, resulting in a halt of trade for ", + ", in a stunning move, has been embargoed by TerraGov, resulting in a halt of trade of ", + ) + +/datum/stock_market_event/lockdown/handle() + . = ..() + SSstock_market.materials_quantity[mat] = 0 //Force the material to be unavailable. + +/datum/stock_market_event/lockdown/end_event() + . = ..() + SSstock_market.materials_quantity[mat] = initial(mat.tradable_base_quantity) //Force the material to be available again. + SSstock_market.materials_prices[mat] = initial(mat.value_per_unit) * SHEET_MATERIAL_AMOUNT //Force the price to be reset once the lockdown is over. + create_news() + + diff --git a/code/modules/cargo/materials_market.dm b/code/modules/cargo/materials_market.dm index 92d83d5d0a1..947197d16f2 100644 --- a/code/modules/cargo/materials_market.dm +++ b/code/modules/cargo/materials_market.dm @@ -166,12 +166,14 @@ var/min_value_override = initial(traded_mat.minimum_value_override) if(min_value_override) minimum_value_threshold = min_value_override - + else + minimum_value_threshold = round(initial(traded_mat.value_per_unit) * SHEET_MATERIAL_AMOUNT * 0.5) //send data material_data += list(list( "name" = initial(traded_mat.name), "price" = SSstock_market.materials_prices[traded_mat], + "rarity" = initial(traded_mat.value_per_unit), "threshold" = minimum_value_threshold, "quantity" = SSstock_market.materials_quantity[traded_mat], "trend" = trend_string, @@ -205,6 +207,7 @@ .["orderBalance"] = current_cost .["orderingPrive"] = ordering_private .["canOrderCargo"] = can_buy_via_budget + .["updateTime"] = SSstock_market.next_fire - world.time /obj/machinery/materials_market/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() @@ -348,8 +351,8 @@ /obj/item/stock_block/Initialize(mapload) . = ..() - addtimer(CALLBACK(src, PROC_REF(value_warning)), 2.5 MINUTES, TIMER_DELETE_ME) - addtimer(CALLBACK(src, PROC_REF(update_value)), 5 MINUTES, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(value_warning)), 1.5 MINUTES, TIMER_DELETE_ME) + addtimer(CALLBACK(src, PROC_REF(update_value)), 3 MINUTES, TIMER_DELETE_ME) /obj/item/stock_block/examine(mob/user) . = ..() diff --git a/tgui/packages/tgui/interfaces/MatMarket.tsx b/tgui/packages/tgui/interfaces/MatMarket.tsx index 41b25dedb00..1f6d69c8d69 100644 --- a/tgui/packages/tgui/interfaces/MatMarket.tsx +++ b/tgui/packages/tgui/interfaces/MatMarket.tsx @@ -1,14 +1,23 @@ +import { sortBy } from 'common/collections'; import { BooleanLike } from 'common/react'; import { toTitleCase } from 'common/string'; import { useBackend } from '../backend'; -import { Button, Modal, Section, Stack } from '../components'; +import { + Button, + Collapsible, + Modal, + NoticeBox, + Section, + Stack, +} from '../components'; import { formatMoney } from '../format'; import { Window } from '../layouts'; type Material = { name: string; quantity: number; + rarity: number; trend: string; price: number; threshold: number; @@ -24,6 +33,7 @@ type Data = { materials: Material[]; catastrophe: BooleanLike; CARGO_CRATE_VALUE: number; + updateTime: number; }; export const MatMarket = (props) => { @@ -66,24 +76,35 @@ export const MatMarket = (props) => { ) } > - Buy orders for material sheets placed here will be ordered on the next - cargo shipment. -

- To sell materials, please insert sheets or similar stacks of - materials. All minerals sold on the market directly are subject to an - 20% market fee. To prevent market manipulation, all registered traders - can buy a total of 10 full stacks of materials at a time. -

- All new purchases will include the cost of the shipped crate, - which may be recycled afterwards. + + + Buy orders for material sheets placed here will be ordered on the + next cargo shipment. +

+ To sell materials, please insert sheets or similar stacks of + materials. All minerals sold on the market directly are subject to + an 20% market fee. To prevent market manipulation, all registered + traders can buy a total of 10 full stacks of materials at a time. +

+ All new purchases will include the cost of the shipped crate, + which may be recycled afterwards. +
+
- + Current Credit Balance: {formatMoney(creditBalance)} cr. - + Current Order Cost: {formatMoney(orderBalance)} cr. + 150 ? 'green' : '#ad7526'} + > + {Math.round(data.updateTime / 10)} seconds until next + update +
- {materials.map((material, i) => ( -
- - - - - {toTitleCase(material.name)} - - - - Trading at {formatMoney(material.price)} cr. - - {material.price < material.threshold ? ( - - Material price critical! -
Trading temporarily suspended. + {sortBy((tempmat: Material) => tempmat.rarity)(materials).map( + (material, i) => ( +
+ + + + + {toTitleCase(material.name)} - ) : ( - - {material.quantity || 'Zero'} sheets of{' '} - {material.name} trading.{' '} - {material.requested || 'Zero'} sheets ordered. - - )} - + Trading at {formatMoney(material.price)} cr. + + {material.price < material.threshold ? ( + + Material price critical! +
Trading temporarily suspended. +
+ ) : ( + + {material.quantity || 'Zero'} sheets of{' '} + {material.name} trading.{' '} + {material.requested || 'Zero'} sheets ordered. + + )} + + + {toTitleCase(material.name)} is trending{' '} + {material.trend}. + +
+
+ + - - - - - - {material.requested > 0 && ( - x {material.requested} - )} -
-
- ))} + Buy 1 + + + + + +
+ {material.requested > 0 && ( + x {material.requested} + )} +
+
+ ), + )} );