diff --git a/code/ATMOSPHERICS/components/unary_devices/cryo.dm b/code/ATMOSPHERICS/components/unary_devices/cryo.dm index f49c772816f7..2f79446bac79 100644 --- a/code/ATMOSPHERICS/components/unary_devices/cryo.dm +++ b/code/ATMOSPHERICS/components/unary_devices/cryo.dm @@ -8,7 +8,7 @@ var/on = 0 var/temperature_archived - var/obj/item/weapon/reagent_containers/beaker = null + var/obj/item/weapon/reagent_containers/glass/beaker = null var/next_trans = 0 var/current_heat_capacity = 50 state_open = 0 @@ -43,7 +43,7 @@ T.contents += contents if(beaker) - beaker.loc = get_step(loc, SOUTH) //Beaker is carefully fed from the wreckage of the cryotube + beaker.loc = get_step(loc, SOUTH) // Beaker is carefully ejected from the wreckage of the cryotube. beaker = null return ..() @@ -159,8 +159,8 @@ data["isBeakerLoaded"] = beaker ? 1 : 0 var beakerContents[0] - if(beaker && beaker:reagents && beaker:reagents.reagent_list.len) - for(var/datum/reagent/R in beaker:reagents.reagent_list) + if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) + for(var/datum/reagent/R in beaker.reagents.reagent_list) beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... data["beakerContents"] = beakerContents return data @@ -187,8 +187,7 @@ if(href_list["ejectBeaker"]) if(beaker) - var/obj/item/weapon/reagent_containers/glass/B = beaker - B.loc = get_step(loc, SOUTH) + beaker.loc = get_step(loc, SOUTH) beaker = null add_fingerprint(usr) diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm new file mode 100644 index 000000000000..3e81a67b1b2f --- /dev/null +++ b/code/__DEFINES/reagents.dm @@ -0,0 +1,3 @@ +#define SOLID 1 +#define LIQUID 2 +#define GAS 3 \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm deleted file mode 100644 index b41c08fa596f..000000000000 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ /dev/null @@ -1,1557 +0,0 @@ -#define SOLID 1 -#define LIQUID 2 -#define GAS 3 - -/obj/machinery/chem_dispenser - name = "chem dispenser" - desc = "Creates and dispenses chemicals." - density = 1 - anchored = 1 - icon = 'icons/obj/chemical.dmi' - icon_state = "dispenser" - use_power = 1 - idle_power_usage = 40 - var/energy = 100 - var/max_energy = 100 - var/amount = 30 - var/beaker = null - var/recharged = 0 - var/recharge_delay = 5 //Time it game ticks between recharges - var/image/icon_beaker = null //cached overlay - var/list/dispensable_reagents = list("hydrogen","lithium","carbon","nitrogen","oxygen","fluorine", - "sodium","aluminium","silicon","phosphorus","sulfur","chlorine","potassium","iron", - "copper","mercury","radium","water","ethanol","sugar","sacid","welding_fuel","silver","iodine","bromine","stable_plasma") - -/obj/machinery/chem_dispenser/proc/recharge() - if(stat & (BROKEN|NOPOWER)) return - var/addenergy = 1 - var/oldenergy = energy - energy = min(energy + addenergy, max_energy) - if(energy != oldenergy) - use_power(1500) // This thing uses up alot of power (this is still low as shit for creating reagents from thin air) - -/obj/machinery/chem_dispenser/power_change() - if(powered()) - stat &= ~NOPOWER - else - spawn(rand(0, 15)) - stat |= NOPOWER - -/obj/machinery/chem_dispenser/process() - - if(recharged < 0) - recharge() - recharged = recharge_delay - else - recharged -= 1 - -/obj/machinery/chem_dispenser/New() - ..() - recharge() - dispensable_reagents = sortList(dispensable_reagents) - -/obj/machinery/chem_dispenser/ex_act(severity, target) - if(severity < 3) - ..() - -/obj/machinery/chem_dispenser/blob_act() - if(prob(50)) - qdel(src) - -/obj/machinery/chem_dispenser/interact(mob/user) - if(stat & BROKEN) - return - ui_interact(user) - -/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) - ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open) - if (!ui) - ui = new(user, src, ui_key, "chem_dispenser.tmpl", name, 500, 650) - ui.open() - -/obj/machinery/chem_dispenser/get_ui_data() - var/data = list() - data["amount"] = amount - data["energy"] = energy - data["maxEnergy"] = max_energy - data["isBeakerLoaded"] = beaker ? 1 : 0 - - var beakerContents[0] - var beakerCurrentVolume = 0 - if(beaker && beaker:reagents && beaker:reagents.reagent_list.len) - for(var/datum/reagent/R in beaker:reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "id" = R.id, "volume" = R.volume))) // list in a list because Byond merges the first list... - beakerCurrentVolume += R.volume - data["beakerContents"] = beakerContents - - if (beaker) - data["beakerCurrentVolume"] = beakerCurrentVolume - data["beakerMaxVolume"] = beaker:volume - else - data["beakerCurrentVolume"] = null - data["beakerMaxVolume"] = null - - var chemicals[0] - for(var/re in dispensable_reagents) - var/datum/reagent/temp = chemical_reagents_list[re] - if(temp) - chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("dispense" = temp.id)))) // list in a list because Byond merges the first list... - data["chemicals"] = chemicals - return data - -/obj/machinery/chem_dispenser/Topic(href, href_list) - if(..()) - return - - if(href_list["amount"]) - amount = round(text2num(href_list["amount"]), 5) // round to nearest 5 - if (amount < 0) // Since the user can actually type the commands himself, some sanity checking - amount = 0 - if (amount > 100) - amount = 100 - - if(href_list["dispense"]) - if (dispensable_reagents.Find(href_list["dispense"]) && beaker != null) - var/obj/item/weapon/reagent_containers/glass/B = src.beaker - var/datum/reagents/R = B.reagents - var/space = R.maximum_volume - R.total_volume - - R.add_reagent(href_list["dispense"], min(amount, energy * 10, space)) - energy = max(energy - min(amount, energy * 10, space) / 10, 0) - - if(href_list["remove"]) - if(beaker) - if(href_list["removeamount"]) - var/amount = text2num(href_list["removeamount"]) - if(isnum(amount) && (amount > 0)) - var/obj/item/weapon/reagent_containers/glass/B = beaker - var/datum/reagents/R = B.reagents - var/id = href_list["remove"] - R.remove_reagent(id, amount) - - if(href_list["ejectBeaker"]) - if(beaker) - var/obj/item/weapon/reagent_containers/glass/B = beaker - B.loc = loc - beaker = null - overlays.Cut() - - add_fingerprint(usr) - -/obj/machinery/chem_dispenser/attackby(obj/item/weapon/reagent_containers/glass/B, mob/user, params) - if(isrobot(user)) - return - - if(!istype(B, /obj/item/weapon/reagent_containers/glass)) - return - - if(src.beaker) - user << "A beaker is already loaded into the machine!" - return - if(!user.drop_item()) - return - - src.beaker = B - B.loc = src - user << "You add the beaker to the machine." - - if(!icon_beaker) - icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position. - icon_beaker.pixel_x = rand(-10,5) - overlays += icon_beaker - -/obj/machinery/chem_dispenser/attack_hand(mob/user) - if (!user) return - interact(user) - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/obj/machinery/chem_dispenser/constructable - name = "portable chem dispenser" - icon = 'icons/obj/chemical.dmi' - icon_state = "minidispenser" - energy = 5 - max_energy = 5 - amount = 5 - recharge_delay = 30 - dispensable_reagents = list() - var/list/special_reagents = list(list("hydrogen", "oxygen", "silicon", "phosphorus", "sulfur", "carbon", "nitrogen", "water"), - list("lithium", "sugar", "sacid", "copper", "mercury", "sodium","iodine","bromine"), - list("ethanol", "chlorine", "potassium", "aluminium", "radium", "fluorine", "iron", "welding_fuel","silver","stable_plasma"), - list("oil", "ash", "acetone", "saltpetre", "ammonia", "diethylamine")) - -/obj/machinery/chem_dispenser/constructable/New() - ..() - component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/chem_dispenser(null) - component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) - component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) - component_parts += new /obj/item/weapon/stock_parts/manipulator(null) - component_parts += new /obj/item/weapon/stock_parts/capacitor(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - component_parts += new /obj/item/weapon/stock_parts/cell/high(null) - RefreshParts() - -/obj/machinery/chem_dispenser/constructable/RefreshParts() - var/time = 0 - var/temp_energy = 0 - var/i - for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) - temp_energy += M.rating - temp_energy-- - max_energy = temp_energy * 5 //max energy = (bin1.rating + bin2.rating - 1) * 5, 5 on lowest 25 on highest - for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) - time += C.rating - for(var/obj/item/weapon/stock_parts/cell/P in component_parts) - time += round(P.maxcharge, 10000) / 10000 - recharge_delay /= time/2 //delay between recharges, double the usual time on lowest 50% less than usual on highest - for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) - for(i=1, i<=M.rating, i++) - dispensable_reagents |= special_reagents[i] - dispensable_reagents = sortList(dispensable_reagents) - -/obj/machinery/chem_dispenser/constructable/attackby(var/obj/item/I, var/mob/user, params) - ..() - if(default_deconstruction_screwdriver(user, "minidispenser-o", "minidispenser", I)) - return - - if(exchange_parts(user, I)) - return - - if(panel_open) - if(istype(I, /obj/item/weapon/crowbar)) - if(beaker) - var/obj/item/weapon/reagent_containers/glass/B = beaker - B.loc = loc - beaker = null - default_deconstruction_crowbar(I) - return 1 - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/obj/machinery/chem_master - name = "ChemMaster 3000" - desc = "Used to bottle chemicals to create pills." - density = 1 - anchored = 1 - icon = 'icons/obj/chemical.dmi' - icon_state = "mixer0" - use_power = 1 - idle_power_usage = 20 - var/obj/item/weapon/reagent_containers/glass/beaker = null - var/obj/item/weapon/storage/pill_bottle/loaded_pill_bottle = null - var/mode = 0 - var/condi = 0 - var/useramount = 30 // Last used amount - - -/obj/machinery/chem_master/New() - create_reagents(100) - overlays += "waitlight" - -/obj/machinery/chem_master/ex_act(severity, target) - if(severity < 3) - ..() - -/obj/machinery/chem_master/blob_act() - if (prob(50)) - qdel(src) - -/obj/machinery/chem_master/power_change() - if(powered()) - stat &= ~NOPOWER - else - spawn(rand(0, 15)) - stat |= NOPOWER - - -/obj/machinery/chem_master/attackby(obj/item/B, mob/user, params) - if(default_unfasten_wrench(user, B)) - return - - if(istype(B, /obj/item/weapon/reagent_containers/glass)) - if(isrobot(user)) - return - if(src.beaker) - user << "A beaker is already loaded into the machine!" - return - if(!user.drop_item()) - return - - src.beaker = B - B.loc = src - user << "You add the beaker to the machine." - src.updateUsrDialog() - icon_state = "mixer1" - - else if(!condi && istype(B, /obj/item/weapon/storage/pill_bottle)) - if(src.loaded_pill_bottle) - user << "A pill bottle is already loaded into the machine!" - return - if(!user.drop_item()) - return - - src.loaded_pill_bottle = B - B.loc = src - user << "You add the pill bottle into the dispenser slot." - src.updateUsrDialog() - - return - -/obj/machinery/chem_master/Topic(href, href_list) - if(..()) - return - - usr.set_machine(src) - - if(href_list["ejectp"]) - if(loaded_pill_bottle) - loaded_pill_bottle.loc = src.loc - loaded_pill_bottle = null - - else if(href_list["close"]) - usr << browse(null, "window=chem_master") - usr.unset_machine() - return - - else if(href_list["toggle"]) - mode = !mode - - else if(href_list["createbottle"]) - var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN) - if(!name) - return - var/obj/item/weapon/reagent_containers/P - if(condi) - P = new/obj/item/weapon/reagent_containers/food/condiment(src.loc) - else - P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) - P.pixel_x = rand(-7, 7) //random position - P.pixel_y = rand(-7, 7) - P.name = trim("[name] bottle") - reagents.trans_to(P, P.volume) - - if(beaker) - - if(href_list["analyze"]) - if(locate(href_list["reagent"])) - var/datum/reagent/R = locate(href_list["reagent"]) - if(R) - var/dat = "" - dat += "

[condi ? "Condiment" : "Chemical"] information:

" - dat += "Name: [initial(R.name)]

" - dat += "State: " - if(initial(R.reagent_state) == 1) - dat += "Solid" - else if(initial(R.reagent_state) == 2) - dat += "Liquid" - else if(initial(R.reagent_state) == 3) - dat += "Gas" - else - dat += "Unknown" - dat += "
" - dat += "Color: [initial(R.color)]

" - dat += "Description: [initial(R.description)]

" - var/const/P = 3 //The number of seconds between life ticks - var/T = initial(R.metabolization_rate) * (60 / P) - dat += "Metabolization Rate: [T]u/minute
" - dat += "Overdose Threshold: [initial(R.overdose_threshold) ? "[initial(R.overdose_threshold)]u" : "none"]
" - dat += "Addiction Threshold: [initial(R.addiction_threshold) ? "[initial(R.addiction_threshold)]u" : "none"]

" - dat += "
Back" - var/datum/browser/popup = new(usr, "chem_master", name) - popup.set_content(dat) - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) - popup.open(1) - return - - else if(href_list["main"]) // Used to exit the analyze screen. - attack_hand(usr) - return - - else if(href_list["add"]) - if(href_list["amount"]) - var/id = href_list["add"] - var/amount = text2num(href_list["amount"]) - if (amount > 0) - beaker.reagents.trans_id_to(src, id, amount) - - else if(href_list["addcustom"]) - var/id = href_list["addcustom"] - var/amt_temp = isgoodnumber(input(usr, "Select the amount to transfer.", "Transfer how much?", useramount) as num|null) - if(!amt_temp) - return - useramount = amt_temp - src.Topic(null, list("amount" = "[useramount]", "add" = "[id]")) - - else if(href_list["remove"]) - if(href_list["amount"]) - var/id = href_list["remove"] - var/amount = text2num(href_list["amount"]) - if (amount > 0) - if(mode) - reagents.trans_id_to(beaker, id, amount) - else - reagents.remove_reagent(id, amount) - - else if(href_list["removecustom"]) - var/id = href_list["removecustom"] - var/amt_temp = isgoodnumber(input(usr, "Select the amount to transfer.", "Transfer how much?", useramount) as num|null) - if(!amt_temp) - return - useramount = amt_temp - src.Topic(null, list("amount" = "[useramount]", "remove" = "[id]")) - - else if(href_list["eject"]) - if(beaker) - beaker.loc = src.loc - beaker = null - reagents.clear_reagents() - icon_state = "mixer0" - - else if(href_list["createpill"]) //Also used for condiment packs. - if(reagents.total_volume == 0) return - if(!condi) - var/amount = 1 - var/vol_each = min(reagents.total_volume, 50) - if(text2num(href_list["many"])) - amount = min(max(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0), 10) - if(!amount) - return - vol_each = min(reagents.total_volume / amount, 50) - var/name = stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) - if(!name || !reagents.total_volume) - return - var/obj/item/weapon/reagent_containers/pill/P - - for(var/i = 0; i < amount; i++) - if(loaded_pill_bottle && loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots) - P = new/obj/item/weapon/reagent_containers/pill(loaded_pill_bottle) - else - P = new/obj/item/weapon/reagent_containers/pill(src.loc) - P.name = trim("[name] pill") - P.pixel_x = rand(-7, 7) //random position - P.pixel_y = rand(-7, 7) - reagents.trans_to(P,vol_each) - else - var/name = stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN) - if(!name || !reagents.total_volume) - return - var/obj/item/weapon/reagent_containers/food/condiment/pack/P = new/obj/item/weapon/reagent_containers/food/condiment/pack(src.loc) - - P.originalname = name - P.name = trim("[name] pack") - P.desc = "A small condiment pack. The label says it contains [name]." - reagents.trans_to(P,10) - - else if(href_list["createpatch"]) - if(reagents.total_volume == 0) return - var/amount = 1 - var/vol_each = min(reagents.total_volume, 50) - if(text2num(href_list["many"])) - amount = min(max(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0), 10) - if(!amount) - return - vol_each = min(reagents.total_volume / amount, 50) - var/name = stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) - if(!name || !reagents.total_volume) - return - var/obj/item/weapon/reagent_containers/pill/P - - for(var/i = 0; i < amount; i++) - P = new/obj/item/weapon/reagent_containers/pill/patch(src.loc) - P.name = trim("[name] patch") - P.pixel_x = rand(-7, 7) //random position - P.pixel_y = rand(-7, 7) - reagents.trans_to(P,vol_each) - - src.updateUsrDialog() - return - -/obj/machinery/chem_master/attack_ai(mob/user) - return src.attack_hand(user) - -/obj/machinery/chem_master/attack_paw(mob/user) - return src.attack_hand(user) - -/obj/machinery/chem_master/attack_hand(mob/user) - if(stat & BROKEN) - return - - user.set_machine(src) - var/dat = "" - if(beaker) - dat += "Beaker \[[beaker.reagents.total_volume]/[beaker.volume]\] Eject and Clear Buffer
" - else - dat = "Please insert beaker.
" - - dat += "
Add to buffer:
Transfer to [(!mode ? "disposal" : "beaker")]:
" - - if(!condi) - if(src.loaded_pill_bottle) - dat += "Pill Bottle \[[loaded_pill_bottle.contents.len]/[loaded_pill_bottle.storage_slots]\] Eject" - else - dat += "No pill bottle inserted." - else - dat += "
" - - dat += "" - dat += "
Close" - var/datum/browser/popup = new(user, "chem_master", name, 470, 500) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open(1) - return - -/obj/machinery/chem_master/proc/isgoodnumber(num) - if(isnum(num)) - if(num > 200) - num = 200 - else if(num < 0) - num = 0 - else - num = round(num) - return num - else - return 0 - - -/obj/machinery/chem_master/condimaster - name = "CondiMaster 3000" - desc = "Used to create condiments and other cooking supplies." - condi = 1 - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/obj/machinery/chem_master/constructable - name = "ChemMaster 2999" - desc = "Used to seperate chemicals and distribute them in a variety of forms." - -/obj/machinery/chem_master/constructable/New() - ..() - component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/chem_master(null) - component_parts += new /obj/item/weapon/stock_parts/manipulator(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(null) - component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(null) - -/obj/machinery/chem_master/constructable/attackby(obj/item/B, mob/user, params) - - if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", B)) - if(beaker) - beaker.loc = src.loc - beaker = null - reagents.clear_reagents() - if(loaded_pill_bottle) - loaded_pill_bottle.loc = src.loc - loaded_pill_bottle = null - return - - if(exchange_parts(user, B)) - return - - if(panel_open) - if(istype(B, /obj/item/weapon/crowbar)) - default_deconstruction_crowbar(B) - return 1 - else - user << "You can't use the [src.name] while it's panel is opened!" - return 1 - - if(istype(B, /obj/item/weapon/reagent_containers/glass)) - if(src.beaker) - user << "A beaker is already loaded into the machine!" - return - if(!user.drop_item()) - return - - src.beaker = B - B.loc = src - user << "You add the beaker to the machine." - src.updateUsrDialog() - icon_state = "mixer1" - - else if(!condi && istype(B, /obj/item/weapon/storage/pill_bottle)) - if(src.loaded_pill_bottle) - user << "A pill bottle is already loaded into the machine!" - return - if(!user.drop_item()) - return - - src.loaded_pill_bottle = B - B.loc = src - user << "You add the pill bottle into the dispenser slot." - src.updateUsrDialog() - - return - -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// - -/obj/machinery/computer/pandemic - name = "PanD.E.M.I.C 2200" - desc = "Used to work with viruses." - density = 1 - anchored = 1 - icon = 'icons/obj/chemical.dmi' - icon_state = "mixer0" - circuit = /obj/item/weapon/circuitboard/pandemic - use_power = 1 - idle_power_usage = 20 - var/temp_html = "" - var/wait = null - var/obj/item/weapon/reagent_containers/glass/beaker = null - -/obj/machinery/computer/pandemic/New() - ..() - update_icon() - -/obj/machinery/computer/pandemic/set_broken() - icon_state = (src.beaker?"mixer1_b":"mixer0_b") - overlays.Cut() - stat |= BROKEN - -/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index) - if(beaker && beaker.reagents) - if(beaker.reagents.reagent_list.len) - var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list - if(BL) - if(BL.data && BL.data["viruses"]) - var/list/viruses = BL.data["viruses"] - return viruses[index] - return null - -/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index) - if(beaker && beaker.reagents) - if(beaker.reagents.reagent_list.len) - var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list - if(BL) - if(BL.data && BL.data["resistances"]) - var/list/resistances = BL.data["resistances"] - return resistances[index] - return null - -/obj/machinery/computer/pandemic/proc/GetVirusTypeByIndex(index) - var/datum/disease/D = GetVirusByIndex(index) - if(D) - return D.GetDiseaseID() - return null - -/obj/machinery/computer/pandemic/proc/replicator_cooldown(waittime) - wait = 1 - update_icon() - spawn(waittime) - src.wait = null - update_icon() - playsound(src.loc, 'sound/machines/ping.ogg', 30, 1) - -/obj/machinery/computer/pandemic/update_icon() - if(stat & BROKEN) - icon_state = (src.beaker?"mixer1_b":"mixer0_b") - return - - icon_state = "mixer[(beaker)?"1":"0"][(powered()) ? "" : "_nopower"]" - - if(wait) - overlays.Cut() - else - overlays += "waitlight" - -/obj/machinery/computer/pandemic/Topic(href, href_list) - if(..()) - return - - usr.set_machine(src) - if(!beaker) return - - if (href_list["create_vaccine"]) - if(!src.wait) - var/obj/item/weapon/reagent_containers/glass/bottle/B = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) - if(B) - B.pixel_x = rand(-3, 3) - B.pixel_y = rand(-3, 3) - var/path = GetResistancesByIndex(text2num(href_list["create_vaccine"])) - var/vaccine_type = path - var/vaccine_name = "Unknown" - - if(!ispath(vaccine_type)) - if(archive_diseases[path]) - var/datum/disease/D = archive_diseases[path] - if(D) - vaccine_name = D.name - vaccine_type = path - else if(vaccine_type) - var/datum/disease/D = new vaccine_type(0, null) - if(D) - vaccine_name = D.name - - if(vaccine_type) - - B.name = "[vaccine_name] vaccine bottle" - B.reagents.add_reagent("vaccine", 15, list(vaccine_type)) - replicator_cooldown(200) - else - src.temp_html = "The replicator is not ready yet." - src.updateUsrDialog() - return - else if (href_list["create_virus_culture"]) - if(!wait) - var/type = GetVirusTypeByIndex(text2num(href_list["create_virus_culture"]))//the path is received as string - converting - var/datum/disease/D = null - if(!ispath(type)) - D = GetVirusByIndex(text2num(href_list["create_virus_culture"])) - var/datum/disease/advance/A = archive_diseases[D.GetDiseaseID()] - if(A) - D = new A.type(0, A) - else if(type) - if(type in diseases) // Make sure this is a disease - D = new type(0, null) - if(!D) - return - var/name = stripped_input(usr,"Name:","Name the culture",D.name,MAX_NAME_LEN) - if(name == null || wait) - return - var/obj/item/weapon/reagent_containers/glass/bottle/B = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) - B.icon_state = "bottle3" - B.pixel_x = rand(-3, 3) - B.pixel_y = rand(-3, 3) - replicator_cooldown(50) - var/list/data = list("viruses"=list(D)) - B.name = "[name] culture bottle" - B.desc = "A small bottle. Contains [D.agent] culture in synthblood medium." - B.reagents.add_reagent("blood",20,data) - src.updateUsrDialog() - else - src.temp_html = "The replicator is not ready yet." - src.updateUsrDialog() - return - else if (href_list["empty_beaker"]) - beaker.reagents.clear_reagents() - src.updateUsrDialog() - return - else if (href_list["eject"]) - beaker:loc = src.loc - beaker = null - icon_state = "mixer0" - src.updateUsrDialog() - return - else if(href_list["clear"]) - src.temp_html = "" - src.updateUsrDialog() - return - else if(href_list["name_disease"]) - var/new_name = stripped_input(usr, "Name the Disease", "New Name", "", MAX_NAME_LEN) - if(!new_name) - return - if(..()) - return - var/id = GetVirusTypeByIndex(text2num(href_list["name_disease"])) - if(archive_diseases[id]) - var/datum/disease/advance/A = archive_diseases[id] - A.AssignName(new_name) - for(var/datum/disease/advance/AD in SSdisease.processing) - AD.Refresh() - src.updateUsrDialog() - - - else - usr << browse(null, "window=pandemic") - src.updateUsrDialog() - return - - src.add_fingerprint(usr) - return - -/obj/machinery/computer/pandemic/attack_hand(mob/user) - if(..()) - return - user.set_machine(src) - var/dat = "" - if(src.temp_html) - dat = "[src.temp_html]

Main Menu" - else if(!beaker) - dat += "Please insert beaker.
" - dat += "Close" - else - var/datum/reagents/R = beaker.reagents - var/datum/reagent/blood/Blood = null - for(var/datum/reagent/blood/B in R.reagent_list) - if(B) - Blood = B - break - if(!R.total_volume||!R.reagent_list.len) - dat += "The beaker is empty
" - else if(!Blood) - dat += "No blood sample found in beaker." - else if(!Blood.data) - dat += "No blood data found in beaker." - else - dat += "

