diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 05de6b9ac69..cc3cc05e809 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -1,3 +1,63 @@ +/* +* Datum that holds the instances and information about the items in the smartfridge. +*/ +/datum/data/stored_item + var/item_name = "name" //Name of the item(s) displayed + var/item_path = null + var/amount = 0 + var/list/instances //What items are actually stored + var/fridge //The attatched fridge + +/datum/data/stored_item/New(var/fridge, var/path, var/name = null, var/amount = 0) + ..() + + src.item_path = path + + if(!name) + var/atom/tmp = path + src.item_name = initial(tmp.name) + else + src.item_name = name + + src.amount = amount + src.fridge = fridge + +/datum/data/stored_item/Destroy() + fridge = null + if(instances) + for(var/product in instances) + qdel(product) + instances.Cut() + . = ..() + +/datum/data/stored_item/proc/get_amount() + return instances ? instances.len : amount + +/datum/data/stored_item/proc/get_product(var/product_location) + if(!get_amount() || !product_location) + return + init_products() + + var/atom/movable/product = instances[instances.len] // Remove the last added product + instances -= product + product.forceMove(product_location) + +/datum/data/stored_item/proc/add_product(var/atom/movable/product) + if(product.type != item_path) + return 0 + init_products() + product.forceMove(fridge) + instances += product + +/datum/data/stored_item/proc/init_products() + if(instances) + return + instances = list() + for(var/i = 1 to amount) + var/new_product = new item_path(fridge) + instances += new_product + + /* SmartFridge. Much todo */ /obj/machinery/smartfridge @@ -15,7 +75,8 @@ var/icon_on = "smartfridge" var/icon_off = "smartfridge-off" var/icon_panel = "smartfridge-panel" - var/item_quants = list() + var/list/item_records = list() + var/datum/data/stored_item/currently_vending = null //What we're putting out of the machine. var/seconds_electrified = 0; var/shoot_inventory = 0 var/locked = 0 @@ -68,11 +129,14 @@ /obj/machinery/smartfridge/secure/extract/New() ..() + var/datum/data/stored_item/I = new(src, /obj/item/xenoproduct/slime/core) + item_records.Add(I) for(var/i=1 to 5) var/obj/item/xenoproduct/slime/core/C = new(src) C.traits = new() C.nameVar = "grey" - item_quants[C.name]++ + I.add_product(C) + /obj/machinery/smartfridge/secure/medbay name = "\improper Refrigerated Medicine Storage" @@ -162,20 +226,19 @@ overlays += "drying_rack_drying" /obj/machinery/smartfridge/drying_rack/proc/dry() - for(var/obj/item/weapon/reagent_containers/food/snacks/S in contents) - if(S.dry) continue - if(S.dried_type == S.type) - S.dry = 1 - item_quants[S.name]-- - S.name = "dried [S.name]" - S.color = "#AAAAAA" - S.loc = loc - else - var/D = S.dried_type - new D(loc) - item_quants[S.name]-- - qdel(S) - return + for(var/datum/data/stored_item/I in item_records) + for(var/obj/item/weapon/reagent_containers/food/snacks/S in I.instances) + if(S.dry) continue + if(S.dried_type == S.type) + S.dry = 1 + S.name = "dried [S.name]" + S.color = "#AAAAAA" + I.get_product(loc) + else + var/D = S.dried_type + new D(loc) + qdel(S) + return return /obj/machinery/smartfridge/process() @@ -222,35 +285,38 @@ return if(accept_check(O)) - if(contents.len >= max_n_of_items) - user << "\The [src] is full." - return 1 - else - user.remove_from_mob(O) - O.loc = src - if(item_quants[O.name]) - item_quants[O.name]++ - else - item_quants[O.name] = 1 - user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") + user.remove_from_mob(O) + var/hasRecord = FALSE //Check to see if this passes or not. + for(var/datum/data/stored_item/I in item_records) + if(istype(O, I.item_path)) + stock(O, I) + qdel(O) + return + if(!hasRecord) + var/datum/data/stored_item/item = new/datum/data/stored_item(src, O.type) + stock(O, item) + item_records.Add(item) + + user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].") - nanomanager.update_uis(src) + nanomanager.update_uis(src) else if(istype(O, /obj/item/weapon/storage/bag)) var/obj/item/weapon/storage/bag/P = O var/plants_loaded = 0 for(var/obj/G in P.contents) if(accept_check(G)) - if(contents.len >= max_n_of_items) - user << "\The [src] is full." - return 1 - else - P.remove_from_storage(G,src) - if(item_quants[G.name]) - item_quants[G.name]++ - else - item_quants[G.name] = 1 - plants_loaded++ + plants_loaded++ + var/hasRecord = FALSE //Check to see if this passes or not. + for(var/datum/data/stored_item/I in item_records) + if(istype(G, I.item_path)) + stock(G, I) + hasRecord = TRUE + if(!hasRecord) + var/datum/data/stored_item/item = new/datum/data/stored_item(src, G.type) + stock(G, item) + item_records.Add(item) + if(plants_loaded) user.visible_message("[user] loads \the [src] with \the [P].", "You load \the [src] with \the [P].") @@ -269,6 +335,14 @@ locked = -1 user << "You short out the product lock on [src]." return 1 + +/obj/machinery/smartfridge/proc/stock(obj/item/O, var/datum/data/stored_item/I) + I.add_product(O) + nanomanager.update_uis(src) + +/obj/machinery/smartfridge/proc/vend(datum/data/stored_item/I) + I.get_product(get_turf(src)) + nanomanager.update_uis(src) /obj/machinery/smartfridge/attack_ai(mob/user as mob) attack_hand(user) @@ -294,11 +368,11 @@ data["secure"] = is_secure var/list/items[0] - for (var/i=1 to length(item_quants)) - var/K = item_quants[i] - var/count = item_quants[K] + for (var/i=1 to length(item_records)) + var/datum/data/stored_item/I = item_records[i] + var/count = I.get_amount() if(count > 0) - items.Add(list(list("display_name" = html_encode(capitalize(K)), "vend" = i, "quantity" = count))) + items.Add(list(list("display_name" = html_encode(capitalize(I.item_name)), "vend" = i, "quantity" = count))) if(items.len > 0) data["contents"] = items @@ -325,20 +399,15 @@ if(href_list["vend"]) var/index = text2num(href_list["vend"]) var/amount = text2num(href_list["amount"]) - var/K = item_quants[index] - var/count = item_quants[K] + var/datum/data/stored_item/I = item_records[index] + var/count = I.get_amount() // Sanity check, there are probably ways to press the button when it shouldn't be possible. if(count > 0) - item_quants[K] = max(count - amount, 0) - - var/i = amount - for(var/obj/O in contents) - if(O.name == K) - O.loc = loc - i-- - if(i <= 0) - return 1 + if((count - amount) < 0) + amount = count + for(var/i = 1 to amount) + vend(I) return 1 return 0 @@ -349,17 +418,12 @@ if(!target) return 0 - for (var/O in item_quants) - if(item_quants[O] <= 0) //Try to use a record that actually has something to dump. + for(var/datum/data/stored_item/I in src.item_records) + throw_item = I.get_product(loc) + if (!throw_item) continue - - item_quants[O]-- - for(var/obj/T in contents) - if(T.name == O) - T.loc = src.loc - throw_item = T - break break + if(!throw_item) return 0 spawn(0) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 8b349959b5b..d7e530b761f 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -108,6 +108,10 @@ steam.start() -- spawns the effect if (istype(T, /turf)) T.hotspot_expose(1000,100) +/obj/effect/effect/sparks/initialize() + ..() + schedule_task_in(5 SECONDS, /proc/qdel, list(src)) + /obj/effect/effect/sparks/Destroy() var/turf/T = src.loc if (istype(T, /turf)) diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index e9f784f4451..9f6992d4046 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -275,7 +275,7 @@ /obj/item/weapon/storage/box/metalfoam/New() ..() for(var/i = 1 to 7) - new /obj/item/weapon/grenade/chem_grenade/metalfoam + new /obj/item/weapon/grenade/chem_grenade/metalfoam(src) /obj/item/weapon/storage/box/trackimp name = "boxed tracking implant kit" diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 6968fde34bc..73ceddb70f6 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -184,6 +184,9 @@ icon_state = "doublebed" base_icon = "doublebed" +/obj/structure/bed/double/padded/New(var/newloc) + ..(newloc,"wood","cotton") + /obj/structure/bed/double/post_buckle_mob(mob/living/M as mob) if(M == buckled_mob) M.pixel_y = 13 diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index 656f54d4778..27aa76cc306 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -107,7 +107,7 @@ datum/preferences/proc/set_biological_gender(var/gender) else if(href_list["metadata"]) var/new_metadata = sanitize(input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , pref.metadata)) as message|null if(new_metadata && CanUseTopic(user)) - pref.metadata = sanitize(new_metadata) + pref.metadata = new_metadata return TOPIC_REFRESH return ..() diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 85be34332b2..b99833670d5 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -14,6 +14,7 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins use_power = 1 idle_power_usage = 30 active_power_usage = 200 + circuit = /obj/item/weapon/circuitboard/fax var/obj/item/weapon/card/id/scan = null // identification var/authenticated = 0 @@ -22,13 +23,11 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins var/destination = null // the department we're sending to /obj/machinery/photocopier/faxmachine/New() - ..() allfaxes += src if(!destination) destination = "[boss_name]" if( !(("[department]" in alldepartments) || ("[department]" in admin_departments)) ) alldepartments |= department - - circuit = new circuit(src) + ..() /obj/machinery/photocopier/faxmachine/attack_hand(mob/user as mob) user.set_machine(src) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 93f928b94f8..5c37577c039 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -82,6 +82,13 @@ var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. var/tmp/lock_time = -100 + var/dna_lock = 0 //whether or not the gun is locked to dna + var/list/stored_dna = list() //list of the dna stored in the gun, used to allow users to use it or not + var/safety_level = 0 //either 0 or 1, at 0 the game buzzes and tells the user they can't use it, at 1 it self destructs after 10 seconds + var/controller_dna = null //The dna of the person who is the primary controller of the gun + var/controller_lock = 0 //whether or not the gun is locked by the primar controller, 0 or 1, at 1 it is locked and does not allow + var/exploding = 0 + /obj/item/weapon/gun/New() ..() for(var/i in 1 to firemodes.len) @@ -90,6 +97,11 @@ if(isnull(scoped_accuracy)) scoped_accuracy = accuracy + if(!dna_lock) + verbs -= /obj/item/weapon/gun/verb/remove_dna + verbs -= /obj/item/weapon/gun/verb/give_dna + verbs -= /obj/item/weapon/gun/verb/allow_dna + /obj/item/weapon/gun/update_held_icon() if(requires_two_hands) var/mob/living/M = loc @@ -114,6 +126,20 @@ return 0 var/mob/living/M = user + if(dna_lock && stored_dna) + if(!authorized_user(user)) + if(safety_level == 0) + M << "\The [src] buzzes in dissapoint and displays an invalid DNA symbol." + return 0 + if(!exploding) + if(safety_level == 1) + M << "\The [src] hisses in dissapointment." + visible_message("\The [src] announces, \"Self-destruct occurring in ten seconds.\"", "\The [src] announces, \"Self-destruct occurring in ten seconds.\"") + sleep(100) + explosion(src, -1, 0, 2, 3, 0) + exploding = 1 + qdel(src) + return 0 if(HULK in M.mutations) M << "Your fingers are much too large for the trigger guard!" return 0 @@ -429,3 +455,80 @@ /obj/item/weapon/gun/attack_self(mob/user) switch_firemodes(user) +<<<<<<< HEAD +======= + +/obj/item/weapon/gun/proc/get_dna(mob/user) + var/mob/living/M = user + if(!controller_lock) + + if(!stored_dna && !(M.dna in stored_dna)) + M << "\The [src] buzzes and displays a symbol showing the gun already contains your DNA." + return 0 + else + stored_dna += M.dna + M << "\The [src] pings and a needle flicks out from the grip, taking a DNA sample from you." + if(!controller_dna) + controller_dna = M.dna + M << "\The [src] processes the dna sample and pings, acknowledging you as the primary controller." + return 1 + else + M << "\The [src] buzzes and displays a locked symbol. It is not allowing DNA samples at this time." + return 0 + +/obj/item/weapon/gun/verb/give_dna() + set name = "Give DNA" + set category = "Object" + set src in usr + get_dna(usr) + +/obj/item/weapon/gun/proc/clear_dna(mob/user) + var/mob/living/M = user + if(!controller_lock) + if(!authorized_user(M)) + M << "\The [src] buzzes and displays an invalid user symbol." + return 0 + else + stored_dna -= user.dna + M << "\The [src] beeps and clears the DNA it has stored." + if(M.dna == controller_dna) + controller_dna = null + M << "\The [src] beeps and removes you as the primary controller." + if(controller_lock) + controller_lock = 0 + return 1 + else + M << "\The [src] buzzes and displays a locked symbol. It is not allowing DNA modifcation at this time." + return 0 + +/obj/item/weapon/gun/verb/remove_dna() + set name = "Remove DNA" + set category = "Object" + set src in usr + clear_dna(usr) + +/obj/item/weapon/gun/proc/toggledna(mob/user) + var/mob/living/M = user + if(authorized_user(M) && user.dna == controller_dna) + if(!controller_lock) + controller_lock = 1 + M << "\The [src] beeps and displays a locked symbol, informing you it will no longer allow DNA samples." + else + controller_lock = 0 + M << "\The [src] beeps and displays an unlocked symbol, informing you it will now allow DNA samples." + else + M << "\The [src] buzzes and displays an invalid user symbol." + +/obj/item/weapon/gun/verb/allow_dna() + set name = "Toggle DNA Samples Allowance" + set category = "Object" + set src in usr + toggledna(usr) + +/obj/item/weapon/gun/proc/authorized_user(mob/user) + if(!stored_dna || !stored_dna.len) + return 1 + if(!(user.dna in stored_dna)) + return 0 + return 1 +>>>>>>> refs/remotes/PolarisSS13/master diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index af531881907..c0ecdbfc3d5 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -510,7 +510,8 @@ other types of metals and chemistry for reagents). /datum/design/item/weapon/decloner id = "decloner" req_tech = list(TECH_COMBAT = 8, TECH_MATERIAL = 7, TECH_BIO = 5, TECH_POWER = 6) - materials = list("gold" = 5000,"uranium" = 10000, "mutagen" = 40) + materials = list("gold" = 5000,"uranium" = 10000) + chemicals = list("mutagen" = 40) build_path = /obj/item/weapon/gun/energy/decloner sort_string = "TAAAE" diff --git a/code/modules/xenobio2/_xeno_setup.dm b/code/modules/xenobio2/_xeno_setup.dm index a08cb546812..e77230b3e5c 100644 --- a/code/modules/xenobio2/_xeno_setup.dm +++ b/code/modules/xenobio2/_xeno_setup.dm @@ -93,6 +93,12 @@ var/global/list/xenoChemList = list("mutationtoxin", var/val = traits["[trait]"] return val +/datum/xeno/traits/proc/copy_traits(var/datum/xeno/traits/target) + target.traits = traits + target.chemlist = chemlist + target.chems = chems + target.source = source + /datum/xeno/traits/New() ..() set_trait(TRAIT_XENO_COLOR, "#CACACA") diff --git a/code/modules/xenobio2/machinery/core_extractor.dm b/code/modules/xenobio2/machinery/core_extractor.dm index 421c8ed22f5..e01bc6f8520 100644 --- a/code/modules/xenobio2/machinery/core_extractor.dm +++ b/code/modules/xenobio2/machinery/core_extractor.dm @@ -110,7 +110,8 @@ icon_state = "scanner_1old" for(var/i=1 to occupant.cores) var/obj/item/xenoproduct/slime/core/C = new(src) - C.traits = occupant.traitdat + C.traits = new() + occupant.traitdat.copy_traits(C.traits) C.nameVar = occupant.nameVar diff --git a/code/modules/xenobio2/mob/slime/slime procs.dm b/code/modules/xenobio2/mob/slime/slime procs.dm index 56ad5d60504..adc8f4e5baf 100644 --- a/code/modules/xenobio2/mob/slime/slime procs.dm +++ b/code/modules/xenobio2/mob/slime/slime procs.dm @@ -13,11 +13,10 @@ Slime specific procs go here. traitdat.traits[TRAIT_XENO_HUNGER] = rand(1, 20) traitdat.traits[TRAIT_XENO_STARVEDAMAGE] = rand(1, 4) traitdat.traits[TRAIT_XENO_EATS] = prob(95) //Odds are, that thing'll need to eat. - traitdat.traits[TRAIT_XENO_CHROMATIC] = prob(5) - if(traitdat.traits[TRAIT_XENO_CHROMATIC]) + traitdat.traits[TRAIT_XENO_HOSTILE] = prob(60) //Let's increase this probabilty. + if(prob(10)) + traitdat.traits[TRAIT_XENO_CHROMATIC] = 1 traitdat.traits[TRAIT_XENO_HOSTILE] = 0 - else - traitdat.traits[TRAIT_XENO_HOSTILE] = prob(30) traitdat.traits[TRAIT_XENO_GLOW_STRENGTH] = round(rand(1,3)) traitdat.traits[TRAIT_XENO_GLOW_RANGE] = round(rand(1,3)) traitdat.traits[TRAIT_XENO_STRENGTH] = round(rand(4,9)) diff --git a/code/modules/xenobio2/mob/xeno procs.dm b/code/modules/xenobio2/mob/xeno procs.dm index e20373c21ce..94da479f5a5 100644 --- a/code/modules/xenobio2/mob/xeno procs.dm +++ b/code/modules/xenobio2/mob/xeno procs.dm @@ -29,10 +29,8 @@ Procs for targeting set_light(traitdat.traits[TRAIT_XENO_GLOW_RANGE], traitdat.traits[TRAIT_XENO_GLOW_STRENGTH], traitdat.traits[TRAIT_XENO_BIO_COLOR]) else set_light(0, 0, "#000000") //Should kill any light that shouldn't be there. - if(chromatic) - hostile = 0 //No. No laser-reflecting hostile creatures. Bad. - else - hostile = traitdat.traits[TRAIT_XENO_HOSTILE] + + hostile = traitdat.traits[TRAIT_XENO_HOSTILE] speed = traitdat.traits[TRAIT_XENO_SPEED] diff --git a/code/modules/xenobio2/tools/xeno_trait_scanner.dm b/code/modules/xenobio2/tools/xeno_trait_scanner.dm index 8063b6071bb..565db473644 100644 --- a/code/modules/xenobio2/tools/xeno_trait_scanner.dm +++ b/code/modules/xenobio2/tools/xeno_trait_scanner.dm @@ -111,7 +111,7 @@ dat += "It bears no characters indicating resilience to damage.
" if(growth_max) - if(growth_level < 25) + if(growth_level < 35) dat += "It appears to be far to growing up.
" else if(growth_level > 40) dat += "It appears to be close to growing up.
" diff --git a/code/unit_tests/research_tests.dm b/code/unit_tests/research_tests.dm index 34c63b9d108..93bf79a0da6 100644 --- a/code/unit_tests/research_tests.dm +++ b/code/unit_tests/research_tests.dm @@ -40,3 +40,33 @@ issues++ return issues + +/datum/unit_test/research_designs_have_valid_materials + name = "RESEARCH: Designs Shall Have Valid Materials and Chemicals" + +/datum/unit_test/research_designs_have_valid_materials/start_test() + var/number_of_issues = 0 + + for(var/design_type in typesof(/datum/design) - /datum/design) + var/datum/design/design = design_type + if(initial(design.id) == "id") + continue + design = new design_type() // Unfortunately we have to actually instantiate to get a list. + + for(var/material_name in design.materials) + var/material/material = get_material_by_name(material_name) + if(!material) + log_unit_test("The entry [design_type] has invalid material type [material_name]") + number_of_issues++ + + for(var/reagent_name in design.chemicals) + if(!(reagent_name in chemical_reagents_list)) + log_unit_test("The entry [design_type] has invalid chemical type [reagent_name]") + number_of_issues++ + + if(number_of_issues) + fail("[number_of_issues] issues with research designs found.") + else + pass("All research designs have valid materials.") + + return 1