diff --git a/code/game/machinery/bloodbankgen.dm b/code/game/machinery/bloodbankgen.dm new file mode 100644 index 0000000000..1f215b4b6d --- /dev/null +++ b/code/game/machinery/bloodbankgen.dm @@ -0,0 +1,314 @@ +/obj/machinery/bloodbankgen + name = "blood bank generator" + desc = "Generates universally applicable synthetics for all blood types. Add regular blood to convert quickly." + icon = 'icons/obj/machines/biogenerator.dmi' + icon_state = "biogen-empty" + density = TRUE + use_power = IDLE_POWER_USE + idle_power_usage = 80 + circuit = /obj/item/circuitboard/machine/bloodbankgen + var/processing = FALSE + var/obj/item/reagent_containers/blood = null + var/points = 0 + var/menustat = "menu" + var/efficiency = 0 + var/productivity = 0 + var/max_items = 40 + var/datum/techweb/stored_research + var/list/show_categories = list("Blood") + +/obj/machinery/bloodbankgen/Initialize() + . = ..() + stored_research = new /datum/techweb/specialized/autounlocking/bloodbankgen + create_reagents(1000) + +/obj/machinery/bloodbankgen/Destroy() + QDEL_NULL(bag) + return ..() + +/obj/machinery/bloodbankgen/contents_explosion(severity, target) + ..() + if(bag) + bag.ex_act(severity, target) + +/obj/machinery/bloodbankgen/handle_atom_del(atom/A) + ..() + if(A == bag) + bag = null + update_icon() + updateUsrDialog() + +/obj/machinery/bloodbankgen/RefreshParts() + var/E = 0 + var/P = 0 + var/max_storage = 40 + for(var/obj/item/stock_parts/matter_bin/B in component_parts) + P += B.rating + max_storage = 40 * B.rating + for(var/obj/item/stock_parts/manipulator/M in component_parts) + E += M.rating + efficiency = E + productivity = P + max_items = max_storage + +/obj/machinery/bloodbankgen/on_reagent_change(changetype) //When the reagents change, change the icon as well. + update_icon() + +/obj/machinery/bloodbankgen/update_icon() + if(panel_open) + icon_state = "biogen-empty-o" + else if(!src.bag) + icon_state = "biogen-empty" + else if(!src.processing) + icon_state = "biogen-stand" + else + icon_state = "biogen-work" + return + +/obj/machinery/bloodbankgen/attackby(obj/item/O, mob/user, params) + if(user.a_intent == INTENT_HARM) + return ..() + + if(processing) + to_chat(user, "The generator is currently processing.") + return + + if(default_deconstruction_screwdriver(user, "biogen-empty-o", "biogen-empty", O)) + if(bag) + var/obj/item/reagent_containers/blood/B = bag + B.forceMove(drop_location()) + bag = null + update_icon() + return + + if(default_deconstruction_crowbar(O)) + return + + if(istype(O, /obj/item/reagent_containers/blood)) + . = 1 //no afterattack + if(!panel_open) + if(bag) + to_chat(user, "A container is already loaded into the machine.") + else + if(!user.transferItemToLoc(O, src)) + return + bag = O + to_chat(user, "You add the container to the machine.") + update_icon() + updateUsrDialog() + else + to_chat(user, "Close the maintenance panel first.") + return + + else if(istype(O, /obj/item/storage/bag/plants)) + var/obj/item/storage/bag/plants/PB = O + var/i = 0 + for(var/obj/item/reagent_containers/food/snacks/grown/G in contents) + i++ + if(i >= max_items) + to_chat(user, "The bloodbankgen is already full! Activate it.") + else + for(var/obj/item/reagent_containers/food/snacks/grown/G in PB.contents) + if(i >= max_items) + break + if(SEND_SIGNAL(PB, COMSIG_TRY_STORAGE_TAKE, G, src)) + i++ + if(iYou empty the plant bag into the bloodbankgen.") + else if(PB.contents.len == 0) + to_chat(user, "You empty the plant bag into the bloodbankgen, filling it to its capacity.") + else + to_chat(user, "You fill the bloodbankgen to its capacity.") + return TRUE //no afterattack + + else if(istype(O, /obj/item/reagent_containers/food/snacks/grown)) + var/i = 0 + for(var/obj/item/reagent_containers/food/snacks/grown/G in contents) + i++ + if(i >= max_items) + to_chat(user, "The bloodbankgen is full! Activate it.") + else + if(user.transferItemToLoc(O, src)) + to_chat(user, "You put [O.name] in [src.name]") + return TRUE //no afterattack + else if (istype(O, /obj/item/disk/design_disk)) + user.visible_message("[user] begins to load \the [O] in \the [src]...", + "You begin to load a design from \the [O]...", + "You hear the chatter of a floppy drive.") + processing = TRUE + var/obj/item/disk/design_disk/D = O + if(do_after(user, 10, target = src)) + for(var/B in D.blueprints) + if(B) + stored_research.add_design(B) + processing = FALSE + return TRUE + else + to_chat(user, "You cannot put this in [src.name]!") + +/obj/machinery/bloodbankgen/ui_interact(mob/user) + if(stat & BROKEN || panel_open) + return + . = ..() + var/dat + if(processing) + dat += "
bloodbankgen is processing! Please wait...