Blood sample data:

" - dat += "Blood DNA: [(Blood.data["blood_DNA"]||"none")]
" - dat += "Blood Type: [(Blood.data["blood_type"]||"none")]
" - - - if(Blood.data["viruses"]) - var/list/vir = Blood.data["viruses"] - if(vir.len) - var/i = 0 - for(var/datum/disease/D in Blood.data["viruses"]) - i++ - if(!(D.visibility_flags & HIDDEN_PANDEMIC)) - - if(istype(D, /datum/disease/advance)) - - var/datum/disease/advance/A = D - D = archive_diseases[A.GetDiseaseID()] - if(D && D.name == "Unknown") - dat += "Name Disease
" - - if(!D) - CRASH("We weren't able to get the advance disease from the archive.") - - dat += "Disease Agent: [D?"[D.agent] - Create virus culture bottle":"none"]
" - dat += "Common name: [(D.name||"none")]
" - dat += "Description: [(D.desc||"none")]
" - dat += "Spread: [(D.spread_text||"none")]
" - dat += "Possible cure: [(D.cure_text||"none")]

" - - if(istype(D, /datum/disease/advance)) - var/datum/disease/advance/A = D - dat += "Symptoms: " - var/english_symptoms = list() - for(var/datum/symptom/S in A.symptoms) - english_symptoms += S.name - dat += english_list(english_symptoms) - - else - dat += "No detectable virus in the sample." - else - dat += "No detectable virus in the sample." - - dat += "
Contains antibodies to: " - if(Blood.data["resistances"]) - var/list/res = Blood.data["resistances"] - if(res.len) - dat += "
" - else - dat += "nothing
" - else - dat += "nothing
" - dat += "
Eject beaker[((R.total_volume&&R.reagent_list.len) ? "-- Empty beaker":"")]
" - dat += "Close" - - user << browse("[src.name]
[dat]", "window=pandemic;size=575x400") - onclose(user, "pandemic") - return - - -/obj/machinery/computer/pandemic/attackby(obj/I, mob/user, params) - if(istype(I, /obj/item/weapon/reagent_containers/glass)) - if(stat & (NOPOWER|BROKEN)) return - if(src.beaker) - user << "A beaker is already loaded into the machine!" - return - if(!user.drop_item()) - return - - src.beaker = I - I.loc = src - user << "You add the beaker to the machine." - src.updateUsrDialog() - icon_state = "mixer1" - - else if(istype(I, /obj/item/weapon/screwdriver)) - if(src.beaker) - beaker.loc = get_turf(src) - ..() - return - else - ..() - return -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -/obj/machinery/reagentgrinder - - name = "All-In-One Grinder" - desc = "Used to grind things up into raw materials." - icon = 'icons/obj/kitchen.dmi' - icon_state = "juicer1" - layer = 2.9 - anchored = 1 - use_power = 1 - idle_power_usage = 5 - active_power_usage = 100 - pass_flags = PASSTABLE - var/operating = 0 - var/obj/item/weapon/reagent_containers/beaker = null - var/limit = 10 - var/list/blend_items = list ( - - //Sheets - /obj/item/stack/sheet/mineral/plasma = list("plasma" = 20), - /obj/item/stack/sheet/metal = list("iron" = 20), - /obj/item/stack/sheet/plasteel = list("iron" = 20, "plasma" = 20), - /obj/item/stack/sheet/mineral/wood = list("carbon" = 20), - /obj/item/stack/sheet/glass = list("silicon" = 20), - /obj/item/stack/sheet/rglass = list("silicon" = 20, "iron" = 20), - /obj/item/stack/sheet/mineral/uranium = list("uranium" = 20), - /obj/item/stack/sheet/mineral/bananium = list("banana" = 20), - /obj/item/stack/sheet/mineral/silver = list("silver" = 20), - /obj/item/stack/sheet/mineral/gold = list("gold" = 20), - /obj/item/weapon/grown/nettle/basic = list("sacid" = 0), - /obj/item/weapon/grown/nettle/death = list("facid" = 0), - /obj/item/weapon/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0), - - //Crayons (for overriding colours) - /obj/item/toy/crayon/red = list("redcrayonpowder" = 10), - /obj/item/toy/crayon/orange = list("orangecrayonpowder" = 10), - /obj/item/toy/crayon/yellow = list("yellowcrayonpowder" = 10), - /obj/item/toy/crayon/green = list("greencrayonpowder" = 10), - /obj/item/toy/crayon/blue = list("bluecrayonpowder" = 10), - /obj/item/toy/crayon/purple = list("purplecrayonpowder" = 10), - /obj/item/toy/crayon/mime = list("invisiblecrayonpowder" = 50), - - //Blender Stuff - /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans = list("soymilk" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = list("ketchup" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/corn = list("cornoil" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/wheat = list("flour" = -5), - /obj/item/weapon/reagent_containers/food/snacks/grown/oat = list("flour" = -5), - /obj/item/weapon/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/bluecherries = list("bluecherryjelly" = 0), - /obj/item/weapon/reagent_containers/food/snacks/egg = list("eggyolk" = -5), - - //Grinder stuff, but only if dry - /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/arabica = list("coffeepowder" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tea/aspera = list("teapowder" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0), - - - - //All types that you can put into the grinder to transfer the reagents to the beaker. !Put all recipes above this.! - /obj/item/weapon/reagent_containers/pill = list(), - /obj/item/weapon/reagent_containers/food = list() - ) - - var/list/juice_items = list ( - - //Juicer Stuff - /obj/item/weapon/reagent_containers/food/snacks/grown/corn = list("corn_starch" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = list("tomatojuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/carrot = list("carrotjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/berries = list("berryjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/banana = list("banana" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/potato = list("potato" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/citrus/lemon = list("lemonjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/citrus/orange = list("orangejuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/citrus/lime = list("limejuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/watermelon = list("watermelonjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/watermelonslice = list("watermelonjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/berries/poison = list("poisonberryjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin = list("pumpkinjuice" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/blumpkin = list("blumpkinjuice" = 0), - ) - - var/list/dried_items = list( - - //Grinder stuff, but only if dry - /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/arabica = list("coffeepowder" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tea/aspera = list("teapowder" = 0), - /obj/item/weapon/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0), - ) - - var/list/holdingitems = list() - -/obj/machinery/reagentgrinder/New() - ..() - beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src) - return - -/obj/machinery/reagentgrinder/update_icon() - icon_state = "juicer"+num2text(!isnull(beaker)) - return - - -/obj/machinery/reagentgrinder/attackby(obj/item/O, mob/user, params) - - if(default_unfasten_wrench(user, O)) - return - - if (istype(O,/obj/item/weapon/reagent_containers/glass) || \ - istype(O,/obj/item/weapon/reagent_containers/food/drinks/drinkingglass) || \ - istype(O,/obj/item/weapon/reagent_containers/food/drinks/shaker)) - - if (beaker) - return 1 - else - if(!user.drop_item()) - return 1 - src.beaker = O - O.loc = src - update_icon() - src.updateUsrDialog() - return 0 - - if(is_type_in_list(O, dried_items)) - if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) - var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O - if(!G.dry) - user << "You must dry that first!" - return 1 - - if(holdingitems && holdingitems.len >= limit) - usr << "The machine cannot hold anymore items." - return 1 - - //Fill machine with a bag! - if(istype(O, /obj/item/weapon/storage/bag)) - var/obj/item/weapon/storage/bag/B = O - - for (var/obj/item/weapon/reagent_containers/food/snacks/grown/G in B.contents) - B.remove_from_storage(G, src) - holdingitems += G - if(holdingitems && holdingitems.len >= limit) //Sanity checking so the blender doesn't overfill - user << "You fill the All-In-One grinder to the brim." - break - - if(!O.contents.len) - user << "You empty the plant bag into the All-In-One grinder." - - src.updateUsrDialog() - return 0 - - if (!is_type_in_list(O, blend_items) && !is_type_in_list(O, juice_items)) - user << "Cannot refine into a reagent!" - return 1 - - user.unEquip(O) - O.loc = src - holdingitems += O - src.updateUsrDialog() - return 0 - -/obj/machinery/reagentgrinder/attack_paw(mob/user) - return src.attack_hand(user) - -/obj/machinery/reagentgrinder/attack_ai(mob/user) - return 0 - -/obj/machinery/reagentgrinder/attack_hand(mob/user) - user.set_machine(src) - interact(user) - -/obj/machinery/reagentgrinder/interact(mob/user) // The microwave Menu - var/is_chamber_empty = 0 - var/is_beaker_ready = 0 - var/processing_chamber = "" - var/beaker_contents = "" - var/dat = "" - - if(!operating) - for (var/obj/item/O in holdingitems) - processing_chamber += "\A [O.name]
" - - if (!processing_chamber) - is_chamber_empty = 1 - processing_chamber = "Nothing." - if (!beaker) - beaker_contents = "No beaker attached.
" - else - is_beaker_ready = 1 - beaker_contents = "The beaker contains:
" - var/anything = 0 - for(var/datum/reagent/R in beaker.reagents.reagent_list) - anything = 1 - beaker_contents += "[R.volume] - [R.name]
" - if(!anything) - beaker_contents += "Nothing
" - - - dat = {" - Processing chamber contains:
- [processing_chamber]
- [beaker_contents]
- "} - if (is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN))) - dat += "Grind the reagents
" - dat += "Juice the reagents

" - if(holdingitems && holdingitems.len > 0) - dat += "Eject the reagents
" - if (beaker) - dat += "Detach the beaker
" - else - dat += "Please wait..." - - var/datum/browser/popup = new(user, "reagentgrinder", "All-In-One Grinder") - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) - popup.open(1) - return - -/obj/machinery/reagentgrinder/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - if(operating) - updateUsrDialog() - return - switch(href_list["action"]) - if ("grind") - grind() - if("juice") - juice() - if("eject") - eject() - if ("detach") - detach() - -/obj/machinery/reagentgrinder/proc/detach() - - if (usr.stat != 0) - return - if (!beaker) - return - beaker.loc = src.loc - beaker = null - update_icon() - updateUsrDialog() - -/obj/machinery/reagentgrinder/proc/eject() - - if (usr.stat != 0) - return - if (holdingitems && holdingitems.len == 0) - return - - for(var/obj/item/O in holdingitems) - O.loc = src.loc - holdingitems -= O - holdingitems = list() - updateUsrDialog() - -/obj/machinery/reagentgrinder/proc/is_allowed(obj/item/weapon/reagent_containers/O) - for (var/i in blend_items) - if(istype(O, i)) - return 1 - return 0 - -/obj/machinery/reagentgrinder/proc/get_allowed_by_id(obj/item/O) - for (var/i in blend_items) - if (istype(O, i)) - return blend_items[i] - -/obj/machinery/reagentgrinder/proc/get_allowed_snack_by_id(obj/item/weapon/reagent_containers/food/snacks/O) - for(var/i in blend_items) - if(istype(O, i)) - return blend_items[i] - -/obj/machinery/reagentgrinder/proc/get_allowed_juice_by_id(obj/item/weapon/reagent_containers/food/snacks/O) - for(var/i in juice_items) - if(istype(O, i)) - return juice_items[i] - -/obj/machinery/reagentgrinder/proc/get_grownweapon_amount(obj/item/weapon/grown/O) - if (!istype(O)) - return 5 - else if (O.potency == -1) - return 5 - else - return round(O.potency) - -/obj/machinery/reagentgrinder/proc/get_juice_amount(obj/item/weapon/reagent_containers/food/snacks/grown/O) - if (!istype(O)) - return 5 - else if (O.potency == -1) - return 5 - else - return round(5*sqrt(O.potency)) - -/obj/machinery/reagentgrinder/proc/remove_object(obj/item/O) - holdingitems -= O - qdel(O) - -/obj/machinery/reagentgrinder/proc/juice() - power_change() - if(stat & (NOPOWER|BROKEN)) - return - if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) - return - playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1) - var/offset = prob(50) ? -2 : 2 - animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking - operating = 1 - updateUsrDialog() - spawn(50) - pixel_x = initial(pixel_x) //return to its spot after shaking - operating = 0 - updateUsrDialog() - - //Snacks - for (var/obj/item/weapon/reagent_containers/food/snacks/O in holdingitems) - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - - var/allowed = get_allowed_juice_by_id(O) - if(isnull(allowed)) - break - - for (var/r_id in allowed) - - var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume - var/amount = get_juice_amount(O) - - beaker.reagents.add_reagent(r_id, min(amount, space)) - - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - - remove_object(O) - -/obj/machinery/reagentgrinder/proc/grind() - - power_change() - if(stat & (NOPOWER|BROKEN)) - return - if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) - return - playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) - var/offset = prob(50) ? -2 : 2 - animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking - operating = 1 - updateUsrDialog() - spawn(60) - pixel_x = initial(pixel_x) //return to its spot after shaking - operating = 0 - updateUsrDialog() - - //Snacks and Plants - for (var/obj/item/weapon/reagent_containers/food/snacks/O in holdingitems) - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - - var/allowed = get_allowed_snack_by_id(O) - if(isnull(allowed)) - break - - for (var/r_id in allowed) - - var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume - var/amount = allowed[r_id] - if(amount <= 0) - if(amount == 0) - if (O.reagents != null && O.reagents.has_reagent("nutriment")) - beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment"), space)) - O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) - else - if (O.reagents != null && O.reagents.has_reagent("nutriment")) - beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment")*abs(amount)), space)) - O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) - - else - O.reagents.trans_id_to(beaker, r_id, min(amount, space)) - - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - - if(O.reagents.reagent_list.len == 0) - remove_object(O) - - //Sheets - for (var/obj/item/stack/sheet/O in holdingitems) - var/allowed = get_allowed_by_id(O) - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - for(var/i = 1; i <= round(O.amount, 1); i++) - for (var/r_id in allowed) - var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume - var/amount = allowed[r_id] - beaker.reagents.add_reagent(r_id,min(amount, space)) - if (space < amount) - break - if (i == round(O.amount, 1)) - remove_object(O) - break - //Plants - for (var/obj/item/weapon/grown/O in holdingitems) - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - var/allowed = get_allowed_by_id(O) - for (var/r_id in allowed) - var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume - var/amount = allowed[r_id] - if (amount == 0) - if (O.reagents != null && O.reagents.has_reagent(r_id)) - beaker.reagents.add_reagent(r_id,min(O.reagents.get_reagent_amount(r_id), space)) - else - beaker.reagents.add_reagent(r_id,min(amount, space)) - - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - remove_object(O) - - - //Crayons - //With some input from aranclanos, now 30% less shoddily copypasta - for (var/obj/item/toy/crayon/O in holdingitems) - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - var/allowed = get_allowed_by_id(O) - for (var/r_id in allowed) - var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume - var/amount = allowed[r_id] - beaker.reagents.add_reagent(r_id,min(amount, space)) - if (space < amount) - break - remove_object(O) - - //Everything else - Transfers reagents from it into beaker - for (var/obj/item/weapon/reagent_containers/O in holdingitems) - if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) - break - var/amount = O.reagents.total_volume - O.reagents.trans_to(beaker, amount) - if(!O.reagents.total_volume) - remove_object(O) -//////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////// -/obj/machinery/chem_heater - name = "chemical heater" - density = 1 - anchored = 1 - icon = 'icons/obj/chemical.dmi' - icon_state = "mixer0b" - use_power = 1 - idle_power_usage = 40 - var/obj/item/weapon/reagent_containers/beaker = null - var/desired_temp = 300 - var/heater_coefficient = 0.10 - var/on = FALSE - -/obj/machinery/chem_heater/New() - ..() - component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/chem_heater(null) - component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) - component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - RefreshParts() - -/obj/machinery/chem_heater/RefreshParts() - heater_coefficient = 0.10 - for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts) - heater_coefficient *= M.rating - -/obj/machinery/chem_heater/process() - ..() - if(stat & NOPOWER) - return - if(on) - if(beaker) - if(beaker.reagents.chem_temp > desired_temp) - beaker.reagents.chem_temp += min(-1, (desired_temp - beaker.reagents.chem_temp) * heater_coefficient) - if(beaker.reagents.chem_temp < desired_temp) - beaker.reagents.chem_temp += max(1, (desired_temp - beaker.reagents.chem_temp) * heater_coefficient) - beaker.reagents.chem_temp = round(beaker.reagents.chem_temp) //stops stuff like 456.12312312302 - - beaker.reagents.handle_reactions() - -/obj/machinery/chem_heater/proc/eject_beaker() - if(beaker) - beaker.loc = get_turf(src) - beaker.reagents.handle_reactions() - beaker = null - icon_state = "mixer0b" - -/obj/machinery/chem_heater/power_change() - if(powered()) - stat &= ~NOPOWER - else - spawn(rand(0, 15)) - stat |= NOPOWER - -/obj/machinery/chem_heater/attackby(obj/item/I, mob/user, params) - if(isrobot(user)) - return - - if(istype(I, /obj/item/weapon/reagent_containers/glass)) - if(beaker) - user << "A beaker is already loaded into the machine!" - return - - if(user.drop_item()) - beaker = I - I.loc = src - user << "You add the beaker to the machine." - icon_state = "mixer1b" - - if(default_deconstruction_screwdriver(user, "mixer0b", "mixer0b", I)) - return - - if(exchange_parts(user, I)) - return - - if(panel_open) - if(istype(I, /obj/item/weapon/crowbar)) - eject_beaker() - default_deconstruction_crowbar(I) - return 1 - -/obj/machinery/chem_heater/attack_hand(mob/user) - if (!user) - return - interact(user) - -/obj/machinery/chem_heater/Topic(href, href_list) - if(..()) - return - - if(href_list["toggle_on"]) - on = !on - - if(href_list["adjust_temperature"]) - var/val = href_list["adjust_temperature"] - if(isnum(val)) - desired_temp = Clamp(desired_temp+val, 0, 1000) - else if(val == "input") - desired_temp = Clamp(input("Please input the target temperature", name) as num, 0, 1000) - else - return - - if(href_list["eject_beaker"]) - eject_beaker() - - add_fingerprint(usr) - -/obj/machinery/chem_heater/interact(mob/user) - if(stat & BROKEN) - return - ui_interact(user) - -/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) - ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open) - if (!ui) - ui = new(user, src, ui_key, "chem_heater.tmpl", name, 350, 400) - ui.open() - -/obj/machinery/chem_heater/get_ui_data() - var/data = list() - data["targetTemp"] = desired_temp - data["isActive"] = on - data["isBeakerLoaded"] = beaker ? 1 : 0 - - data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null - data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null - data["beakerMaxVolume"] = beaker ? beaker.volume : null - - //copy-pasted from chem dispenser - var beakerContents[0] - if(beaker) - for(var/datum/reagent/R in beaker.reagents.reagent_list) - beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... - data["beakerContents"] = beakerContents - return data - -/////////////////////////////////////////////////////////////////////////// - -/obj/machinery/chem_dispenser/drinks - name = "soda dispenser" - anchored = 1 - icon = 'icons/obj/chemical.dmi' - icon_state = "soda_dispenser" - energy = 100 - max_energy = 100 - amount = 30 - recharge_delay = 5 - dispensable_reagents = list("water","ice","coffee","cream","tea","icetea","cola","spacemountainwind","dr_gibb","space_up","tonic","sodawater","lemon_lime","sugar","orangejuice","limejuice","tomatojuice") - -/obj/machinery/chem_dispenser/drinks/attackby(obj/item/O, mob/user) - - if(default_unfasten_wrench(user, O)) - return - - if (istype(O,/obj/item/weapon/reagent_containers/glass) || \ - istype(O,/obj/item/weapon/reagent_containers/food/drinks/drinkingglass) || \ - istype(O,/obj/item/weapon/reagent_containers/food/drinks/shaker)) - - if (beaker) - return 1 - else - if(!user.drop_item()) - return 1 - src.beaker = O - O.loc = src - update_icon() - src.updateUsrDialog() - return 0 - - - -/obj/machinery/chem_dispenser/drinks/beer - name = "booze dispenser" - anchored = 1 - icon = 'icons/obj/chemical.dmi' - icon_state = "booze_dispenser" - dispensable_reagents = list("lemon_lime","sugar","orangejuice","limejuice","sodawater","tonic","beer","kahlua","whiskey","wine","vodka","gin","rum","tequila","vermouth","cognac","ale") diff --git a/code/modules/reagents/Chemistry-Colours.dm b/code/modules/reagents/chemistry/colors.dm similarity index 91% rename from code/modules/reagents/Chemistry-Colours.dm rename to code/modules/reagents/chemistry/colors.dm index 7251c9c25e18..05ee15c2936d 100644 --- a/code/modules/reagents/Chemistry-Colours.dm +++ b/code/modules/reagents/chemistry/colors.dm @@ -1,24 +1,21 @@ - -/proc/mix_color_from_reagents(list/reagent_list) - if(!istype(reagent_list)) - return - - var/color - var/vol_counter = 0 - var/vol_temp - - for(var/datum/reagent/R in reagent_list) - vol_temp = R.volume - vol_counter += vol_temp - - if(!color) - color = R.color - - else if (length(color) >= length(R.color)) - color = BlendRGB(color, R.color, vol_temp/vol_counter) - else - color = BlendRGB(R.color, color, vol_temp/vol_counter) - - return color - - +/proc/mix_color_from_reagents(list/reagent_list) + if(!istype(reagent_list)) + return + + var/color + var/vol_counter = 0 + var/vol_temp + + for(var/datum/reagent/R in reagent_list) + vol_temp = R.volume + vol_counter += vol_temp + + if(!color) + color = R.color + + else if (length(color) >= length(R.color)) + color = BlendRGB(color, R.color, vol_temp/vol_counter) + else + color = BlendRGB(R.color, color, vol_temp/vol_counter) + + return color \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/chemistry/holder.dm similarity index 96% rename from code/modules/reagents/Chemistry-Holder.dm rename to code/modules/reagents/chemistry/holder.dm index 495f438bd7ac..e26987c1e312 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -1,603 +1,613 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -var/const/TOUCH = 1 //splashing -var/const/INGEST = 2 //ingestion -var/const/VAPOR = 3 //foam, spray, blob attack -var/const/PATCH = 4 //patches -var/const/INJECT = 5 //injection - -/////////////////////////////////////////////////////////////////////////////////// - -/datum/reagents - var/list/datum/reagent/reagent_list = new/list() - var/total_volume = 0 - var/maximum_volume = 100 - var/atom/my_atom = null - var/chem_temp = 150 - var/last_tick = 1 - var/addiction_tick = 1 - var/list/datum/reagent/addiction_list = new/list() - -/datum/reagents/New(maximum=100) - maximum_volume = maximum - SSobj.processing |= src - //I dislike having these here but map-objects are initialised before world/New() is called. >_> - if(!chemical_reagents_list) - //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id - var/paths = subtypesof(/datum/reagent) - chemical_reagents_list = list() - for(var/path in paths) - var/datum/reagent/D = new path() - chemical_reagents_list[D.id] = D - if(!chemical_reactions_list) - //Chemical Reactions - Initialises all /datum/chemical_reaction into a list - // It is filtered into multiple lists within a list. - // For example: - // chemical_reaction_list["plasma"] is a list of all reactions relating to plasma - - var/paths = subtypesof(/datum/chemical_reaction) - chemical_reactions_list = list() - - for(var/path in paths) - - var/datum/chemical_reaction/D = new path() - var/list/reaction_ids = list() - - if(D.required_reagents && D.required_reagents.len) - for(var/reaction in D.required_reagents) - reaction_ids += reaction - - // Create filters based on each reagent id in the required reagents list - for(var/id in reaction_ids) - if(!chemical_reactions_list[id]) - chemical_reactions_list[id] = list() - chemical_reactions_list[id] += D - break // Don't bother adding ourselves to other reagent ids, it is redundant. - -/datum/reagents/Destroy() - . = ..() - SSobj.processing.Remove(src) - for(var/datum/reagent/R in reagent_list) - qdel(R) - reagent_list.Cut() - reagent_list = null - if(my_atom && my_atom.reagents == src) - my_atom.reagents = null - -/datum/reagents/proc/remove_any(amount=1) - var/total_transfered = 0 - var/current_list_element = 1 - - current_list_element = rand(1,reagent_list.len) - - while(total_transfered != amount) - if(total_transfered >= amount) break - if(total_volume <= 0 || !reagent_list.len) break - - if(current_list_element > reagent_list.len) current_list_element = 1 - var/datum/reagent/current_reagent = reagent_list[current_list_element] - - src.remove_reagent(current_reagent.id, 1) - - current_list_element++ - total_transfered++ - src.update_total() - - handle_reactions() - return total_transfered - -/datum/reagents/proc/get_master_reagent_name() - var/the_name = null - var/the_volume = 0 - for(var/datum/reagent/A in reagent_list) - if(A.volume > the_volume) - the_volume = A.volume - the_name = A.name - - return the_name - -/datum/reagents/proc/get_master_reagent_id() - var/the_id = null - var/the_volume = 0 - for(var/datum/reagent/A in reagent_list) - if(A.volume > the_volume) - the_volume = A.volume - the_id = A.id - - return the_id - -/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. - if (!target ) - return - var/datum/reagents/R - if(istype(target,/datum/reagents/)) - R = target - else - if (!target.reagents || src.total_volume<=0) - return - R = target.reagents - amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) - var/part = amount / src.total_volume - var/trans_data = null - for (var/datum/reagent/current_reagent in src.reagent_list) - if (current_reagent.id == "blood" && ishuman(target)) - var/mob/living/carbon/human/H = target - H.inject_blood(my_atom, amount) - continue - var/current_reagent_transfer = current_reagent.volume * part - if(preserve_data) - trans_data = copy_data(current_reagent) - R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, src.chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered. - src.remove_reagent(current_reagent.id, current_reagent_transfer) - - src.update_total() - R.update_total() - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1) - if(!target) - return - if(!target.reagents || src.total_volume<=0) - return - var/datum/reagents/R = target.reagents - amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) - var/part = amount / src.total_volume - var/trans_data = null - for (var/datum/reagent/current_reagent in src.reagent_list) - var/current_reagent_transfer = current_reagent.volume * part - if(preserve_data) - trans_data = current_reagent.data - R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data) - - src.update_total() - R.update_total() - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N - if (!target) - return - if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) - return - - var/datum/reagents/R = target.reagents - if(src.get_reagent_amount(reagent) R.maximum_volume) return 0 - - current_list_element = rand(1,reagent_list.len) //Eh, bandaid fix. - - while(total_transfered != amount) - if(total_transfered >= amount) break //Better safe than sorry. - if(total_volume <= 0 || !reagent_list.len) break - if(R.total_volume >= R.maximum_volume) break - - if(current_list_element > reagent_list.len) current_list_element = 1 - var/datum/reagent/current_reagent = reagent_list[current_list_element] - if(preserve_data) - trans_data = current_reagent.data - R.add_reagent(current_reagent.id, (1 * multiplier), trans_data) - src.remove_reagent(current_reagent.id, 1) - - current_list_element++ - total_transfered++ - src.update_total() - R.update_total() - R.handle_reactions() - handle_reactions() - - return total_transfered -*/ - -/datum/reagents/proc/metabolize(mob/M, can_overdose = 0) - if(M) - chem_temp = M.bodytemperature - handle_reactions() - - for(var/A in reagent_list) - var/datum/reagent/R = A - if(!R.holder) - continue - if(!M) - M = R.holder.my_atom - if(M && R) - if(M.reagent_check(R) != 1) - if(can_overdose) - if(R.overdose_threshold) - if(R.volume >= R.overdose_threshold && !R.overdosed) - R.overdosed = 1 - R.overdose_start(M) - if(R.addiction_threshold) - if(R.volume >= R.addiction_threshold && !is_type_in_list(R, addiction_list)) - var/datum/reagent/new_reagent = new R.type() - addiction_list.Add(new_reagent) - if(R.overdosed) - R.overdose_process(M) - if(is_type_in_list(R,addiction_list)) - for(var/datum/reagent/addicted_reagent in addiction_list) - if(istype(R, addicted_reagent)) - addicted_reagent.addiction_stage = -15 // you're satisfied for a good while. - R.on_mob_life(M) - - if(can_overdose) - if(addiction_tick == 6) - addiction_tick = 1 - for(var/A in addiction_list) - var/datum/reagent/R = A - if(M && R) - if(R.addiction_stage <= 0) - R.addiction_stage++ - if(R.addiction_stage > 0 && R.addiction_stage <= 10) - R.addiction_act_stage1(M) - R.addiction_stage++ - if(R.addiction_stage > 10 && R.addiction_stage <= 20) - R.addiction_act_stage2(M) - R.addiction_stage++ - if(R.addiction_stage > 20 && R.addiction_stage <= 30) - R.addiction_act_stage3(M) - R.addiction_stage++ - if(R.addiction_stage > 30 && R.addiction_stage <= 40) - R.addiction_act_stage4(M) - R.addiction_stage++ - if(R.addiction_stage > 40) - M << "You feel like you've gotten over your need for [R.name]." - addiction_list.Remove(R) - addiction_tick++ - update_total() - -/datum/reagents/process() - for(var/datum/reagent/R in reagent_list) - R.on_tick() - return - -/datum/reagents/proc/conditional_update_move(atom/A, Running = 0) - for(var/datum/reagent/R in reagent_list) - R.on_move (A, Running) - update_total() - -/datum/reagents/proc/conditional_update(atom/A) - for(var/datum/reagent/R in reagent_list) - R.on_update (A) - update_total() - -/datum/reagents/proc/handle_reactions() - if(my_atom.flags & NOREACT) return //Yup, no reactions here. No siree. - - var/reaction_occured = 0 - do - reaction_occured = 0 - for(var/datum/reagent/R in reagent_list) // Usually a small list - for(var/reaction in chemical_reactions_list[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id - - if(!reaction) - continue - - var/datum/chemical_reaction/C = reaction - var/total_required_reagents = C.required_reagents.len - var/total_matching_reagents = 0 - var/total_required_catalysts = C.required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = 0 - var/matching_other = 0 - var/list/multipliers = new/list() - var/required_temp = C.required_temp - - for(var/B in C.required_reagents) - if(!has_reagent(B, C.required_reagents[B])) break - total_matching_reagents++ - multipliers += round(get_reagent_amount(B) / C.required_reagents[B]) - for(var/B in C.required_catalysts) - if(!has_reagent(B, C.required_catalysts[B])) break - total_matching_catalysts++ - - if(!C.required_container) - matching_container = 1 - - else - if(my_atom.type == C.required_container) - matching_container = 1 - if (isliving(my_atom)) //Makes it so certain chemical reactions don't occur in mobs - if (C.mob_react) - return - if(!C.required_other) - matching_other = 1 - - else if(istype(my_atom, /obj/item/slime_extract)) - var/obj/item/slime_extract/M = my_atom - - if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = 1 - - if(required_temp == 0) - required_temp = chem_temp - - - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && chem_temp >= required_temp) - var/multiplier = min(multipliers) - for(var/B in C.required_reagents) - remove_reagent(B, (multiplier * C.required_reagents[B]), safety = 1) - - var/created_volume = C.result_amount*multiplier - if(C.result) - feedback_add_details("chemical_reaction","[C.result]|[C.result_amount*multiplier]") - multiplier = max(multiplier, 1) //this shouldnt happen ... - add_reagent(C.result, C.result_amount*multiplier, null, chem_temp) - - var/list/seen = viewers(4, get_turf(my_atom)) - - if(!istype(my_atom, /mob)) // No bubbling mobs - playsound(get_turf(my_atom), 'sound/effects/bubbles.ogg', 80, 1) - for(var/mob/M in seen) - M << "\icon[my_atom] [C.mix_message]" - - if(istype(my_atom, /obj/item/slime_extract)) - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead - for(var/mob/M in seen) - M << "\icon[my_atom] \The [my_atom]'s power is consumed in the reaction." - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." - - C.on_reaction(src, created_volume) - reaction_occured = 1 - break - - while(reaction_occured) - update_total() - return 0 - -/datum/reagents/proc/isolate_reagent(reagent) - for(var/A in reagent_list) - var/datum/reagent/R = A - if (R.id != reagent) - del_reagent(R.id) - update_total() - -/datum/reagents/proc/del_reagent(reagent) - for(var/datum/reagent/R in reagent_list) - if (R.id == reagent) - if(istype(my_atom, /mob/living)) - var/mob/living/M = my_atom - R.on_mob_delete(M) - qdel(R) - reagent_list -= R - update_total() - my_atom.on_reagent_change() - check_ignoreslow(my_atom) - check_gofast(my_atom) - check_goreallyfast(my_atom) - return 1 - -/datum/reagents/proc/check_ignoreslow(mob/M) - if(istype(M, /mob)) - if(M.reagents.has_reagent("morphine")||M.reagents.has_reagent("ephedrine")) - return 1 - else - M.status_flags &= ~IGNORESLOWDOWN - -/datum/reagents/proc/check_gofast(mob/M) - if(istype(M, /mob)) - if(M.reagents.has_reagent("unholywater")||M.reagents.has_reagent("nuka_cola")||M.reagents.has_reagent("stimulants")) - return 1 - else - M.status_flags &= ~GOTTAGOFAST - -/datum/reagents/proc/check_goreallyfast(mob/M) - if(istype(M, /mob)) - if(M.reagents.has_reagent("methamphetamine")) - return 1 - else - M.status_flags &= ~GOTTAGOREALLYFAST - -/datum/reagents/proc/update_total() - total_volume = 0 - for(var/datum/reagent/R in reagent_list) - if(R.volume < 0.1) - del_reagent(R.id) - else - total_volume += R.volume - - return 0 - -/datum/reagents/proc/clear_reagents() - for(var/datum/reagent/R in reagent_list) - del_reagent(R.id) - return 0 - -/datum/reagents/proc/reaction(atom/A, method=TOUCH, volume_modifier=1,show_message=1) - if(isliving(A)) - var/mob/living/L = A - var/touch_protection = 0 - if(method == VAPOR) - touch_protection = L.get_permeability_protection() - for(var/datum/reagent/R in reagent_list) - R.reaction_mob(L, method, R.volume*volume_modifier, show_message, touch_protection) - else if(isturf(A)) - for(var/datum/reagent/R in reagent_list) - R.reaction_turf(A, R.volume*volume_modifier, show_message) - else if(isobj(A)) - for(var/datum/reagent/R in reagent_list) - R.reaction_obj(A, R.volume*volume_modifier, show_message) - -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0) - if(!isnum(amount) || !amount) - return 1 - update_total() - if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. - chem_temp = round(((amount * reagtemp) + (total_volume * chem_temp)) / (total_volume + amount)) //equalize with new chems - - for(var/A in reagent_list) - - var/datum/reagent/R = A - if (R.id == reagent) - R.volume += amount - update_total() - my_atom.on_reagent_change() - R.on_merge(data) - if(!no_react) - handle_reactions() - return 0 - - var/datum/reagent/D = chemical_reagents_list[reagent] - if(D) - - var/datum/reagent/R = new D.type(data) - reagent_list += R - R.holder = src - R.volume = amount - if(data) - R.data = data - R.on_new(data) - - update_total() - my_atom.on_reagent_change() - if(!no_react) - handle_reactions() - return 0 - else - WARNING("[my_atom] attempted to add a reagent called ' [reagent] ' which doesn't exist. ([usr])") - - if(!no_react) - handle_reactions() - - return 1 - -/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) - for(var/r_id in list_reagents) - var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data) - -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to - - if(!isnum(amount)) return 1 - - for(var/A in reagent_list) - var/datum/reagent/R = A - if (R.id == reagent) - R.volume -= amount - update_total() - if(!safety)//So it does not handle reactions when it need not to - handle_reactions() - my_atom.on_reagent_change() - return 0 - - return 1 - -/datum/reagents/proc/has_reagent(reagent, amount = -1) - - for(var/A in reagent_list) - var/datum/reagent/R = A - if (R.id == reagent) - if(!amount) return R - else - if(R.volume >= amount) return R - else return 0 - - return 0 - -/datum/reagents/proc/get_reagent_amount(reagent) - for(var/A in reagent_list) - var/datum/reagent/R = A - if (R.id == reagent) - return R.volume - - return 0 - -/datum/reagents/proc/get_reagents() - var/res = "" - for(var/datum/reagent/A in reagent_list) - if (res != "") res += "," - res += A.name - - return res - -/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. - if(!isnum(amount)) return 1 - - var/has_removed_reagent = 0 - - for(var/datum/reagent/R in reagent_list) - var/matches = 0 - // Switch between how we check the reagent type - if(strict) - if(R.type == reagent_type) - matches = 1 - else - if(istype(R, reagent_type)) - matches = 1 - // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. - if(matches) - // Have our other proc handle removement - has_removed_reagent = remove_reagent(R.id, amount, safety) - - return has_removed_reagent - - //two helper functions to preserve data across reactions (needed for xenoarch) -/datum/reagents/proc/get_data(reagent_id) - for(var/datum/reagent/D in reagent_list) - if(D.id == reagent_id) - //world << "proffering a data-carrying reagent ([reagent_id])" - return D.data - -/datum/reagents/proc/set_data(reagent_id, new_data) - for(var/datum/reagent/D in reagent_list) - if(D.id == reagent_id) - //world << "reagent data set ([reagent_id])" - D.data = new_data - -/datum/reagents/proc/copy_data(datum/reagent/current_reagent) - if (!current_reagent || !current_reagent.data) return null - if (!istype(current_reagent.data, /list)) return current_reagent.data - - var/list/trans_data = current_reagent.data.Copy() - - // We do this so that introducing a virus to a blood sample - // doesn't automagically infect all other blood samples from - // the same donor. - // - // Technically we should probably copy all data lists, but - // that could possibly eat up a lot of memory needlessly - // if most data lists are read-only. - if (trans_data["viruses"]) - var/list/v = trans_data["viruses"] - trans_data["viruses"] = v.Copy() - - return trans_data - - -/////////////////////////////////////////////////////////////////////////////////// - - -// Convenience proc to create a reagents holder for an atom -// Max vol is maximum volume of holder -/atom/proc/create_reagents(max_vol) - if(reagents) - qdel(reagents) - reagents = new/datum/reagents(max_vol) - reagents.my_atom = src +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +var/const/TOUCH = 1 //splashing +var/const/INGEST = 2 //ingestion +var/const/VAPOR = 3 //foam, spray, blob attack +var/const/PATCH = 4 //patches +var/const/INJECT = 5 //injection + +/////////////////////////////////////////////////////////////////////////////////// + +/datum/reagents + var/list/datum/reagent/reagent_list = new/list() + var/total_volume = 0 + var/maximum_volume = 100 + var/atom/my_atom = null + var/chem_temp = 150 + var/last_tick = 1 + var/addiction_tick = 1 + var/list/datum/reagent/addiction_list = new/list() + +/datum/reagents/New(maximum=100) + maximum_volume = maximum + SSobj.processing |= src + //I dislike having these here but map-objects are initialised before world/New() is called. >_> + if(!chemical_reagents_list) + //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id + var/paths = subtypesof(/datum/reagent) + chemical_reagents_list = list() + for(var/path in paths) + var/datum/reagent/D = new path() + chemical_reagents_list[D.id] = D + if(!chemical_reactions_list) + //Chemical Reactions - Initialises all /datum/chemical_reaction into a list + // It is filtered into multiple lists within a list. + // For example: + // chemical_reaction_list["plasma"] is a list of all reactions relating to plasma + + var/paths = subtypesof(/datum/chemical_reaction) + chemical_reactions_list = list() + + for(var/path in paths) + + var/datum/chemical_reaction/D = new path() + var/list/reaction_ids = list() + + if(D.required_reagents && D.required_reagents.len) + for(var/reaction in D.required_reagents) + reaction_ids += reaction + + // Create filters based on each reagent id in the required reagents list + for(var/id in reaction_ids) + if(!chemical_reactions_list[id]) + chemical_reactions_list[id] = list() + chemical_reactions_list[id] += D + break // Don't bother adding ourselves to other reagent ids, it is redundant. + +/datum/reagents/Destroy() + . = ..() + SSobj.processing.Remove(src) + for(var/datum/reagent/R in reagent_list) + qdel(R) + reagent_list.Cut() + reagent_list = null + if(my_atom && my_atom.reagents == src) + my_atom.reagents = null + +/datum/reagents/proc/remove_any(amount = 1) + var/total_transfered = 0 + var/current_list_element = 1 + + current_list_element = rand(1,reagent_list.len) + + while(total_transfered != amount) + if(total_transfered >= amount) break + if(total_volume <= 0 || !reagent_list.len) break + + if(current_list_element > reagent_list.len) current_list_element = 1 + var/datum/reagent/current_reagent = reagent_list[current_list_element] + + src.remove_reagent(current_reagent.id, 1) + + current_list_element++ + total_transfered++ + src.update_total() + + handle_reactions() + return total_transfered + +/datum/reagents/proc/remove_all(amount = 1) + var/part = amount / src.total_volume + for (var/datum/reagent/current_reagent in src.reagent_list) + var/current_reagent_transfer = current_reagent.volume * part + src.remove_reagent(current_reagent.id, current_reagent_transfer) + + src.update_total() + src.handle_reactions() + return amount + +/datum/reagents/proc/get_master_reagent_name() + var/the_name = null + var/the_volume = 0 + for(var/datum/reagent/A in reagent_list) + if(A.volume > the_volume) + the_volume = A.volume + the_name = A.name + + return the_name + +/datum/reagents/proc/get_master_reagent_id() + var/the_id = null + var/the_volume = 0 + for(var/datum/reagent/A in reagent_list) + if(A.volume > the_volume) + the_volume = A.volume + the_id = A.id + + return the_id + +/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. + if (!target ) + return + var/datum/reagents/R + if(istype(target,/datum/reagents/)) + R = target + else + if (!target.reagents || src.total_volume<=0) + return + R = target.reagents + amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) + var/part = amount / src.total_volume + var/trans_data = null + for (var/datum/reagent/current_reagent in src.reagent_list) + if (current_reagent.id == "blood" && ishuman(target)) + var/mob/living/carbon/human/H = target + H.inject_blood(my_atom, amount) + continue + var/current_reagent_transfer = current_reagent.volume * part + if(preserve_data) + trans_data = copy_data(current_reagent) + R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, src.chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered. + src.remove_reagent(current_reagent.id, current_reagent_transfer) + + src.update_total() + R.update_total() + R.handle_reactions() + src.handle_reactions() + return amount + +/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1) + if(!target) + return + if(!target.reagents || src.total_volume<=0) + return + var/datum/reagents/R = target.reagents + amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) + var/part = amount / src.total_volume + var/trans_data = null + for (var/datum/reagent/current_reagent in src.reagent_list) + var/current_reagent_transfer = current_reagent.volume * part + if(preserve_data) + trans_data = current_reagent.data + R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data) + + src.update_total() + R.update_total() + R.handle_reactions() + src.handle_reactions() + return amount + +/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N + if (!target) + return + if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) + return + + var/datum/reagents/R = target.reagents + if(src.get_reagent_amount(reagent) R.maximum_volume) return 0 + + current_list_element = rand(1,reagent_list.len) //Eh, bandaid fix. + + while(total_transfered != amount) + if(total_transfered >= amount) break //Better safe than sorry. + if(total_volume <= 0 || !reagent_list.len) break + if(R.total_volume >= R.maximum_volume) break + + if(current_list_element > reagent_list.len) current_list_element = 1 + var/datum/reagent/current_reagent = reagent_list[current_list_element] + if(preserve_data) + trans_data = current_reagent.data + R.add_reagent(current_reagent.id, (1 * multiplier), trans_data) + src.remove_reagent(current_reagent.id, 1) + + current_list_element++ + total_transfered++ + src.update_total() + R.update_total() + R.handle_reactions() + handle_reactions() + + return total_transfered +*/ + +/datum/reagents/proc/metabolize(mob/M, can_overdose = 0) + if(M) + chem_temp = M.bodytemperature + handle_reactions() + + for(var/A in reagent_list) + var/datum/reagent/R = A + if(!R.holder) + continue + if(!M) + M = R.holder.my_atom + if(M && R) + if(M.reagent_check(R) != 1) + if(can_overdose) + if(R.overdose_threshold) + if(R.volume >= R.overdose_threshold && !R.overdosed) + R.overdosed = 1 + R.overdose_start(M) + if(R.addiction_threshold) + if(R.volume >= R.addiction_threshold && !is_type_in_list(R, addiction_list)) + var/datum/reagent/new_reagent = new R.type() + addiction_list.Add(new_reagent) + if(R.overdosed) + R.overdose_process(M) + if(is_type_in_list(R,addiction_list)) + for(var/datum/reagent/addicted_reagent in addiction_list) + if(istype(R, addicted_reagent)) + addicted_reagent.addiction_stage = -15 // you're satisfied for a good while. + R.on_mob_life(M) + + if(can_overdose) + if(addiction_tick == 6) + addiction_tick = 1 + for(var/A in addiction_list) + var/datum/reagent/R = A + if(M && R) + if(R.addiction_stage <= 0) + R.addiction_stage++ + if(R.addiction_stage > 0 && R.addiction_stage <= 10) + R.addiction_act_stage1(M) + R.addiction_stage++ + if(R.addiction_stage > 10 && R.addiction_stage <= 20) + R.addiction_act_stage2(M) + R.addiction_stage++ + if(R.addiction_stage > 20 && R.addiction_stage <= 30) + R.addiction_act_stage3(M) + R.addiction_stage++ + if(R.addiction_stage > 30 && R.addiction_stage <= 40) + R.addiction_act_stage4(M) + R.addiction_stage++ + if(R.addiction_stage > 40) + M << "You feel like you've gotten over your need for [R.name]." + addiction_list.Remove(R) + addiction_tick++ + update_total() + +/datum/reagents/process() + for(var/datum/reagent/R in reagent_list) + R.on_tick() + return + +/datum/reagents/proc/conditional_update_move(atom/A, Running = 0) + for(var/datum/reagent/R in reagent_list) + R.on_move (A, Running) + update_total() + +/datum/reagents/proc/conditional_update(atom/A) + for(var/datum/reagent/R in reagent_list) + R.on_update (A) + update_total() + +/datum/reagents/proc/handle_reactions() + if(my_atom.flags & NOREACT) return //Yup, no reactions here. No siree. + + var/reaction_occured = 0 + do + reaction_occured = 0 + for(var/datum/reagent/R in reagent_list) // Usually a small list + for(var/reaction in chemical_reactions_list[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id + + if(!reaction) + continue + + var/datum/chemical_reaction/C = reaction + var/total_required_reagents = C.required_reagents.len + var/total_matching_reagents = 0 + var/total_required_catalysts = C.required_catalysts.len + var/total_matching_catalysts= 0 + var/matching_container = 0 + var/matching_other = 0 + var/list/multipliers = new/list() + var/required_temp = C.required_temp + + for(var/B in C.required_reagents) + if(!has_reagent(B, C.required_reagents[B])) break + total_matching_reagents++ + multipliers += round(get_reagent_amount(B) / C.required_reagents[B]) + for(var/B in C.required_catalysts) + if(!has_reagent(B, C.required_catalysts[B])) break + total_matching_catalysts++ + + if(!C.required_container) + matching_container = 1 + + else + if(my_atom.type == C.required_container) + matching_container = 1 + if (isliving(my_atom)) //Makes it so certain chemical reactions don't occur in mobs + if (C.mob_react) + return + if(!C.required_other) + matching_other = 1 + + else if(istype(my_atom, /obj/item/slime_extract)) + var/obj/item/slime_extract/M = my_atom + + if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this + matching_other = 1 + + if(required_temp == 0) + required_temp = chem_temp + + + if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && chem_temp >= required_temp) + var/multiplier = min(multipliers) + for(var/B in C.required_reagents) + remove_reagent(B, (multiplier * C.required_reagents[B]), safety = 1) + + var/created_volume = C.result_amount*multiplier + if(C.result) + feedback_add_details("chemical_reaction","[C.result]|[C.result_amount*multiplier]") + multiplier = max(multiplier, 1) //this shouldnt happen ... + add_reagent(C.result, C.result_amount*multiplier, null, chem_temp) + + var/list/seen = viewers(4, get_turf(my_atom)) + + if(!istype(my_atom, /mob)) // No bubbling mobs + playsound(get_turf(my_atom), 'sound/effects/bubbles.ogg', 80, 1) + for(var/mob/M in seen) + M << "\icon[my_atom] [C.mix_message]" + + if(istype(my_atom, /obj/item/slime_extract)) + var/obj/item/slime_extract/ME2 = my_atom + ME2.Uses-- + if(ME2.Uses <= 0) // give the notification that the slime core is dead + for(var/mob/M in seen) + M << "\icon[my_atom] \The [my_atom]'s power is consumed in the reaction." + ME2.name = "used slime extract" + ME2.desc = "This extract has been used up." + + C.on_reaction(src, created_volume) + reaction_occured = 1 + break + + while(reaction_occured) + update_total() + return 0 + +/datum/reagents/proc/isolate_reagent(reagent) + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id != reagent) + del_reagent(R.id) + update_total() + +/datum/reagents/proc/del_reagent(reagent) + for(var/datum/reagent/R in reagent_list) + if (R.id == reagent) + if(istype(my_atom, /mob/living)) + var/mob/living/M = my_atom + R.on_mob_delete(M) + qdel(R) + reagent_list -= R + update_total() + my_atom.on_reagent_change() + check_ignoreslow(my_atom) + check_gofast(my_atom) + check_goreallyfast(my_atom) + return 1 + +/datum/reagents/proc/check_ignoreslow(mob/M) + if(istype(M, /mob)) + if(M.reagents.has_reagent("morphine")||M.reagents.has_reagent("ephedrine")) + return 1 + else + M.status_flags &= ~IGNORESLOWDOWN + +/datum/reagents/proc/check_gofast(mob/M) + if(istype(M, /mob)) + if(M.reagents.has_reagent("unholywater")||M.reagents.has_reagent("nuka_cola")||M.reagents.has_reagent("stimulants")) + return 1 + else + M.status_flags &= ~GOTTAGOFAST + +/datum/reagents/proc/check_goreallyfast(mob/M) + if(istype(M, /mob)) + if(M.reagents.has_reagent("methamphetamine")) + return 1 + else + M.status_flags &= ~GOTTAGOREALLYFAST + +/datum/reagents/proc/update_total() + total_volume = 0 + for(var/datum/reagent/R in reagent_list) + if(R.volume < 0.1) + del_reagent(R.id) + else + total_volume += R.volume + + return 0 + +/datum/reagents/proc/clear_reagents() + for(var/datum/reagent/R in reagent_list) + del_reagent(R.id) + return 0 + +/datum/reagents/proc/reaction(atom/A, method=TOUCH, volume_modifier=1,show_message=1) + if(isliving(A)) + var/mob/living/L = A + var/touch_protection = 0 + if(method == VAPOR) + touch_protection = L.get_permeability_protection() + for(var/datum/reagent/R in reagent_list) + R.reaction_mob(L, method, R.volume*volume_modifier, show_message, touch_protection) + else if(isturf(A)) + for(var/datum/reagent/R in reagent_list) + R.reaction_turf(A, R.volume*volume_modifier, show_message) + else if(isobj(A)) + for(var/datum/reagent/R in reagent_list) + R.reaction_obj(A, R.volume*volume_modifier, show_message) + +/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0) + if(!isnum(amount) || !amount) + return 1 + update_total() + if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. + chem_temp = round(((amount * reagtemp) + (total_volume * chem_temp)) / (total_volume + amount)) //equalize with new chems + + for(var/A in reagent_list) + + var/datum/reagent/R = A + if (R.id == reagent) + R.volume += amount + update_total() + my_atom.on_reagent_change() + R.on_merge(data) + if(!no_react) + handle_reactions() + return 0 + + var/datum/reagent/D = chemical_reagents_list[reagent] + if(D) + + var/datum/reagent/R = new D.type(data) + reagent_list += R + R.holder = src + R.volume = amount + if(data) + R.data = data + R.on_new(data) + + update_total() + my_atom.on_reagent_change() + if(!no_react) + handle_reactions() + return 0 + else + WARNING("[my_atom] attempted to add a reagent called ' [reagent] ' which doesn't exist. ([usr])") + + if(!no_react) + handle_reactions() + + return 1 + +/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) + for(var/r_id in list_reagents) + var/amt = list_reagents[r_id] + add_reagent(r_id, amt, data) + +/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to + + if(!isnum(amount)) return 1 + + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + R.volume -= amount + update_total() + if(!safety)//So it does not handle reactions when it need not to + handle_reactions() + my_atom.on_reagent_change() + return 0 + + return 1 + +/datum/reagents/proc/has_reagent(reagent, amount = -1) + + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + if(!amount) return R + else + if(R.volume >= amount) return R + else return 0 + + return 0 + +/datum/reagents/proc/get_reagent_amount(reagent) + for(var/A in reagent_list) + var/datum/reagent/R = A + if (R.id == reagent) + return R.volume + + return 0 + +/datum/reagents/proc/get_reagents() + var/res = "" + for(var/datum/reagent/A in reagent_list) + if (res != "") res += "," + res += A.name + + return res + +/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. + if(!isnum(amount)) return 1 + + var/has_removed_reagent = 0 + + for(var/datum/reagent/R in reagent_list) + var/matches = 0 + // Switch between how we check the reagent type + if(strict) + if(R.type == reagent_type) + matches = 1 + else + if(istype(R, reagent_type)) + matches = 1 + // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. + if(matches) + // Have our other proc handle removement + has_removed_reagent = remove_reagent(R.id, amount, safety) + + return has_removed_reagent + + //two helper functions to preserve data across reactions (needed for xenoarch) +/datum/reagents/proc/get_data(reagent_id) + for(var/datum/reagent/D in reagent_list) + if(D.id == reagent_id) + //world << "proffering a data-carrying reagent ([reagent_id])" + return D.data + +/datum/reagents/proc/set_data(reagent_id, new_data) + for(var/datum/reagent/D in reagent_list) + if(D.id == reagent_id) + //world << "reagent data set ([reagent_id])" + D.data = new_data + +/datum/reagents/proc/copy_data(datum/reagent/current_reagent) + if (!current_reagent || !current_reagent.data) return null + if (!istype(current_reagent.data, /list)) return current_reagent.data + + var/list/trans_data = current_reagent.data.Copy() + + // We do this so that introducing a virus to a blood sample + // doesn't automagically infect all other blood samples from + // the same donor. + // + // Technically we should probably copy all data lists, but + // that could possibly eat up a lot of memory needlessly + // if most data lists are read-only. + if (trans_data["viruses"]) + var/list/v = trans_data["viruses"] + trans_data["viruses"] = v.Copy() + + return trans_data + + +/////////////////////////////////////////////////////////////////////////////////// + + +// Convenience proc to create a reagents holder for an atom +// Max vol is maximum volume of holder +/atom/proc/create_reagents(max_vol) + if(reagents) + qdel(reagents) + reagents = new/datum/reagents(max_vol) + reagents.my_atom = src diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm new file mode 100644 index 000000000000..c9f2492deba7 --- /dev/null +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -0,0 +1,359 @@ +/obj/machinery/chem_dispenser + name = "chem dispenser" + desc = "Creates and dispenses chemicals." + density = 1 + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "dispenser" + use_power = 1 + idle_power_usage = 40 + var/energy = 100 + var/max_energy = 100 + var/amount = 30 + var/recharged = 0 + var/recharge_delay = 5 + var/image/icon_beaker = null + var/obj/item/weapon/reagent_containers/beaker = null + var/list/dispensable_reagents = list( + "hydrogen", + "lithium", + "carbon", + "nitrogen", + "oxygen", + "fluorine", + "sodium", + "aluminium", + "silicon", + "phosphorus", + "sulfur", + "chlorine", + "potassium", + "iron", + "copper", + "mercury", + "radium", + "water", + "ethanol", + "sugar", + "sacid", + "welding_fuel", + "silver", + "iodine", + "bromine", + "stable_plasma" + ) + +/obj/machinery/chem_dispenser/New() + ..() + recharge() + dispensable_reagents = sortList(dispensable_reagents) + +/obj/machinery/chem_dispenser/power_change() + if(powered()) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + stat |= NOPOWER + +/obj/machinery/chem_dispenser/process() + + if(recharged < 0) + recharge() + recharged = recharge_delay + else + recharged -= 1 + +/obj/machinery/chem_dispenser/proc/recharge() + if(stat & (BROKEN|NOPOWER)) return + var/addenergy = 1 + var/oldenergy = energy + energy = min(energy + addenergy, max_energy) + if(energy != oldenergy) + use_power(2500) + +/obj/machinery/chem_dispenser/ex_act(severity, target) + if(severity < 3) + ..() + +/obj/machinery/chem_dispenser/blob_act() + if(prob(50)) + qdel(src) + +/obj/machinery/chem_dispenser/interact(mob/user) + if(stat & BROKEN) + return + ui_interact(user) + +/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) + ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open) + if (!ui) + ui = new(user, src, ui_key, "chem_dispenser.tmpl", name, 500, 650) + ui.open() + +/obj/machinery/chem_dispenser/get_ui_data() + var/data = list() + data["amount"] = amount + data["energy"] = energy + data["maxEnergy"] = max_energy + data["isBeakerLoaded"] = beaker ? 1 : 0 + + var beakerContents[0] + var beakerCurrentVolume = 0 + if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) + for(var/datum/reagent/R in beaker.reagents.reagent_list) + beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... + beakerCurrentVolume += R.volume + data["beakerContents"] = beakerContents + + if (beaker) + data["beakerCurrentVolume"] = beakerCurrentVolume + data["beakerMaxVolume"] = beaker.volume + data["beakerTransferAmounts"] = beaker.possible_transfer_amounts + else + data["beakerCurrentVolume"] = null + data["beakerMaxVolume"] = null + data["beakerTransferAmounts"] = null + + var chemicals[0] + for(var/re in dispensable_reagents) + var/datum/reagent/temp = chemical_reagents_list[re] + if(temp) + chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("dispense" = temp.id)))) // list in a list because Byond merges the first list... + data["chemicals"] = chemicals + return data + +/obj/machinery/chem_dispenser/Topic(href, href_list) + if(..()) + return + + if(href_list["amount"]) + amount = round(text2num(href_list["amount"]), 5) // round to nearest 5 + if (amount < 0) // Since the user can actually type the commands himself, some sanity checking + amount = 0 + if (amount > 100) + amount = 100 + + if(href_list["dispense"]) + if(beaker && dispensable_reagents.Find(href_list["dispense"])) + var/datum/reagents/R = beaker.reagents + var/space = R.maximum_volume - R.total_volume + + R.add_reagent(href_list["dispense"], min(amount, energy * 10, space)) + energy = max(energy - min(amount, energy * 10, space) / 10, 0) + + if(href_list["remove"]) + if(beaker) + var/amount = text2num(href_list["remove"]) + if(isnum(amount) && (amount > 0) && (amount in beaker.possible_transfer_amounts)) + beaker.reagents.remove_all(amount) + + if(href_list["ejectBeaker"]) + if(beaker) + beaker.loc = loc + beaker = null + overlays.Cut() + + add_fingerprint(usr) + +/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params) + if(default_unfasten_wrench(user, I)) + return + + if(isrobot(user)) + return + + var/obj/item/weapon/reagent_containers/B = I // Get a beaker from it? + if(!istype(B)) + return // Not a beaker? + + if(beaker) + user << "A beaker is already loaded into the machine!" + return + + if(!user.drop_item()) // Can't let go? + return + + beaker = B + beaker.loc = src + user << "You add the beaker to the machine." + + if(!icon_beaker) + icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position. + icon_beaker.pixel_x = rand(-10,5) + overlays += icon_beaker + +/obj/machinery/chem_dispenser/attack_hand(mob/user) + if (!user) + return + interact(user) + + +/obj/machinery/chem_dispenser/constructable + name = "portable chem dispenser" + icon = 'icons/obj/chemical.dmi' + icon_state = "minidispenser" + energy = 5 + max_energy = 5 + amount = 5 + recharge_delay = 30 + dispensable_reagents = list() + var/list/dispensable_reagent_tiers = list( + list( + "hydrogen", + "oxygen", + "silicon", + "phosphorus", + "sulfur", + "carbon", + "nitrogen", + "water" + ), + list( + "lithium", + "sugar", + "sacid", + "copper", + "mercury", + "sodium", + "iodine", + "bromine" + ), + list( + "ethanol", + "chlorine", + "potassium", + "aluminium", + "radium", + "fluorine", + "iron", + "welding_fuel", + "silver", + "stable_plasma" + ), + list( + "oil", + "ash", + "acetone", + "saltpetre", + "ammonia", + "diethylamine" + ) + ) + +/obj/machinery/chem_dispenser/constructable/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/chem_dispenser(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + component_parts += new /obj/item/weapon/stock_parts/capacitor(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + component_parts += new /obj/item/weapon/stock_parts/cell/high(null) + RefreshParts() + +/obj/machinery/chem_dispenser/constructable/RefreshParts() + var/time = 0 + var/temp_energy = 0 + var/i + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + temp_energy += M.rating + temp_energy-- + max_energy = temp_energy * 5 //max energy = (bin1.rating + bin2.rating - 1) * 5, 5 on lowest 25 on highest + for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) + time += C.rating + for(var/obj/item/weapon/stock_parts/cell/P in component_parts) + time += round(P.maxcharge, 10000) / 10000 + recharge_delay /= time/2 //delay between recharges, double the usual time on lowest 50% less than usual on highest + for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) + for(i=1, i<=M.rating, i++) + dispensable_reagents |= dispensable_reagent_tiers[i] + dispensable_reagents = sortList(dispensable_reagents) + +/obj/machinery/chem_dispenser/constructable/attackby(var/obj/item/I, var/mob/user, params) + ..() + if(default_deconstruction_screwdriver(user, "minidispenser-o", "minidispenser", I)) + return + + if(exchange_parts(user, I)) + return + + if(panel_open) + if(istype(I, /obj/item/weapon/crowbar)) + if(beaker) + beaker.loc = loc + beaker = null + default_deconstruction_crowbar(I) + return 1 + +/obj/machinery/chem_dispenser/drinks + name = "soda dispenser" + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "soda_dispenser" + energy = 100 + max_energy = 100 + amount = 30 + recharge_delay = 5 + dispensable_reagents = list( + "water", + "ice", + "coffee", + "cream", + "tea", + "icetea", + "cola", + "spacemountainwind", + "dr_gibb", + "space_up", + "tonic", + "sodawater", + "lemon_lime", + "sugar", + "orangejuice", + "limejuice", + "tomatojuice" + ) + +/obj/machinery/chem_dispenser/drinks/attackby(obj/item/I, mob/user) + if(default_unfasten_wrench(user, I)) + return + + if (istype(I, /obj/item/weapon/reagent_containers/glass) || \ + istype(I, /obj/item/weapon/reagent_containers/food/drinks/drinkingglass) || \ + istype(I, /obj/item/weapon/reagent_containers/food/drinks/shaker)) + + if (beaker) + return 1 + else + if(!user.drop_item()) + return 1 + src.beaker = I + beaker.loc = src + update_icon() + return + +/obj/machinery/chem_dispenser/drinks/beer + name = "booze dispenser" + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "booze_dispenser" + dispensable_reagents = list( + "lemon_lime", + "sugar", + "orangejuice", + "limejuice", + "sodawater", + "tonic", + "beer", + "kahlua", + "whiskey", + "wine", + "vodka", + "gin", + "rum", + "tequila", + "vermouth", + "cognac", + "ale" + ) diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm new file mode 100644 index 000000000000..179d26763eed --- /dev/null +++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm @@ -0,0 +1,134 @@ +/obj/machinery/chem_heater + name = "chemical heater" + density = 1 + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "mixer0b" + use_power = 1 + idle_power_usage = 40 + var/obj/item/weapon/reagent_containers/beaker = null + var/desired_temp = 300 + var/heater_coefficient = 0.10 + var/on = FALSE + +/obj/machinery/chem_heater/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/chem_heater(null) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + RefreshParts() + +/obj/machinery/chem_heater/RefreshParts() + heater_coefficient = 0.10 + for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts) + heater_coefficient *= M.rating + +/obj/machinery/chem_heater/process() + ..() + if(stat & NOPOWER) + return + if(on) + if(beaker) + if(beaker.reagents.chem_temp > desired_temp) + beaker.reagents.chem_temp += min(-1, (desired_temp - beaker.reagents.chem_temp) * heater_coefficient) + if(beaker.reagents.chem_temp < desired_temp) + beaker.reagents.chem_temp += max(1, (desired_temp - beaker.reagents.chem_temp) * heater_coefficient) + beaker.reagents.chem_temp = round(beaker.reagents.chem_temp) //stops stuff like 456.12312312302 + + beaker.reagents.handle_reactions() + +/obj/machinery/chem_heater/proc/eject_beaker() + if(beaker) + beaker.loc = get_turf(src) + beaker.reagents.handle_reactions() + beaker = null + icon_state = "mixer0b" + +/obj/machinery/chem_heater/power_change() + if(powered()) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + stat |= NOPOWER + +/obj/machinery/chem_heater/attackby(obj/item/I, mob/user, params) + if(isrobot(user)) + return + + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + if(beaker) + user << "A beaker is already loaded into the machine!" + return + + if(user.drop_item()) + beaker = I + I.loc = src + user << "You add the beaker to the machine." + icon_state = "mixer1b" + + if(default_deconstruction_screwdriver(user, "mixer0b", "mixer0b", I)) + return + + if(exchange_parts(user, I)) + return + + if(panel_open) + if(istype(I, /obj/item/weapon/crowbar)) + eject_beaker() + default_deconstruction_crowbar(I) + return 1 + +/obj/machinery/chem_heater/attack_hand(mob/user) + if (!user) + return + interact(user) + +/obj/machinery/chem_heater/Topic(href, href_list) + if(..()) + return + + if(href_list["toggle_on"]) + on = !on + + if(href_list["adjust_temperature"]) + var/val = href_list["adjust_temperature"] + if(isnum(val)) + desired_temp = Clamp(desired_temp+val, 0, 1000) + else if(val == "input") + desired_temp = Clamp(input("Please input the target temperature", name) as num, 0, 1000) + else + return + + if(href_list["eject_beaker"]) + eject_beaker() + + add_fingerprint(usr) + +/obj/machinery/chem_heater/interact(mob/user) + if(stat & BROKEN) + return + ui_interact(user) + +/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0) + ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open) + if (!ui) + ui = new(user, src, ui_key, "chem_heater.tmpl", name, 350, 400) + ui.open() + +/obj/machinery/chem_heater/get_ui_data() + var/data = list() + data["targetTemp"] = desired_temp + data["isActive"] = on + data["isBeakerLoaded"] = beaker ? 1 : 0 + + data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null + data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null + data["beakerMaxVolume"] = beaker ? beaker.volume : null + + var beakerContents[0] + if(beaker) + for(var/datum/reagent/R in beaker.reagents.reagent_list) + beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list... + data["beakerContents"] = beakerContents + return data diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm new file mode 100644 index 000000000000..1030f9dc2a6f --- /dev/null +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -0,0 +1,391 @@ +/obj/machinery/chem_master + name = "ChemMaster 3000" + desc = "Used to bottle chemicals to create pills." + density = 1 + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "mixer0" + use_power = 1 + idle_power_usage = 20 + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/obj/item/weapon/storage/pill_bottle/bottle = null + var/mode = 0 + var/condi = 0 + var/useramount = 30 // Last used amount + +/obj/machinery/chem_master/New() + create_reagents(100) + overlays += "waitlight" + +/obj/machinery/chem_master/ex_act(severity, target) + if(severity < 3) + ..() + +/obj/machinery/chem_master/blob_act() + if (prob(50)) + qdel(src) + +/obj/machinery/chem_master/power_change() + if(powered()) + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + stat |= NOPOWER + +/obj/machinery/chem_master/attackby(obj/item/I, mob/user, params) + if(default_unfasten_wrench(user, I)) + return + + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + if(isrobot(user)) + return + if(beaker) + user << "A beaker is already loaded into the machine!" + return + if(!user.drop_item()) + return + + beaker = I + beaker.loc = src + user << "You add the beaker to the machine." + src.updateUsrDialog() + icon_state = "mixer1" + + else if(!condi && istype(I, /obj/item/weapon/storage/pill_bottle)) + if(bottle) + user << "A pill bottle is already loaded into the machine!" + return + if(!user.drop_item()) + return + + bottle = I + bottle.loc = src + user << "You add the pill bottle into the dispenser slot." + src.updateUsrDialog() + + return + +/obj/machinery/chem_master/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + + if(href_list["ejectp"]) + if(bottle) + bottle.loc = src.loc + bottle = null + + else if(href_list["close"]) + usr << browse(null, "window=chem_master") + usr.unset_machine() + return + + else if(href_list["toggle"]) + mode = !mode + + else if(href_list["createbottle"]) + var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN) + if(!name) + return + var/obj/item/weapon/reagent_containers/P + if(condi) + P = new/obj/item/weapon/reagent_containers/food/condiment(src.loc) + else + P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) + P.pixel_x = rand(-7, 7) //random position + P.pixel_y = rand(-7, 7) + P.name = trim("[name] bottle") + reagents.trans_to(P, P.volume) + + if(beaker) + + if(href_list["analyze"]) + if(locate(href_list["reagent"])) + var/datum/reagent/R = locate(href_list["reagent"]) + if(R) + var/dat = "" + dat += "

[condi ? "Condiment" : "Chemical"] information:

" + dat += "Name: [initial(R.name)]

" + dat += "State: " + if(initial(R.reagent_state) == 1) + dat += "Solid" + else if(initial(R.reagent_state) == 2) + dat += "Liquid" + else if(initial(R.reagent_state) == 3) + dat += "Gas" + else + dat += "Unknown" + dat += "
" + dat += "Color: [initial(R.color)]

" + dat += "Description: [initial(R.description)]

" + var/const/P = 3 //The number of seconds between life ticks + var/T = initial(R.metabolization_rate) * (60 / P) + dat += "Metabolization Rate: [T]u/minute
" + dat += "Overdose Threshold: [initial(R.overdose_threshold) ? "[initial(R.overdose_threshold)]u" : "none"]
" + dat += "Addiction Threshold: [initial(R.addiction_threshold) ? "[initial(R.addiction_threshold)]u" : "none"]

" + dat += "
Back" + var/datum/browser/popup = new(usr, "chem_master", name) + popup.set_content(dat) + popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) + popup.open(1) + return + + else if(href_list["main"]) // Used to exit the analyze screen. + attack_hand(usr) + return + + else if(href_list["add"]) + if(href_list["amount"]) + var/id = href_list["add"] + var/amount = text2num(href_list["amount"]) + if (amount > 0) + beaker.reagents.trans_id_to(src, id, amount) + + else if(href_list["addcustom"]) + var/id = href_list["addcustom"] + var/amt_temp = isgoodnumber(input(usr, "Select the amount to transfer.", "Transfer how much?", useramount) as num|null) + if(!amt_temp) + return + useramount = amt_temp + src.Topic(null, list("amount" = "[useramount]", "add" = "[id]")) + + else if(href_list["remove"]) + if(href_list["amount"]) + var/id = href_list["remove"] + var/amount = text2num(href_list["amount"]) + if (amount > 0) + if(mode) + reagents.trans_id_to(beaker, id, amount) + else + reagents.remove_reagent(id, amount) + + else if(href_list["removecustom"]) + var/id = href_list["removecustom"] + var/amt_temp = isgoodnumber(input(usr, "Select the amount to transfer.", "Transfer how much?", useramount) as num|null) + if(!amt_temp) + return + useramount = amt_temp + src.Topic(null, list("amount" = "[useramount]", "remove" = "[id]")) + + else if(href_list["eject"]) + if(beaker) + beaker.loc = src.loc + beaker = null + reagents.clear_reagents() + icon_state = "mixer0" + + else if(href_list["createpill"]) //Also used for condiment packs. + if(reagents.total_volume == 0) return + if(!condi) + var/amount = 1 + var/vol_each = min(reagents.total_volume, 50) + if(text2num(href_list["many"])) + amount = min(max(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0), 10) + if(!amount) + return + vol_each = min(reagents.total_volume / amount, 50) + var/name = stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) + if(!name || !reagents.total_volume) + return + var/obj/item/weapon/reagent_containers/pill/P + + for(var/i = 0; i < amount; i++) + if(bottle && bottle.contents.len < bottle.storage_slots) + P = new/obj/item/weapon/reagent_containers/pill(bottle) + else + P = new/obj/item/weapon/reagent_containers/pill(src.loc) + P.name = trim("[name] pill") + P.pixel_x = rand(-7, 7) //random position + P.pixel_y = rand(-7, 7) + reagents.trans_to(P,vol_each) + else + var/name = stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN) + if(!name || !reagents.total_volume) + return + var/obj/item/weapon/reagent_containers/food/condiment/pack/P = new/obj/item/weapon/reagent_containers/food/condiment/pack(src.loc) + + P.originalname = name + P.name = trim("[name] pack") + P.desc = "A small condiment pack. The label says it contains [name]." + reagents.trans_to(P,10) + + else if(href_list["createpatch"]) + if(reagents.total_volume == 0) return + var/amount = 1 + var/vol_each = min(reagents.total_volume, 50) + if(text2num(href_list["many"])) + amount = min(max(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0), 10) + if(!amount) + return + vol_each = min(reagents.total_volume / amount, 50) + var/name = stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN) + if(!name || !reagents.total_volume) + return + var/obj/item/weapon/reagent_containers/pill/P + + for(var/i = 0; i < amount; i++) + P = new/obj/item/weapon/reagent_containers/pill/patch(src.loc) + P.name = trim("[name] patch") + P.pixel_x = rand(-7, 7) //random position + P.pixel_y = rand(-7, 7) + reagents.trans_to(P,vol_each) + + src.updateUsrDialog() + return + +/obj/machinery/chem_master/attack_hand(mob/user) + if(stat & BROKEN) + return + + user.set_machine(src) + var/dat = "" + if(beaker) + dat += "Beaker \[[beaker.reagents.total_volume]/[beaker.volume]\] Eject and Clear Buffer
" + else + dat = "Please insert beaker.
" + + dat += "
Add to buffer:
Transfer to [(!mode ? "disposal" : "beaker")]:
" + + if(!condi) + if(bottle) + dat += "Pill Bottle \[[bottle.contents.len]/[bottle.storage_slots]\] Eject" + else + dat += "No pill bottle inserted." + else + dat += "
" + + dat += "" + dat += "
Close" + var/datum/browser/popup = new(user, "chem_master", name, 470, 500) + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open(1) + return + +/obj/machinery/chem_master/proc/isgoodnumber(num) + if(isnum(num)) + if(num > 200) + num = 200 + else if(num < 0) + num = 0 + else + num = round(num) + return num + else + return 0 + + +/obj/machinery/chem_master/condimaster + name = "CondiMaster 3000" + desc = "Used to create condiments and other cooking supplies." + condi = 1 + +/obj/machinery/chem_master/constructable + name = "ChemMaster 2999" + desc = "Used to seperate chemicals and distribute them in a variety of forms." + +/obj/machinery/chem_master/constructable/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/chem_master(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(null) + component_parts += new /obj/item/weapon/reagent_containers/glass/beaker(null) + +/obj/machinery/chem_master/constructable/attackby(obj/item/B, mob/user, params) + + if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", B)) + if(beaker) + beaker.loc = src.loc + beaker = null + reagents.clear_reagents() + if(bottle) + bottle.loc = src.loc + bottle = null + return + + if(exchange_parts(user, B)) + return + + if(panel_open) + if(istype(B, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(B) + return 1 + else + user << "You can't use the [src.name] while it's panel is opened!" + return 1 + + if(istype(B, /obj/item/weapon/reagent_containers/glass)) + if(beaker) + user << "A beaker is already loaded into the machine!" + return + if(!user.drop_item()) + return + + beaker = B + beaker.loc = src + user << "You add the beaker to the machine." + src.updateUsrDialog() + icon_state = "mixer1" + + else if(!condi && istype(B, /obj/item/weapon/storage/pill_bottle)) + if(bottle) + user << "A pill bottle is already loaded into the machine!" + return + if(!user.drop_item()) + return + + src.bottle = B + B.loc = src + user << "You add the pill bottle into the dispenser slot." + src.updateUsrDialog() + + return diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm new file mode 100644 index 000000000000..bb068c421c1a --- /dev/null +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -0,0 +1,295 @@ +/obj/machinery/computer/pandemic + name = "PanD.E.M.I.C 2200" + desc = "Used to work with viruses." + density = 1 + anchored = 1 + icon = 'icons/obj/chemical.dmi' + icon_state = "mixer0" + circuit = /obj/item/weapon/circuitboard/pandemic + use_power = 1 + idle_power_usage = 20 + var/temp_html = "" + var/wait = null + var/obj/item/weapon/reagent_containers/glass/beaker = null + +/obj/machinery/computer/pandemic/New() + ..() + update_icon() + +/obj/machinery/computer/pandemic/set_broken() + icon_state = (beaker ? "mixer1_b" : "mixer0_b") + overlays.Cut() + stat |= BROKEN + +/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index) + if(beaker && beaker.reagents) + if(beaker.reagents.reagent_list.len) + var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list + if(BL) + if(BL.data && BL.data["viruses"]) + var/list/viruses = BL.data["viruses"] + return viruses[index] + return null + +/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index) + if(beaker && beaker.reagents) + if(beaker.reagents.reagent_list.len) + var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list + if(BL) + if(BL.data && BL.data["resistances"]) + var/list/resistances = BL.data["resistances"] + return resistances[index] + return null + +/obj/machinery/computer/pandemic/proc/GetVirusTypeByIndex(index) + var/datum/disease/D = GetVirusByIndex(index) + if(D) + return D.GetDiseaseID() + return null + +/obj/machinery/computer/pandemic/proc/replicator_cooldown(waittime) + wait = 1 + update_icon() + spawn(waittime) + src.wait = null + update_icon() + playsound(src.loc, 'sound/machines/ping.ogg', 30, 1) + +/obj/machinery/computer/pandemic/update_icon() + if(stat & BROKEN) + icon_state = (beaker ? "mixer1_b" : "mixer0_b") + return + + icon_state = "mixer[(beaker)?"1":"0"][(powered()) ? "" : "_nopower"]" + + if(wait) + overlays.Cut() + else + overlays += "waitlight" + +/obj/machinery/computer/pandemic/Topic(href, href_list) + if(..()) + return + + usr.set_machine(src) + if(!beaker) return + + if (href_list["create_vaccine"]) + if(!src.wait) + var/obj/item/weapon/reagent_containers/glass/bottle/B = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) + if(B) + B.pixel_x = rand(-3, 3) + B.pixel_y = rand(-3, 3) + var/path = GetResistancesByIndex(text2num(href_list["create_vaccine"])) + var/vaccine_type = path + var/vaccine_name = "Unknown" + + if(!ispath(vaccine_type)) + if(archive_diseases[path]) + var/datum/disease/D = archive_diseases[path] + if(D) + vaccine_name = D.name + vaccine_type = path + else if(vaccine_type) + var/datum/disease/D = new vaccine_type(0, null) + if(D) + vaccine_name = D.name + + if(vaccine_type) + + B.name = "[vaccine_name] vaccine bottle" + B.reagents.add_reagent("vaccine", 15, list(vaccine_type)) + replicator_cooldown(200) + else + src.temp_html = "The replicator is not ready yet." + src.updateUsrDialog() + return + else if (href_list["create_virus_culture"]) + if(!wait) + var/type = GetVirusTypeByIndex(text2num(href_list["create_virus_culture"]))//the path is received as string - converting + var/datum/disease/D = null + if(!ispath(type)) + D = GetVirusByIndex(text2num(href_list["create_virus_culture"])) + var/datum/disease/advance/A = archive_diseases[D.GetDiseaseID()] + if(A) + D = new A.type(0, A) + else if(type) + if(type in diseases) // Make sure this is a disease + D = new type(0, null) + if(!D) + return + var/name = stripped_input(usr,"Name:","Name the culture",D.name,MAX_NAME_LEN) + if(name == null || wait) + return + var/obj/item/weapon/reagent_containers/glass/bottle/B = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) + B.icon_state = "bottle3" + B.pixel_x = rand(-3, 3) + B.pixel_y = rand(-3, 3) + replicator_cooldown(50) + var/list/data = list("viruses"=list(D)) + B.name = "[name] culture bottle" + B.desc = "A small bottle. Contains [D.agent] culture in synthblood medium." + B.reagents.add_reagent("blood",20,data) + src.updateUsrDialog() + else + src.temp_html = "The replicator is not ready yet." + src.updateUsrDialog() + return + else if (href_list["empty_beaker"]) + beaker.reagents.clear_reagents() + src.updateUsrDialog() + return + else if (href_list["eject"]) + beaker:loc = src.loc + beaker = null + icon_state = "mixer0" + src.updateUsrDialog() + return + else if(href_list["clear"]) + src.temp_html = "" + src.updateUsrDialog() + return + else if(href_list["name_disease"]) + var/new_name = stripped_input(usr, "Name the Disease", "New Name", "", MAX_NAME_LEN) + if(!new_name) + return + if(..()) + return + var/id = GetVirusTypeByIndex(text2num(href_list["name_disease"])) + if(archive_diseases[id]) + var/datum/disease/advance/A = archive_diseases[id] + A.AssignName(new_name) + for(var/datum/disease/advance/AD in SSdisease.processing) + AD.Refresh() + src.updateUsrDialog() + + + else + usr << browse(null, "window=pandemic") + src.updateUsrDialog() + return + + src.add_fingerprint(usr) + return + +/obj/machinery/computer/pandemic/attack_hand(mob/user) + if(..()) + return + user.set_machine(src) + var/dat = "" + if(src.temp_html) + dat = "[src.temp_html]

