mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-31 00:49:06 +01:00
Mitigates (autolathe) recycling exploits by minimizing what can be recycled, adding unit tests and fixing the recipes (#10375)
* Mitigates research recycling exploits by minimizing what can be recycled * Moves the research design check into a new unit test * Adds unit test for stack material recipes costs and fixes these costs * Instead of changing recipes the resulting materials are worth less * Crap fix
This commit is contained in:
@@ -160,8 +160,8 @@
|
||||
|
||||
//Resources are being loaded.
|
||||
var/obj/item/eating = O
|
||||
if(!eating.matter)
|
||||
to_chat(user, "\The [eating] does not contain significant amounts of useful materials and cannot be accepted.")
|
||||
if(!eating.matter || !eating.recyclable)
|
||||
to_chat(user, SPAN_WARNING("\The [eating] cannot be recycled by \the [src]."))
|
||||
return
|
||||
|
||||
var/filltype = 0 // Used to determine message.
|
||||
@@ -192,7 +192,7 @@
|
||||
mass_per_sheet += eating.matter[material]
|
||||
|
||||
if(!filltype)
|
||||
to_chat(user, SPAN_NOTICE("\The [src] is full. Please remove material from the autolathe in order to insert more."))
|
||||
to_chat(user, SPAN_WARNING("\The [src] is full. Please remove some material in order to insert more."))
|
||||
return
|
||||
else if(filltype == 1)
|
||||
to_chat(user, SPAN_NOTICE("You fill \the [src] to capacity with \the [eating]."))
|
||||
|
||||
@@ -12,6 +12,7 @@ var/list/floor_light_cache = list()
|
||||
active_power_usage = 20
|
||||
power_channel = LIGHT
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 2500, MATERIAL_GLASS = 2750)
|
||||
recyclable = TRUE
|
||||
|
||||
var/on
|
||||
var/on_state = "on"
|
||||
|
||||
@@ -12,5 +12,4 @@
|
||||
throw_speed = 3
|
||||
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 50, MATERIAL_GLASS = 20)
|
||||
|
||||
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
|
||||
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_state = "jar_lid"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
matter = list(MATERIAL_GLASS = 200)
|
||||
recyclable = TRUE
|
||||
flags = NOBLUDGEON
|
||||
var/list/accept_mobs = list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/rat)
|
||||
var/contains = 0 // 0 = nothing, 1 = money, 2 = animal, 3 = spiderling
|
||||
|
||||
@@ -29,7 +29,8 @@ var/global/list/datum/stack_recipe/rod_recipes = list(
|
||||
throw_range = 20
|
||||
drop_sound = 'sound/items/drop/metalweapon.ogg'
|
||||
pickup_sound = 'sound/items/pickup/metalweapon.ogg'
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 1875)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 937.5)
|
||||
recyclable = TRUE
|
||||
max_amount = 60
|
||||
attack_verb = list("hit", "bludgeoned", "whacked")
|
||||
lock_picking_level = 3
|
||||
|
||||
@@ -155,23 +155,7 @@
|
||||
return
|
||||
|
||||
if (use(required))
|
||||
var/atom/O
|
||||
if(recipe.use_material)
|
||||
O = new recipe.result_type(user.loc, recipe.use_material)
|
||||
else
|
||||
O = new recipe.result_type(user.loc)
|
||||
O.set_dir(user.dir)
|
||||
O.add_fingerprint(user)
|
||||
|
||||
if (istype(O, /obj/item/stack))
|
||||
var/obj/item/stack/S = O
|
||||
S.amount = produced
|
||||
S.update_icon()
|
||||
S.add_to_stacks(user)
|
||||
|
||||
if (istype(O, /obj/item/storage)) //BubbleWrap - so newly formed boxes are empty
|
||||
for (var/obj/item/I in O)
|
||||
qdel(I)
|
||||
recipe.Produce(produced, user.loc, user.dir, user)
|
||||
|
||||
/obj/item/stack/Topic(href, href_list)
|
||||
..()
|
||||
@@ -388,6 +372,30 @@
|
||||
src.on_floor = on_floor
|
||||
src.use_material = supplied_material
|
||||
|
||||
/datum/stack_recipe/proc/Produce(var/amount = 1, var/loc = null, var/dir = NORTH, var/user = null)
|
||||
if(amount < 1)
|
||||
return null
|
||||
|
||||
var/atom/O
|
||||
if(use_material)
|
||||
O = new result_type(loc, use_material)
|
||||
else
|
||||
O = new result_type(loc)
|
||||
O.set_dir(dir)
|
||||
O.add_fingerprint(user)
|
||||
|
||||
if (istype(O, /obj/item/stack))
|
||||
var/obj/item/stack/S = O
|
||||
S.amount = amount
|
||||
S.update_icon()
|
||||
if(user)
|
||||
S.add_to_stacks(user)
|
||||
|
||||
if (istype(O, /obj/item/storage)) //BubbleWrap - so newly formed boxes are empty
|
||||
for (var/obj/item/I in O)
|
||||
qdel(I)
|
||||
return O
|
||||
|
||||
/*
|
||||
* Recipe list datum
|
||||
*/
|
||||
@@ -397,4 +405,4 @@
|
||||
|
||||
/datum/stack_recipe_list/New(new_title, new_recipes)
|
||||
src.title = new_title
|
||||
src.recipes = new_recipes
|
||||
src.recipes = new_recipes
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
* Carpet
|
||||
*/
|
||||
|
||||
#define TILE_MATERIAL_AMOUNT 468
|
||||
|
||||
/obj/item/stack/tile
|
||||
name = "tile"
|
||||
singular_name = "tile"
|
||||
desc = "A non-descript floor tile"
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
max_amount = 60
|
||||
recyclable = TRUE
|
||||
icon = 'icons/obj/stacks/tiles.dmi'
|
||||
item_icons = list(
|
||||
slot_l_hand_str = 'icons/mob/items/stacks/lefthand_tiles.dmi',
|
||||
@@ -139,7 +142,7 @@
|
||||
flags = 0
|
||||
drop_sound = 'sound/items/drop/cloth.ogg'
|
||||
pickup_sound = 'sound/items/pickup/cloth.ogg'
|
||||
matter = list(MATERIAL_PLASTIC = 937.5)
|
||||
matter = list(MATERIAL_PLASTIC = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/lino_grey
|
||||
name = "linoleum"
|
||||
@@ -153,7 +156,7 @@
|
||||
flags = 0
|
||||
drop_sound = 'sound/items/drop/cloth.ogg'
|
||||
pickup_sound = 'sound/items/pickup/cloth.ogg'
|
||||
matter = list(MATERIAL_PLASTIC = 937.5)
|
||||
matter = list(MATERIAL_PLASTIC = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/*
|
||||
* Circuits
|
||||
@@ -165,7 +168,7 @@
|
||||
desc = "An advanced tile covered in various circuitry and wiring."
|
||||
icon_state = "tile_bcircuit"
|
||||
force = 6.0
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 937.5, MATERIAL_GLASS = 937.5)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = TILE_MATERIAL_AMOUNT, MATERIAL_GLASS = TILE_MATERIAL_AMOUNT)
|
||||
throwforce = 15.0
|
||||
throw_speed = 5
|
||||
throw_range = 20
|
||||
@@ -177,7 +180,7 @@
|
||||
desc = "An advanced tile covered in various circuitry and wiring."
|
||||
icon_state = "tile_gcircuit"
|
||||
force = 6.0
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 937.5, MATERIAL_GLASS = 937.5)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = TILE_MATERIAL_AMOUNT, MATERIAL_GLASS = TILE_MATERIAL_AMOUNT)
|
||||
throwforce = 15.0
|
||||
throw_speed = 5
|
||||
throw_range = 20
|
||||
@@ -193,7 +196,7 @@
|
||||
desc = "Those could work as a pretty decent throwing weapon" //why?
|
||||
icon_state = "tile"
|
||||
force = 6.0
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 937.5)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = TILE_MATERIAL_AMOUNT)
|
||||
throwforce = 15.0
|
||||
throw_speed = 5
|
||||
throw_range = 20
|
||||
@@ -209,13 +212,13 @@
|
||||
name = "steel floor tile"
|
||||
singular_name = "steel floor tile"
|
||||
icon_state = "tile_steel"
|
||||
matter = list(MATERIAL_PLASTEEL = 937.5)
|
||||
matter = list(MATERIAL_PLASTEEL = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/floor_white
|
||||
name = "white floor tile"
|
||||
singular_name = "white floor tile"
|
||||
icon_state = "tile_white"
|
||||
matter = list(MATERIAL_PLASTIC = 937.5)
|
||||
matter = list(MATERIAL_PLASTIC = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/floor_yellow
|
||||
name = "yellow floor tile"
|
||||
@@ -227,43 +230,43 @@
|
||||
name = "dark floor tile"
|
||||
singular_name = "dark floor tile"
|
||||
icon_state = "fr_tile"
|
||||
matter = list(MATERIAL_PLASTEEL = 937.5)
|
||||
matter = list(MATERIAL_PLASTEEL = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/floor_freezer
|
||||
name = "freezer floor tile"
|
||||
singular_name = "freezer floor tile"
|
||||
icon_state = "tile_freezer"
|
||||
matter = list(MATERIAL_PLASTIC = 937.5)
|
||||
matter = list(MATERIAL_PLASTIC = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/silver
|
||||
name = "silver floor tile"
|
||||
singular_name = "silver floor tile"
|
||||
icon_state = "tile_silver"
|
||||
matter = list(MATERIAL_SILVER = 937.5)
|
||||
matter = list(MATERIAL_SILVER = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/gold
|
||||
name = "golden floor tile"
|
||||
singular_name = "golden floor tile"
|
||||
icon_state = "tile_gold"
|
||||
matter = list(MATERIAL_GOLD = 937.5)
|
||||
matter = list(MATERIAL_GOLD = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/uranium
|
||||
name = "uranium floor tile"
|
||||
singular_name = "uranium floor tile"
|
||||
icon_state = "tile_uranium"
|
||||
matter = list(MATERIAL_URANIUM = 937.5)
|
||||
matter = list(MATERIAL_URANIUM = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/phoron
|
||||
name = "phoron floor tile"
|
||||
singular_name = "phoron floor tile"
|
||||
icon_state = "tile_plasma"
|
||||
matter = list(MATERIAL_PHORON = 937.5)
|
||||
matter = list(MATERIAL_PHORON = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/stack/tile/diamond
|
||||
name = "diamond floor tile"
|
||||
singular_name = "diamond floor tile"
|
||||
icon_state = "tile_diamond"
|
||||
matter = list(MATERIAL_DIAMOND = 937.5)
|
||||
matter = list(MATERIAL_DIAMOND = TILE_MATERIAL_AMOUNT)
|
||||
|
||||
/*
|
||||
* Cyborg modules
|
||||
@@ -320,3 +323,5 @@
|
||||
charge_costs = list(250)
|
||||
stacktype = /obj/item/stack/tile/carpet
|
||||
build_type = /obj/item/stack/tile/carpet
|
||||
|
||||
#undef TILE_MATERIAL_AMOUNT
|
||||
|
||||
@@ -141,7 +141,8 @@
|
||||
item_state = "rfdammo"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
origin_tech = list(TECH_MATERIAL = 2)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 30000, MATERIAL_GLASS = 15000)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 2000, MATERIAL_GLASS = 2000)
|
||||
recyclable = TRUE
|
||||
|
||||
/*
|
||||
RFD Construction-Class
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
throw_range = 5
|
||||
origin_tech = list(TECH_MATERIAL = 1)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 500)
|
||||
recyclable = TRUE
|
||||
var/elastic
|
||||
var/dispenser = 0
|
||||
var/breakouttime = 1200 //Deciseconds = 120s = 2 minutes
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
randpixel = 8
|
||||
sharp = 1
|
||||
edge = 1
|
||||
recyclable = TRUE
|
||||
w_class = ITEMSIZE_SMALL
|
||||
force_divisor = 0.2 // 6 with hardness 30 (glass)
|
||||
thrown_force_divisor = 0.4 // 4 with weight 15 (glass)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
var/rigged = 0 // true if rigged to explode
|
||||
var/minor_fault = 0 //If not 100% reliable, it will build up faults.
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 700, MATERIAL_GLASS = 50)
|
||||
recyclable = TRUE
|
||||
|
||||
//currently only used by energy-type guns, that may change in the future.
|
||||
/obj/item/cell/device
|
||||
@@ -94,7 +95,7 @@
|
||||
origin_tech = list(TECH_POWER = 6)
|
||||
icon_state = "hpcell"
|
||||
maxcharge = 30000
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 700, MATERIAL_GLASS = 80)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 200, MATERIAL_GOLD = 50, MATERIAL_SILVER = 50, MATERIAL_GLASS = 40)
|
||||
|
||||
/obj/item/cell/hyper/empty/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
slot_r_hand_str = 'icons/mob/items/weapons/righthand_shield.dmi'
|
||||
)
|
||||
var/base_block_chance = 50
|
||||
recyclable = TRUE
|
||||
|
||||
/obj/item/shield/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
|
||||
if(user.incapacitated())
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Circular Saw
|
||||
* Tray
|
||||
*/
|
||||
/obj/item/surgery/
|
||||
/obj/item/surgery
|
||||
name = "surgery tool"
|
||||
desc = "hey, you aren't supposed to have this"
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
@@ -19,6 +19,7 @@
|
||||
slot_l_hand_str = 'icons/mob/items/lefthand_medical.dmi',
|
||||
slot_r_hand_str = 'icons/mob/items/righthand_medical.dmi',
|
||||
)
|
||||
recyclable = TRUE
|
||||
|
||||
/*
|
||||
* Retractor
|
||||
|
||||
@@ -140,7 +140,7 @@ Frequency:
|
||||
|
||||
/obj/item/hand_tele/Initialize()
|
||||
. = ..()
|
||||
if(ismob(loc) || ismob(loc.loc))
|
||||
if(get(loc, /mob))
|
||||
maptext = held_maptext
|
||||
|
||||
/obj/item/hand_tele/attack_self(mob/user)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/obj
|
||||
animate_movement = 2
|
||||
|
||||
|
||||
var/list/matter //Used to store information about the contents of the object.
|
||||
var/recyclable = FALSE //Whether the object can be recycled (eaten) by something like the Autolathe
|
||||
var/w_class // Size of the object.
|
||||
var/list/origin_tech = null //Used by R&D to determine what research bonuses it grants.
|
||||
var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj.
|
||||
|
||||
|
||||
var/obj_flags //Special flags such as whether or not this object can be rotated.
|
||||
var/throwforce = 1
|
||||
var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
|
||||
@@ -221,11 +221,11 @@
|
||||
/obj/proc/rotate(var/mob/user, var/anchored_ignore = FALSE)
|
||||
if(use_check_and_message(user))
|
||||
return
|
||||
|
||||
|
||||
if(anchored && !anchored_ignore)
|
||||
to_chat(user, SPAN_WARNING("\The [src] is bolted down to the floor!"))
|
||||
return
|
||||
|
||||
|
||||
set_dir(turn(dir, 90))
|
||||
update_icon()
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
drop_sound = 'sound/items/drop/accessory.ogg'
|
||||
pickup_sound = 'sound/items/pickup/accessory.ogg'
|
||||
matter = list(MATERIAL_GLASS = 150, MATERIAL_GOLD = 50)
|
||||
recyclable = TRUE
|
||||
w_class = ITEMSIZE_TINY
|
||||
var/closed = FALSE
|
||||
|
||||
@@ -128,6 +129,7 @@
|
||||
drop_sound = 'sound/items/drop/accessory.ogg'
|
||||
pickup_sound = 'sound/items/pickup/accessory.ogg'
|
||||
matter = list(MATERIAL_GLASS = 150, MATERIAL_GOLD = 50)
|
||||
recyclable = TRUE
|
||||
w_class = ITEMSIZE_TINY
|
||||
var/datum/weakref/thrall = null
|
||||
var/time_counter = 0
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
flags = CONDUCT
|
||||
w_class = ITEMSIZE_SMALL
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 100)
|
||||
recyclable = TRUE
|
||||
throwforce = 2
|
||||
throw_speed = 3
|
||||
throw_range = 10
|
||||
@@ -108,4 +109,4 @@
|
||||
|
||||
|
||||
/obj/item/device/assembly/interact(mob/user)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
w_class = 3.0
|
||||
flags = CONDUCT
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 3000)
|
||||
recyclable = TRUE
|
||||
hitsound = /decl/sound_category/bottle_hit_broken
|
||||
drop_sound = /decl/sound_category/bottle_hit_broken
|
||||
var/max_carry = 20
|
||||
|
||||
@@ -267,14 +267,14 @@
|
||||
..()
|
||||
recipes += new /datum/stack_recipe_list("[display_name] construction",
|
||||
list(
|
||||
new /datum/stack_recipe("phoron floor tile", /turf/simulated/floor/phoron, 1, 4, 20)
|
||||
new /datum/stack_recipe("phoron floor tile", /obj/item/stack/tile/phoron, 1, 4, 20)
|
||||
))
|
||||
|
||||
/material/diamond/generate_recipes()
|
||||
..()
|
||||
recipes += new /datum/stack_recipe_list("[display_name] construction",
|
||||
list(
|
||||
new /datum/stack_recipe("diamond floor tile", /turf/simulated/floor/diamond, 1, 4, 20)
|
||||
new /datum/stack_recipe("diamond floor tile", /obj/item/stack/tile/diamond, 1, 4, 20)
|
||||
))
|
||||
|
||||
/material/leather/generate_recipes()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 3
|
||||
max_amount = 50
|
||||
recyclable = TRUE // Pretty much all materials should be recyclable
|
||||
|
||||
var/default_type = DEFAULT_WALL_MATERIAL
|
||||
var/material/material
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
uses_charge = 1
|
||||
charge_costs = list(1000)
|
||||
gender = NEUTER
|
||||
matter = null // Don't shove it in the autholathe.
|
||||
|
||||
// Don't shove it in the autholathe
|
||||
recyclable = FALSE
|
||||
matter = null
|
||||
|
||||
/obj/item/stack/material/cyborg/New()
|
||||
if(..())
|
||||
@@ -39,4 +42,4 @@
|
||||
As a synthetic, you can gain more reinforced glass by recharging."
|
||||
icon_state = "sheet-rglass"
|
||||
default_type = MATERIAL_GLASS_REINFORCED
|
||||
charge_costs = list(500, 1000)
|
||||
charge_costs = list(500, 1000)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
ingested = new /datum/reagents/metabolism(240, owner, CHEM_INGEST)
|
||||
if(!ingested.my_atom)
|
||||
ingested.my_atom = src
|
||||
if(species.gluttonous)
|
||||
if(species && species.gluttonous)
|
||||
action_button_name = PUKE_ACTION_NAME
|
||||
|
||||
/obj/item/organ/internal/stomach/removed()
|
||||
@@ -140,4 +140,4 @@
|
||||
if(!QDELETED(M))
|
||||
qdel(M)
|
||||
|
||||
#undef PUKE_ACTION_NAME
|
||||
#undef PUKE_ACTION_NAME
|
||||
|
||||
@@ -475,6 +475,7 @@ obj/structure/cable/proc/cableColor(var/colorC)
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 50, MATERIAL_GLASS = 20)
|
||||
recyclable = TRUE
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = null
|
||||
w_class = ITEMSIZE_SMALL
|
||||
recyclable = TRUE
|
||||
var/amount_per_transfer_from_this = 5
|
||||
var/possible_transfer_amounts = list(5,10,15,25,30)
|
||||
var/volume = 30
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
desc = "A bluespace beaker, powered by experimental bluespace technology."
|
||||
icon_state = "beakerbluespace"
|
||||
center_of_mass = list("x" = 16,"y" = 11)
|
||||
matter = list(MATERIAL_GLASS = 5000)
|
||||
matter = list(MATERIAL_PHORON = 1000, MATERIAL_DIAMOND = 100)
|
||||
volume = 300
|
||||
amount_per_transfer_from_this = 10
|
||||
possible_transfer_amounts = list(5,10,15,25,30,60,120,300)
|
||||
|
||||
@@ -116,11 +116,11 @@
|
||||
/datum/design/item/beaker/noreact
|
||||
desc = "A cryostasis beaker that allows for chemical storage without reactions. Can hold up to 50 units."
|
||||
req_tech = list(TECH_MATERIAL = 2)
|
||||
materials = list(DEFAULT_WALL_MATERIAL = 3000)
|
||||
materials = list(DEFAULT_WALL_MATERIAL = 2000, MATERIAL_GLASS = 1000)
|
||||
build_path = /obj/item/reagent_containers/glass/beaker/noreact
|
||||
|
||||
/datum/design/item/beaker/bluespace
|
||||
desc = "A bluespace beaker, powered by experimental bluespace technology and Element Cuban combined with the Compound Pete. Can hold up to 300 units."
|
||||
req_tech = list(TECH_BLUESPACE = 2, TECH_MATERIAL = 6)
|
||||
materials = list(DEFAULT_WALL_MATERIAL = 3000, MATERIAL_PHORON = 3000, MATERIAL_DIAMOND = 500)
|
||||
build_path = /obj/item/reagent_containers/glass/beaker/bluespace
|
||||
build_path = /obj/item/reagent_containers/glass/beaker/bluespace
|
||||
|
||||
@@ -309,14 +309,14 @@ won't update every console in existence) but it's more of a hassle to do. Also,
|
||||
sync = !sync
|
||||
|
||||
else if(href_list["protolathe_category"])
|
||||
var/choice = input("Which category do you wish to display?") as null|anything in files.protolathe_categories+"All"
|
||||
var/choice = input("Which category do you wish to display?") as null|anything in designs_protolathe_categories+"All"
|
||||
if(!choice)
|
||||
return
|
||||
protolathe_category = choice
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["imprinter_category"])
|
||||
var/choice = input("Which category do you wish to display?") as null|anything in files.imprinter_categories+"All"
|
||||
var/choice = input("Which category do you wish to display?") as null|anything in designs_protolathe_categories+"All"
|
||||
if(!choice)
|
||||
return
|
||||
imprinter_category = choice
|
||||
@@ -867,4 +867,4 @@ won't update every console in existence) but it's more of a hassle to do. Also,
|
||||
/obj/machinery/computer/rdconsole/core
|
||||
name = "core R&D console"
|
||||
desc = "A console which is used to operate various research devices. It is the backbone of any megacorporate research division."
|
||||
id = 1
|
||||
id = 1
|
||||
|
||||
@@ -11,7 +11,6 @@ with these since they should be the default version of the datums. They're actua
|
||||
refer to them since it makes it a bit easier to search through them for specific information.
|
||||
- know_tech is the companion list to possible_tech. It's the tech you can actually research and improve. Until it's added to this
|
||||
list, it can't be improved. All the tech in this list are visible to the player.
|
||||
- possible_designs is functionally identical to possbile_tech except it's for /datum/design.
|
||||
- known_designs is functionally identical to known_tech except it's for /datum/design
|
||||
|
||||
Procs:
|
||||
@@ -23,7 +22,7 @@ it doesn't have it, it adds it. Note: It does NOT check possible_tech at all. So
|
||||
a player made tech?) you can.
|
||||
- AddDesign2Known: Same as AddTech2Known except for /datum/design and known_designs.
|
||||
- RefreshResearch: This is the workhorse of the R&D system. It updates the /datum/research holder and adds any unlocked tech paths
|
||||
and designs you have reached the requirements for. It only checks through possible_tech and possible_designs, however, so it won't
|
||||
and designs you have reached the requirements for. It only checks through possible_tech and designs, however, so it won't
|
||||
accidentally add "secret" tech to it.
|
||||
- UpdateTech is used as part of the actual researching process. It takes an ID and finds techs with that same ID in known_tech. When
|
||||
it finds it, it checks to see whether it can improve it at all. If the known_tech's level is less then or equal to
|
||||
@@ -44,11 +43,13 @@ research holder datum.
|
||||
** Includes all the helper procs and basic tech processing. **
|
||||
***************************************************************/
|
||||
|
||||
// Global design lists
|
||||
var/global/list/designs = null
|
||||
var/global/list/designs_protolathe_categories = list()
|
||||
var/global/list/designs_imprinter_categories = list()
|
||||
|
||||
/datum/research //Holder for all the existing, archived, and known tech. Individual to console.
|
||||
var/list/known_tech = list() //List of locally known tech. Datum/tech go here.
|
||||
var/list/possible_designs = list() //List of all designs.
|
||||
var/list/protolathe_categories = list()
|
||||
var/list/imprinter_categories = list()
|
||||
var/list/known_designs = list() //List of available designs.
|
||||
|
||||
var/standard_start_level // The level non-antag techs are set at
|
||||
@@ -67,14 +68,8 @@ research holder datum.
|
||||
else
|
||||
if(antag_start_level)
|
||||
T.level = antag_start_level
|
||||
if(load_designs)
|
||||
for(var/design_path in subtypesof(/datum/design))
|
||||
var/datum/design/D = new design_path(src)
|
||||
if(D.build_type & PROTOLATHE)
|
||||
protolathe_categories |= D.p_category
|
||||
if(D.build_type & IMPRINTER)
|
||||
imprinter_categories |= D.p_category
|
||||
possible_designs[D.type] = D
|
||||
if(load_designs && isnull(designs))
|
||||
InitializeDesigns()
|
||||
RefreshResearch()
|
||||
|
||||
/datum/research/techonly
|
||||
@@ -83,6 +78,16 @@ research holder datum.
|
||||
/datum/research/hightech
|
||||
standard_start_level = 3
|
||||
|
||||
/datum/research/proc/InitializeDesigns()
|
||||
designs = list()
|
||||
for(var/T in subtypesof(/datum/design))
|
||||
var/datum/design/D = new T
|
||||
designs[D.type] = D
|
||||
if(D.build_type & PROTOLATHE)
|
||||
designs_protolathe_categories |= D.p_category
|
||||
if(D.build_type & IMPRINTER)
|
||||
designs_imprinter_categories |= D.p_category
|
||||
|
||||
//Checks to see if design has all the required pre-reqs.
|
||||
//Input: datum/design; Output: 0/1 (false/true)
|
||||
/datum/research/proc/DesignHasReqs(var/datum/design/D)
|
||||
@@ -123,10 +128,11 @@ research holder datum.
|
||||
//Input/Output: n/a
|
||||
/datum/research/proc/RefreshResearch()
|
||||
known_designs.Cut() // this is to refresh the ordering of the designs, the alternative is an expensive insertion or sorting proc
|
||||
for(var/path in possible_designs)
|
||||
var/datum/design/PD = possible_designs[path]
|
||||
if(DesignHasReqs(PD))
|
||||
AddDesign2Known(PD)
|
||||
if(load_designs)
|
||||
for(var/path in designs)
|
||||
var/datum/design/PD = designs[path]
|
||||
if(DesignHasReqs(PD))
|
||||
AddDesign2Known(PD)
|
||||
for(var/id in known_tech)
|
||||
var/datum/tech/T = known_tech[id]
|
||||
T.level = between(0, T.level, MAX_TECH_LEVEL)
|
||||
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Unit Tests for various recipes.
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/unit_test/research_design_cost
|
||||
name = "RECIPES: Design Cost"
|
||||
|
||||
/datum/unit_test/research_design_cost/start_test()
|
||||
var/tested_count = 0
|
||||
var/error_count = 0
|
||||
for(var/T in subtypesof(/datum/design))
|
||||
var/datum/design/D = new T
|
||||
if(ispath(D.build_path, /obj/item))
|
||||
var/obj/item/I = D.Fabricate()
|
||||
if(I.matter && D.materials && I.recyclable) // non-recyclable items can't be exploited
|
||||
for(var/mat in I.matter)
|
||||
tested_count++
|
||||
if(mat in D.materials)
|
||||
if(I.matter[mat] > D.materials[mat])
|
||||
fail("Design '[D.name]' costs less material '[mat]' ([D.materials[mat]]) than the product is worth ([I.matter[mat]]).")
|
||||
error_count++
|
||||
else
|
||||
fail("Design '[D.name]' does not require material '[mat]' even though the product is worth [I.matter[mat]].")
|
||||
error_count++
|
||||
qdel(I)
|
||||
qdel(D)
|
||||
|
||||
if(error_count)
|
||||
fail("[error_count] design error(s) found. Every research design should cost more than what its product is worth when recycled.")
|
||||
else
|
||||
pass("All [tested_count] research designs with recyclable products have correct material costs.")
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/datum/unit_test/stack_recipe_cost
|
||||
name = "RECIPES: Stack Recipes"
|
||||
|
||||
/datum/unit_test/stack_recipe_cost/start_test()
|
||||
var/tested_count = 0
|
||||
var/error_count = 0
|
||||
for(var/T in subtypesof(/material))
|
||||
var/material/D = new T
|
||||
var/list/datum/stack_recipe_list/recipe_lists = D.get_recipes()
|
||||
var/list/temp_matter = D.get_matter()
|
||||
for(var/datum/stack_recipe_list/L in recipe_lists)
|
||||
for(var/datum/stack_recipe/R in L.recipes)
|
||||
if(!ispath(R.result_type, /obj/item))
|
||||
continue
|
||||
var/obj/item/I = R.Produce()
|
||||
if(I.matter && I.recyclable) // non-recyclable items can't be exploited
|
||||
tested_count++
|
||||
for(var/mat in I.matter)
|
||||
if(mat in temp_matter)
|
||||
var/item_matter_value = I.matter[mat] * R.res_amount
|
||||
var/consumed_matter_value = temp_matter[mat] * R.req_amount
|
||||
if(item_matter_value > consumed_matter_value)
|
||||
fail("Recipe '[R.title]' on material '[D.name]' consumes less material '[mat]' ([R.req_amount] × [temp_matter[mat]] = [consumed_matter_value]) than the product is worth ([R.res_amount] × [I.matter[mat]] = [item_matter_value]).")
|
||||
error_count++
|
||||
else
|
||||
warn("Recipe '[R.title]' on material '[D.name]' creates product with material '[mat]', but that material is not required by the recipe.")
|
||||
qdel(I)
|
||||
qdel(D)
|
||||
|
||||
if(error_count)
|
||||
fail("[error_count] stack recipe error(s) found. Every stack recipe should cost more than what its product is worth when recycled.")
|
||||
else
|
||||
pass("All [tested_count] stack recipes with recyclable /obj/item products have correct material costs.")
|
||||
|
||||
return 1
|
||||
@@ -1,11 +1,11 @@
|
||||
/* Unit Tests originally designed by Ccomp5950
|
||||
*
|
||||
*
|
||||
* Tests are created to prevent changes that would create bugs or change expected behaviour.
|
||||
* For the most part I think any test can be created that doesn't require a client in a mob or require a game mode other then extended
|
||||
*
|
||||
*
|
||||
* The easiest way to make effective tests is to create a "template" if you intend to run the same test over and over and make your actual
|
||||
* tests be a "child object" of those templates. Be sure and name your templates with the word "template" somewhere in var/name.
|
||||
*
|
||||
*
|
||||
* The goal is to have all sorts of tests that run and to run them as quickly as possible.
|
||||
*
|
||||
* Tests that require time to run we instead just check back on their results later instead of waiting around in a sleep(1) for each test.
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* If your test requires a significant amount of time...cheat on the timers. Either speed up the process/life runs or do as we did in the timers for the shuttle
|
||||
* transfers in zas_tests.dm we move a shuttle but instead of waiting 3 minutes we set the travel time to a very low number.
|
||||
*
|
||||
*
|
||||
* At the same time, Unit tests are intended to reflect standard usage so avoid changing to much about how stuff is processed.
|
||||
*
|
||||
*
|
||||
@@ -34,6 +34,7 @@ var/total_unit_tests = 0
|
||||
var/ascii_esc = ascii2text(27)
|
||||
var/ascii_red = "[ascii_esc]\[31m"
|
||||
var/ascii_green = "[ascii_esc]\[32m"
|
||||
var/ascii_yellow = "[ascii_esc]\[33m"
|
||||
var/ascii_reset = "[ascii_esc]\[0m"
|
||||
|
||||
|
||||
@@ -58,13 +59,16 @@ datum/unit_test/proc/pass(var/message)
|
||||
reported = 1
|
||||
log_unit_test("[ascii_green]*** SUCCESS *** \[[name]\]: [message][ascii_reset]")
|
||||
|
||||
datum/unit_test/proc/warn(var/message)
|
||||
log_unit_test("[ascii_yellow]=== WARNING === \[[name]\]: [message][ascii_reset]")
|
||||
|
||||
datum/unit_test/proc/start_test()
|
||||
fail("No test proc.")
|
||||
|
||||
datum/unit_test/proc/check_result()
|
||||
fail("No check results proc")
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
proc/load_unit_test_changes()
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user