mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-11 15:15:32 +01:00
6ac39e264e
* it's yours my friend as long as you have enough * Sellable AND bombcode is fixed * this * Craftable * Update code/controllers/subsystems/supply.dm * Update code/modules/economy/cargo_point_scanner.dm * Apply suggestion from @Cameron-The-Raven
401 lines
14 KiB
Plaintext
401 lines
14 KiB
Plaintext
/datum/element/sellable
|
|
var/sale_info = "This can be sold on the cargo shuttle if packed in a crate."
|
|
var/needs_crate = TRUE
|
|
|
|
/datum/element/sellable/Attach(datum/target)
|
|
. = ..()
|
|
if(!isobj(target))
|
|
return ELEMENT_INCOMPATIBLE
|
|
RegisterSignal(target, COMSIG_ITEM_EXPORTED, PROC_REF(sell))
|
|
RegisterSignal(target, COMSIG_ITEM_SCAN_PROFIT, PROC_REF(calculate_sell_value))
|
|
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
|
return
|
|
|
|
/datum/element/sellable/Detach(datum/source)
|
|
UnregisterSignal(source, COMSIG_ITEM_EXPORTED)
|
|
UnregisterSignal(source, COMSIG_ITEM_SCAN_PROFIT)
|
|
UnregisterSignal(source, COMSIG_ATOM_EXAMINE)
|
|
return ..()
|
|
|
|
// Override this for sub elements that need to do complex calculations when sold
|
|
/datum/element/sellable/proc/sell_error(obj/source)
|
|
return null // returns a string explaining why the item couldn't be sold. Otherwise null to allow it to be sold.
|
|
|
|
/datum/element/sellable/proc/calculate_sell_value(obj/source)
|
|
return 1
|
|
|
|
/datum/element/sellable/proc/calculate_sell_quantity(obj/source)
|
|
return 1
|
|
// End overrides
|
|
|
|
/datum/element/sellable/proc/sell(obj/source, datum/exported_crate/EC, in_crate)
|
|
SIGNAL_HANDLER
|
|
|
|
if(needs_crate && !in_crate)
|
|
EC.contents = list("error" = "Error: Product was improperly packaged. Payment rendered null under terms of agreement.")
|
|
return FALSE
|
|
|
|
var/sell_error = sell_error(source)
|
|
if(sell_error)
|
|
EC.contents = list("error" = sell_error)
|
|
return FALSE
|
|
|
|
EC.contents[++EC.contents.len] = list(
|
|
"object" = "\proper[source.name]",
|
|
"value" = calculate_sell_value(source),
|
|
"quantity" = calculate_sell_quantity(source)
|
|
)
|
|
EC.value += EC.contents[EC.contents.len]["value"]
|
|
return TRUE
|
|
|
|
/datum/element/sellable/proc/on_examine(datum/source, mob/user, list/examine_texts)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
SIGNAL_HANDLER
|
|
if(sale_info)
|
|
examine_texts += span_notice(sale_info)
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Subtypes
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Manifest papers
|
|
/datum/element/sellable/manifest/calculate_sell_value(obj/source)
|
|
var/obj/item/paper/manifest/slip = source
|
|
if(!slip.is_copy && slip.stamped && slip.stamped.len) //yes, the clown stamp will work. clown is the highest authority on the station, it makes sense
|
|
return SSsupply.points_per_slip
|
|
return 0
|
|
|
|
|
|
// Material stacks
|
|
/datum/element/sellable/material_stack/calculate_sell_value(obj/source)
|
|
var/obj/item/stack/P = source
|
|
var/datum/material/mat = P.get_material()
|
|
if(!mat || !mat.supply_conversion_value)
|
|
return 0
|
|
return P.get_amount() * mat.supply_conversion_value
|
|
|
|
/datum/element/sellable/material_stack/calculate_sell_quantity(obj/source)
|
|
var/obj/item/stack/P = source
|
|
return P.get_amount()
|
|
|
|
|
|
// 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 FLOOR((cashmoney.worth / SSsupply.money_per_points),1)
|
|
|
|
/datum/element/sellable/spacecash/calculate_sell_quantity(obj/source)
|
|
var/obj/item/spacecash/cashmoney = source
|
|
return cashmoney.worth
|
|
|
|
|
|
// Research samples
|
|
/datum/element/sellable/research_sample/calculate_sell_value(obj/source)
|
|
var/obj/item/research_sample/sample = source
|
|
return sample.supply_value
|
|
|
|
|
|
// Research containers
|
|
/datum/element/sellable/sample_container/calculate_sell_value(obj/source)
|
|
var/obj/item/storage/sample_container/sample_can = source
|
|
var/sample_sum = 0
|
|
var/obj/item/research_sample/stored_sample
|
|
if(LAZYLEN(sample_can.contents))
|
|
for(stored_sample in sample_can.contents)
|
|
sample_sum += stored_sample.supply_value
|
|
return sample_sum
|
|
|
|
/datum/element/sellable/sample_container/calculate_sell_quantity(obj/source)
|
|
var/obj/item/storage/sample_container/sample_can = source
|
|
return "[sample_can.contents.len] sample(s) "
|
|
|
|
|
|
// Vaccine samples
|
|
/datum/element/sellable/vaccine
|
|
sale_info = "This can be sold on the cargo shuttle if packed in a freezer crate."
|
|
|
|
/datum/element/sellable/vaccine/sell_error(obj/source)
|
|
if(!istype(source.loc, /obj/structure/closet/crate/freezer))
|
|
return "Error: Product was improperly packaged. Vaccines must be sold in a freezer crate to preserve for transport. Payment rendered null under terms of agreement."
|
|
var/obj/item/reagent_containers/glass/beaker/vial/vaccine/sale_bottle = source
|
|
if(sale_bottle.reagents.reagent_list.len != 1 || sale_bottle.reagents.get_reagent_amount(REAGENT_ID_VACCINE) < sale_bottle.volume)
|
|
return "Error: Tainted product in vaccine batch. Was opened, contaminated, or wasn't filled to full. Payment rendered null under terms of agreement."
|
|
return null
|
|
|
|
/datum/element/sellable/vaccine/calculate_sell_value(obj/source)
|
|
return 5
|
|
|
|
|
|
// Refinery chemical tanks
|
|
/datum/element/sellable/trolley_tank
|
|
sale_info = "This can be sold on the cargo shuttle if filled with a single reagent."
|
|
needs_crate = FALSE
|
|
|
|
/datum/element/sellable/trolley_tank/sell_error(obj/source)
|
|
var/obj/vehicle/train/trolley_tank/tank = source
|
|
if(!tank.reagents || tank.reagents.reagent_list.len == 0)
|
|
return "Error: Product was not filled with any reagents to sell. Payment rendered null under terms of agreement."
|
|
var/min_tank = (CARGOTANKER_VOLUME - 100)
|
|
if(tank.reagents.total_volume < min_tank)
|
|
return "Error: Product was improperly packaged. Send full tanks only (minimum [min_tank] units). Payment rendered null under terms of agreement."
|
|
if(tank.reagents.reagent_list.len > 1)
|
|
return "Error: Product was improperly refined. Send purified mixtures only (too many reagents in tank). Payment rendered null under terms of agreement."
|
|
return null
|
|
|
|
/datum/element/sellable/trolley_tank/calculate_sell_value(obj/source)
|
|
var/obj/vehicle/train/trolley_tank/tank = source
|
|
if(!length(tank.reagents.reagent_list))
|
|
return 0
|
|
|
|
// Update export values
|
|
var/datum/reagent/R = tank.reagents.reagent_list[1]
|
|
var/reagent_value = FLOOR(R.volume * R.supply_conversion_value, 1)
|
|
|
|
return reagent_value
|
|
|
|
/datum/element/sellable/trolley_tank/calculate_sell_quantity(obj/source)
|
|
var/obj/vehicle/train/trolley_tank/tank = source
|
|
if(!tank.reagents || tank.reagents.reagent_list.len == 0)
|
|
return "0u "
|
|
var/datum/reagent/R = tank.reagents.reagent_list[1]
|
|
return "[R.name] [tank.reagents.total_volume]u "
|
|
|
|
/datum/element/sellable/trolley_tank/sell(obj/source, datum/exported_crate/EC, in_crate)
|
|
. = ..()
|
|
var/obj/vehicle/train/trolley_tank/tank = source
|
|
if(. && tank.reagents?.reagent_list?.len)
|
|
// Update end round data, has nothing to do with actual cargo sales
|
|
var/datum/reagent/R = tank.reagents.reagent_list[1]
|
|
var/reagent_value = FLOOR(R.volume * R.supply_conversion_value, 1)
|
|
if(R.industrial_use)
|
|
if(isnull(GLOB.refined_chems_sold[R.industrial_use]))
|
|
var/list/data = list()
|
|
data["units"] = FLOOR(R.volume, 1)
|
|
data["value"] = reagent_value
|
|
GLOB.refined_chems_sold[R.industrial_use] = data
|
|
else
|
|
GLOB.refined_chems_sold[R.industrial_use]["units"] += FLOOR(R.volume, 1)
|
|
GLOB.refined_chems_sold[R.industrial_use]["value"] += reagent_value
|
|
|
|
/datum/element/sellable/salvage //For selling /obj/item/salvage
|
|
|
|
/datum/element/sellable/salvage/calculate_sell_value(obj/source)
|
|
var/obj/item/salvage/salvagedStuff = source
|
|
return salvagedStuff.worth
|
|
|
|
/datum/element/sellable/organ //For selling /obj/item/organ/internal
|
|
/datum/element/sellable/organ/calculate_sell_value(obj/source)
|
|
var/obj/item/organ/internal/organ_stuff = source
|
|
return organ_stuff.supply_conversion_value
|
|
|
|
/datum/element/sellable/organ/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."
|
|
var/obj/item/organ/internal/organ_stuff = source
|
|
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)
|