Main Menu" + else if(!beaker) + dat += "Please insert beaker.
" + dat += "Close" + else + var/datum/reagents/R = beaker.reagents + var/datum/reagent/blood/Blood = null + for(var/datum/reagent/blood/B in R.reagent_list) + if(B) + Blood = B + break + if(!R.total_volume||!R.reagent_list.len) + dat += "The beaker is empty
" + else if(!Blood) + dat += "No blood sample found in beaker." + else if(!Blood.data) + dat += "No blood data found in beaker." + else + dat += "

Blood sample data:

" + dat += "Blood DNA: [(Blood.data["blood_DNA"]||"none")]
" + dat += "Blood Type: [(Blood.data["blood_type"]||"none")]
" + + + if(Blood.data["viruses"]) + var/list/vir = Blood.data["viruses"] + if(vir.len) + var/i = 0 + for(var/datum/disease/D in Blood.data["viruses"]) + i++ + if(!(D.visibility_flags & HIDDEN_PANDEMIC)) + + if(istype(D, /datum/disease/advance)) + + var/datum/disease/advance/A = D + D = archive_diseases[A.GetDiseaseID()] + if(D && D.name == "Unknown") + dat += "Name Disease
" + + if(!D) + CRASH("We weren't able to get the advance disease from the archive.") + + dat += "Disease Agent: [D?"[D.agent] - Create virus culture bottle":"none"]
" + dat += "Common name: [(D.name||"none")]
" + dat += "Description: [(D.desc||"none")]
" + dat += "Spread: [(D.spread_text||"none")]
" + dat += "Possible cure: [(D.cure_text||"none")]

