Fermichem part 2.2 Adds new tools, crafts and methods for ghetto chemists to handle the new reaction mechanics. (#56871)

Since reactions now require a bit more involvement from chemists, ghetto chemistry is a bit harder. This seeks to help some of those problems by providing new tools for those without a chem heater/reaction chamber.

Also some of these might be useful for chemists in the lab too!

Here's what you can make:
image
the burners are similar to candles - except they burn their internal reagents. The temperature they heat by is dependant on the flame, fuel and oil burn for a lower amount, ethanol for a higher amount and plasma for the highest amount. They can be put on tables and bonked with beakers for a quick way to heat them (similar to lighters). You'll need to light them with a match or lighter too, though, and can be put out by use in hand.

The thermometer looks like this and gives you temperature readings!
thermom

The pH booklets are the same as before - but you can now craft them by making universal indicator. These are the best way for a ghetto chemist to check their pH, and multiple sheets should be used over a reaction.

The improvised chem heater looks like this, and is a reconfigured space heater, it requires more materials and tools lending itself to a static drug den, but has the best method of adjusting temperature and fighting against exo/endo thermic reactions:
Improv_heater

Finally, the cooling spray lets chemists do the oposite of a lighter on their beaker - cooling the reagents within. In addition, fire extinquishers perform the same function.

In addition ice and universal indicator have been added as reactions.

Co-authored-by: Rohesie <rohesie@gmail.com>
Co-authored-by: Mothblocks <35135081+Jared-Fogle@users.noreply.github.com>
Co-authored-by: Aleksej Komarov <stylemistake@gmail.com>
This commit is contained in:
Thalpy
2021-02-19 20:28:48 +02:00
committed by GitHub
co-authored by Rohesie Mothblocks Aleksej Komarov
parent 1d6de2e5aa
commit fa575db934
29 changed files with 969 additions and 172 deletions
+1
View File
@@ -95,6 +95,7 @@
#define CAT_SPAGHETTI "Spaghettis"
#define CAT_ICE "Frozen"
#define CAT_DRINK "Drinks"
#define CAT_CHEMISTRY "Chemistry"
//rcd modes
#define RCD_FLOORWALL 0
+2
View File
@@ -194,6 +194,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isgun(A) (istype(A, /obj/item/gun))
#define is_reagent_container(O) (istype(O, /obj/item/reagent_containers))
//Assemblies
#define isassembly(O) (istype(O, /obj/item/assembly))
+35
View File
@@ -89,3 +89,38 @@
return
for(var/mob/M in viewers(5, location))
to_chat(M, notification)
#define CONVERT_PH_TO_COLOR(pH, color) \
switch(pH) {\
if(14 to INFINITY)\
{ color = "#462c83" }\
if(13 to 14)\
{ color = "#63459b" }\
if(12 to 13)\
{ color = "#5a51a2" }\
if(11 to 12)\
{ color = "#3853a4" }\
if(10 to 11)\
{ color = "#3f93cf" }\
if(9 to 10)\
{ color = "#0bb9b7" }\
if(8 to 9)\
{ color = "#23b36e" }\
if(7 to 8)\
{ color = "#3aa651" }\
if(6 to 7)\
{ color = "#4cb849" }\
if(5 to 6)\
{ color = "#b5d335" }\
if(4 to 5)\
{ color = "#f7ec1e" }\
if(3 to 4)\
{ color = "#fbc314" }\
if(2 to 3)\
{ color = "#f26724" }\
if(1 to 2)\
{ color = "#ef1d26" }\
if(-INFINITY to 1)\
{ color = "#c6040c" }\
}
@@ -132,6 +132,7 @@ GLOBAL_LIST_INIT(common_loot, list( //common: basic items
/obj/item/reagent_containers/glass/beaker = 1,
/obj/item/reagent_containers/glass/rag = 1,
/obj/item/reagent_containers/hypospray/medipen/pumpup = 2,
/obj/item/reagent_containers/glass/bottle/random_buffer = 2,
) = 1,
list(//food
+68 -53
View File
@@ -68,8 +68,10 @@
*/
/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents)
var/list/item_instances = contents["instances"]
var/list/machines = contents["machinery"]
contents = contents["other"]
var/list/requirements_list = list()
// Process all requirements
@@ -100,6 +102,10 @@
if(contents[requirement_path] < R.chem_catalysts[requirement_path])
return FALSE
for(var/machinery_path in R.machinery)
if(!machines[machinery_path])//We don't care for volume with machines, just if one is there or not
return FALSE
return R.check_requirements(a, requirements_list)
/datum/component/personal_crafting/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1)
@@ -119,24 +125,27 @@
.["tool_behaviour"] = list()
.["other"] = list()
.["instances"] = list()
for(var/obj/item/I in get_environment(a,blacklist))
if(.["instances"][I.type])
.["instances"][I.type] += I
else
.["instances"][I.type] = list(I)
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
.["other"][I.type] += S.amount
else if(I.tool_behaviour)
.["tool_behaviour"] += I.tool_behaviour
.["other"][I.type] += 1
else
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
if(RC.is_drainable())
for(var/datum/reagent/A in RC.reagents.reagent_list)
.["other"][A.type] += A.volume
.["other"][I.type] += 1
.["machinery"] = list()
for(var/obj/object in get_environment(a, blacklist))
if(isitem(object))
var/obj/item/item = object
LAZYADDASSOCLIST(.["instances"], item.type, item)
if(isstack(item))
var/obj/item/stack/stack = item
.["other"][item.type] += stack.amount
else if(item.tool_behaviour)
.["tool_behaviour"] += item.tool_behaviour
.["other"][item.type] += 1
else
if(is_reagent_container(item))
var/obj/item/reagent_containers/container = item
if(container.is_drainable())
for(var/datum/reagent/reagent in container.reagents.reagent_list)
.["other"][reagent.type] += reagent.volume
.["other"][item.type] += 1
else if (ismachinery(object))
LAZYADDASSOCLIST(.["machinery"], object.type, object)
/// Returns a boolean on whether the tool requirements of the input recipe are satisfied by the input source and surroundings.
@@ -166,7 +175,7 @@
if(present_qualities[required_quality])
continue
return FALSE
for(var/required_path in recipe.tool_paths)
var/found_this_tool = FALSE
for(var/tool_path in available_tools)
@@ -177,7 +186,7 @@
if(found_this_tool)
continue
return FALSE
return TRUE
@@ -233,17 +242,24 @@
. = list()
var/data
var/amt
var/list/requirements = list()
if(R.reqs)
requirements += R.reqs
if(R.machinery)
requirements += R.machinery
main_loop:
for(var/A in R.reqs)
amt = R.reqs[A]
for(var/path_key in requirements)
amt = R.reqs[path_key] || R.machinery[path_key]
if(!amt)//since machinery can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it!
continue main_loop
surroundings = get_environment(a, R.blacklist)
surroundings -= Deletion
if(ispath(A, /datum/reagent))
var/datum/reagent/RG = new A
if(ispath(path_key, /datum/reagent))
var/datum/reagent/RG = new path_key
var/datum/reagent/RGNT
while(amt > 0)
var/obj/item/reagent_containers/RC = locate() in surroundings
RG = RC.reagents.get_reagent(A)
RG = RC.reagents.get_reagent(path_key)
if(RG)
if(!locate(RG.type) in Deletion)
Deletion += new RG.type()
@@ -267,11 +283,11 @@
SEND_SIGNAL(RC.reagents, COMSIG_REAGENTS_CRAFTING_PING) // - [] TODO: Make this entire thing less spaghetti
else
surroundings -= RC
else if(ispath(A, /obj/item/stack))
else if(ispath(path_key, /obj/item/stack))
var/obj/item/stack/S
var/obj/item/stack/SD
while(amt > 0)
S = locate(A) in surroundings
S = locate(path_key) in surroundings
if(S.amount >= amt)
if(!locate(S.type) in Deletion)
SD = new S.type()
@@ -292,34 +308,34 @@
else
var/atom/movable/I
while(amt > 0)
I = locate(A) in surroundings
I = locate(path_key) in surroundings
Deletion += I
surroundings -= I
amt--
var/list/partlist = list(R.parts.len)
for(var/M in R.parts)
partlist[M] = R.parts[M]
for(var/A in R.parts)
if(istype(A, /datum/reagent))
var/datum/reagent/RG = locate(A) in Deletion
if(RG.volume > partlist[A])
RG.volume = partlist[A]
for(var/part in R.parts)
if(istype(part, /datum/reagent))
var/datum/reagent/RG = locate(part) in Deletion
if(RG.volume > partlist[part])
RG.volume = partlist[part]
. += RG
Deletion -= RG
continue
else if(istype(A, /obj/item/stack))
var/obj/item/stack/ST = locate(A) in Deletion
if(ST.amount > partlist[A])
ST.amount = partlist[A]
else if(istype(part, /obj/item/stack))
var/obj/item/stack/ST = locate(part) in Deletion
if(ST.amount > partlist[part])
ST.amount = partlist[part]
. += ST
Deletion -= ST
continue
else
while(partlist[A] > 0)
var/atom/movable/AM = locate(A) in Deletion
while(partlist[part] > 0)
var/atom/movable/AM = locate(part) in Deletion
. += AM
Deletion -= AM
partlist[A] -= 1
partlist[part] -= 1
while(Deletion.len)
var/DL = Deletion[Deletion.len]
Deletion.Cut(Deletion.len)
@@ -423,6 +439,7 @@
else
result.forceMove(user.drop_location())
to_chat(user, "<span class='notice'>[TR.name] constructed.</span>")
TR.on_craft_completion(user, result)
else
to_chat(user, "<span class='warning'>Construction failed[result]</span>")
busy = FALSE
@@ -441,26 +458,24 @@
var/list/data = list()
data["name"] = R.name
data["ref"] = "[REF(R)]"
var/req_text = ""
var/catalyst_text = ""
var/list/req_text = list()
var/list/tool_list = list()
var/list/catalyst_text = list()
for(var/a in R.reqs)
for(var/atom/req_atom as anything in R.reqs)
//We just need the name, so cheat-typecast to /atom for speed (even tho Reagents are /datum they DO have a "name" var)
//Also these are typepaths so sadly we can't just do "[a]"
var/atom/A = a
req_text += " [R.reqs[A]] [initial(A.name)],"
req_text += "[R.reqs[req_atom]] [initial(req_atom.name)]"
for(var/obj/machinery/content as anything in R.machinery)
req_text += "[R.reqs[content]] [initial(content.name)]"
if(R.additional_req_text)
req_text += R.additional_req_text
req_text = replacetext(req_text,",","",-1)
data["req_text"] = req_text
data["req_text"] = req_text.Join(", ")
for(var/a in R.chem_catalysts)
var/atom/A = a //cheat-typecast
catalyst_text += " [R.chem_catalysts[A]] [initial(A.name)],"
catalyst_text = replacetext(catalyst_text,",","",-1)
data["catalyst_text"] = catalyst_text
for(var/atom/req_catalyst as anything in R.chem_catalysts)
catalyst_text += "[R.chem_catalysts[req_catalyst]] [initial(req_catalyst.name)]"
data["catalyst_text"] = catalyst_text.Join(", ")
var/list/tool_list = list()
for(var/required_quality in R.tool_behaviors)
tool_list += required_quality
for(var/obj/item/required_path as anything in R.tool_paths)
+120 -1
View File
@@ -1,3 +1,7 @@
///If the machine is used/deleted in the crafting process
#define CRAFTING_MACHINERY_CONSUME 1
///If the machine is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it
#define CRAFTING_MACHINERY_USE 0
/datum/crafting_recipe
var/name = "" //in-game display name
@@ -10,12 +14,14 @@
var/list/tool_paths
var/time = 30 //time in deciseconds
var/list/parts = list() //type paths of items that will be placed in the result
var/list/chem_catalysts = list() //like tools but for reagents
var/list/chem_catalysts = list() //like tool_behaviors but for reagents
var/category = CAT_NONE //where it shows up in the crafting UI
var/subcategory = CAT_NONE
var/always_available = TRUE //Set to FALSE if it needs to be learned first.
/// Additonal requirements text shown in UI
var/additional_req_text
///Required machines for the craft, set the assigned value of the typepath to CRAFTING_MACHINERY_CONSUME or CRAFTING_MACHINERY_USE. Lazy associative list: type_path key -> flag value.
var/list/machinery
/datum/crafting_recipe/New()
if(!(result in reqs))
@@ -34,6 +40,9 @@
/datum/crafting_recipe/proc/check_requirements(mob/user, list/collected_requirements)
return TRUE
/datum/crafting_recipe/proc/on_craft_completion(mob/user, atom/result)
return
/datum/crafting_recipe/improv_explosive
name = "IED"
result = /obj/item/grenade/iedcasing
@@ -1158,3 +1167,113 @@
/obj/item/aquarium_kit = 1
)
category = CAT_MISC
/datum/crafting_recipe/alcohol_burner
name = "Alcohol burner"
result = /obj/item/burner
time = 5 SECONDS
reqs = list(/obj/item/reagent_containers/glass/beaker = 1,
/datum/reagent/consumable/ethanol = 15,
/obj/item/paper = 1
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/oil_burner
name = "Oil burner"
result = /obj/item/burner/oil
time = 5 SECONDS
reqs = list(/obj/item/reagent_containers/glass/beaker = 1,
/datum/reagent/fuel/oil = 15,
/obj/item/paper = 1
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/fuel_burner
name = "Fuel burner"
result = /obj/item/burner/fuel
time = 5 SECONDS
reqs = list(/obj/item/reagent_containers/glass/beaker = 1,
/datum/reagent/fuel = 15,
/obj/item/paper = 1
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/thermometer
name = "Thermometer"
tool_behaviors = list(TOOL_WELDER)
result = /obj/item/thermometer
time = 5 SECONDS
reqs = list(
/datum/reagent/mercury = 5,
/obj/item/stack/sheet/glass = 1
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/thermometer_alt
name = "Thermometer"
result = /obj/item/thermometer/pen
time = 5 SECONDS
reqs = list(
/datum/reagent/mercury = 5,
/obj/item/pen = 1
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/ph_booklet
name = "pH booklet"
result = /obj/item/ph_booklet
time = 5 SECONDS
reqs = list(
/datum/reagent/universal_indicator = 5,
/obj/item/paper = 1
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/dropper //Maybe make a glass pipette icon?
name = "Dropper"
result = /obj/item/reagent_containers/dropper
tool_behaviors = list(TOOL_WELDER)
time = 5 SECONDS
reqs = list(
/obj/item/stack/sheet/glass = 1,
)
category = CAT_CHEMISTRY
/datum/crafting_recipe/improvised_chem_heater
name = "Improvised chem heater"
result = /obj/machinery/space_heater/improvised_chem_heater
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER)
time = 15 SECONDS
reqs = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stack/sheet/glass = 2,
/obj/item/stack/sheet/iron = 2,
/datum/reagent/water = 50,
/obj/item/thermometer = 1
)
machinery = list(/obj/machinery/space_heater = CRAFTING_MACHINERY_CONSUME)
category = CAT_CHEMISTRY
/datum/crafting_recipe/improvised_chem_heater/on_craft_completion(mob/user, atom/result)
var/obj/item/stock_parts/cell/cell = locate(/obj/item/stock_parts/cell) in range(1)
if(!cell)
return
var/obj/machinery/space_heater/improvised_chem_heater/heater = result
var/turf/turf = get_turf(cell)
heater.forceMove(turf)
heater.attackby(cell, user) //puts it into the heater
/datum/crafting_recipe/improvised_coolant
name = "Improvised cooling spray"
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
result = /obj/item/extinguisher/crafted
time = 10 SECONDS
reqs = list(
/obj/item/toy/crayon/spraycan = 1,
/datum/reagent/water = 20,
/datum/reagent/consumable/ice = 10
)
category = CAT_CHEMISTRY
#undef CRAFTING_MACHINERY_CONSUME
#undef CRAFTING_MACHINERY_USE
+176 -4
View File
@@ -1,6 +1,7 @@
#define HEATER_MODE_STANDBY "standby"
#define HEATER_MODE_HEAT "heat"
#define HEATER_MODE_COOL "cool"
#define HEATER_MODE_AUTO "auto"
/obj/machinery/space_heater
anchored = FALSE
@@ -16,10 +17,10 @@
circuit = /obj/item/circuitboard/machine/space_heater
/// We don't use area power, we always use the cell
use_power = NO_POWER_USE
var/obj/item/stock_parts/cell/cell
var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell
var/on = FALSE
var/mode = HEATER_MODE_STANDBY
var/setMode = "auto" // Anything other than "heat" or "cool" is considered auto.
var/setMode = HEATER_MODE_AUTO // Anything other than "heat" or "cool" is considered auto.
var/targetTemperature = T20C
var/heatingPower = 20000
var/efficiency = 20000
@@ -32,7 +33,8 @@
/obj/machinery/space_heater/Initialize()
. = ..()
cell = new(src)
if(ispath(cell))
cell = new cell(src)
update_appearance()
/obj/machinery/space_heater/on_construction()
@@ -60,7 +62,8 @@
/obj/machinery/space_heater/update_icon_state()
icon_state = "[base_icon_state]-[on ? mode : "off"]"
return ..()
. = ..()
return
/obj/machinery/space_heater/update_overlays()
. = ..()
@@ -179,6 +182,7 @@
data["on"] = on
data["mode"] = setMode
data["hasPowercell"] = !!cell
data["chemHacked"] = FALSE
if(cell)
data["powerLevel"] = round(cell.percent(), 1)
data["targetTemp"] = round(targetTemperature - T0C, 1)
@@ -232,6 +236,174 @@
cell = null
. = TRUE
///For use with heating reagents in a ghetto way
/obj/machinery/space_heater/improvised_chem_heater
icon = 'icons/obj/chemical.dmi'
icon_state = "sheater-off"
name = "Improvised chem heater"
desc = "A space heater hacked to reroute heating to a water bath on the top."
panel_open = TRUE //This is always open - since we've injected wires in the panel
//We inherit the cell from the heater prior
cell = null
///The beaker within the heater
var/obj/item/reagent_containers/beaker = null
///How powerful the heating is, upgrades with parts. (ala chem_heater.dm's method, basically the same level of heating, but this is restricted)
var/chem_heating_power = 1
/obj/machinery/space_heater/improvised_chem_heater/Destroy()
. = ..()
QDEL_NULL(beaker)
/obj/machinery/space_heater/improvised_chem_heater/process(delta_time)
if(!on)
update_appearance()
return PROCESS_KILL
if(!is_operational || !cell || cell.charge <= 0)
on = FALSE
update_appearance()
return PROCESS_KILL
if(!beaker)//No beaker to heat
update_appearance()
return
if(beaker.reagents.total_volume)
var/power_mod = 0.1 * chem_heating_power
switch(setMode)
if(HEATER_MODE_AUTO)
power_mod *= 0.5
beaker.reagents.adjust_thermal_energy((targetTemperature - beaker.reagents.chem_temp) * power_mod * delta_time * SPECIFIC_HEAT_DEFAULT * beaker.reagents.total_volume)
beaker.reagents.handle_reactions()
if(HEATER_MODE_HEAT)
if(targetTemperature < beaker.reagents.chem_temp)
return
beaker.reagents.adjust_thermal_energy((targetTemperature - beaker.reagents.chem_temp) * power_mod * delta_time * SPECIFIC_HEAT_DEFAULT * beaker.reagents.total_volume)
if(HEATER_MODE_COOL)
if(targetTemperature > beaker.reagents.chem_temp)
return
beaker.reagents.adjust_thermal_energy((targetTemperature - beaker.reagents.chem_temp) * power_mod * delta_time * SPECIFIC_HEAT_DEFAULT * beaker.reagents.total_volume)
var/requiredEnergy = heatingPower * delta_time * (power_mod * 4)
cell.use(requiredEnergy / efficiency)
beaker.reagents.handle_reactions()
update_appearance()
/obj/machinery/space_heater/improvised_chem_heater/ui_data()
. = ..()
.["chemHacked"] = TRUE
.["beaker"] = beaker
.["currentTemp"] = beaker ? (round(beaker.reagents.chem_temp - T0C)) : "N/A"
/obj/machinery/space_heater/improvised_chem_heater/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("ejectBeaker")
//Eject doesn't turn it off, so you can preheat for beaker swapping
replace_beaker(usr)
. = TRUE
///Slightly modified to ignore the open_hatch - it's always open, we hacked it.
/obj/machinery/space_heater/improvised_chem_heater/attackby(obj/item/item, mob/user, params)
add_fingerprint(user)
if(default_unfasten_wrench(user, item))
return
if(default_deconstruction_crowbar(item))
return
if(istype(item, /obj/item/stock_parts/cell))
if(cell)
to_chat(user, "<span class='warning'>There is already a power cell inside!</span>")
return
else if(!user.transferItemToLoc(item, src))
return
cell = item
item.add_fingerprint(usr)
user.visible_message("<span class='notice'>\The [user] inserts a power cell into \the [src].</span>", "<span class='notice'>You insert the power cell into \the [src].</span>")
SStgui.update_uis(src)
//reagent containers
if(is_reagent_container(item) && !(item.item_flags & ABSTRACT) && item.is_open_container())
. = TRUE //no afterattack
var/obj/item/reagent_containers/container = item
if(!user.transferItemToLoc(container, src))
return
replace_beaker(user, container)
to_chat(user, "<span class='notice'>You add [container] to [src]'s water bath.</span>")
updateUsrDialog()
return
//Dropper tools
if(beaker)
if(is_type_in_list(item, list(/obj/item/reagent_containers/dropper, /obj/item/ph_meter, /obj/item/ph_paper, /obj/item/reagent_containers/syringe)))
item.afterattack(beaker, user, 1)
return
/obj/machinery/space_heater/improvised_chem_heater/on_deconstruction(disassembled = TRUE)
. = ..()
if(disassembled)
beaker?.forceMove(drop_location())
beaker = null
var/static/bonus_junk = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stack/sheet/glass = 2,
/obj/item/stack/sheet/iron = 2,
/obj/item/thermometer = 1
)
for(var/item in bonus_junk)
if(prob(80))
new item(get_turf(loc))
/obj/machinery/space_heater/improvised_chem_heater/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
if(!user)
return FALSE
if(beaker)
try_put_in_hand(beaker, user)
beaker = null
if(new_beaker)
beaker = new_beaker
update_appearance()
return TRUE
/obj/machinery/space_heater/improvised_chem_heater/AltClick(mob/living/user)
. = ..()
if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
replace_beaker(user)
/obj/machinery/space_heater/improvised_chem_heater/update_icon_state()
. = ..()
if(!on || !beaker || !cell)
icon_state = "sheater-off"
return
if(targetTemperature < beaker.reagents.chem_temp)
icon_state = "sheater-cool"
return
if(targetTemperature > beaker.reagents.chem_temp)
icon_state = "sheater-heat"
return
icon_state = "sheater-off"
/obj/machinery/space_heater/improvised_chem_heater/RefreshParts()
var/lasers_rating = 0
var/capacitors_rating = 0
for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
lasers_rating += laser.rating
for(var/obj/item/stock_parts/capacitor/capacitor in component_parts)
capacitors_rating += capacitor.rating
heatingPower = lasers_rating * 20000
settableTemperatureRange = capacitors_rating * 50 //-20 - 80 at base
efficiency = (capacitors_rating + 1) * 10000
targetTemperature = clamp(targetTemperature,
max(settableTemperatureMedian - settableTemperatureRange, TCMB),
settableTemperatureMedian + settableTemperatureRange)
chem_heating_power = efficiency/20000 //1-2.5
#undef HEATER_MODE_STANDBY
#undef HEATER_MODE_HEAT
#undef HEATER_MODE_COOL
#undef HEATER_MODE_AUTO
@@ -22,6 +22,8 @@
/obj/effect/particle_effect/water/Bump(atom/A)
if(reagents)
reagents.expose(A)
if(A.reagents)
A.reagents.expose_temperature(-25)
return ..()
@@ -51,3 +53,7 @@
/datum/effect_system/steam_spread
effect_type = /obj/effect/particle_effect/steam
/obj/effect/particle_effect/water/Bump(atom/A)
if(A.reagents && reagents)
A.reagents.expose_temperature(reagents.chem_temp)
+22
View File
@@ -44,6 +44,28 @@
sprite_name = "miniFE"
dog_fashion = null
/obj/item/extinguisher/crafted
name = "Improvised cooling spray"
desc = "Spraycan turned coolant dipsenser. Can be sprayed on containers to cool them. Refll using water."
icon_state = "coolant0"
inhand_icon_state = "miniFE"
hitsound = null //it is much lighter, after all.
flags_1 = null //doesn't CONDUCT_1
throwforce = 1
w_class = WEIGHT_CLASS_SMALL
force = 3
custom_materials = list(/datum/material/iron = 50, /datum/material/glass = 40)
max_water = 30
sprite_name = "coolant"
dog_fashion = null
cooling_power = 1.5
power = 3
/obj/item/extinguisher/crafted/attack_self(mob/user)
safety = !safety
icon_state = "[sprite_name][!safety]"
to_chat(user, "[safety ? "You remove the straw and put it on the side of the cool canister" : "You insert the straw, readying it for use"].")
/obj/item/extinguisher/proc/refill()
if(!chem)
return
@@ -116,6 +116,20 @@
if(hotness && reagents)
reagents.expose_temperature(hotness)
to_chat(user, "<span class='notice'>You heat [name] with [I]!</span>")
//Cooling method
if(istype(I, /obj/item/extinguisher))
var/obj/item/extinguisher/extinguisher = I
if(extinguisher.safety)
return
if(extinguisher.reagents.total_volume < 1)
to_chat(user, "<span class='warning'>\The [extinguisher] is empty!</span>")
return
var/cooling = (0 - reagents.chem_temp) * (extinguisher.cooling_power * 2)
reagents.expose_temperature(cooling)
to_chat(user, "<span class='notice'>You cool the [name] with the [I]!</span>")
playsound(loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3)
extinguisher.reagents.remove_all(1)
..()
/obj/item/reagent_containers/food/drinks/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
@@ -66,7 +66,7 @@
new /obj/item/food/chocolatebar(location)
return
/datum/chemical_reaction/soysauce
/datum/chemical_reaction/food/soysauce
results = list(/datum/reagent/consumable/soysauce = 5)
required_reagents = list(/datum/reagent/consumable/soymilk = 4, /datum/reagent/toxin/acid = 1)
+204 -35
View File
@@ -79,45 +79,15 @@
var/used = FALSE
/obj/item/ph_paper/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
var/obj/item/reagent_containers/cont = target
if(!istype(cont))
if(!is_reagent_container(target))
return
var/obj/item/reagent_containers/cont = target
if(used == TRUE)
to_chat(user, "<span class='warning'>[src] has already been used!</span>")
return
if(!LAZYLEN(cont.reagents.reagent_list))
return
switch(round(cont.reagents.ph, 1))
if(14 to INFINITY)
color = "#462c83"
if(13 to 14)
color = "#63459b"
if(12 to 13)
color = "#5a51a2"
if(11 to 12)
color = "#3853a4"
if(10 to 11)
color = "#3f93cf"
if(9 to 10)
color = "#0bb9b7"
if(8 to 9)
color = "#23b36e"
if(7 to 8)
color = "#3aa651"
if(6 to 7)
color = "#4cb849"
if(5 to 6)
color = "#b5d335"
if(4 to 5)
color = "#f7ec1e"
if(3 to 4)
color = "#fbc314"
if(2 to 3)
color = "#f26724"
if(1 to 2)
color = "#ef1d26"
if(-INFINITY to 1)
color = "#c6040c"
CONVERT_PH_TO_COLOR(round(cont.reagents.ph, 1), color)
desc += " The paper looks to be around a pH of [round(cont.reagents.ph, 1)]"
name = "used [name]"
used = TRUE
@@ -130,7 +100,6 @@
desc = "An electrode attached to a small circuit box that will display details of a solution. Can be toggled to provide a description of each of the reagents. The screen currently displays nothing."
icon_state = "pHmeter"
icon = 'icons/obj/chemical.dmi'
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
///level of detail for output for the meter
var/scanmode = DETAILED_CHEM_OUTPUT
@@ -145,7 +114,7 @@
/obj/item/ph_meter/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!istype(target, /obj/item/reagent_containers))
if(!is_reagent_container(target))
return
var/obj/item/reagent_containers/cont = target
if(LAZYLEN(cont.reagents.reagent_list) == null)
@@ -162,3 +131,203 @@
out_message += "<b>Analysis:</b> [R.description]\n"
to_chat(user, "[out_message.Join()]</span>")
desc = "An electrode attached to a small circuit box that will display details of a solution. Can be toggled to provide a description of each of the reagents. The screen currently displays detected vol: [round(cont.volume, 0.01)] detected pH:[round(cont.reagents.ph, 0.1)]."
/obj/item/burner
name = "Alcohol burner"
desc = "A small table size burner used for heating up beakers."
icon = 'icons/obj/chemical.dmi'
icon_state = "burner"
grind_results = list(/datum/reagent/consumable/ethanol = 5, /datum/reagent/silicon = 10)
item_flags = NOBLUDGEON
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
heat = 2000
///If the flame is lit - i.e. if we're processing and burning
var/lit = FALSE
///total reagent volume
var/max_volume = 50
///What the creation reagent is
var/reagent_type = /datum/reagent/consumable/ethanol
/obj/item/burner/Initialize()
. = ..()
create_reagents(max_volume, TRANSPARENT)//We have our own refillable - since we want to heat and pour
if(reagent_type)
reagents.add_reagent(reagent_type, 15)
/obj/item/burner/attackby(obj/item/I, mob/living/user, params)
. = ..()
if(is_reagent_container(I))
if(lit)
var/obj/item/reagent_containers/container = I
container.reagents.expose_temperature(get_temperature())
to_chat(user, "<span class='notice'>You heat up the [I] with the [src].</span>")
playsound(user.loc, 'sound/chemistry/heatdam.ogg', 50, TRUE)
return
else if(I.is_drainable()) //Transfer FROM it TO us. Special code so it only happens when flame is off.
var/obj/item/reagent_containers/container = I
if(!container.reagents.total_volume)
to_chat(user, "<span class='warning'>[container] is empty and can't be poured!</span>")
return
if(reagents.holder_full())
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
var/trans = container.reagents.trans_to(src, container.amount_per_transfer_from_this, transfered_by = user)
to_chat(user, "<span class='notice'>You fill [src] with [trans] unit\s of the contents of [container].</span>")
if(I.heat < 1000)
return
set_lit(TRUE)
user.visible_message("<span class='notice'>[user] lights up the [src].</span>")
/obj/item/burner/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(lit)
if(is_reagent_container(target))
var/obj/item/reagent_containers/container = target
container.reagents.expose_temperature(get_temperature())
to_chat(user, "<span class='notice'>You heat up the [src].</span>")
playsound(user.loc, 'sound/chemistry/heatdam.ogg', 50, TRUE)
return
else if(isitem(target))
var/obj/item/item = target
if(item.heat > 1000)
set_lit(TRUE)
user.visible_message("<span class='notice'>[user] lights up the [src].</span>")
/obj/item/burner/update_icon_state()
. = ..()
icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
/obj/item/burner/proc/set_lit(new_lit)
if(lit == new_lit)
return
lit = new_lit
if(lit)
force = 5
damtype = BURN
hitsound = 'sound/items/welder.ogg'
attack_verb_continuous = string_list(list("burns", "sings"))
attack_verb_simple = string_list(list("burn", "sing"))
START_PROCESSING(SSobj, src)
else
hitsound = "swing_hit"
force = 0
attack_verb_continuous = null //human_defense.dm takes care of it
attack_verb_simple = null
STOP_PROCESSING(SSobj, src)
set_light_on(lit)
update_icon()
/obj/item/burner/extinguish()
set_lit(FALSE)
/obj/item/burner/attack_self(mob/living/user)
. = ..()
if(.)
return
if(lit)
set_lit(FALSE)
user.visible_message("<span class='notice'>[user] snuffs out [src]'s flame.</span>")
/obj/item/burner/attack(mob/living/carbon/M, mob/living/carbon/user)
if(lit && M.IgniteMob())
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
return ..()
/obj/item/burner/process()
var/current_heat = 0
var/number_of_burning_reagents = 0
for(var/datum/reagent/reagent as anything in reagents.reagent_list)
reagent.burn(reagents) //burn can set temperatures of reagents
if(!isnull(reagent.burning_temperature))
current_heat += reagent.burning_temperature
number_of_burning_reagents += 1
reagents.remove_reagent(reagent.type, reagent.burning_volume)
continue
if(!number_of_burning_reagents)
set_lit(FALSE)
heat = 0
return
open_flame()
current_heat /= number_of_burning_reagents
heat = current_heat
/obj/item/burner/get_temperature()
return lit * heat
/obj/item/burner/oil
name = "Oil burner"
reagent_type = /datum/reagent/fuel/oil
grind_results = list(/datum/reagent/fuel/oil = 5, /datum/reagent/silicon = 10)
/obj/item/burner/fuel
name = "Fuel burner"
reagent_type = /datum/reagent/fuel
grind_results = list(/datum/reagent/fuel = 5, /datum/reagent/silicon = 10)
/obj/item/thermometer
name = "thermometer"
desc = "A thermometer for checking a beaker's temperature"
icon_state = "thermometer"
icon = 'icons/obj/chemical.dmi'
item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_TINY
grind_results = list(/datum/reagent/mercury = 5)
///The reagents datum that this object is attached to, so we know where we are when it's added to something.
var/datum/reagents/attached_to_reagents
/obj/item/thermometer/Destroy()
QDEL_NULL(attached_to_reagents) //I have no idea how you can destroy this, but not the beaker, but here we go
return ..()
/obj/item/thermometer/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(target.reagents)
if(!user.transferItemToLoc(src, target))
return
attached_to_reagents = target.reagents
to_chat(user, "<span class='notice'>You add the [src] to the [target].</span>")
ui_interact(usr, null)
/obj/item/thermometer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Thermometer", name)
ui.open()
/obj/item/thermometer/ui_close(mob/user)
. = ..()
remove_thermometer(user)
/obj/item/thermometer/ui_status(mob/user)
if(!(in_range(src, user)))
return UI_CLOSE
return UI_INTERACTIVE
/obj/item/thermometer/ui_state(mob/user)
return GLOB.physical_state
/obj/item/thermometer/ui_data(mob/user)
if(!attached_to_reagents)
ui_close(user)
var/data = list()
data["Temperature"] = round(attached_to_reagents.chem_temp)
return data
/obj/item/thermometer/proc/remove_thermometer(mob/target)
try_put_in_hand(src, target)
attached_to_reagents = null
/obj/item/thermometer/proc/try_put_in_hand(obj/object, mob/living/user)
to_chat(user, "<span class='notice'>You remove the [src] from the [attached_to_reagents.my_atom].</span>")
if(!issilicon(user) && in_range(src.loc, user))
user.put_in_hands(object)
else
object.forceMove(drop_location())
/obj/item/thermometer/pen
color = "#888888"
+10 -1
View File
@@ -81,10 +81,15 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
var/impure_chem = /datum/reagent/impurity
/// If the impurity is below 0.5, replace ALL of the chem with inverse_chem upon metabolising
var/inverse_chem_val = 0.25
/// What chem is metabolised when purity is below inverse_chem_val
/// What chem is metabolised when purity is below inverse_chem_val
var/inverse_chem = /datum/reagent/impurity/toxic
///what chem is made at the end of a reaction IF the purity is below the recipies purity_min at the END of a reaction only
var/failed_chem = /datum/reagent/consumable/failed_reaction
///Thermodynamic vars
///How hot this reagent burns when it's on fire - null means it can't burn
var/burning_temperature = null
///How much is consumed when it is burnt per second
var/burning_volume = 0.5
///Assoc list with key type of addiction this reagent feeds, and value amount of addiction points added per unit of reagent metabolzied (which means * REAGENTS_METABOLISM every life())
var/list/addiction_types = null
@@ -129,6 +134,10 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
return SEND_SIGNAL(src, COMSIG_REAGENT_EXPOSE_TURF, exposed_turf, reac_volume)
///Called whenever a reagent is on fire, or is in a holder that is on fire. (WIP)
/datum/reagent/proc/burn(datum/reagents/holder)
return
/// Called from [/datum/reagents/proc/metabolize]
/datum/reagent/proc/on_mob_life(mob/living/carbon/M, delta_time, times_fired)
current_cycle++
@@ -14,6 +14,8 @@
taste_description = "alcohol"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
ph = 7.33
burning_temperature = 2193//ethanol burns at 1970C (at it's peak)
burning_volume = 0.1
var/boozepwr = 65 //Higher numbers equal higher hardness, higher hardness equals more intense alcohol poisoning
/*
@@ -156,6 +156,8 @@
color = "#0000C8"
taste_description = "blue"
ph = 11
burning_temperature = 20 //cold burning
burning_volume = 0.1
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
/datum/reagent/medicine/cryoxadone/on_mob_life(mob/living/carbon/M, delta_time, times_fired)
@@ -12,6 +12,12 @@
penetrates_skin = NONE
ph = 7.4
// FEED ME
/datum/reagent/blood/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray)
. = ..()
if(chems.has_reagent(type, 1))
mytray.adjustPests(rand(2,3))
/datum/reagent/blood/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message=TRUE, touch_protection=0)
. = ..()
if(data && data["viruses"])
@@ -224,6 +230,14 @@
ph = 7.5 //God is alkaline
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
// Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits. Also ALSO increases instability.
/datum/reagent/water/holywater/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray)
if(chems.has_reagent(type, 1))
mytray.adjustWater(round(chems.get_reagent_amount(type) * 1))
mytray.adjustHealth(round(chems.get_reagent_amount(type) * 0.1))
if(myseed)
myseed.adjust_instability(round(chems.get_reagent_amount(type) * 0.15))
/datum/reagent/water/holywater/on_mob_metabolize(mob/living/L)
..()
ADD_TRAIT(L, TRAIT_HOLY, type)
@@ -1103,6 +1117,8 @@
glass_desc = "Unless you're an industrial tool, this is probably not safe for consumption."
penetrates_skin = NONE
ph = 4
burning_temperature = 1725 //more refined than oil
burning_volume = 0.2
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
addiction_types = list(/datum/addiction/alcohol = 4)
@@ -1711,6 +1727,8 @@
reagent_state = LIQUID
color = "#2D2D2D"
taste_description = "oil"
burning_temperature = 1200//Oil is crude
burning_volume = 0.05 //but has a lot of hydrocarbons
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
addiction_types = null
@@ -2573,3 +2591,16 @@
M.adjustBruteLoss(2 * REM * delta_time, FALSE)
..()
/datum/reagent/universal_indicator
name = "Universal indicator"
description = "A solution that can be used to create pH paper booklets, or sprayed on things to colour them by their pH."
taste_description = "a strong chemical taste"
color = "#1f8016"
//Colours things by their pH
/datum/reagent/universal_indicator/expose_atom(atom/exposed_atom, reac_volume)
. = ..()
if(exposed_atom.reagents)
var/color
CONVERT_PH_TO_COLOR(exposed_atom.reagents.ph, color)
exposed_atom.add_atom_colour(color, WASHABLE_COLOUR_PRIORITY)
@@ -216,8 +216,14 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "bitterness"
self_consuming = TRUE
burning_volume = 0.05
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
/datum/reagent/cryostylane/burn(datum/reagents/holder)
if(holder.has_reagent(/datum/reagent/oxygen))
burning_temperature = 0//king chilly
return
burning_temperature = null
/datum/reagent/cryostylane/on_mob_life(mob/living/carbon/M, delta_time, times_fired) //TODO: code freezing into an ice cube
if(M.reagents.has_reagent(/datum/reagent/oxygen))
@@ -242,6 +248,8 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "bitterness"
self_consuming = TRUE
burning_temperature = null
burning_volume = 0.05
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
/datum/reagent/pyrosium/on_mob_life(mob/living/carbon/M, delta_time, times_fired)
@@ -253,6 +261,12 @@
humi.adjust_coretemperature(15 * REM * delta_time)
..()
/datum/reagent/pyrosium/burn(datum/reagents/holder)
if(holder.has_reagent(/datum/reagent/oxygen))
burning_temperature = 3500
return
burning_temperature = null
/datum/reagent/teslium //Teslium. Causes periodic shocks, and makes shocks against the target much more effective.
name = "Teslium"
description = "An unstable, electrically-charged metallic slurry. Periodically electrocutes its victim, and makes electrocutions against them more deadly. Excessively heating teslium results in dangerous destabilization. Do not allow to come into contact with water."
@@ -78,6 +78,8 @@
material = /datum/material/plasma
penetrates_skin = NONE
ph = 4
burning_temperature = 4500//plasma is hot!!
burning_volume = 0.3//But burns fast
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
/datum/reagent/toxin/plasma/on_new(data)
@@ -21,7 +21,6 @@
///Determines if a chemical reaction can occur inside a mob
var/mob_react = TRUE
///The message shown to nearby people upon mixing, if applicable
var/mix_message = "The solution begins to bubble."
///The sound played upon mixing, if applicable
@@ -643,3 +643,50 @@
for(var/i in 1 to created_volume)
new /obj/item/stack/sheet/mineral/silver(location)
//////////////////////////////////// Water ////////////////////////////////////////////////
/datum/chemical_reaction/ice
results = list(/datum/reagent/consumable/ice = 1.09)//density
required_reagents = list(/datum/reagent/water = 1)
is_cold_recipe = TRUE
required_temp = 274 // So we can be sure that basic ghetto rigged stuff can freeze
optimal_temp = 200
overheat_temp = 0
optimal_ph_min = 0
optimal_ph_max = 14
thermic_constant = 0
H_ion_release = 0
rate_up_lim = 50
purity_min = 0
mix_message = "The solution freezes up into ice!"
reaction_flags = REACTION_COMPETITIVE
/datum/chemical_reaction/water
results = list(/datum/reagent/water = 0.92)//rough density excahnge
required_reagents = list(/datum/reagent/consumable/ice = 1)
required_temp = 275
optimal_temp = 350
overheat_temp = 99999
optimal_ph_min = 0
optimal_ph_max = 14
thermic_constant = 0
H_ion_release = 0
rate_up_lim = 50
purity_min = 0
mix_message = "The ice melts back into water!"
////////////////////////////////////
/datum/chemical_reaction/universal_indicator
results = list(/datum/reagent/universal_indicator = 3)//rough density excahnge
required_reagents = list(/datum/reagent/ash = 1, /datum/reagent/consumable/ethanol = 1, /datum/reagent/iodine = 1)
required_temp = 274
optimal_temp = 350
overheat_temp = 99999
optimal_ph_min = 0
optimal_ph_max = 14
thermic_constant = 0
H_ion_release = 0
rate_up_lim = 50
purity_min = 0
mix_message = "The mixture's colors swirl together."
@@ -32,9 +32,6 @@
RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change)
RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del)
/obj/item/reagent_containers/Destroy()
return ..()
/obj/item/reagent_containers/attack(mob/living/M, mob/living/user, params)
if (!user.combat_mode)
return
@@ -86,6 +86,20 @@
reagents.expose_temperature(hotness)
to_chat(user, "<span class='notice'>You heat [name] with [I]!</span>")
//Cooling method
if(istype(I, /obj/item/extinguisher))
var/obj/item/extinguisher/extinguisher = I
if(extinguisher.safety)
return
if (extinguisher.reagents.total_volume < 1)
to_chat(user, "<span class='warning'>\The [extinguisher] is empty!</span>")
return
var/cooling = (0 - reagents.chem_temp) * extinguisher.cooling_power * 2
reagents.expose_temperature(cooling)
to_chat(user, "<span class='notice'>You cool the [name] with the [I]!</span>")
playsound(loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3)
extinguisher.reagents.remove_all(1)
if(istype(I, /obj/item/food/egg)) //breaking eggs
var/obj/item/food/egg/E = I
if(reagents)
@@ -129,6 +129,21 @@
if(hotness && reagents)
reagents.expose_temperature(hotness)
to_chat(user, "<span class='notice'>You heat [name] with [I]!</span>")
//Cooling method
if(istype(I, /obj/item/extinguisher))
var/obj/item/extinguisher/extinguisher = I
if(extinguisher.safety)
return
if (extinguisher.reagents.total_volume < 1)
to_chat(user, "<span class='warning'>\The [extinguisher] is empty!</span>")
return
var/cooling = (0 - reagents.chem_temp) * extinguisher.cooling_power * 2
reagents.expose_temperature(cooling)
to_chat(user, "<span class='notice'>You cool the [name] with the [I]!</span>")
playsound(loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3)
extinguisher.reagents.remove_all(1)
return ..()
/obj/item/reagent_containers/spray/verb/empty()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

+5
View File
@@ -30,6 +30,11 @@ export const COLORS = {
burn: '#e67e22',
brute: '#e74c3c',
},
// reagent / chemistry related colours
reagent: {
acidicbuffer: "#fbc314",
basicbuffer: "#3853a4",
},
};
// Colors defined in CSS
+72 -73
View File
@@ -1,12 +1,11 @@
import { resolveAsset } from '../assets';
import { round, toFixed } from 'common/math';
import { resolveAsset } from '../assets';
import { useBackend } from '../backend';
import { AnimatedNumber, Box, Button, NumberInput, Section, ProgressBar, Table, RoundGauge, Flex, Icon, TextArea } from '../components';
import { TableCell, TableRow } from '../components/Table';
import { AnimatedNumber, Box, Button, Flex, Icon, NumberInput, ProgressBar, RoundGauge, Section, Table } from '../components';
import { COLORS } from '../constants';
import { Window } from '../layouts';
import { BeakerContents } from './common/BeakerContents';
export const ChemHeater = (props, context) => {
const { act, data } = useBackend(context);
const {
@@ -26,7 +25,7 @@ export const ChemHeater = (props, context) => {
beakerContents = [],
activeReactions = [],
} = data;
return (
return (
<Window
width={330}
height={tutorialMessage ? 680 : 350}>
@@ -51,17 +50,15 @@ export const ChemHeater = (props, context) => {
)}>
<Table>
<Table.Row>
<Table.Cell
bold
collapsing color="label">
<Table.Cell bold collapsing color="label">
Heat
</Table.Cell>
<TableCell />
<Table.Cell />
<Table.Cell bold collapsing color="label">
Buffers
</Table.Cell>
<TableCell />
<TableCell>
<Table.Cell />
<Table.Cell>
<NumberInput
width="45px"
unit="u"
@@ -73,13 +70,13 @@ export const ChemHeater = (props, context) => {
onDrag={(e, value) => act('disp_vol', {
target: value,
})} />
</TableCell>
</Table.Cell>
</Table.Row>
<TableRow>
<TableCell collapsing color="label">
<Table.Row>
<Table.Cell collapsing color="label">
Target:
</TableCell>
<TableCell>
</Table.Cell>
<Table.Cell>
<NumberInput
width="65px"
unit="K"
@@ -91,11 +88,11 @@ export const ChemHeater = (props, context) => {
onDrag={(e, value) => act('temperature', {
target: value,
})} />
</TableCell>
<TableCell collapsing color="label">
</Table.Cell>
<Table.Cell collapsing color="label">
Acidic:
</TableCell>
<TableCell>
</Table.Cell>
<Table.Cell>
<Button
icon={'syringe'}
disabled={!acidicBufferVol}
@@ -104,11 +101,11 @@ export const ChemHeater = (props, context) => {
onClick={() => act('acidBuffer', {
target: 1,
})} />
</TableCell>
<TableCell color={"#fbc314"} textAlign="center">
{acidicBufferVol+"u"}
</TableCell>
<TableCell>
</Table.Cell>
<Table.Cell color={COLORS.reagent.acidicbuffer} textAlign="center">
{acidicBufferVol + "u"}
</Table.Cell>
<Table.Cell>
<Button
icon={'upload'}
tooltip={'Draw all'}
@@ -117,13 +114,13 @@ export const ChemHeater = (props, context) => {
onClick={() => act('acidBuffer', {
target: -100,
})} />
</TableCell>
</TableRow>
<TableRow>
<TableCell collapsing color="label">
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell collapsing color="label">
Reading:
</TableCell>
<TableCell collapsing color="default">
</Table.Cell>
<Table.Cell collapsing color="default">
<Box
width="60px"
textAlign="right">
@@ -133,24 +130,24 @@ export const ChemHeater = (props, context) => {
format={value => toFixed(value) + ' K'} />
) || '—'}
</Box>
</TableCell>
<TableCell collapsing color="label">
</Table.Cell>
<Table.Cell collapsing color="label">
Basic:
</TableCell>
<TableCell>
</Table.Cell>
<Table.Cell>
<Button
icon={'syringe'}
tooltip={'Inject'}
tooltipPosition={"left"}
tooltipPosition={"left"}
disabled={!basicBufferVol}
onClick={() => act('basicBuffer', {
target: 1,
})} />
</TableCell>
<TableCell color={"#3853a4"} textAlign="center">
{basicBufferVol+"u"}
</TableCell>
<TableCell>
</Table.Cell>
<Table.Cell color={COLORS.reagent.basicbuffer} textAlign="center">
{basicBufferVol + "u"}
</Table.Cell>
<Table.Cell>
<Button
icon={'upload'}
tooltip={'Draw all'}
@@ -158,8 +155,8 @@ export const ChemHeater = (props, context) => {
onClick={() => act('basicBuffer', {
target: -100,
})} />
</TableCell>
</TableRow>
</Table.Cell>
</Table.Row>
</Table>
</Section>
{!!isBeakerLoaded && (
@@ -175,7 +172,7 @@ export const ChemHeater = (props, context) => {
<Flex.Item>
<AnimatedNumber value={currentpH}>
{(_, value) => (
<RoundGauge
<RoundGauge
size={1.60}
value={value}
minValue={0}
@@ -205,34 +202,34 @@ export const ChemHeater = (props, context) => {
No active reactions.
</Box>
) || (
<Table collapsing={false} key={"reactions"}>
<TableRow>
<TableCell bold color="label">
<Table>
<Table.Row>
<Table.Cell bold color="label">
Reaction
</TableCell>
<TableCell bold color="label">
</Table.Cell>
<Table.Cell bold color="label">
{upgradeLevel < 4 ? "Status" : "Reaction quality"}
</TableCell>
<TableCell bold color="label">
</Table.Cell>
<Table.Cell bold color="label">
Target
</TableCell>
</TableRow>
</Table.Cell>
</Table.Row>
{activeReactions.map(reaction => (
<TableRow key="reactions">
<TableCell width={'60px'} color={reaction.danger ? "red" : "white"}>
<Table.Row key="reactions">
<Table.Cell width={'60px'} color={reaction.danger && "red"}>
{reaction.name}
</TableCell>
<TableCell width={'100px'} pr={'10px'}>
</Table.Cell>
<Table.Cell width={'100px'} pr={'10px'}>
{upgradeLevel < 4 && (
<Icon
name={reaction.danger ? "exclamation-triangle" : "spinner"}
color={reaction.danger ? "red" : "white"}
spin={reaction.danger ? false : true}
<Icon
name={reaction.danger ? "exclamation-triangle" : "spinner"}
color={reaction.danger && "red"}
spin={!reaction.danger}
ml={2.5} />
) || (
<AnimatedNumber value={reaction.quality}>
{(_, value) => (
<RoundGauge
<RoundGauge
size={1.30}
value={value}
minValue={0}
@@ -250,42 +247,44 @@ export const ChemHeater = (props, context) => {
)}
</AnimatedNumber>
)}
</TableCell>
<TableCell width={'70px'}>
</Table.Cell>
<Table.Cell width={'70px'}>
{upgradeLevel > 2 && (
<ProgressBar
value={reaction.reactedVol}
minValue={0}
maxValue={reaction.targetVol}
textAlign={'center'}
icon={reaction.overheat ? "thermometer-full" : ""}
icon={reaction.overheat && "thermometer-full"}
width={7}
color={reaction.overheat ? "red" : "label"}>
{reaction.targetVol}u
</ProgressBar>
) || (
<Box
color={reaction.danger ? "red" : "white"}
color={reaction.danger && "red"}
ml={2}>
{reaction.targetVol}u
</Box>
)}
</TableCell>
</TableRow>
</Table.Cell>
</Table.Row>
))}
<TableRow />
<Table.Row />
</Table>
)}
</Section>
)}
{tutorialMessage && (
<Section
title="Tutorial"
<Section
title="Tutorial"
style={{
'white-space': 'pre-wrap',
}}>
<img left={-1} mx={-1} src={resolveAsset("chem_help_advisor.gif")} width={"30px"} />
{tutorialMessage}
<img
src={resolveAsset("chem_help_advisor.gif")}
width="30px" />
{tutorialMessage}
</Section>
)}
<Section
@@ -13,6 +13,13 @@ export const SpaceHeater = (props, context) => {
title="Power"
buttons={(
<>
{!!data.chemHacked && (
<Button
icon="eject"
content="Eject beaker"
disabled={!data.beaker}
onClick={() => act('ejectBeaker')} />
)}
<Button
icon="eject"
content="Eject Cell"
@@ -0,0 +1,98 @@
import { Component } from 'inferno';
import { useBackend } from '../backend';
import { Box, Stack } from '../components';
import { Window } from '../layouts';
export class Thermometer extends Component {
componentDidMount() {
Byond.winset(window.__windowId__, {
'transparent-color': '#242322',
});
}
componentWillUnmount() {
Byond.winset(window.__windowId__, {
'transparent-color': null,
});
}
render() {
const { act, data } = useBackend(this.context);
return (
<Window
width={70}
height={430}>
<Stack
fill
align="center"
justify="space-around"
backgroundColor="#242322"
style={{
'background-image': "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEVya3UjIyN3S/1dAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAMSURBVAjXY2hgcAAAAcQAwUlFKkkAAAAASUVORK5CYII=')",
}}>
<Stack.Item ml={1}>
<ThermometerIcon
temperature={data.Temperature}
maxTemperature={1000} />
</Stack.Item>
</Stack>
</Window>
);
}
}
const ThermometerIcon = props => {
const { temperature, maxTemperature } = props;
return (
<Box>
<Box
style={{
'position': 'relative',
'width': '22px',
'height': '340px',
'margin': '0 auto',
'background-color': '#595959',
'border': '4px solid #363636',
'border-radius': '12px',
'border-bottom': 'none',
'border-index': '0',
'box-shadow': '4px 4px #000000',
}}>
<Box
style={{
'position': 'absolute',
'width': '5x',
'bottom': 0,
'left': '0px',
'right': 0,
'transition': 'height 2s ease-out',
// Temp in %
'height': `${((temperature / maxTemperature)*100)}%`,
'background-color': '#bd2020',
'border-radius': '8px',
'border-bottom': 'none',
'z-index': '1',
}} />
</Box>
<Box
style={{
'position': 'relative',
'width': '56px',
'line-height': '48px',
'text-align': 'center',
'margin': '-8px auto 0 auto',
'background-color': '#bd2020',
'border': '4px solid #363636',
'border-spacing': '5px',
'border-radius': '35px',
'border-index': '1',
'border-bottom': '0.1',
'box-shadow': '4px 4px #000000',
'z-index': '0',
}}>
{temperature}K
</Box>
</Box>
);
};