diff --git a/code/_helpers/roundstats.dm b/code/_helpers/roundstats.dm
index 9db69b9658..5b4061c38f 100644
--- a/code/_helpers/roundstats.dm
+++ b/code/_helpers/roundstats.dm
@@ -90,14 +90,27 @@ GLOBAL_LIST_EMPTY(refined_chems_sold)
points += GLOB.refined_chems_sold[D]["value"]
if(GLOB.refined_chems_sold[D]["units"] >= 1000) // Don't spam the list
- var/dols = GLOB.refined_chems_sold[D]["value"] * SSsupply.points_per_money
+ var/dols = GLOB.refined_chems_sold[D]["value"] * SSsupply.money_per_points
dols = FLOOR(dols * 100,1) / 100 // Truncate decimals
valid_stats_list.Add("[GLOB.refined_chems_sold[D]["units"]]u of [D], for [GLOB.refined_chems_sold[D]["value"]] points! A total of [dols] [dols > 1 ? "thalers" : "thaler"]")
- var/end_dols = points * SSsupply.points_per_money
+ var/end_dols = points * SSsupply.money_per_points
end_dols = FLOOR(end_dols * 100,1) / 100 // Truncate decimals
valid_stats_list.Add("For a total of: [points] points, or [end_dols] [end_dols > 1 ? "thalers" : "thaler"]!")
+ if(SSsupply.warheads_sold > 0)
+ var/end_dols = SSsupply.warheads_value * SSsupply.money_per_points
+ end_dols = FLOOR(end_dols * 100,1) / 100 // Truncate decimals
+ valid_stats_list.Add("[SSsupply.warheads_sold] TTV warheads were sold! For a total of: [SSsupply.warheads_value] points, or [end_dols] [end_dols > 1 ? "thalers" : "thaler"]!")
+
+ //NYI
+ if(SSsupply.watts_sold >= 1 GIGAWATTS)
+ var/gws = FLOOR(SSsupply.watts_sold / (1 GIGAWATTS),1) // Truncate decimals
+ points = FLOOR(SSsupply.watts_sold / SSsupply.points_per_watt,1)
+ var/end_dols = points * SSsupply.money_per_points
+ end_dols = FLOOR(end_dols * 100,1) / 100 // Truncate decimals
+ valid_stats_list.Add("[gws] gigawatt[gws > 1 ? "s" : ""] of power were sold! For a total of: [points] points, or [end_dols] [end_dols > 1 ? "thalers" : "thaler"]!")
+
if(SSnerdle)
var/word_export = "This shift's nerdle Was: [SSnerdle.target_word]!
"
word_export += "There were [SSnerdle.total_players] players this shift!
"
diff --git a/code/controllers/subsystems/internal_wiki.dm b/code/controllers/subsystems/internal_wiki.dm
index a398d2c6fb..c16332b228 100644
--- a/code/controllers/subsystems/internal_wiki.dm
+++ b/code/controllers/subsystems/internal_wiki.dm
@@ -841,7 +841,7 @@ SUBSYSTEM_DEF(internal_wiki)
data["stack_size"] = initial(stack_path.max_amount) ? initial(stack_path.max_amount) : 0
var/supply_value = M.supply_conversion_value ? M.supply_conversion_value : 0
data["supply_points"] = supply_value
- var/value = supply_value * SSsupply.points_per_money
+ var/value = supply_value * SSsupply.money_per_points
value = FLOOR(value * 100, 1) / 100 // Truncate decimals
data["market_price"] = value
@@ -1132,7 +1132,7 @@ SUBSYSTEM_DEF(internal_wiki)
data["industrial_use"] = R.industrial_use
data["supply_points"] = R.supply_conversion_value ? R.supply_conversion_value : 0
data["cooling_mod"] = R.coolant_modifier
- var/value = R.supply_conversion_value * REAGENTS_PER_SHEET * SSsupply.points_per_money
+ var/value = R.supply_conversion_value * REAGENTS_PER_SHEET * SSsupply.money_per_points
value = FLOOR(value * 100,1) / 100 // Truncate decimals
data["market_price"] = value
data["sintering"] = SSinternal_wiki.assemble_sintering(GLOB.reagent_sheets[R.id])
@@ -1243,7 +1243,7 @@ SUBSYSTEM_DEF(internal_wiki)
var/list/recipe_data = list()
var/value = recipe["Price"] ? recipe["Price"] : 0
recipe_data["supply_points"] = value
- value *= SSsupply.points_per_money // convert to cash
+ value *= SSsupply.money_per_points // convert to cash
value = FLOOR(value * 100,1) / 100 // Truncate decimals
recipe_data["market_price"] = value
recipe_data["appliance"] = recipe["Appliance"]
diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm
index 456deca754..99a1556637 100644
--- a/code/controllers/subsystems/supply.dm
+++ b/code/controllers/subsystems/supply.dm
@@ -7,11 +7,23 @@ SUBSYSTEM_DEF(supply)
//Initializes at default time
flags = SS_NO_TICK_CHECK
- //supply points
+ /// Supply points
var/points = 50
- var/points_per_process = 1.0 // Processes every 20 seconds, so this is 3 per minute
+ /// How many points we get every SSSupply fire.
+ var/points_per_process = 1.0
+ /// How much money we get for every stamped slip we return to Central
var/points_per_slip = 2
- var/points_per_money = 0.02 // 1 point for $50
+ /// How much money one SP is worth in thalers. Shows up in the end of round stats.
+ var/money_per_points = 50
+ /// How much power we've sold this round.
+ var/watts_sold = 0
+ /// How many watts that have to be sold for a point - NYI
+ var/points_per_watt = 10 MEGAWATTS
+ /// How many TTVs we have sold this round.
+ var/warheads_sold = 0
+ /// How many points we've made selling TTVs
+ var/warheads_value = 0
+
//control
var/ordernum = 0 // Start at zero, it's per-shift tracking
var/list/shoppinglist = list() // Approved orders
@@ -53,10 +65,12 @@ SUBSYSTEM_DEF(supply)
return 1
if(istype(A,/obj/item/radio/beacon))
return 1
- if(istype(A,/obj/item/perfect_tele_beacon)) //VOREStation Addition: Translocator beacons
- return 1 //VOREStation Addition: Translocator beacons
- if(istype(A,/obj/machinery/power/quantumpad)) // //VOREStation Add: Quantum pads
- return 1 //VOREStation Add: Quantum pads
+ if(istype(A,/obj/item/perfect_tele_beacon))
+ return 1
+ if(istype(A,/obj/machinery/power/quantumpad))
+ return 1
+ if(istype(A,/obj/structure/extraction_point))
+ return 1
for(var/atom/B in A.contents)
if(.(B))
@@ -68,7 +82,7 @@ SUBSYSTEM_DEF(supply)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_SUPPLY_SHUTTLE_DEPART, shuttle.shuttle_area)
for(var/area/subarea in shuttle.shuttle_area)
for(var/atom/movable/MA in subarea)
- if(MA.anchored)
+ if(MA.anchored && !istype(MA,/obj/mecha))
continue
var/datum/exported_crate/EC = new /datum/exported_crate()
@@ -376,3 +390,6 @@ SUBSYSTEM_DEF(supply)
var/ordered_at // Date and time the order was requested at
var/approved_at // Date and time the order was approved at
var/status // [Requested, Accepted, Denied, Shipped]
+
+/datum/controller/subsystem/supply/proc/points_to_cash(val)
+ return FLOOR(((val * money_per_points)), 1)
diff --git a/code/datums/elements/sellable.dm b/code/datums/elements/sellable.dm
index 4790ce30bc..3b372bf4a3 100644
--- a/code/datums/elements/sellable.dm
+++ b/code/datums/elements/sellable.dm
@@ -80,9 +80,12 @@
// Money
+/datum/element/sellable/spacecash
+ sale_info = "This can be sold on the cargo shuttle if packed in a crate. Due to taxes, this is worth less than its face value when sold to the cargo shuttle."
+
/datum/element/sellable/spacecash/calculate_sell_value(obj/source)
var/obj/item/spacecash/cashmoney = source
- return cashmoney.worth * SSsupply.points_per_money
+ return FLOOR((cashmoney.worth / SSsupply.money_per_points),1)
/datum/element/sellable/spacecash/calculate_sell_quantity(obj/source)
var/obj/item/spacecash/cashmoney = source
@@ -195,3 +198,203 @@
if(organ_stuff.health != initial(organ_stuff.health) )
return "Error: Product was damaged on arrival."
return null
+
+// Selling slimes
+/datum/element/sellable/slime_extract/calculate_sell_value(obj/source)
+ var/obj/item/slime_extract/slime_stuff = source
+ return FLOOR(slime_stuff.supply_conversion_value,1)
+
+
+// Selling food
+/datum/element/sellable/food_snack
+ sale_info = "This can be sold on the cargo shuttle if packed in a freezer crate."
+
+/datum/element/sellable/food_snack/sell_error(obj/source)
+ if(!istype(source.loc, /obj/structure/closet/crate/freezer))
+ return "Error: Product was improperly packaged. Send contents in freezer crate to preserve contents for transport. Payment rendered null under terms of agreement."
+ var/obj/item/reagent_containers/food/food_stuff = source
+ if(istype(food_stuff,/obj/item/reagent_containers/food/snacks))
+ var/obj/item/reagent_containers/food/snacks/S = food_stuff
+ if(S.bitecount > 0)
+ return "Error: Product was partially consumed, and is unfit for sale. Payment rendered null under terms of agreement."
+ return null
+
+/datum/element/sellable/food_snack/calculate_sell_value(obj/source)
+ var/obj/item/reagent_containers/food/food_stuff = source
+ return FLOOR(food_stuff.price_tag,1) // Converts old price system into supply point cost
+
+
+// Selling TTVs
+/datum/element/sellable/transfer_valve/calculate_sell_value(obj/source)
+ var/obj/item/transfer_valve/TTV = source
+
+ if(!TTV.tank_one || !TTV.tank_two)
+ return 0
+
+ var/datum/gas_mixture/faketank = new()
+ QDEL_IN(faketank,5)
+
+ // Highest pressure must be in tank 1!
+ var/obj/item/tank/tank1 = TTV.tank_one
+ var/obj/item/tank/tank2 = TTV.tank_two
+ faketank.volume = tank1.air_contents.volume + tank2.air_contents.volume
+ faketank.copy_from(tank1.air_contents)
+ var/faketank_integrity = tank1.integrity
+ faketank.merge(tank2.air_contents)
+
+ // Perform the explosion
+ faketank.merge(tank2.air_contents)
+ faketank.react()
+ var/pressure = faketank.return_pressure()
+ if(pressure <= TANK_FRAGMENT_PRESSURE)
+ return 0
+ var/intervals = 0
+ //Very dumbed down version. Close enough for our purposes.
+ while(faketank_integrity >= 7)
+ if(intervals < 0 || intervals >= 13) //13 because we calculate for adminspawn bombs or pre-welded bombs, too, which start at 20 integrity. If it's losing integrity, it's going to rupture eventually!
+ break
+ intervals++
+ faketank.react()
+ pressure = faketank.return_pressure()
+ if(pressure > TANK_FRAGMENT_PRESSURE)
+ faketank_integrity -= 7
+
+ else if(pressure > TANK_RUPTURE_PRESSURE)
+ faketank_integrity -= 5
+
+ if(faketank_integrity > 7)
+ return 0
+
+ faketank.react()
+ faketank.react()
+ faketank.react()
+ pressure = faketank.return_pressure()
+
+ var/strength = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE
+ var/mult = ((faketank.volume/140)**(1/2)) * (faketank.total_moles**(2/3))/((29*0.64) **(2/3)) //Don't ask me what this is, see tanks.dm
+
+ var/dev_value = round((mult*strength)*1)
+ var/heavy_value = round((mult*strength)*0.5)
+ var/light_value = round((mult*strength)*0.25)
+
+ return FLOOR(dev_value + heavy_value + light_value,1)
+
+/datum/element/sellable/transfer_valve/sell(obj/source, datum/exported_crate/EC, in_crate)
+ . = ..()
+ if(. && EC.contents[EC.contents.len]["value"] > 0)
+ SSsupply.warheads_sold++
+ SSsupply.warheads_value += EC.contents[EC.contents.len]["value"]
+
+
+// Mech selling
+/datum/element/sellable/mecha
+ needs_crate = FALSE
+ sale_info = "This can be sold on the cargo shuttle. It's condition and parts would greatly affects its price."
+
+/datum/element/sellable/mecha/sell_error(obj/source)
+ var/obj/mecha/exo = source
+ exo.wreckage = null // Exo sold, remove it's lootpile on qdel, or we'll have issues in cargo....
+ var/check_val = calculate_sell_value(source)
+ if(!check_val)
+ if((exo.health / exo.maxhealth) < 0.5)
+ return "Error: The unit is too damaged to sell, and will be used as scrap. Payment rendered null under terms of agreement."
+ return "Error: The unit in its current condition has no resale value at all, and will be used as scrap. Payment rendered null under terms of agreement."
+ return null
+
+/datum/element/sellable/mecha/calculate_sell_value(obj/source)
+ var/obj/mecha/exo = source
+ var/amount = exo.health / 10
+ amount += exo.max_temperature / 1000
+
+ // generic bonuses
+ for(var/slot in exo.internal_components)
+ var/obj/item/mecha_parts/component/MC = exo.internal_components[slot]
+ amount += MC.integrity
+ amount += MC.emp_resistance * 10
+
+ // special bonuses
+ if(exo.internal_components[MECH_ACTUATOR])
+ var/obj/item/mecha_parts/component/actuator/MC = exo.internal_components[MECH_ACTUATOR]
+ amount += MC.integrity
+ amount += 20 * MC.strafing_multiplier
+
+ if(exo.internal_components[MECH_ARMOR])
+ var/obj/item/mecha_parts/component/armor/MC = exo.internal_components[MECH_ARMOR]
+ amount += MC.deflect_chance
+ for(var/dam in MC.damage_absorption)
+ amount += MC.damage_absorption[dam] * 10
+
+ if(exo.internal_components[MECH_ELECTRIC])
+ var/obj/item/mecha_parts/component/electrical/MC = exo.internal_components[MECH_ELECTRIC]
+ amount += MC.integrity
+ amount -= 100 * MC.charge_cost_mod
+
+ // Extra equipment
+ for(var/E in exo.hull_equipment)
+ amount += 3
+
+ for(var/E in exo.weapon_equipment)
+ amount += 3
+
+ for(var/E in exo.utility_equipment)
+ amount += 2
+
+ for(var/E in exo.universal_equipment)
+ amount += 1
+
+ for(var/E in exo.special_equipment)
+ amount += 4
+
+ // Don't bother somehow...
+ if(amount < 0)
+ return 0
+
+ // Special mech multipliers
+ if(istype(exo,/obj/mecha/combat/phazon))
+ amount *= 30
+ else if(istype(exo,/obj/mecha/combat/fighter)) // More niche
+ amount *= 8
+ else if(istype(exo,/obj/mecha/medical))
+ amount *= 11
+ else if(istype(exo,/obj/mecha/combat))
+ amount *= 6
+ else if(istype(exo,/obj/mecha/micro)) // Teeny weenies!
+ amount *= 3.5
+ else
+ amount *= 1
+
+ // Final health scaler
+ amount *= (exo.health / exo.maxhealth)
+ if(amount < 100)
+ return 0
+ return FLOOR(amount,10)
+
+
+// Selling GUNZ
+/datum/element/sellable/gun/calculate_sell_value(obj/source)
+ var/amount = 10
+ var/obj/item/gun/G = source
+ var/obj/item/projectile/P = initial(G.projectile_type)
+
+ if(istype(G,/obj/item/gun/projectile))
+ var/obj/item/gun/projectile/PG = G
+ amount += initial(PG.recoil) * 2 // We can assume bigger bang
+ amount += initial(PG.max_shells) * 1.5 // More shots more bang
+
+ if(istype(G,/obj/item/gun/energy))
+ var/obj/item/gun/energy/EG = G
+ amount += initial(EG.charge_cost) / 100 // We can assume bigger bang
+
+ if(P)
+ // Default bullet breakdown
+ amount += initial(P.damage) / 2
+ amount += initial(P.stun)
+ amount += initial(P.weaken)
+ amount += initial(P.paralyze)
+ amount += initial(P.irradiate) / 2
+ amount += initial(P.agony) / 2
+ // Stop trying to sell donksofts
+ if(initial(P.nodamage))
+ amount /= 20
+
+ return FLOOR(amount,5)
diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester_vr.dm
index 6b5b0c7090..aed85b6680 100644
--- a/code/game/machinery/bomb_tester_vr.dm
+++ b/code/game/machinery/bomb_tester_vr.dm
@@ -242,7 +242,7 @@
var/dev = round((mult*strength)*0.15)
var/heavy = round((mult*strength)*0.35)
var/light = round((mult*strength)*0.80)
- simulation_results += "