" + + if(istype(D, /datum/disease/advance)) + var/datum/disease/advance/A = D + dat += "Symptoms: " + var/english_symptoms = list() + for(var/datum/symptom/S in A.symptoms) + english_symptoms += S.name + dat += english_list(english_symptoms) + + else + dat += "No detectable virus in the sample." + else + dat += "No detectable virus in the sample." + + dat += "
Contains antibodies to: " + if(Blood.data["resistances"]) + var/list/res = Blood.data["resistances"] + if(res.len) + dat += "
" + else + dat += "nothing
" + else + dat += "nothing
" + dat += "
Eject beaker[((R.total_volume&&R.reagent_list.len) ? "-- Empty beaker":"")]
" + dat += "Close" + + user << browse("[src.name]
[dat]", "window=pandemic;size=575x400") + onclose(user, "pandemic") + return + + +/obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + if(stat & (NOPOWER|BROKEN)) return + if(beaker) + user << "A beaker is already loaded into the machine!" + return + if(!user.drop_item()) + return + + beaker = I + beaker.loc = src + user << "You add the beaker to the machine." + src.updateUsrDialog() + icon_state = "mixer1" + + else if(istype(I, /obj/item/weapon/screwdriver)) + if(src.beaker) + beaker.loc = get_turf(src) + ..() + return + else + ..() + return diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm new file mode 100644 index 000000000000..f27773397d9d --- /dev/null +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -0,0 +1,441 @@ +/obj/machinery/reagentgrinder + name = "All-In-One Grinder" + desc = "Used to grind things up into raw materials." + icon = 'icons/obj/kitchen.dmi' + icon_state = "juicer1" + layer = 2.9 + anchored = 1 + use_power = 1 + idle_power_usage = 5 + active_power_usage = 100 + pass_flags = PASSTABLE + var/operating = 0 + var/obj/item/weapon/reagent_containers/beaker = null + var/limit = 10 + var/list/blend_items = list ( + + //Sheets + /obj/item/stack/sheet/mineral/plasma = list("plasma" = 20), + /obj/item/stack/sheet/metal = list("iron" = 20), + /obj/item/stack/sheet/plasteel = list("iron" = 20, "plasma" = 20), + /obj/item/stack/sheet/mineral/wood = list("carbon" = 20), + /obj/item/stack/sheet/glass = list("silicon" = 20), + /obj/item/stack/sheet/rglass = list("silicon" = 20, "iron" = 20), + /obj/item/stack/sheet/mineral/uranium = list("uranium" = 20), + /obj/item/stack/sheet/mineral/bananium = list("banana" = 20), + /obj/item/stack/sheet/mineral/silver = list("silver" = 20), + /obj/item/stack/sheet/mineral/gold = list("gold" = 20), + /obj/item/weapon/grown/nettle/basic = list("sacid" = 0), + /obj/item/weapon/grown/nettle/death = list("facid" = 0), + /obj/item/weapon/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0), + + //Crayons (for overriding colours) + /obj/item/toy/crayon/red = list("redcrayonpowder" = 10), + /obj/item/toy/crayon/orange = list("orangecrayonpowder" = 10), + /obj/item/toy/crayon/yellow = list("yellowcrayonpowder" = 10), + /obj/item/toy/crayon/green = list("greencrayonpowder" = 10), + /obj/item/toy/crayon/blue = list("bluecrayonpowder" = 10), + /obj/item/toy/crayon/purple = list("purplecrayonpowder" = 10), + /obj/item/toy/crayon/mime = list("invisiblecrayonpowder" = 50), + + //Blender Stuff + /obj/item/weapon/reagent_containers/food/snacks/grown/soybeans = list("soymilk" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = list("ketchup" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/corn = list("cornoil" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/wheat = list("flour" = -5), + /obj/item/weapon/reagent_containers/food/snacks/grown/oat = list("flour" = -5), + /obj/item/weapon/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/bluecherries = list("bluecherryjelly" = 0), + /obj/item/weapon/reagent_containers/food/snacks/egg = list("eggyolk" = -5), + + //Grinder stuff, but only if dry + /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/arabica = list("coffeepowder" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/tea/aspera = list("teapowder" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0), + + + + //All types that you can put into the grinder to transfer the reagents to the beaker. !Put all recipes above this.! + /obj/item/weapon/reagent_containers/pill = list(), + /obj/item/weapon/reagent_containers/food = list() + ) + + var/list/juice_items = list ( + + //Juicer Stuff + /obj/item/weapon/reagent_containers/food/snacks/grown/corn = list("corn_starch" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/tomato = list("tomatojuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/carrot = list("carrotjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/berries = list("berryjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/banana = list("banana" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/potato = list("potato" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/citrus/lemon = list("lemonjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/citrus/orange = list("orangejuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/citrus/lime = list("limejuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/watermelon = list("watermelonjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/watermelonslice = list("watermelonjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/berries/poison = list("poisonberryjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/pumpkin = list("pumpkinjuice" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/blumpkin = list("blumpkinjuice" = 0), + ) + + var/list/dried_items = list( + + //Grinder stuff, but only if dry + /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/arabica = list("coffeepowder" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/tea/aspera = list("teapowder" = 0), + /obj/item/weapon/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0), + ) + + var/list/holdingitems = list() + +/obj/machinery/reagentgrinder/New() + ..() + beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + return + +/obj/machinery/reagentgrinder/update_icon() + icon_state = "juicer"+num2text(!isnull(beaker)) + return + + +/obj/machinery/reagentgrinder/attackby(obj/item/I, mob/user, params) + if(default_unfasten_wrench(user, I)) + return + + if (istype(I, /obj/item/weapon/reagent_containers/glass) || \ + istype(I, /obj/item/weapon/reagent_containers/food/drinks/drinkingglass) || \ + istype(I, /obj/item/weapon/reagent_containers/food/drinks/shaker)) + + if (beaker) + return 1 + else + if(!user.drop_item()) + return 1 + beaker = I + beaker.loc = src + update_icon() + src.updateUsrDialog() + return 0 + + if(is_type_in_list(I, dried_items)) + if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/grown)) + var/obj/item/weapon/reagent_containers/food/snacks/grown/G = I + if(!G.dry) + user << "You must dry that first!" + return 1 + + if(holdingitems && holdingitems.len >= limit) + usr << "The machine cannot hold anymore items." + return 1 + + //Fill machine with a bag! + if(istype(I, /obj/item/weapon/storage/bag)) + var/obj/item/weapon/storage/bag/B = I + for (var/obj/item/weapon/reagent_containers/food/snacks/grown/G in B.contents) + B.remove_from_storage(G, src) + holdingitems += G + if(holdingitems && holdingitems.len >= limit) //Sanity checking so the blender doesn't overfill + user << "You fill the All-In-One grinder to the brim." + break + + if(!I.contents.len) + user << "You empty the plant bag into the All-In-One grinder." + + src.updateUsrDialog() + return 0 + + if (!is_type_in_list(I, blend_items) && !is_type_in_list(I, juice_items)) + user << "Cannot refine into a reagent!" + return 1 + + user.unEquip(I) + I.loc = src + holdingitems += I + src.updateUsrDialog() + return 0 + +/obj/machinery/reagentgrinder/attack_paw(mob/user) + return src.attack_hand(user) + +/obj/machinery/reagentgrinder/attack_ai(mob/user) + return 0 + +/obj/machinery/reagentgrinder/attack_hand(mob/user) + user.set_machine(src) + interact(user) + +/obj/machinery/reagentgrinder/interact(mob/user) // The microwave Menu + var/is_chamber_empty = 0 + var/is_beaker_ready = 0 + var/processing_chamber = "" + var/beaker_contents = "" + var/dat = "" + + if(!operating) + for (var/obj/item/O in holdingitems) + processing_chamber += "\A [O.name]
" + + if (!processing_chamber) + is_chamber_empty = 1 + processing_chamber = "Nothing." + if (!beaker) + beaker_contents = "No beaker attached.
" + else + is_beaker_ready = 1 + beaker_contents = "The beaker contains:
" + var/anything = 0 + for(var/datum/reagent/R in beaker.reagents.reagent_list) + anything = 1 + beaker_contents += "[R.volume] - [R.name]
" + if(!anything) + beaker_contents += "Nothing
" + + + dat = {" + Processing chamber contains:
+ [processing_chamber]
+ [beaker_contents]
+ "} + if (is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN))) + dat += "Grind the reagents
" + dat += "Juice the reagents

" + if(holdingitems && holdingitems.len > 0) + dat += "Eject the reagents
" + if (beaker) + dat += "Detach the beaker
" + else + dat += "Please wait..." + + var/datum/browser/popup = new(user, "reagentgrinder", "All-In-One Grinder") + popup.set_content(dat) + popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.open(1) + return + +/obj/machinery/reagentgrinder/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + if(operating) + updateUsrDialog() + return + switch(href_list["action"]) + if ("grind") + grind() + if("juice") + juice() + if("eject") + eject() + if ("detach") + detach() + +/obj/machinery/reagentgrinder/proc/detach() + + if (usr.stat != 0) + return + if (!beaker) + return + beaker.loc = src.loc + beaker = null + update_icon() + updateUsrDialog() + +/obj/machinery/reagentgrinder/proc/eject() + + if (usr.stat != 0) + return + if (holdingitems && holdingitems.len == 0) + return + + for(var/obj/item/O in holdingitems) + O.loc = src.loc + holdingitems -= O + holdingitems = list() + updateUsrDialog() + +/obj/machinery/reagentgrinder/proc/is_allowed(obj/item/weapon/reagent_containers/O) + for (var/i in blend_items) + if(istype(O, i)) + return 1 + return 0 + +/obj/machinery/reagentgrinder/proc/get_allowed_by_id(obj/item/O) + for (var/i in blend_items) + if (istype(O, i)) + return blend_items[i] + +/obj/machinery/reagentgrinder/proc/get_allowed_snack_by_id(obj/item/weapon/reagent_containers/food/snacks/O) + for(var/i in blend_items) + if(istype(O, i)) + return blend_items[i] + +/obj/machinery/reagentgrinder/proc/get_allowed_juice_by_id(obj/item/weapon/reagent_containers/food/snacks/O) + for(var/i in juice_items) + if(istype(O, i)) + return juice_items[i] + +/obj/machinery/reagentgrinder/proc/get_grownweapon_amount(obj/item/weapon/grown/O) + if (!istype(O)) + return 5 + else if (O.potency == -1) + return 5 + else + return round(O.potency) + +/obj/machinery/reagentgrinder/proc/get_juice_amount(obj/item/weapon/reagent_containers/food/snacks/grown/O) + if (!istype(O)) + return 5 + else if (O.potency == -1) + return 5 + else + return round(5*sqrt(O.potency)) + +/obj/machinery/reagentgrinder/proc/remove_object(obj/item/O) + holdingitems -= O + qdel(O) + +/obj/machinery/reagentgrinder/proc/juice() + power_change() + if(stat & (NOPOWER|BROKEN)) + return + if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) + return + playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1) + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking + operating = 1 + updateUsrDialog() + spawn(50) + pixel_x = initial(pixel_x) //return to its spot after shaking + operating = 0 + updateUsrDialog() + + //Snacks + for (var/obj/item/weapon/reagent_containers/food/snacks/O in holdingitems) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + + var/allowed = get_allowed_juice_by_id(O) + if(isnull(allowed)) + break + + for (var/r_id in allowed) + + var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = get_juice_amount(O) + + beaker.reagents.add_reagent(r_id, min(amount, space)) + + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + + remove_object(O) + +/obj/machinery/reagentgrinder/proc/grind() + + power_change() + if(stat & (NOPOWER|BROKEN)) + return + if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume)) + return + playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) + var/offset = prob(50) ? -2 : 2 + animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking + operating = 1 + updateUsrDialog() + spawn(60) + pixel_x = initial(pixel_x) //return to its spot after shaking + operating = 0 + updateUsrDialog() + + //Snacks and Plants + for (var/obj/item/weapon/reagent_containers/food/snacks/O in holdingitems) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + + var/allowed = get_allowed_snack_by_id(O) + if(isnull(allowed)) + break + + for (var/r_id in allowed) + + var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = allowed[r_id] + if(amount <= 0) + if(amount == 0) + if (O.reagents != null && O.reagents.has_reagent("nutriment")) + beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment"), space)) + O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) + else + if (O.reagents != null && O.reagents.has_reagent("nutriment")) + beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment")*abs(amount)), space)) + O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) + + else + O.reagents.trans_id_to(beaker, r_id, min(amount, space)) + + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + + if(O.reagents.reagent_list.len == 0) + remove_object(O) + + //Sheets + for (var/obj/item/stack/sheet/O in holdingitems) + var/allowed = get_allowed_by_id(O) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + for(var/i = 1; i <= round(O.amount, 1); i++) + for (var/r_id in allowed) + var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = allowed[r_id] + beaker.reagents.add_reagent(r_id,min(amount, space)) + if (space < amount) + break + if (i == round(O.amount, 1)) + remove_object(O) + break + //Plants + for (var/obj/item/weapon/grown/O in holdingitems) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + var/allowed = get_allowed_by_id(O) + for (var/r_id in allowed) + var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = allowed[r_id] + if (amount == 0) + if (O.reagents != null && O.reagents.has_reagent(r_id)) + beaker.reagents.add_reagent(r_id,min(O.reagents.get_reagent_amount(r_id), space)) + else + beaker.reagents.add_reagent(r_id,min(amount, space)) + + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + remove_object(O) + + + //Crayons + //With some input from aranclanos, now 30% less shoddily copypasta + for (var/obj/item/toy/crayon/O in holdingitems) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + var/allowed = get_allowed_by_id(O) + for (var/r_id in allowed) + var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = allowed[r_id] + beaker.reagents.add_reagent(r_id,min(amount, space)) + if (space < amount) + break + remove_object(O) + + //Everything else - Transfers reagents from it into beaker + for (var/obj/item/weapon/reagent_containers/O in holdingitems) + if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + break + var/amount = O.reagents.total_volume + O.reagents.trans_to(beaker, amount) + if(!O.reagents.total_volume) + remove_object(O) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Readme.dm b/code/modules/reagents/chemistry/readme.dm similarity index 97% rename from code/modules/reagents/Chemistry-Readme.dm rename to code/modules/reagents/chemistry/readme.dm index b754f17596fd..b2759dbe7af3 100644 --- a/code/modules/reagents/Chemistry-Readme.dm +++ b/code/modules/reagents/chemistry/readme.dm @@ -1,267 +1,270 @@ -/* -NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README. - -Structure: /////////////////// ////////////////////////// - // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. - /////////////////// ////////////////////////// - | | - The object that holds everything. V - reagent_list var (list) A List of datums, each datum is a reagent. - - | | | - V V V - - reagents (datums) Reagents. I.e. Water , cryoxadone or mercury. - - -Random important notes: - - An objects on_reagent_change will be called every time the objects reagents change. - Useful if you want to update the objects icon etc. - -About the Holder: - - The holder (reagents datum) is the datum that holds a list of all reagents - currently in the object.It also has all the procs needed to manipulate reagents - - remove_any(var/amount) - This proc removes reagents from the holder until the passed amount - is matched. It'll try to remove some of ALL reagents contained. - - trans_to(var/obj/target, var/amount) - This proc equally transfers the contents of the holder to another - objects holder. You need to pass it the object (not the holder) you want - to transfer to and the amount you want to transfer. Its return value is the - actual amount transfered (if one of the objects is full/empty) - - trans_id_to(var/obj/target, var/reagent, var/amount) - Same as above but only for a specific reagent in the reagent list. - If the specified amount is greater than what is available, it will use - the amount of the reagent that is available. If no reagent exists, returns null. - - metabolize(var/mob/M) - This proc is called by the mobs life proc. It simply calls on_mob_life for - all contained reagents. You shouldnt have to use this one directly. - - handle_reactions() - This proc check all recipes and, on a match, uses them. - It will also call the recipe's on_reaction proc (for explosions or w/e). - Currently, this proc is automatically called by trans_to. - - isolate_reagent(var/reagent) - Pass it a reagent id and it will remove all reagents but that one. - It's that simple. - - del_reagent(var/reagent) - Completely remove the reagent with the matching id. - - reaction_fire(exposed_temp) - Simply calls the reaction_fire procs of all contained reagents. - - update_total() - This one simply updates the total volume of the holder. - (the volume of all reagents added together) - - clear_reagents() - This proc removes ALL reagents from the holder. - - reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0) - This proc calls the appropriate reaction procs of the reagents. - I.e. if A is an object, it will call the reagents reaction_obj - proc. The method var is used for reaction on mobs. It simply tells - us if the mob TOUCHed the reagent, if it INGESTed the reagent, if the reagent - was VAPORIZEd on them, if the reagent was INJECTed, or transfered via a PATCH to them. - Since the volume can be checked in a reagents proc, you might want to - use the volume_modifier var to modifiy the passed value without actually - changing the volume of the reagents. - If you're not sure if you need to use this the answer is very most likely 'No'. - You'll want to use this proc whenever an atom first comes in - contact with the reagents of a holder. (in the 'splash' part of a beaker i.e.) - More on the reaction in the reagent part of this readme. - - add_reagent(var/reagent, var/amount, var/data) - Attempts to add X of the matching reagent to the holder. - You wont use this much. Mostly in new procs for pre-filled - objects. - - remove_reagent(var/reagent, var/amount) - The exact opposite of the add_reagent proc. - - has_reagent(var/reagent, var/amount) - Returns 1 if the holder contains this reagent. - Or 0 if not. - If you pass it an amount it will additionally check - if the amount is matched. This is optional. - - get_reagent_amount(var/reagent) - Returns the amount of the matching reagent inside the - holder. Returns 0 if the reagent is missing. - - Important variables: - - total_volume - This variable contains the total volume of all reagents in this holder. - - reagent_list - This is a list of all contained reagents. More specifically, references - to the reagent datums. - - maximum_volume - This is the maximum volume of the holder. - - my_atom - This is the atom the holder is 'in'. Useful if you need to find the location. - (i.e. for explosions) - - -About Reagents: - - Reagents are all the things you can mix and fille in bottles etc. This can be anything from - rejuvs over water to ... iron. Each reagent also has a few procs - i'll explain those below. - - reaction_mob(var/mob/M, var/method=TOUCH) - This is called by the holder's reation proc. - This version is only called when the reagent - reacts with a mob. The method var can be either - TOUCH or INGEST. You'll want to put stuff like - acid-facemelting in here. - - reaction_obj(var/obj/O) - This is called by the holder's reation proc. - This version is called when the reagents reacts - with an object. You'll want to put stuff like - object melting in here ... or something. i dunno. - - reaction_turf(var/turf/T) - This is called by the holder's reation proc. - This version is called when the reagents reacts - with a turf. You'll want to put stuff like extra - slippery floors for lube or something in here. - - on_mob_life(var/mob/M) - This proc is called everytime the mobs life proc executes. - This is the place where you put damage for toxins , - drowsyness for sleep toxins etc etc. - You'll want to call the parents proc by using ..() . - If you dont, the chemical will stay in the mob forever - - unless you write your own piece of code to slowly remove it. - (Should be pretty easy, 1 line of code) - - Important variables: - - holder - This variable contains a reference to the holder the chemical is 'in' - - volume - This is the volume of the reagent. - - id - The id of the reagent - - name - The name of the reagent. - - data - This var can be used for whatever the fuck you want. I used it for the sleep - toxins to make them work slowly instead of instantly. You could also use this - for DNA in a blood reagent or ... well whatever you want. - - color - This is a hexadecimal color that represents the reagent outside of containers, - you define it as "#RRGGBB", or, red green blue. You can also define it using the - rgb() proc, which returns a hexadecimal value too. The color is black by default. - - A good website for color calculations: http://www.psyclops.com/tools/rgb/ - - - - -About Recipes: - - Recipes are simple datums that contain a list of required reagents and a result. - They also have a proc that is called when the recipe is matched. - - on_reaction(var/datum/reagents/holder, var/created_volume) - This proc is called when the recipe is matched. - You'll want to add explosions etc here. - To find the location you'll have to do something - like get_turf(holder.my_atom) - - name & id - Should be pretty obvious. - - result - This var contains the id of the resulting reagent. - - required_reagents - This is a list of ids of the required reagents. - Each id also needs an associated value that gives us the minimum required amount - of that reagent. The handle_reaction proc can detect mutiples of the same recipes - so for most cases you want to set the required amount to 1. - - required_catalysts - This is a list of the ids of the required catalysts. - Functionally similar to required_reagents, it is a list of reagents that are required - for the reaction. However, unlike required_reagents, catalysts are NOT consumed. - They mearly have to be present in the container. - - result_amount - This is the amount of the resulting reagent this recipe will produce. - I recommend you set this to the total volume of all required reagent. - - required_container - The container the recipe has to take place in in order to happen. Leave this blank/null - if you want the reaction to happen anywhere. - - required_other - Basically like a reagent's data variable. You can set extra requirements for a - reaction with this. - - required_temp - This is the required temperature. - - -About the Tools: - - By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. - system you'll need to add something like this in its new proc: - - var/datum/reagents/R = new/datum/reagents(100) <<<<< create a new datum , 100 is the maximum_volume of the new holder datum. - reagents = R <<<<< assign the new datum to the objects reagents var - R.my_atom = src <<<<< set the holders my_atom to src so that we know where we are. - - This can also be done by calling a convenience proc: - atom/proc/create_reagents(var/max_volume) - - Other important stuff: - - amount_per_transfer_from_this var - This var is mostly used by beakers and bottles. - It simply tells us how much to transfer when - 'pouring' our reagents into something else. - - atom/proc/is_open_container() - Checks atom/var/flags & OPENCONTAINER. - If this returns 1 , you can use syringes, beakers etc - to manipulate the contents of this object. - If it's 0, you'll need to write your own custom reagent - transfer code since you will not be able to use the standard - tools to manipulate it. - -*/ - - - - -/* GOON CHEMS README: - - Credit goes to Cogwerks, and all the other goonstation coders - for the original idea and implementation of this over at goonstation. - - THE REQUESTED DON'T PORT LIST: IF YOU PORT THESE THE GOONS WILL MURDER US IN OUR SLEEP SO PLEASE DON'T KTHX - Iamgoofball - Any of the Secret Chems - Goon in-joke chems (Eg. Cat Drugs, Hairgrownium) - Liquid Electricity - Rajajajah - +/* +NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README. + +Structure: /////////////////// ////////////////////////// + // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. + /////////////////// ////////////////////////// + | | + The object that holds everything. V + reagent_list var (list) A List of datums, each datum is a reagent. + + | | | + V V V + + reagents (datums) Reagents. I.e. Water , cryoxadone or mercury. + + +Random important notes: + + An objects on_reagent_change will be called every time the objects reagents change. + Useful if you want to update the objects icon etc. + +About the Holder: + + The holder (reagents datum) is the datum that holds a list of all reagents + currently in the object.It also has all the procs needed to manipulate reagents + + remove_any(var/amount) + This proc removes reagents from the holder until the passed amount + is matched. It'll try to remove some of ALL reagents contained. + + remove_all(var/amount) + This proc removes reagents from the holder equally. + + trans_to(var/obj/target, var/amount) + This proc equally transfers the contents of the holder to another + objects holder. You need to pass it the object (not the holder) you want + to transfer to and the amount you want to transfer. Its return value is the + actual amount transfered (if one of the objects is full/empty) + + trans_id_to(var/obj/target, var/reagent, var/amount) + Same as above but only for a specific reagent in the reagent list. + If the specified amount is greater than what is available, it will use + the amount of the reagent that is available. If no reagent exists, returns null. + + metabolize(var/mob/M) + This proc is called by the mobs life proc. It simply calls on_mob_life for + all contained reagents. You shouldnt have to use this one directly. + + handle_reactions() + This proc check all recipes and, on a match, uses them. + It will also call the recipe's on_reaction proc (for explosions or w/e). + Currently, this proc is automatically called by trans_to. + + isolate_reagent(var/reagent) + Pass it a reagent id and it will remove all reagents but that one. + It's that simple. + + del_reagent(var/reagent) + Completely remove the reagent with the matching id. + + reaction_fire(exposed_temp) + Simply calls the reaction_fire procs of all contained reagents. + + update_total() + This one simply updates the total volume of the holder. + (the volume of all reagents added together) + + clear_reagents() + This proc removes ALL reagents from the holder. + + reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0) + This proc calls the appropriate reaction procs of the reagents. + I.e. if A is an object, it will call the reagents reaction_obj + proc. The method var is used for reaction on mobs. It simply tells + us if the mob TOUCHed the reagent, if it INGESTed the reagent, if the reagent + was VAPORIZEd on them, if the reagent was INJECTed, or transfered via a PATCH to them. + Since the volume can be checked in a reagents proc, you might want to + use the volume_modifier var to modifiy the passed value without actually + changing the volume of the reagents. + If you're not sure if you need to use this the answer is very most likely 'No'. + You'll want to use this proc whenever an atom first comes in + contact with the reagents of a holder. (in the 'splash' part of a beaker i.e.) + More on the reaction in the reagent part of this readme. + + add_reagent(var/reagent, var/amount, var/data) + Attempts to add X of the matching reagent to the holder. + You wont use this much. Mostly in new procs for pre-filled + objects. + + remove_reagent(var/reagent, var/amount) + The exact opposite of the add_reagent proc. + + has_reagent(var/reagent, var/amount) + Returns 1 if the holder contains this reagent. + Or 0 if not. + If you pass it an amount it will additionally check + if the amount is matched. This is optional. + + get_reagent_amount(var/reagent) + Returns the amount of the matching reagent inside the + holder. Returns 0 if the reagent is missing. + + Important variables: + + total_volume + This variable contains the total volume of all reagents in this holder. + + reagent_list + This is a list of all contained reagents. More specifically, references + to the reagent datums. + + maximum_volume + This is the maximum volume of the holder. + + my_atom + This is the atom the holder is 'in'. Useful if you need to find the location. + (i.e. for explosions) + + +About Reagents: + + Reagents are all the things you can mix and fille in bottles etc. This can be anything from + rejuvs over water to ... iron. Each reagent also has a few procs - i'll explain those below. + + reaction_mob(var/mob/M, var/method=TOUCH) + This is called by the holder's reation proc. + This version is only called when the reagent + reacts with a mob. The method var can be either + TOUCH or INGEST. You'll want to put stuff like + acid-facemelting in here. + + reaction_obj(var/obj/O) + This is called by the holder's reation proc. + This version is called when the reagents reacts + with an object. You'll want to put stuff like + object melting in here ... or something. i dunno. + + reaction_turf(var/turf/T) + This is called by the holder's reation proc. + This version is called when the reagents reacts + with a turf. You'll want to put stuff like extra + slippery floors for lube or something in here. + + on_mob_life(var/mob/M) + This proc is called everytime the mobs life proc executes. + This is the place where you put damage for toxins , + drowsyness for sleep toxins etc etc. + You'll want to call the parents proc by using ..() . + If you dont, the chemical will stay in the mob forever - + unless you write your own piece of code to slowly remove it. + (Should be pretty easy, 1 line of code) + + Important variables: + + holder + This variable contains a reference to the holder the chemical is 'in' + + volume + This is the volume of the reagent. + + id + The id of the reagent + + name + The name of the reagent. + + data + This var can be used for whatever the fuck you want. I used it for the sleep + toxins to make them work slowly instead of instantly. You could also use this + for DNA in a blood reagent or ... well whatever you want. + + color + This is a hexadecimal color that represents the reagent outside of containers, + you define it as "#RRGGBB", or, red green blue. You can also define it using the + rgb() proc, which returns a hexadecimal value too. The color is black by default. + + A good website for color calculations: http://www.psyclops.com/tools/rgb/ + + + + +About Recipes: + + Recipes are simple datums that contain a list of required reagents and a result. + They also have a proc that is called when the recipe is matched. + + on_reaction(var/datum/reagents/holder, var/created_volume) + This proc is called when the recipe is matched. + You'll want to add explosions etc here. + To find the location you'll have to do something + like get_turf(holder.my_atom) + + name & id + Should be pretty obvious. + + result + This var contains the id of the resulting reagent. + + required_reagents + This is a list of ids of the required reagents. + Each id also needs an associated value that gives us the minimum required amount + of that reagent. The handle_reaction proc can detect mutiples of the same recipes + so for most cases you want to set the required amount to 1. + + required_catalysts + This is a list of the ids of the required catalysts. + Functionally similar to required_reagents, it is a list of reagents that are required + for the reaction. However, unlike required_reagents, catalysts are NOT consumed. + They mearly have to be present in the container. + + result_amount + This is the amount of the resulting reagent this recipe will produce. + I recommend you set this to the total volume of all required reagent. + + required_container + The container the recipe has to take place in in order to happen. Leave this blank/null + if you want the reaction to happen anywhere. + + required_other + Basically like a reagent's data variable. You can set extra requirements for a + reaction with this. + + required_temp + This is the required temperature. + + +About the Tools: + + By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. + system you'll need to add something like this in its new proc: + + var/datum/reagents/R = new/datum/reagents(100) <<<<< create a new datum , 100 is the maximum_volume of the new holder datum. + reagents = R <<<<< assign the new datum to the objects reagents var + R.my_atom = src <<<<< set the holders my_atom to src so that we know where we are. + + This can also be done by calling a convenience proc: + atom/proc/create_reagents(var/max_volume) + + Other important stuff: + + amount_per_transfer_from_this var + This var is mostly used by beakers and bottles. + It simply tells us how much to transfer when + 'pouring' our reagents into something else. + + atom/proc/is_open_container() + Checks atom/var/flags & OPENCONTAINER. + If this returns 1 , you can use syringes, beakers etc + to manipulate the contents of this object. + If it's 0, you'll need to write your own custom reagent + transfer code since you will not be able to use the standard + tools to manipulate it. + +*/ + + + + +/* GOON CHEMS README: + + Credit goes to Cogwerks, and all the other goonstation coders + for the original idea and implementation of this over at goonstation. + + THE REQUESTED DON'T PORT LIST: IF YOU PORT THESE THE GOONS WILL MURDER US IN OUR SLEEP SO PLEASE DON'T KTHX - Iamgoofball + Any of the Secret Chems + Goon in-joke chems (Eg. Cat Drugs, Hairgrownium) + Liquid Electricity + Rajajajah + */ \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/chemistry/reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents.dm rename to code/modules/reagents/chemistry/reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Drink-Reagents/Alcohols.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Drink-Reagents/Alcohols.dm rename to code/modules/reagents/chemistry/reagents/alcohol_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Blob-Reagents.dm b/code/modules/reagents/chemistry/reagents/blob_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Blob-Reagents.dm rename to code/modules/reagents/chemistry/reagents/blob_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Drink-Reagents/Drinks.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Drink-Reagents/Drinks.dm rename to code/modules/reagents/chemistry/reagents/drink_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Drug-Reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Drug-Reagents.dm rename to code/modules/reagents/chemistry/reagents/drug_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm rename to code/modules/reagents/chemistry/reagents/food_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm rename to code/modules/reagents/chemistry/reagents/medicine_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm rename to code/modules/reagents/chemistry/reagents/other_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Pyrotechnic-Reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Pyrotechnic-Reagents.dm rename to code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm diff --git a/code/modules/reagents/Chemistry-Reagents/Toxin-Reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm similarity index 100% rename from code/modules/reagents/Chemistry-Reagents/Toxin-Reagents.dm rename to code/modules/reagents/chemistry/reagents/toxin_reagents.dm diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/chemistry/recipes.dm similarity index 95% rename from code/modules/reagents/Chemistry-Recipes.dm rename to code/modules/reagents/chemistry/recipes.dm index 84822634782f..366ca9e74030 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -1,91 +1,90 @@ -/////////////////////////////////////////////////////////////////////////////////// -/datum/chemical_reaction - var/name = null - var/id = null - var/result = null - var/list/required_reagents = new/list() - var/list/required_catalysts = new/list() - - // Both of these variables are mostly going to be used with slime cores - but if you want to, you can use them for other things - var/atom/required_container = null // the container required for the reaction to happen - var/required_other = 0 // an integer required for the reaction to happen - - var/result_amount = 0 - var/secondary = 0 // set to nonzero if secondary reaction - var/mob_react = 0 //Determines if a chemical reaction can occur inside a mob - - var/required_temp = 0 - var/mix_message = "The solution begins to bubble." - -/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume) - return - //I recommend you set the result amount to the total volume of all components. - -var/list/chemical_mob_spawn_meancritters = list() // list of possible hostile mobs -var/list/chemical_mob_spawn_nicecritters = list() // and possible friendly mobs -/datum/chemical_reaction/proc/chemical_mob_spawn(datum/reagents/holder, amount_to_spawn, reaction_name, mob_faction = "chemicalsummon") - if(holder && holder.my_atom) - if (chemical_mob_spawn_meancritters.len <= 0 || chemical_mob_spawn_nicecritters.len <= 0) - for (var/T in typesof(/mob/living/simple_animal)) - var/mob/living/simple_animal/SA = T - switch(initial(SA.gold_core_spawnable)) - if(1) - chemical_mob_spawn_meancritters += T - if(2) - chemical_mob_spawn_nicecritters += T - var/atom/A = holder.my_atom - var/turf/T = get_turf(A) - var/area/my_area = get_area(T) - var/message = "A [reaction_name] reaction has occured in [my_area.name]. (JMP)" - message += " (VV)" - - var/mob/M = get(A, /mob) - if(M) - message += " - Carried By: [key_name_admin(M)](?) (FLW)" - else - message += " - Last Fingerprint: [(A.fingerprintslast ? A.fingerprintslast : "N/A")]" - - message_admins(message, 0, 1) - - playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - - for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null)) - C.flash_eyes() - for(var/i = 1, i <= amount_to_spawn, i++) - var/chosen - if (reaction_name == "Friendly Gold Slime") - chosen = pick(chemical_mob_spawn_nicecritters) - else - chosen = pick(chemical_mob_spawn_meancritters) - var/mob/living/simple_animal/C = new chosen - C.faction |= mob_faction - C.loc = get_turf(holder.my_atom) - if(prob(50)) - for(var/j = 1, j <= rand(1, 3), j++) - step(C, pick(NORTH,SOUTH,EAST,WEST)) - -/datum/chemical_reaction/proc/goonchem_vortex(turf/simulated/T, setting_type, range) - for(var/atom/movable/X in orange(range, T)) - if(istype(X, /obj/effect)) - continue - if(!X.anchored) - var/distance = get_dist(X, T) - var/moving_power = max(range - distance, 1) - spawn(0) //so everything moves at the same time. - if(moving_power > 2) //if the vortex is powerful and we're close, we get thrown - if(setting_type) - var/atom/throw_target = get_edge_target_turf(X, get_dir(X, get_step_away(X, T))) - X.throw_at(throw_target, moving_power, 1) - else - X.throw_at(T, moving_power, 1) - else - if(setting_type) - for(var/i = 0, i < moving_power, i++) - sleep(2) - if(!step_away(X, T)) - break - else - for(var/i = 0, i < moving_power, i++) - sleep(2) - if(!step_towards(X, T)) - break +/datum/chemical_reaction + var/name = null + var/id = null + var/result = null + var/list/required_reagents = new/list() + var/list/required_catalysts = new/list() + + // Both of these variables are mostly going to be used with slime cores - but if you want to, you can use them for other things + var/atom/required_container = null // the container required for the reaction to happen + var/required_other = 0 // an integer required for the reaction to happen + + var/result_amount = 0 + var/secondary = 0 // set to nonzero if secondary reaction + var/mob_react = 0 //Determines if a chemical reaction can occur inside a mob + + var/required_temp = 0 + var/mix_message = "The solution begins to bubble." + +/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume) + return + //I recommend you set the result amount to the total volume of all components. + +var/list/chemical_mob_spawn_meancritters = list() // list of possible hostile mobs +var/list/chemical_mob_spawn_nicecritters = list() // and possible friendly mobs +/datum/chemical_reaction/proc/chemical_mob_spawn(datum/reagents/holder, amount_to_spawn, reaction_name, mob_faction = "chemicalsummon") + if(holder && holder.my_atom) + if (chemical_mob_spawn_meancritters.len <= 0 || chemical_mob_spawn_nicecritters.len <= 0) + for (var/T in typesof(/mob/living/simple_animal)) + var/mob/living/simple_animal/SA = T + switch(initial(SA.gold_core_spawnable)) + if(1) + chemical_mob_spawn_meancritters += T + if(2) + chemical_mob_spawn_nicecritters += T + var/atom/A = holder.my_atom + var/turf/T = get_turf(A) + var/area/my_area = get_area(T) + var/message = "A [reaction_name] reaction has occured in [my_area.name]. (JMP)" + message += " (VV)" + + var/mob/M = get(A, /mob) + if(M) + message += " - Carried By: [key_name_admin(M)](?) (FLW)" + else + message += " - Last Fingerprint: [(A.fingerprintslast ? A.fingerprintslast : "N/A")]" + + message_admins(message, 0, 1) + + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) + + for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null)) + C.flash_eyes() + for(var/i = 1, i <= amount_to_spawn, i++) + var/chosen + if (reaction_name == "Friendly Gold Slime") + chosen = pick(chemical_mob_spawn_nicecritters) + else + chosen = pick(chemical_mob_spawn_meancritters) + var/mob/living/simple_animal/C = new chosen + C.faction |= mob_faction + C.loc = get_turf(holder.my_atom) + if(prob(50)) + for(var/j = 1, j <= rand(1, 3), j++) + step(C, pick(NORTH,SOUTH,EAST,WEST)) + +/datum/chemical_reaction/proc/goonchem_vortex(turf/simulated/T, setting_type, range) + for(var/atom/movable/X in orange(range, T)) + if(istype(X, /obj/effect)) + continue + if(!X.anchored) + var/distance = get_dist(X, T) + var/moving_power = max(range - distance, 1) + spawn(0) //so everything moves at the same time. + if(moving_power > 2) //if the vortex is powerful and we're close, we get thrown + if(setting_type) + var/atom/throw_target = get_edge_target_turf(X, get_dir(X, get_step_away(X, T))) + X.throw_at(throw_target, moving_power, 1) + else + X.throw_at(T, moving_power, 1) + else + if(setting_type) + for(var/i = 0, i < moving_power, i++) + sleep(2) + if(!step_away(X, T)) + break + else + for(var/i = 0, i < moving_power, i++) + sleep(2) + if(!step_towards(X, T)) + break diff --git a/code/modules/reagents/Chemistry-Recipes/Drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm similarity index 100% rename from code/modules/reagents/Chemistry-Recipes/Drugs.dm rename to code/modules/reagents/chemistry/recipes/drugs.dm diff --git a/code/modules/reagents/Chemistry-Recipes/Medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm similarity index 100% rename from code/modules/reagents/Chemistry-Recipes/Medicine.dm rename to code/modules/reagents/chemistry/recipes/medicine.dm diff --git a/code/modules/reagents/Chemistry-Recipes/Others.dm b/code/modules/reagents/chemistry/recipes/others.dm similarity index 100% rename from code/modules/reagents/Chemistry-Recipes/Others.dm rename to code/modules/reagents/chemistry/recipes/others.dm diff --git a/code/modules/reagents/Chemistry-Recipes/Pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm similarity index 100% rename from code/modules/reagents/Chemistry-Recipes/Pyrotechnics.dm rename to code/modules/reagents/chemistry/recipes/pyrotechnics.dm diff --git a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm similarity index 100% rename from code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm rename to code/modules/reagents/chemistry/recipes/slime_extracts.dm diff --git a/code/modules/reagents/Chemistry-Recipes/Toxins.dm b/code/modules/reagents/chemistry/recipes/toxins.dm similarity index 100% rename from code/modules/reagents/Chemistry-Recipes/Toxins.dm rename to code/modules/reagents/chemistry/recipes/toxins.dm diff --git a/nano/interfaces/chem_dispenser.tmpl b/nano/interfaces/chem_dispenser.tmpl index fe5072df5c2a..37b7b3464291 100644 --- a/nano/interfaces/chem_dispenser.tmpl +++ b/nano/interfaces/chem_dispenser.tmpl @@ -34,7 +34,10 @@

Beaker

- {{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}} + {{:helper.link('Eject', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}} + {{for data.beakerTransferAmounts :amount:i}} + {{:helper.link(amount, 'minus', {'remove': amount})}} + {{/for}}
Contents: @@ -43,16 +46,7 @@ {{if data.isBeakerLoaded}} Volume: {{:data.beakerCurrentVolume}}/{{:data.beakerMaxVolume}} Units
{{for data.beakerContents}} -
- - {{:helper.link('5', 'minus', {'remove' : value.id, 'removeamount' : 5})}} - {{:helper.link('10', 'minus', {'remove' : value.id, 'removeamount' : 10})}} - {{:helper.link('All', 'close', {'remove' : value.id, 'removeamount' : value.volume})}} - - - {{:value.volume}} units of {{:value.name}} - -
+ {{:value.volume}} units of {{:value.name}}
{{empty}} Beaker Empty {{/for}} diff --git a/nano/interfaces/chem_heater.tmpl b/nano/interfaces/chem_heater.tmpl index e7c223326cac..fdeaeb371c68 100644 --- a/nano/interfaces/chem_heater.tmpl +++ b/nano/interfaces/chem_heater.tmpl @@ -19,7 +19,7 @@

Beaker

- {{:helper.link('Eject Beaker', 'eject', {'eject_beaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}} + {{:helper.link('Eject', 'eject', {'eject_beaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
Contents: diff --git a/nano/interfaces/cryo.tmpl b/nano/interfaces/cryo.tmpl index fbea9aaba7d4..8110fc2fe80e 100644 --- a/nano/interfaces/cryo.tmpl +++ b/nano/interfaces/cryo.tmpl @@ -128,7 +128,7 @@

Beaker

- {{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}} + {{:helper.link('Eject', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
Contents: diff --git a/tgstation.dme b/tgstation.dme index 1e8065680fec..748d0fd19a81 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -37,6 +37,7 @@ #include "code\__DEFINES\pipe_construction.dm" #include "code\__DEFINES\preferences.dm" #include "code\__DEFINES\qdel.dm" +#include "code\__DEFINES\reagents.dm" #include "code\__DEFINES\role_preferences.dm" #include "code\__DEFINES\say.dm" #include "code\__DEFINES\sight.dm" @@ -1479,29 +1480,33 @@ #include "code\modules\projectiles\projectile\magic.dm" #include "code\modules\projectiles\projectile\reusable.dm" #include "code\modules\projectiles\projectile\special.dm" -#include "code\modules\reagents\Chemistry-Colours.dm" -#include "code\modules\reagents\Chemistry-Holder.dm" -#include "code\modules\reagents\Chemistry-Machinery.dm" -#include "code\modules\reagents\Chemistry-Readme.dm" -#include "code\modules\reagents\Chemistry-Reagents.dm" -#include "code\modules\reagents\Chemistry-Recipes.dm" #include "code\modules\reagents\reagent_containers.dm" #include "code\modules\reagents\reagent_dispenser.dm" -#include "code\modules\reagents\Chemistry-Reagents\Blob-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Drug-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Medicine-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Other-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Pyrotechnic-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Toxin-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Consumable-Reagents\Food-Reagents.dm" -#include "code\modules\reagents\Chemistry-Reagents\Consumable-Reagents\Drink-Reagents\Alcohols.dm" -#include "code\modules\reagents\Chemistry-Reagents\Consumable-Reagents\Drink-Reagents\Drinks.dm" -#include "code\modules\reagents\Chemistry-Recipes\Drugs.dm" -#include "code\modules\reagents\Chemistry-Recipes\Medicine.dm" -#include "code\modules\reagents\Chemistry-Recipes\Others.dm" -#include "code\modules\reagents\Chemistry-Recipes\Pyrotechnics.dm" -#include "code\modules\reagents\Chemistry-Recipes\Slime_extracts.dm" -#include "code\modules\reagents\Chemistry-Recipes\Toxins.dm" +#include "code\modules\reagents\chemistry\colors.dm" +#include "code\modules\reagents\chemistry\holder.dm" +#include "code\modules\reagents\chemistry\readme.dm" +#include "code\modules\reagents\chemistry\reagents.dm" +#include "code\modules\reagents\chemistry\recipes.dm" +#include "code\modules\reagents\chemistry\machinery\chem_dispenser.dm" +#include "code\modules\reagents\chemistry\machinery\chem_heater.dm" +#include "code\modules\reagents\chemistry\machinery\chem_master.dm" +#include "code\modules\reagents\chemistry\machinery\pandemic.dm" +#include "code\modules\reagents\chemistry\machinery\reagentgrinder.dm" +#include "code\modules\reagents\chemistry\reagents\alcohol_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\blob_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\drink_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\drug_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\food_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\medicine_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\other_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\pyrotechnic_reagents.dm" +#include "code\modules\reagents\chemistry\reagents\toxin_reagents.dm" +#include "code\modules\reagents\chemistry\recipes\drugs.dm" +#include "code\modules\reagents\chemistry\recipes\medicine.dm" +#include "code\modules\reagents\chemistry\recipes\others.dm" +#include "code\modules\reagents\chemistry\recipes\pyrotechnics.dm" +#include "code\modules\reagents\chemistry\recipes\slime_extracts.dm" +#include "code\modules\reagents\chemistry\recipes\toxins.dm" #include "code\modules\reagents\reagent_containers\blood_pack.dm" #include "code\modules\reagents\reagent_containers\borghydro.dm" #include "code\modules\reagents\reagent_containers\bottle.dm" diff --git a/tools/ColonCatcher/2015-10-25-colon_operator_log.txt b/tools/ColonCatcher/2015-10-25-colon_operator_log.txt deleted file mode 100644 index f8908a0fdae5..000000000000 --- a/tools/ColonCatcher/2015-10-25-colon_operator_log.txt +++ /dev/null @@ -1,434 +0,0 @@ -..code\world.dm Lines: 27, 28, 98?, 102?, 119?, 149?, 230? Total Colons: 7 -..code\ATMOSPHERICS\atmospherics.dm Lines: 213? Total Colons: 1 -..code\ATMOSPHERICS\components\binary_devices\dp_vent_pump.dm Lines: 137? Total Colons: 1 -..code\ATMOSPHERICS\components\binary_devices\passive_gate.dm Lines: 134?, 163? Total Colons: 2 -..code\ATMOSPHERICS\components\binary_devices\pump.dm Lines: 43?, 139?, 167? Total Colons: 3 -..code\ATMOSPHERICS\components\binary_devices\valve.dm Lines: 25?, 33?, 38? Total Colons: 3 -..code\ATMOSPHERICS\components\binary_devices\volume_pump.dm Lines: 42?, 136?, 163? Total Colons: 3 -..code\ATMOSPHERICS\components\trinary_devices\filter.dm Lines: 66?, 69?, 214? Total Colons: 3 -..code\ATMOSPHERICS\components\trinary_devices\mixer.dm Lines: 36?, 39?, 151? Total Colons: 3 -..code\ATMOSPHERICS\components\unary_devices\cryo.dm Lines: 152?, 187?, 189, 190, 312?, 313? Total Colons: 7 -..code\ATMOSPHERICS\components\unary_devices\Freezer.dm Lines: 82?, 205? Total Colons: 2 -..code\ATMOSPHERICS\components\unary_devices\vent_pump.dm Lines: 175?, 196?, 197?, 228? Total Colons: 4 -..code\ATMOSPHERICS\components\unary_devices\vent_scrubber.dm Lines: 140?, 141? Total Colons: 2 -..code\ATMOSPHERICS\pipes\manifold.dm Lines: 28? Total Colons: 1 -..code\ATMOSPHERICS\pipes\manifold4w.dm Lines: 19? Total Colons: 1 -..code\ATMOSPHERICS\pipes\pipes.dm Lines: 30?, 32?, 33?, 34?, 43? Total Colons: 5 -..code\ATMOSPHERICS\pipes\heat_exchange\manifold.dm Lines: 25?, 51? Total Colons: 2 -..code\controllers\subsystem\air.dm Lines: 100 Total Colons: 1 -..code\controllers\subsystem\bots.dm Lines: 18, 20 Total Colons: 2 -..code\controllers\subsystem\diseases.dm Lines: 18 Total Colons: 1 -..code\controllers\subsystem\events.dm Lines: 41, 199?, 200? Total Colons: 3 -..code\controllers\subsystem\jobs.dm Lines: 370? Total Colons: 1 -..code\controllers\subsystem\machines.dm Lines: 41, 42, 43 Total Colons: 3 -..code\controllers\subsystem\mobs.dm Lines: 20 Total Colons: 1 -..code\controllers\subsystem\objects.dm Lines: 37 Total Colons: 1 -..code\controllers\subsystem\shuttles.dm Lines: 251?, 253, 261?, 262?, 284, 285 Total Colons: 6 -..code\controllers\subsystem\ticker.dm Lines: 382?, 405? Total Colons: 4 -..code\controllers\subsystem\voting.dm Lines: 203?, 211? Total Colons: 2 -..code\controllers\subsystem\shuttles\emergency.dm Lines: 52?, 65? Total Colons: 4 -..code\controllers\subsystem\shuttles\supply.dm Lines: 97, 316?, 347?, 488?, 505? Total Colons: 10 -..code\datums\browser.dm Lines: 79? Total Colons: 1 -..code\datums\datacore.dm Lines: 91?, 127?, 132?, 137?, 142?, 147?, 152?, 157?, 163?, 169?, 259? Total Colons: 23 -..code\datums\datumvars.dm Lines: 57?, 93 Total Colons: 3 -..code\datums\material_container.dm Lines: 194? Total Colons: 1 -..code\datums\mind.dm Lines: 228?, 229?, 290?, 581?, 633, 634, 643, 648, 720?, 1243, 1244, 1245 Total Colons: 13 -..code\datums\mutations.dm Lines: 34?, 135?, 329? Total Colons: 3 -..code\datums\recipe.dm Lines: 52?, 114?, 115? Total Colons: 3 -..code\datums\diseases\_disease.dm Lines: 125? Total Colons: 1 -..code\datums\helper_datums\teleport.dm Lines: 63?, 64?, 74?, 75? Total Colons: 4 -..code\datums\helper_datums\topic_input.dm Lines: 23?, 27?, 31?, 35?, 42?, 46?, 50?, 56?, 60? Total Colons: 9 -..code\datums\spells\dumbfire.dm Lines: 43 Total Colons: 1 -..code\datums\spells\knock.dm Lines: 21 Total Colons: 1 -..code\datums\spells\projectile.dm Lines: 35 Total Colons: 1 -..code\datums\wires\airlock.dm Lines: 37?, 38?, 39?, 40?, 41?, 42?, 43? Total Colons: 7 -..code\datums\wires\alarm.dm Lines: 21? Total Colons: 3 -..code\datums\wires\apc.dm Lines: 13? Total Colons: 3 -..code\datums\wires\autolathe.dm Lines: 13? Total Colons: 3 -..code\datums\wires\particle_accelerator.dm Lines: 50? Total Colons: 1 -..code\datums\wires\pizza_bomb.dm Lines: 45?, 46? Total Colons: 2 -..code\datums\wires\robot.dm Lines: 16?, 17?, 18? Total Colons: 4 -..code\datums\wires\r_n_d.dm Lines: 48?, 49?, 50? Total Colons: 3 -..code\datums\wires\syndicatebomb.dm Lines: 46?, 75? Total Colons: 2 -..code\datums\wires\vending.dm Lines: 28?, 29?, 30?, 31? Total Colons: 4 -..code\datums\wires\wires.dm Lines: 119?, 121? Total Colons: 2 -..code\game\atoms.dm Lines: 297? Total Colons: 1 -..code\game\atoms_movable.dm Lines: 181?, 182?, 216? Total Colons: 3 -..code\game\communications.dm Lines: 288 Total Colons: 3 -..code\game\data_huds.dm Lines: 35? Total Colons: 1 -..code\game\dna.dm Lines: 231? Total Colons: 1 -..code\game\say.dm Lines: 45?, 49? Total Colons: 2 -..code\game\sound.dm Lines: 72? Total Colons: 1 -..code\game\gamemodes\antag_spawner.dm Lines: 103, 104 Total Colons: 3 -..code\game\gamemodes\objective.dm Lines: 84?, 112?, 139?, 172?, 201?, 433, 806 Total Colons: 7 -..code\game\gamemodes\abduction\abduction_gear.dm Lines: 159? Total Colons: 1 -..code\game\gamemodes\abduction\machinery\experiment.dm Lines: 41?, 107? Total Colons: 2 -..code\game\gamemodes\blob\blob_finish.dm Lines: 47? Total Colons: 1 -..code\game\gamemodes\blob\blob_report.dm Lines: 64, 70, 76, 85 Total Colons: 4 -..code\game\gamemodes\changeling\evolution_menu.dm Lines: 59? Total Colons: 3 -..code\game\gamemodes\changeling\powers\adrenaline.dm Lines: 12? Total Colons: 1 -..code\game\gamemodes\changeling\powers\mutations.dm Lines: 83? Total Colons: 1 -..code\game\gamemodes\cult\cult.dm Lines: 44? Total Colons: 1 -..code\game\gamemodes\cult\runes.dm Lines: 705?, 706? Total Colons: 2 -..code\game\gamemodes\gang\dominator.dm Lines: 101?, 187? Total Colons: 2 -..code\game\gamemodes\gang\gang.dm Lines: 261?, 266? Total Colons: 2 -..code\game\gamemodes\gang\gang_datum.dm Lines: 43?, 53?, 121? Total Colons: 3 -..code\game\gamemodes\gang\gang_pen.dm Lines: 59? Total Colons: 1 -..code\game\gamemodes\gang\recaller.dm Lines: 48?, 51? Total Colons: 4 -..code\game\gamemodes\malfunction\malfunction.dm Lines: 63, 64, 65, 185, 188, 189, 192, 204, 205, 216, 218, 219, 221, 233, 234 Total Colons: 15 -..code\game\gamemodes\meteor\meteors.dm Lines: 177? Total Colons: 2 -..code\game\gamemodes\nuclear\nuclearbomb.dm Lines: 197?, 212?, 215?, 217?, 220?, 222?, 265?, 359, 359?, 360, 365, 383? Total Colons: 25 -..code\game\gamemodes\revolution\revolution.dm Lines: 265?, 266?, 286? Total Colons: 3 -..code\game\gamemodes\shadowling\shadowling.dm Lines: 304? Total Colons: 1 -..code\game\gamemodes\traitor\traitor.dm Lines: 335? Total Colons: 1 -..code\game\gamemodes\wizard\artefact.dm Lines: 148? Total Colons: 1 -..code\game\gamemodes\wizard\rightandwrong.dm Lines: 9?, 10?, 11? Total Colons: 3 -..code\game\gamemodes\wizard\soulstone.dm Lines: 123, 195 Total Colons: 2 -..code\game\gamemodes\wizard\spellbook.dm Lines: 93?, 512?, 533? Total Colons: 3 -..code\game\gamemodes\wizard\wizard.dm Lines: 183?, 258, 261, 264, 278? Total Colons: 5 -..code\game\machinery\airlock_control.dm Lines: 59?, 60? Total Colons: 2 -..code\game\machinery\ai_slipper.dm Lines: 39?, 67, 77?, 93? Total Colons: 5 -..code\game\machinery\alarm.dm Lines: 134?, 135?, 730?, 742?, 895?, 934?, 1056?, 1071?, 1127?, 1128? Total Colons: 16 -..code\game\machinery\announcement_system.dm Lines: 45?, 47?, 136?, 137? Total Colons: 4 -..code\game\machinery\atmo_control.dm Lines: 273?, 284?, 396? Total Colons: 3 -..code\game\machinery\autolathe.dm Lines: 139?, 178?, 187?, 295?, 322?, 336?, 345? Total Colons: 10 -..code\game\machinery\Beacon.dm Lines: 31? Total Colons: 1 -..code\game\machinery\buttons.dm Lines: 22?, 23? Total Colons: 4 -..code\game\machinery\cell_charger.dm Lines: 15?, 31?, 64? Total Colons: 4 -..code\game\machinery\cloning.dm Lines: 88?, 92? Total Colons: 2 -..code\game\machinery\constructable_frame.dm Lines: 48?, 90?, 94?, 99?, 102?, 475? Total Colons: 8 -..code\game\machinery\deployable.dm Lines: 92 Total Colons: 1 -..code\game\machinery\dna_scanner.dm Lines: 44?, 48?, 57? Total Colons: 3 -..code\game\machinery\droneDispenser.dm Lines: 190? Total Colons: 1 -..code\game\machinery\iv_drip.dm Lines: 192?, 200?, 210? Total Colons: 3 -..code\game\machinery\lightswitch.dm Lines: 41? Total Colons: 1 -..code\game\machinery\machinery.dm Lines: 372?, 375? Total Colons: 2 -..code\game\machinery\magnet.dm Lines: 53?, 275?, 279? Total Colons: 3 -..code\game\machinery\navbeacon.dm Lines: 63?, 84?, 92?, 122?, 130? Total Colons: 6 -..code\game\machinery\newscaster.dm Lines: 205?, 206?, 291?, 304?, 311?, 318?, 319?, 372, 391?, 409?, 420?, 423, 424?, 430?, 431?, 436, 460?, 465?, 486, 614?, 724?, 727?, 922 Total Colons: 27 -..code\game\machinery\overview.dm Lines: 98, 167?, 243, 292? Total Colons: 4 -..code\game\machinery\portable_turret.dm Lines: 162?, 164?, 169?, 170?, 171?, 172?, 173?, 183?, 285?, 862?, 864?, 869?, 870?, 871?, 872?, 873?, 877?, 889?, 891?, 896?, 897?, 898?, 899?, 900?, 910?, 968?, 1049?, 1085, 1097?, 1098? Total Colons: 32 -..code\game\machinery\recharger.dm Lines: 19? Total Colons: 1 -..code\game\machinery\rechargestation.dm Lines: 122?, 124? Total Colons: 2 -..code\game\machinery\recycler.dm Lines: 43?, 44?, 45?, 84? Total Colons: 4 -..code\game\machinery\requests_console.dm Lines: 201?, 202?, 212?, 213? Total Colons: 4 -..code\game\machinery\robot_fabricator.dm Lines: 21, 23, 24, 25, 28 Total Colons: 5 -..code\game\machinery\shieldgen.dm Lines: 247?, 261?, 263?, 441? Total Colons: 4 -..code\game\machinery\Sleeper.dm Lines: 142?, 156?, 162? Total Colons: 4 -..code\game\machinery\slotmachine.dm Lines: 219?, 265?, 271? Total Colons: 3 -..code\game\machinery\spaceheater.dm Lines: 33?, 35?, 37?, 69?, 89?, 107? Total Colons: 9 -..code\game\machinery\status_display.dm Lines: 167 Total Colons: 4 -..code\game\machinery\suit_storage_unit.dm Lines: 199?, 200?, 212?, 215?, 218?, 221?, 227?, 231?, 232?, 519? Total Colons: 12 -..code\game\machinery\syndicatebeacon.dm Lines: 151? Total Colons: 1 -..code\game\machinery\syndicatebomb.dm Lines: 22?, 53?, 77?, 323?, 326? Total Colons: 6 -..code\game\machinery\teleporter.dm Lines: 69?, 442? Total Colons: 3 -..code\game\machinery\turrets.dm Lines: 542?, 578, 590?, 591? Total Colons: 6 -..code\game\machinery\vending.dm Lines: 248?, 323? Total Colons: 2 -..code\game\machinery\atmoalter\canister.dm Lines: 248, 289?, 290?, 291?, 292?, 295?, 297? Total Colons: 7 -..code\game\machinery\atmoalter\pump.dm Lines: 109? Total Colons: 3 -..code\game\machinery\atmoalter\scrubber.dm Lines: 127?, 203? Total Colons: 3 -..code\game\machinery\bots\bots.dm Lines: 244?, 337?, 338?, 340?, 416?, 481? Total Colons: 6 -..code\game\machinery\bots\cleanbot.dm Lines: 84?, 85?, 87?, 88?, 109? Total Colons: 6 -..code\game\machinery\bots\ed209bot.dm Lines: 107?, 109?, 115?, 116?, 117?, 118?, 119?, 120?, 155?, 258?, 456? Total Colons: 12 -..code\game\machinery\bots\floorbot.dm Lines: 104?, 105?, 107?, 109?, 110?, 111?, 112?, 113?, 114?, 115?, 116?, 147?, 360? Total Colons: 13 -..code\game\machinery\bots\medbot.dm Lines: 147?, 148?, 154?, 171?, 173?, 174?, 175?, 176?, 177?, 231?, 320?, 532? Total Colons: 12 -..code\game\machinery\bots\mulebot.dm Lines: 99?, 147?, 187?, 209?, 210?, 211?, 225?, 226?, 227?, 228?, 249?, 282?, 346?, 354?, 363?, 535? Total Colons: 17 -..code\game\machinery\bots\secbot.dm Lines: 97?, 99?, 104?, 105?, 106?, 107?, 108?, 109?, 142?, 222? Total Colons: 11 -..code\game\machinery\camera\camera.dm Lines: 141?, 151?, 152? Total Colons: 3 -..code\game\machinery\camera\tracking.dm Lines: 19?, 83? Total Colons: 2 -..code\game\machinery\computer\arcade.dm Lines: 860?, 862?, 863?, 871? Total Colons: 6 -..code\game\machinery\computer\camera.dm Lines: 56? Total Colons: 1 -..code\game\machinery\computer\camera_advanced.dm Lines: 154? Total Colons: 1 -..code\game\machinery\computer\card.dm Lines: 148?, 164?, 209?, 364?, 372?, 390? Total Colons: 6 -..code\game\machinery\computer\cloning.dm Lines: 146? Total Colons: 1 -..code\game\machinery\computer\communications.dm Lines: 106, 148?, 272?, 428?, 429?, 430, 453?, 468?, 531?, 532?, 533, 554? Total Colons: 12 -..code\game\machinery\computer\crew.dm Lines: 153?, 158?, 169? Total Colons: 3 -..code\game\machinery\computer\dna_console.dm Lines: 94?, 139?, 141?, 143?, 181? Total Colons: 5 -..code\game\machinery\computer\medical.dm Lines: 40?, 46, 153? Total Colons: 4 -..code\game\machinery\computer\message.dm Lines: 73?, 76?, 131?, 150? Total Colons: 4 -..code\game\machinery\computer\Operating.dm Lines: 50? Total Colons: 1 -..code\game\machinery\computer\pod.dm Lines: 56? Total Colons: 2 -..code\game\machinery\computer\robot.dm Lines: 65?, 107?, 109?, 110?, 112?, 114? Total Colons: 6 -..code\game\machinery\computer\security.dm Lines: 49?, 62, 117, 130, 275, 285 Total Colons: 7 -..code\game\machinery\computer\shuttle.dm Lines: 24, 25, 28, 30, 33, 34, 47, 48, 60 Total Colons: 9 -..code\game\machinery\computer\station_alert.dm Lines: 73? Total Colons: 1 -..code\game\machinery\doors\airlock.dm Lines: 790?, 791?, 800?, 801?, 809?, 877, 888 Total Colons: 7 -..code\game\machinery\doors\airlock_electronics.dm Lines: 81 Total Colons: 1 -..code\game\machinery\doors\brigdoors.dm Lines: 123?, 158?, 247 Total Colons: 7 -..code\game\machinery\doors\firedoor.dm Lines: 49?, 69 Total Colons: 2 -..code\game\machinery\doors\windowdoor.dm Lines: 188?, 200, 276? Total Colons: 3 -..code\game\machinery\embedded_controller\access_controller.dm Lines: 295?, 297? Total Colons: 2 -..code\game\machinery\embedded_controller\airlock_controller.dm Lines: 258?, 259?, 260?, 261? Total Colons: 4 -..code\game\machinery\pipe\construction.dm Lines: 134?, 162? Total Colons: 2 -..code\game\machinery\telecomms\machine_interactions.dm Lines: 57?, 64?, 159?, 160?, 161?, 184?, 220? Total Colons: 7 -..code\game\mecha\mecha.dm Lines: 561?, 582?, 838?, 843?, 935?, 936?, 937?, 986?, 987? Total Colons: 11 -..code\game\mecha\mecha_control_console.dm Lines: 72? Total Colons: 1 -..code\game\mecha\mecha_topic.dm Lines: 33?, 34?, 36?, 40?, 90?, 164?, 168?, 190?, 197? Total Colons: 21 -..code\game\mecha\mecha_wreckage.dm Lines: 25?, 42? Total Colons: 2 -..code\game\mecha\mech_fabricator.dm Lines: 120?, 132?, 237? Total Colons: 6 -..code\game\mecha\combat\combat.dm Lines: 65?, 67? Total Colons: 3 -..code\game\mecha\combat\durand.dm Lines: 38?, 50? Total Colons: 2 -..code\game\mecha\combat\gygax.dm Lines: 69?, 74?, 105? Total Colons: 3 -..code\game\mecha\combat\honker.dm Lines: 32?, 33?, 35? Total Colons: 14 -..code\game\mecha\combat\marauder.dm Lines: 70?, 158?, 160? Total Colons: 5 -..code\game\mecha\combat\phazon.dm Lines: 39?, 97?, 98? Total Colons: 3 -..code\game\mecha\equipment\mecha_equipment.dm Lines: 57? Total Colons: 3 -..code\game\mecha\equipment\tools\medical_tools.dm Lines: 96, 96?, 129?, 249?, 333?, 366, 370?, 371? Total Colons: 20 -..code\game\mecha\equipment\tools\mining_tools.dm Lines: 40, 51 Total Colons: 2 -..code\game\mecha\equipment\tools\other_tools.dm Lines: 132?, 160?, 182?, 222?, 328?, 406, 406?, 446? Total Colons: 10 -..code\game\mecha\equipment\tools\work_tools.dm Lines: 329?, 350?, 351?, 368, 368? Total Colons: 7 -..code\game\mecha\equipment\weapons\weapons.dm Lines: 208? Total Colons: 1 -..code\game\mecha\working\ripley.dm Lines: 53?, 55? Total Colons: 2 -..code\game\objects\explosion.dm Lines: 11?, 12?, 68? Total Colons: 5 -..code\game\objects\items.dm Lines: 213? Total Colons: 1 -..code\game\objects\items\candle.dm Lines: 23? Total Colons: 1 -..code\game\objects\items\crayons.dm Lines: 117, 171?, 172?, 173?, 210? Total Colons: 5 -..code\game\objects\items\toys.dm Lines: 133?, 187?, 234?, 452?, 471? Total Colons: 6 -..code\game\objects\items\devices\aicard.dm Lines: 83?, 85?, 129?, 138? Total Colons: 4 -..code\game\objects\items\devices\flashlight.dm Lines: 60? Total Colons: 2 -..code\game\objects\items\devices\geiger_counter.dm Lines: 93? Total Colons: 1 -..code\game\objects\items\devices\paicard.dm Lines: 40?, 41? Total Colons: 2 -..code\game\objects\items\devices\scanners.dm Lines: 123?, 137?, 139?, 141?, 143?, 147?, 149, 164?, 212?, 396? Total Colons: 11 -..code\game\objects\items\devices\taperecorder.dm Lines: 28?, 97, 117, 142 Total Colons: 4 -..code\game\objects\items\devices\transfer_valve.dm Lines: 69?, 102 Total Colons: 6 -..code\game\objects\items\devices\PDA\cart.dm Lines: 241, 245, 275, 292?, 293?, 294, 348?, 424, 435, 473?, 499?, 533?, 546?, 557?, 585, 594, 601, 605, 606, 609, 610, 611, 612, 631, 642?, 649?, 702?, 703?, 705?, 706?, 707?, 708?, 709?, 711, 712, 713, 716, 717, 718 Total Colons: 44 -..code\game\objects\items\devices\PDA\PDA.dm Lines: 298?, 299?, 330?, 356?, 358?, 360?, 364?, 378?, 382?, 383?, 388, 390, 392, 618, 619, 631, 632, 692, 693, 918, 1010?, 1036, 1039, 1131?, 1143? Total Colons: 25 -..code\game\objects\items\devices\radio\electropack.dm Lines: 129? Total Colons: 1 -..code\game\objects\items\devices\radio\radio.dm Lines: 136?, 137, 137?, 138, 138?, 139, 140, 141, 143, 144, 146, 147?, 148, 148?, 149, 150, 151, 153, 154, 155 Total Colons: 22 -..code\game\objects\items\robot\robot_parts.dm Lines: 137, 143, 150, 258?, 259?, 261?, 262?, 263?, 264? Total Colons: 11 -..code\game\objects\items\robot\robot_upgrades.dm Lines: 250? Total Colons: 1 -..code\game\objects\items\stacks\sheets\glass.dm Lines: 303? Total Colons: 1 -..code\game\objects\items\weapons\AI_modules.dm Lines: 37?, 72?, 73?, 74? Total Colons: 4 -..code\game\objects\items\weapons\cards_ids.dm Lines: 115?, 118?, 148? Total Colons: 6 -..code\game\objects\items\weapons\cigs_lighters.dm Lines: 479?, 496? Total Colons: 2 -..code\game\objects\items\weapons\cosmetics.dm Lines: 36?, 54? Total Colons: 2 -..code\game\objects\items\weapons\defib.dm Lines: 470?, 485?, 487?, 489?, 491?, 508?, 527?, 530? Total Colons: 8 -..code\game\objects\items\weapons\explosives.dm Lines: 57? Total Colons: 1 -..code\game\objects\items\weapons\extinguisher.dm Lines: 45?, 46? Total Colons: 2 -..code\game\objects\items\weapons\flamethrower.dm Lines: 90?, 128? Total Colons: 2 -..code\game\objects\items\weapons\handcuffs.dm Lines: 208? Total Colons: 1 -..code\game\objects\items\weapons\RCD.dm Lines: 500, 505 Total Colons: 4 -..code\game\objects\items\weapons\singularityhammer.dm Lines: 42 Total Colons: 1 -..code\game\objects\items\weapons\stunbaton.dm Lines: 94? Total Colons: 1 -..code\game\objects\items\weapons\grenades\chem_grenade.dm Lines: 60? Total Colons: 1 -..code\game\objects\items\weapons\grenades\grenade.dm Lines: 49? Total Colons: 1 -..code\game\objects\items\weapons\implants\implantchair.dm Lines: 46?, 47?, 49? Total Colons: 5 -..code\game\objects\items\weapons\implants\implantpad.dm Lines: 56 Total Colons: 1 -..code\game\objects\items\weapons\storage\book.dm Lines: 180 Total Colons: 1 -..code\game\objects\items\weapons\storage\fancy.dm Lines: 39? Total Colons: 1 -..code\game\objects\items\weapons\storage\secure.dm Lines: 32?, 39?, 84? Total Colons: 3 -..code\game\objects\items\weapons\storage\storage.dm Lines: 177? Total Colons: 1 -..code\game\objects\items\weapons\tanks\jetpack.dm Lines: 26?, 44?, 151? Total Colons: 3 -..code\game\objects\items\weapons\tanks\tanks.dm Lines: 121?, 122? Total Colons: 2 -..code\game\objects\items\weapons\tanks\watertank.dm Lines: 177?, 178? Total Colons: 2 -..code\game\objects\structures\ai_core.dm Lines: 212?, 213? Total Colons: 2 -..code\game\objects\structures\displaycase.dm Lines: 119?, 128?, 130? Total Colons: 3 -..code\game\objects\structures\fireaxe.dm Lines: 129? Total Colons: 1 -..code\game\objects\structures\grille.dm Lines: 148?, 149? Total Colons: 2 -..code\game\objects\structures\musician.dm Lines: 50?, 130?, 132? Total Colons: 3 -..code\game\objects\structures\safe.dm Lines: 78?, 98?, 104?, 188? Total Colons: 4 -..code\game\objects\structures\tank_dispenser.dm Lines: 43?, 44? Total Colons: 2 -..code\game\objects\structures\watercloset.dm Lines: 51?, 54? Total Colons: 3 -..code\game\objects\structures\windoor_assembly.dm Lines: 50? Total Colons: 1 -..code\game\objects\structures\window.dm Lines: 197?, 199?, 201?, 206?, 207?, 211?, 215?, 218?, 222?, 223?, 425? Total Colons: 11 -..code\game\objects\structures\beds_chairs\bed.dm Lines: 129? Total Colons: 1 -..code\game\objects\structures\crates_lockers\closets.dm Lines: 66?, 234?, 241?, 243?, 392? Total Colons: 6 -..code\game\objects\structures\transit_tubes\station.dm Lines: 130? Total Colons: 1 -..code\game\objects\structures\transit_tubes\transit_tube_construction.dm Lines: 41?, 43? Total Colons: 2 -..code\game\turfs\turf.dm Lines: 137, 248?, 250? Total Colons: 4 -..code\game\turfs\space\space.dm Lines: 114?, 125? Total Colons: 2 -..code\game\verbs\ooc.dm Lines: 44?, 53?, 55?, 57?, 69? Total Colons: 6 -..code\LINDA\LINDA_turf_tile.dm Lines: 458?, 463? Total Colons: 2 -..code\modules\admin\admin.dm Lines: 30?, 62?, 63?, 64?, 65?, 66?, 67?, 122, 129, 141, 192?, 205?, 212?, 246, 262?, 277?, 288?, 292, 293?, 300?, 301?, 306, 334?, 352, 415?, 442?, 550?, 551?, 676?, 677?, 696? Total Colons: 35 -..code\modules\admin\admin_verbs.dm Lines: 441?, 442? Total Colons: 2 -..code\modules\admin\create_poll.dm Lines: 25?, 26?, 94?, 95? Total Colons: 4 -..code\modules\admin\newbanjob.dm Lines: 216? Total Colons: 2 -..code\modules\admin\player_panel.dm Lines: 111?, 113?, 119?, 123?, 129?, 155?, 160?, 166?, 181?, 186?, 195?, 207?, 219?, 228?, 240?, 249?, 258?, 269?, 284?, 297? Total Colons: 36 -..code\modules\admin\sql_notes.dm Lines: 153 Total Colons: 2 -..code\modules\admin\topic.dm Lines: 299?, 310?, 341?, 348?, 349?, 447?, 986?, 1559?, 1561?, 1589?, 1796?, 1797?, 1798?, 1800?, 1982?, 2093?, 2096?, 2101?, 2102? Total Colons: 21 -..code\modules\admin\DB ban\functions.dm Lines: 93, 94, 95, 127?, 131?, 304, 305, 306, 441? Total Colons: 20 -..code\modules\admin\verbs\adminjump.dm Lines: 91, 127 Total Colons: 2 -..code\modules\admin\verbs\deadsay.dm Lines: 24? Total Colons: 1 -..code\modules\admin\verbs\debug.dm Lines: 82?, 86?, 89?, 112?, 116?, 289, 306, 498, 501 Total Colons: 9 -..code\modules\admin\verbs\diagnostics.dm Lines: 15?, 81 Total Colons: 5 -..code\modules\admin\verbs\massmodvar.dm Lines: 132 Total Colons: 1 -..code\modules\admin\verbs\modifyvariables.dm Lines: 542 Total Colons: 1 -..code\modules\admin\verbs\one_click_antag.dm Lines: 333?, 478?, 481?, 484?, 487?, 490?, 493?, 496?, 517? Total Colons: 9 -..code\modules\admin\verbs\panicbunker.dm Lines: 10?, 11? Total Colons: 2 -..code\modules\admin\verbs\randomverbs.dm Lines: 38?, 114?, 116?, 117?, 189?, 212?, 409?, 448?, 721?, 722?, 799, 804, 810, 816, 822, 828, 834, 840, 846, 852, 858, 864, 870, 876, 882, 888, 894, 900 Total Colons: 28 -..code\modules\assembly\bomb.dm Lines: 44 Total Colons: 1 -..code\modules\assembly\doorcontrol.dm Lines: 62? Total Colons: 1 -..code\modules\assembly\health.dm Lines: 77? Total Colons: 1 -..code\modules\assembly\infrared.dm Lines: 24?, 110? Total Colons: 3 -..code\modules\assembly\mousetrap.dm Lines: 30?, 127? Total Colons: 2 -..code\modules\assembly\proximity.dm Lines: 26?, 109?, 110? Total Colons: 3 -..code\modules\assembly\signaler.dm Lines: 142? Total Colons: 1 -..code\modules\assembly\timer.dm Lines: 75? Total Colons: 1 -..code\modules\assembly\voice.dm Lines: 32? Total Colons: 1 -..code\modules\awaymissions\maploader\reader.dm Lines: 262? Total Colons: 1 -..code\modules\awaymissions\maploader\swapmaps.dm Lines: 152, 153, 154, 161?, 162?, 163?, 343?, 356?, 362?, 385? Total Colons: 19 -..code\modules\client\client procs.dm Lines: 36, 36?, 177? Total Colons: 3 -..code\modules\client\preferences.dm Lines: 129?, 130?, 151?, 161?, 166?, 186?, 335?, 336?, 337?, 338?, 339?, 340?, 341?, 342?, 343?, 349?, 350?, 353?, 356?, 397?, 523? Total Colons: 21 -..code\modules\client\preferences_toggles.dm Lines: 7?, 16?, 25?, 34?, 43?, 54?, 64?, 74?, 83?, 92?, 113?, 122?, 172?, 226?, 235?, 259? Total Colons: 16 -..code\modules\clothing\clothing.dm Lines: 357? Total Colons: 1 -..code\modules\clothing\glasses\engine_goggles.dm Lines: 83?, 108? Total Colons: 2 -..code\modules\clothing\head\helmet.dm Lines: 240? Total Colons: 1 -..code\modules\clothing\head\soft_caps.dm Lines: 45? Total Colons: 1 -..code\modules\clothing\masks\gasmask.dm Lines: 66? Total Colons: 1 -..code\modules\clothing\masks\miscellaneous.dm Lines: 56? Total Colons: 1 -..code\modules\clothing\shoes\bananashoes.dm Lines: 59?, 65? Total Colons: 3 -..code\modules\clothing\shoes\magboots.dm Lines: 32?, 41? Total Colons: 2 -..code\modules\clothing\spacesuits\chronosuit.dm Lines: 146, 151, 152, 153, 158, 172, 175, 176, 177 Total Colons: 9 -..code\modules\crafting\table.dm Lines: 15, 59, 113, 126, 143, 167 Total Colons: 6 -..code\modules\detectivework\detective_work.dm Lines: 16? Total Colons: 1 -..code\modules\events\event.dm Lines: 37 Total Colons: 2 -..code\modules\events\shuttle_loan.dm Lines: 195, 196 Total Colons: 2 -..code\modules\flufftext\Hallucination.dm Lines: 47?, 49?, 51? Total Colons: 3 -..code\modules\food&drinks\food\customizables.dm Lines: 37? Total Colons: 1 -..code\modules\food&drinks\kitchen machinery\gibber.dm Lines: 165? Total Colons: 1 -..code\modules\food&drinks\kitchen machinery\monkeyrecycler.dm Lines: 72? Total Colons: 1 -..code\modules\food&drinks\kitchen machinery\processor.dm Lines: 198? Total Colons: 1 -..code\modules\games\cards.dm Lines: 177?, 211?, 225? Total Colons: 3 -..code\modules\holiday\easter.dm Lines: 77? Total Colons: 1 -..code\modules\html_interface\html_interface.dm Lines: 292? Total Colons: 1 -..code\modules\hydroponics\grown.dm Lines: 704 Total Colons: 1 -..code\modules\hydroponics\growninedible.dm Lines: 71, 194? Total Colons: 2 -..code\modules\hydroponics\hydroponics.dm Lines: 642?, 836? Total Colons: 2 -..code\modules\hydroponics\seeds.dm Lines: 1377?, 1378? Total Colons: 2 -..code\modules\library\lib_items.dm Lines: 186? Total Colons: 1 -..code\modules\library\lib_machines.dm Lines: 519 Total Colons: 1 -..code\modules\lighting\lighting_system.dm Lines: 254 Total Colons: 1 -..code\modules\mob\inventory.dm Lines: 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170 Total Colons: 22 -..code\modules\mob\login.dm Lines: 6? Total Colons: 1 -..code\modules\mob\mob.dm Lines: 329?, 599?, 690, 756? Total Colons: 5 -..code\modules\mob\mob_helpers.dm Lines: 485? Total Colons: 2 -..code\modules\mob\transform_procs.dm Lines: 295 Total Colons: 1 -..code\modules\mob\dead\observer\observer.dm Lines: 285? Total Colons: 1 -..code\modules\mob\living\living.dm Lines: 181?, 359?, 402 Total Colons: 3 -..code\modules\mob\living\say.dm Lines: 116? Total Colons: 1 -..code\modules\mob\living\carbon\carbon.dm Lines: 114, 286?, 288?, 291?, 310?, 311?, 322?, 323?, 566? Total Colons: 12 -..code\modules\mob\living\carbon\life.dm Lines: 468? Total Colons: 1 -..code\modules\mob\living\carbon\alien\humanoid\emote.dm Lines: 60? Total Colons: 1 -..code\modules\mob\living\carbon\alien\humanoid\humanoid.dm Lines: 93? Total Colons: 2 -..code\modules\mob\living\carbon\alien\humanoid\caste\hunter.dm Lines: 43?, 46? Total Colons: 2 -..code\modules\mob\living\carbon\alien\larva\emote.dm Lines: 79? Total Colons: 1 -..code\modules\mob\living\carbon\brain\MMI.dm Lines: 131?, 132? Total Colons: 2 -..code\modules\mob\living\carbon\human\examine.dm Lines: 48?, 55?, 62?, 69?, 76?, 83?, 90?, 97?, 115?, 122?, 129?, 136? Total Colons: 12 -..code\modules\mob\living\carbon\human\human.dm Lines: 87?, 96?, 192?, 194?, 196?, 200?, 205?, 210?, 215?, 219?, 221?, 223?, 231?, 236?, 241?, 248?, 250?, 252?, 253?, 254?, 324?, 325?, 341?, 563?, 734? Total Colons: 26 -..code\modules\mob\living\carbon\human\human_attackalien.dm Lines: 10? Total Colons: 1 -..code\modules\mob\living\carbon\human\inventory.dm Lines: 223?, 234?, 238?, 246?, 250?, 254? Total Colons: 6 -..code\modules\mob\living\carbon\human\species.dm Lines: 115?, 117?, 126?, 329?, 673? Total Colons: 5 -..code\modules\mob\living\carbon\human\update_icons.dm Lines: 112?, 186?, 479? Total Colons: 4 -..code\modules\mob\living\carbon\human\whisper.dm Lines: 43? Total Colons: 1 -..code\modules\mob\living\carbon\monkey\emote.dm Lines: 60? Total Colons: 1 -..code\modules\mob\living\silicon\silicon.dm Lines: 129, 324? Total Colons: 2 -..code\modules\mob\living\silicon\ai\ai.dm Lines: 255?, 280?, 281?, 341?, 530?, 532?, 585?, 593? Total Colons: 9 -..code\modules\mob\living\silicon\ai\life.dm Lines: 73, 75, 78, 80, 96, 97, 121, 145, 150, 166 Total Colons: 10 -..code\modules\mob\living\silicon\ai\say.dm Lines: 15? Total Colons: 2 -..code\modules\mob\living\silicon\ai\freelook\eye.dm Lines: 106? Total Colons: 1 -..code\modules\mob\living\silicon\pai\pai.dm Lines: 161, 181 Total Colons: 2 -..code\modules\mob\living\silicon\pai\software.dm Lines: 220?, 277?, 279?, 281?, 317?, 410?, 415?, 422?, 434, 434?, 435, 436, 436?, 437, 437?, 438, 438?, 439, 439?, 440, 442, 443, 444, 445, 446, 550, 557? Total Colons: 29 -..code\modules\mob\living\silicon\robot\examine.dm Lines: 29?, 31? Total Colons: 2 -..code\modules\mob\living\silicon\robot\inventory.dm Lines: 54, 62, 70 Total Colons: 3 -..code\modules\mob\living\silicon\robot\laws.dm Lines: 47? Total Colons: 1 -..code\modules\mob\living\silicon\robot\life.dm Lines: 173, 175, 177 Total Colons: 3 -..code\modules\mob\living\silicon\robot\robot.dm Lines: 259?, 393?, 492?, 545?, 806?, 1034? Total Colons: 8 -..code\modules\mob\living\simple_animal\parrot.dm Lines: 412?, 414? Total Colons: 2 -..code\modules\mob\living\simple_animal\worm.dm Lines: 74? Total Colons: 1 -..code\modules\mob\living\simple_animal\friendly\drone\interaction.dm Lines: 103? Total Colons: 2 -..code\modules\mob\living\simple_animal\friendly\drone\verbs.dm Lines: 25? Total Colons: 1 -..code\modules\mob\living\simple_animal\friendly\drone\_drone.dm Lines: 123?, 130?, 137?, 144? Total Colons: 4 -..code\modules\mob\living\simple_animal\hostile\hostile.dm Lines: 255, 256 Total Colons: 4 -..code\modules\mob\living\simple_animal\morph\morph.dm Lines: 183? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\death.dm Lines: 15? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\life.dm Lines: 190? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\powers.dm Lines: 75? Total Colons: 1 -..code\modules\mob\living\simple_animal\slime\slime.dm Lines: 79?, 80?, 90? Total Colons: 3 -..code\modules\mob\new_player\new_player.dm Lines: 27, 29, 44?, 69?, 73? Total Colons: 5 -..code\modules\mob\new_player\poll.dm Lines: 12?, 29?, 478? Total Colons: 3 -..code\modules\nano\JSON Reader.dm Lines: 71 Total Colons: 2 -..code\modules\nano\nanoui.dm Lines: 304? Total Colons: 1 -..code\modules\ninja\admin_ninja_verbs.dm Lines: 30, 32 Total Colons: 2 -..code\modules\ninja\ninja_event.dm Lines: 141? Total Colons: 1 -..code\modules\ninja\suit\gloves.dm Lines: 80?, 87? Total Colons: 2 -..code\modules\ninja\suit\mask.dm Lines: 116?, 129?, 132?, 139? Total Colons: 4 -..code\modules\ninja\suit\ninjaDrainAct.dm Lines: 128?, 159? Total Colons: 2 -..code\modules\ninja\suit\suit.dm Lines: 75?, 79?, 116?, 172? Total Colons: 4 -..code\modules\ninja\suit\suit_attackby.dm Lines: 10?, 12?, 19? Total Colons: 3 -..code\modules\ninja\suit\suit_initialisation.dm Lines: 84 Total Colons: 1 -..code\modules\ninja\suit\n_suit_verbs\energy_net_nets.dm Lines: 64, 65, 112?, 131 Total Colons: 4 -..code\modules\ninja\suit\n_suit_verbs\ninja_stars.dm Lines: 12? Total Colons: 1 -..code\modules\paperwork\filingcabinet.dm Lines: 57? Total Colons: 1 -..code\modules\paperwork\folders.dm Lines: 43? Total Colons: 1 -..code\modules\paperwork\paper.dm Lines: 86? Total Colons: 1 -..code\modules\paperwork\paperbin.dm Lines: 97? Total Colons: 1 -..code\modules\paperwork\photocopier.dm Lines: 123?, 264?, 268? Total Colons: 5 -..code\modules\paperwork\photography.dm Lines: 66?, 67?, 79?, 183, 184, 189, 190, 217, 217?, 219, 219? Total Colons: 14 -..code\modules\power\apc.dm Lines: 128?, 129?, 133, 148, 199?, 201?, 202?, 262?, 454?, 469?, 474, 647, 647?, 664?, 671?, 715?, 838, 839, 840, 1184, 1221? Total Colons: 25 -..code\modules\power\cable.dm Lines: 108?, 293?, 564? Total Colons: 3 -..code\modules\power\generator.dm Lines: 117? Total Colons: 2 -..code\modules\power\gravitygenerator.dm Lines: 230?, 250?, 258?, 264?, 279?, 280?, 287? Total Colons: 7 -..code\modules\power\lighting.dm Lines: 261?, 440? Total Colons: 2 -..code\modules\power\port_gen.dm Lines: 89?, 273? Total Colons: 2 -..code\modules\power\smes.dm Lines: 57, 419? Total Colons: 4 -..code\modules\power\solar.dm Lines: 388?, 391? Total Colons: 2 -..code\modules\power\turbine.dm Lines: 308?, 365?, 367?, 369? Total Colons: 5 -..code\modules\power\antimatter\control.dm Lines: 267? Total Colons: 1 -..code\modules\power\antimatter\shielding.dm Lines: 119 Total Colons: 1 -..code\modules\power\singularity\collector.dm Lines: 44?, 45?, 46?, 98? Total Colons: 6 -..code\modules\power\singularity\emitter.dm Lines: 252? Total Colons: 1 -..code\modules\power\singularity\singularity.dm Lines: 117?, 236? Total Colons: 2 -..code\modules\power\singularity\particle_accelerator\particle.dm Lines: 42 Total Colons: 1 -..code\modules\power\singularity\particle_accelerator\particle_accelerator.dm Lines: 364 Total Colons: 1 -..code\modules\power\singularity\particle_accelerator\particle_control.dm Lines: 215?, 216?, 217? Total Colons: 6 -..code\modules\procedural mapping\mapGenerator.dm Lines: 153? Total Colons: 1 -..code\modules\projectiles\ammunition.dm Lines: 29?, 30?, 155? Total Colons: 3 -..code\modules\projectiles\gun.dm Lines: 108?, 110?, 310? Total Colons: 3 -..code\modules\projectiles\ammunition\magazines.dm Lines: 173? Total Colons: 1 -..code\modules\projectiles\guns\magic\wand.dm Lines: 25? Total Colons: 1 -..code\modules\projectiles\guns\projectile\automatic.dm Lines: 28?, 109?, 127?, 160?, 165?, 250? Total Colons: 11 -..code\modules\projectiles\guns\projectile\launchers.dm Lines: 49? Total Colons: 1 -..code\modules\projectiles\guns\projectile\pistol.dm Lines: 15?, 36? Total Colons: 3 -..code\modules\projectiles\guns\projectile\shotgun.dm Lines: 30?, 63?, 114?, 282? Total Colons: 4 -..code\modules\projectiles\guns\projectile\toy.dm Lines: 33? Total Colons: 1 -..code\modules\reagents\Chemistry-Machinery.dm Lines: 85?, 89, 90, 97, 330?, 350?, 367?, 368?, 512?, 551?, 665?, 705?, 708?, 788, 867?, 910?, 1248?, 1286?, 1508?, 1510?, 1511?, 1512? Total Colons: 24 -..code\modules\reagents\Chemistry-Recipes.dm Lines: 46? Total Colons: 1 -..code\modules\reagents\reagent_containers.dm Lines: 64? Total Colons: 1 -..code\modules\reagents\Chemistry-Reagents\Consumable-Reagents\Food-Reagents.dm Lines: 331 Total Colons: 2 -..code\modules\reagents\reagent_containers\spray.dm Lines: 97?, 98?, 99?, 177? Total Colons: 4 -..code\modules\recycling\disposal-construction.dm Lines: 86?, 91? Total Colons: 2 -..code\modules\recycling\disposal-structures.dm Lines: 240? Total Colons: 1 -..code\modules\recycling\disposal-unit.dm Lines: 82? Total Colons: 1 -..code\modules\recycling\sortingmachinery.dm Lines: 217? Total Colons: 1 -..code\modules\research\experimentor.dm Lines: 253? Total Colons: 1 -..code\modules\research\message_server.dm Lines: 130? Total Colons: 2 -..code\modules\shuttle\shuttle.dm Lines: 266?, 270?, 515?, 522?, 547?, 564? Total Colons: 8 -..code\modules\surgery\organs\augments_internal.dm Lines: 33?, 76?, 77?, 94? Total Colons: 4 -..code\modules\telesci\telesci_computer.dm Lines: 46?, 122?, 269? Total Colons: 4 -..code\modules\tooltip\tooltip.dm Lines: 90? Total Colons: 1 -..code\modules\vehicles\VehicleBase.dm Lines: 101?, 103?, 105?, 107? Total Colons: 4 -..code\modules\vehicles\VehicleClickInteractions.dm Lines: 128?, 157?, 186?, 214?, 252?, 254?, 257?, 259?, 262?, 264?, 267?, 269?, 272?, 274? Total Colons: 14 -..code\modules\vehicles\VehicleDefense.dm Lines: 31? Total Colons: 1 -..code\orphaned procs\dbcore.dm Lines: 79? Total Colons: 5 -..code\orphaned procs\statistics.dm Lines: 63, 64, 98, 99 Total Colons: 4 -..code\_onclick\other_mobs.dm Lines: 89 Total Colons: 1 -..code\_onclick\hud\action.dm Lines: 184? Total Colons: 1 -..code\_onclick\hud\alien.dm Lines: 90? Total Colons: 1 -..code\_onclick\hud\alien_larva.dm Lines: 16? Total Colons: 1 -..code\_onclick\hud\human.dm Lines: 59? Total Colons: 1 -..code\_onclick\hud\monkey.dm Lines: 17? Total Colons: 1 -..code\__DATASTRUCTURES\priority_queue.dm Lines: 33? Total Colons: 1 -..code\__DATASTRUCTURES\stacks.dm Lines: 29? Total Colons: 1 -..code\__HELPERS\game.dm Lines: 216? Total Colons: 1 -..code\__HELPERS\icons.dm Lines: 216?, 233?, 386?, 389?, 392?, 425?, 439?, 456?, 526?, 557?, 559?, 601?, 607?, 635?, 636?, 637?, 638?, 715, 752, 757, 762, 763, 764, 765, 774, 786, 787, 809?, 828?, 839? Total Colons: 38 -..code\__HELPERS\icon_smoothing.dm Lines: 176?, 178? Total Colons: 2 -..code\__HELPERS\lists.dm Lines: 201?, 206?, 214? Total Colons: 3 -..code\__HELPERS\maths.dm Lines: 13?, 18?, 35?, 39? Total Colons: 4 -..code\__HELPERS\mobs.dm Lines: 137?, 139?, 140? Total Colons: 11 -..code\__HELPERS\names.dm Lines: 63?, 174? Total Colons: 3 -..code\__HELPERS\sanitize_values.dm Lines: 34? Total Colons: 1 -..code\__HELPERS\text.dm Lines: 157?, 350? Total Colons: 2 -..code\__HELPERS\type2type.dm Lines: 68?, 143?, 381? Total Colons: 5 -..code\__HELPERS\unsorted.dm Lines: 41?, 573, 904, 991? Total Colons: 4 -..code\__HELPERS\sorts\__main.dm Lines: 2?, 57?, 391, 491, 585? Total Colons: 5 -433/1564 files have colons in them \ No newline at end of file