" + else + switch(menustat) + if("nopoints") + dat += "
You do not have enough biomass to create products.
Please, put growns into reactor and activate it.
" + menustat = "menu" + if("complete") + dat += "
Operation complete.
" + menustat = "menu" + if("void") + dat += "
Error: No growns inside.
Please, put growns into reactor.
" + menustat = "menu" + if("nobagspace") + dat += "
Not enough space left in container. Unable to create product.
" + menustat = "menu" + if(bag) + var/categories = show_categories.Copy() + for(var/V in categories) + categories[V] = list() + for(var/V in stored_research.researched_designs) + var/datum/design/D = stored_research.researched_designs[V] + for(var/C in categories) + if(C in D.category) + categories[C] += D + + dat += "
Biomass: [points] units.

" + dat += "ActivateDetach Container" + for(var/cat in categories) + dat += "

[cat]:

" + dat += "
" + for(var/V in categories[cat]) + var/datum/design/D = V + dat += "[D.name]: Make" + if(cat in timesFiveCategories) + dat += "x5" + if(ispath(D.build_path, /obj/item/stack)) + dat += "x10" + dat += "([D.materials[MAT_BIOMASS]/efficiency])
" + dat += "
" + else + dat += "
No container inside, please insert container.
" + + var/datum/browser/popup = new(user, "biogen", name, 350, 520) + popup.set_content(dat) + popup.open() + +/obj/machinery/bloodbankgen/proc/activate() + if (usr.stat != CONSCIOUS) + return + if (src.stat != NONE) //NOPOWER etc + return + if(processing) + to_chat(usr, "The bloodbankgen is in the process of working.") + return + var/S = 0 + for(var/obj/item/reagent_containers/food/snacks/grown/I in contents) + S += 5 + if(I.reagents.get_reagent_amount("nutriment") < 0.1) + points += 1*productivity + else points += I.reagents.get_reagent_amount("nutriment")*10*productivity + qdel(I) + if(S) + processing = TRUE + update_icon() + updateUsrDialog() + playsound(src.loc, 'sound/machines/blender.ogg', 50, 1) + use_power(S*30) + sleep(S+15/productivity) + processing = FALSE + update_icon() + else + menustat = "void" + +/obj/machinery/bloodbankgen/proc/check_cost(list/materials, multiplier = 1, remove_points = 1) + if(materials.len != 1 || materials[1] != MAT_BIOMASS) + return FALSE + if (materials[MAT_BIOMASS]*multiplier/efficiency > points) + menustat = "nopoints" + return FALSE + else + if(remove_points) + points -= materials[MAT_BIOMASS]*multiplier/efficiency + update_icon() + updateUsrDialog() + return TRUE + +/obj/machinery/bloodbankgen/proc/check_container_volume(list/reagents, multiplier = 1) + var/sum_reagents = 0 + for(var/R in reagents) + sum_reagents += reagents[R] + sum_reagents *= multiplier + + if(bag.reagents.total_volume + sum_reagents > bag.reagents.maximum_volume) + menustat = "nobagspace" + return FALSE + + return TRUE + +/obj/machinery/bloodbankgen/proc/create_product(datum/design/D, amount) + if(!bag || !loc) + return FALSE + + if(ispath(D.build_path, /obj/item/stack)) + if(!check_container_volume(D.make_reagents, amount)) + return FALSE + if(!check_cost(D.materials, amount)) + return FALSE + + new D.build_path(drop_location(), amount) + for(var/R in D.make_reagents) + bag.reagents.add_reagent(R, D.make_reagents[R]*amount) + else + var/i = amount + while(i > 0) + if(!check_container_volume(D.make_reagents)) + return . + if(!check_cost(D.materials)) + return . + if(D.build_path) + new D.build_path(loc) + for(var/R in D.make_reagents) + bag.reagents.add_reagent(R, D.make_reagents[R]) + . = 1 + --i + + menustat = "complete" + update_icon() + return . + +/obj/machinery/bloodbankgen/proc/detach() + if(bag) + bag.forceMove(drop_location()) + bag = null + update_icon() + +/obj/machinery/bloodbankgen/Topic(href, href_list) + if(..() || panel_open) + return + + usr.set_machine(src) + + if(href_list["activate"]) + activate() + updateUsrDialog() + + else if(href_list["detach"]) + detach() + updateUsrDialog() + + else if(href_list["create"]) + var/amount = (text2num(href_list["amount"])) + //Can't be outside these (if you change this keep a sane limit) + amount = CLAMP(amount, 1, 50) + var/datum/design/D = locate(href_list["create"]) + create_product(D, amount) + updateUsrDialog() + + else if(href_list["menu"]) + menustat = "menu" + updateUsrDialog() diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index a3250fe1b0..1229b4a308 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -29,6 +29,10 @@ "fly", "moth", "plasmaman", + "mammal", + "aquatic", + "insect", + "xenoperson", "other" ) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 53a8ab42c3..13f2476eef 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1302,17 +1302,31 @@ /datum/supply_pack/medical/bloodpacks name = "Blood Pack Variety Crate" - desc = "Contains eight different blood packs for reintroducing blood to patients." + desc = "Contains ten different blood packs for reintroducing blood to patients." cost = 3000 - contains = list(/obj/item/reagent_containers/blood, - /obj/item/reagent_containers/blood, + contains = list(/obj/item/reagent_containers/blood/random, + /obj/item/reagent_containers/blood/random, /obj/item/reagent_containers/blood/APlus, /obj/item/reagent_containers/blood/AMinus, /obj/item/reagent_containers/blood/BPlus, /obj/item/reagent_containers/blood/BMinus, /obj/item/reagent_containers/blood/OPlus, /obj/item/reagent_containers/blood/OMinus, - /obj/item/reagent_containers/blood/lizard) + /obj/item/reagent_containers/blood/lizard, + /obj/item/reagent_containers/blood/jellyblood, + /obj/item/reagent_containers/blood/jellyblood) + crate_name = "blood freezer" + crate_type = /obj/structure/closet/crate/freezer + +/datum/supply_pack/medical/bloodpackssynth + name = "Synthetics Blood Pack Crate" + desc = "Contains five synthetics blood packs for reintroducing blood to patients." + cost = 3000 + contains = list(/obj/item/reagent_containers/blood/synthetics, + /obj/item/reagent_containers/blood/synthetics, + /obj/item/reagent_containers/blood/synthetics, + /obj/item/reagent_containers/blood/synthetics, + /obj/item/reagent_containers/blood/synthetics) crate_name = "blood freezer" crate_type = /obj/structure/closet/crate/freezer diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index de39197b8c..60bd1477f9 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -149,13 +149,13 @@ C.ForceContractDisease(D) if(!(blood_data["blood_type"] in get_safe_blood(C.dna.blood_type))) if((blood_data["blood_type"] == "GEL") && (C.dna.species.exotic_blood != "jellyblood")) - C.reagents.add_reagent("toxin", amount * 1.5) //filthy xenos bloooood + C.reagents.add_reagent("bonehurtingjuice", amount * 1.5) //filthy xenos bloooood else if((blood_data["blood_type"] == "HF") && (C.dna.species.exotic_blood != "oilblood")) - C.reagents.add_reagent("toxin", amount * 1) //don't fucking put oil in people + C.reagents.add_reagent("bonehurtingjuice", amount * 1) //don't fucking put oil in people else if((blood_data["blood_type"] == "X*") && (C.dna.species.exotic_blood != "xenoblood")) - C.reagents.add_reagent("toxin", amount * 1.5) //acid blooood + C.reagents.add_reagent("sacid", amount * 1.5) //acid blooood else - C.reagents.add_reagent("toxin", amount * 0.5) + C.reagents.add_reagent("bonehurtingjuice", amount * 0.5) else C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAXIMUM) return 1