diff --git a/baystation12.dme b/baystation12.dme index ccda06046aa..f64b9f8e6b6 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -684,6 +684,9 @@ #include "code\modules\admin\verbs\possess.dm" #include "code\modules\admin\verbs\pray.dm" #include "code\modules\admin\verbs\randomverbs.dm" +#include "code\modules\admin\verbs\SDQL.dm" +#include "code\modules\admin\verbs\SDQL_2.dm" +#include "code\modules\admin\verbs\SDQL_2_parser.dm" #include "code\modules\admin\verbs\striketeam.dm" #include "code\modules\admin\verbs\striketeam_syndicate.dm" #include "code\modules\admin\verbs\ticklag.dm" @@ -805,7 +808,6 @@ #include "code\modules\events\spider_infestation.dm" #include "code\modules\events\spontaneous_appendicitis.dm" #include "code\modules\events\viral_infection.dm" -#include "code\modules\events\viral_outbreak.dm" #include "code\modules\events\wallrot.dm" #include "code\modules\ext_scripts\irc.dm" #include "code\modules\ext_scripts\python.dm" @@ -1201,22 +1203,18 @@ #include "code\modules\research\xenoarchaeology\finds\finds_fossils.dm" #include "code\modules\research\xenoarchaeology\finds\finds_misc.dm" #include "code\modules\research\xenoarchaeology\finds\finds_talkingitem.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_accelerator.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_base.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_fourier_transform.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_gas_chromatography.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_hyperspectral.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_ion_mobility.dm" -#include "code\modules\research\xenoarchaeology\machinery\analysis_isotope_ratio.dm" #include "code\modules\research\xenoarchaeology\machinery\artifact_analyser.dm" #include "code\modules\research\xenoarchaeology\machinery\artifact_harvester.dm" #include "code\modules\research\xenoarchaeology\machinery\artifact_scanner.dm" +#include "code\modules\research\xenoarchaeology\machinery\coolant.dm" +#include "code\modules\research\xenoarchaeology\machinery\geosample_scanner.dm" #include "code\modules\research\xenoarchaeology\tools\ano_device_battery.dm" #include "code\modules\research\xenoarchaeology\tools\anomaly_suit.dm" #include "code\modules\research\xenoarchaeology\tools\bunsen_burner.dm" #include "code\modules\research\xenoarchaeology\tools\gearbelt.dm" #include "code\modules\research\xenoarchaeology\tools\suspension_generator.dm" #include "code\modules\research\xenoarchaeology\tools\tools.dm" +#include "code\modules\research\xenoarchaeology\tools\tools_anoscanner.dm" #include "code\modules\research\xenoarchaeology\tools\tools_coresampler.dm" #include "code\modules\research\xenoarchaeology\tools\tools_depthscanner.dm" #include "code\modules\research\xenoarchaeology\tools\tools_locater.dm" @@ -1254,6 +1252,9 @@ #include "code\modules\surgery\ribcage.dm" #include "code\modules\surgery\robolimbs.dm" #include "code\modules\surgery\surgery.dm" +#include "code\modules\telesci\gps.dm" +#include "code\modules\telesci\telepad.dm" +#include "code\modules\telesci\telesci_computer.dm" #include "code\modules\virus2\analyser.dm" #include "code\modules\virus2\antibodies.dm" #include "code\modules\virus2\centrifuge.dm" diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index ed755aac990..131eb8d8bef 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -161,7 +161,7 @@ obj/machinery/atmospherics/pipe proc/burst() src.visible_message("\red \bold [src] bursts!"); playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new + var/datum/effect/effect/system/smoke_spread/smoke = new smoke.set_up(1,0, src.loc, 0) smoke.start() del(src) diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/fusion_reactions.dm b/code/WorkInProgress/Cael_Aislinn/Rust/fusion_reactions.dm index c083cad713a..8293e060f41 100644 --- a/code/WorkInProgress/Cael_Aislinn/Rust/fusion_reactions.dm +++ b/code/WorkInProgress/Cael_Aislinn/Rust/fusion_reactions.dm @@ -145,14 +145,14 @@ datum/fusion_reaction/pergium_tritium energy_production = 0 radiation = 5 -datum/fusion_reaction/pergium_deuterium +datum/fusion_reaction/pergium_obdurium primary_reactant = "Pergium" secondary_reactant = "Obdurium" energy_consumption = 5 energy_production = 0 radiation = 5 -datum/fusion_reaction/pergium_tritium +datum/fusion_reaction/pergium_solonium primary_reactant = "Pergium" secondary_reactant = "Solonium" energy_consumption = 5 diff --git a/code/WorkInProgress/Cib/MedicalSideEffects.dm b/code/WorkInProgress/Cib/MedicalSideEffects.dm index 3419cf54426..62f9cf75f80 100644 --- a/code/WorkInProgress/Cib/MedicalSideEffects.dm +++ b/code/WorkInProgress/Cib/MedicalSideEffects.dm @@ -23,7 +23,8 @@ /datum/medical_effect/proc/cure(mob/living/carbon/human/H) for(var/R in cures) if(H.reagents.has_reagent(R)) - H <<"\red [cure_message]" + if (cure_message) + H <<"\blue [cure_message]" return 1 return 0 @@ -39,16 +40,21 @@ M.start = life_tick return - var/list/L = typesof(/datum/medical_effect)-/datum/medical_effect - for(var/T in L) - var/datum/medical_effect/M = new T - if(M.name == name) - M.strength = strength - M.start = life_tick - side_effects += M + var/T = side_effects[name] + if (!T) + return + + var/datum/medical_effect/M = new T + if(M.name == name) + M.strength = strength + M.start = life_tick + side_effects += M /mob/living/carbon/human/proc/handle_medical_side_effects() + //Going to handle those things only every few ticks. + if(life_tick % 15 != 0) + return 0 var/list/L = typesof(/datum/medical_effect)-/datum/medical_effect for(var/T in L) @@ -60,18 +66,14 @@ for (var/datum/medical_effect/M in side_effects) if (!M) continue var/strength_percent = sin((life_tick - M.start) / 2) - log_debug ("[src], tick [life_tick] : Processing [M], Current phase: [strength_percent]") // Only do anything if the effect is currently strong enough if(strength_percent >= 0.4) - log_debug ("[src], tick [life_tick] : Active phase ; strength [M.strength]") if (M.cure(src) || M.strength > 50) - log_debug ("[src], tick [life_tick] : [M] cured or reached end of lifecycle") side_effects -= M - del(M) + M = null else if(life_tick % 45 == 0) - log_debug ("[src], tick [life_tick] : Activating [M] ") M.on_life(src, strength_percent*M.strength) // Effect slowly growing stronger M.strength+=0.08 @@ -81,7 +83,7 @@ /datum/medical_effect/headache name = "Headache" triggers = list("cryoxadone" = 10, "bicaridine" = 15, "tricordrazine" = 15) - cures = list("alkysine", "tramadol") + cures = list("alkysine", "tramadol", "paracetamol", "oxycodone") cure_message = "Your head stops throbbing..." /datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength) @@ -92,7 +94,6 @@ H.custom_pain("You feel a throbbing pain in your head!",1) if(31 to INFINITY) H.custom_pain("You feel an excrutiating pain in your head!",1) - H.adjustBrainLoss(1) // BAD STOMACH // =========== @@ -110,7 +111,6 @@ H.custom_pain("Your stomach hurts.",0) if(31 to INFINITY) H.custom_pain("You feel sick.",1) - H.adjustToxLoss(1) // CRAMPS // ====== @@ -129,7 +129,6 @@ if(31 to INFINITY) H.emote("me",1,"flinches as all the muscles in their body cramp up.") H.custom_pain("There's pain all over your body.",1) - H.adjustToxLoss(1) // ITCH // ==== @@ -148,4 +147,3 @@ if(31 to INFINITY) H.emote("me",1,"shivers slightly.") H.custom_pain("This itch makes it really hard to concentrate.",1) - H.adjustToxLoss(1) \ No newline at end of file diff --git a/code/WorkInProgress/Cib/amorph/life.dm b/code/WorkInProgress/Cib/amorph/life.dm index 14c4d41ccab..e23662bbbba 100644 --- a/code/WorkInProgress/Cib/amorph/life.dm +++ b/code/WorkInProgress/Cib/amorph/life.dm @@ -148,7 +148,7 @@ if(!block) - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) smoke.reagents.reaction(src, INGEST) spawn(5) diff --git a/code/WorkInProgress/explosion_particles.dm b/code/WorkInProgress/explosion_particles.dm index 11e2cc4f01f..90020e50801 100644 --- a/code/WorkInProgress/explosion_particles.dm +++ b/code/WorkInProgress/explosion_particles.dm @@ -65,6 +65,6 @@ P.set_up(10,location) P.start() spawn(5) - var/datum/effect/effect/system/harmless_smoke_spread/S = new/datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/S = new/datum/effect/effect/system/smoke_spread() S.set_up(5,0,location,null) S.start() \ No newline at end of file diff --git a/code/WorkInProgress/kilakk/fax.dm b/code/WorkInProgress/kilakk/fax.dm index 7ab0440a6bc..76bcc0baa40 100644 --- a/code/WorkInProgress/kilakk/fax.dm +++ b/code/WorkInProgress/kilakk/fax.dm @@ -1,19 +1,35 @@ +var/list/obj/machinery/faxmachine/allfaxes = list() +var/list/alldepartments = list("Central Command") + /obj/machinery/faxmachine name = "fax machine" icon = 'icons/obj/library.dmi' icon_state = "fax" - req_access = list(access_lawyer) + req_one_access = list(access_lawyer, access_heads) anchored = 1 density = 1 use_power = 1 idle_power_usage = 30 active_power_usage = 200 power_channel = EQUIP + var/obj/item/weapon/card/id/scan = null // identification var/authenticated = 0 - var/obj/item/weapon/paper/tofax = null // what we're sending to central + + var/obj/item/weapon/paper/tofax = null // what we're sending var/sendcooldown = 0 // to avoid spamming fax messages + var/department = "Unknown" // our department + + var/dpt = "Central Command" // the department we're sending to + +/obj/machinery/faxmachine/New() + ..() + allfaxes += src + + if( !("[department]" in alldepartments) ) + alldepartments += department + /obj/machinery/faxmachine/process() return 0 @@ -26,7 +42,7 @@ /obj/machinery/faxmachine/attack_hand(mob/user as mob) user.set_machine(src) - var/dat = "Central Command Fax Machine
" + var/dat = "Fax Machine
" var/scan_name if(scan) @@ -54,14 +70,15 @@ else dat += "Send
" - dat += "Currently sending: [tofax.name]" + dat += "Currently sending: [tofax.name]
" + dat += "Sending to: [dpt]
" else if(sendcooldown) - dat += "Please insert paper to send to Central Command via secure connection.

" + dat += "Please insert paper to send via secure connection.

" dat += "Transmitter arrays realigning. Please stand by.
" else - dat += "Please insert paper to send to Central Command via secure connection.

" + dat += "Please insert paper to send via secure connection.

" else dat += "Proper authentication is required to use this device.

" @@ -76,10 +93,18 @@ /obj/machinery/faxmachine/Topic(href, href_list) if(href_list["send"]) if(tofax) - Centcomm_fax(tofax.info, tofax.name, usr) - usr << "Message transmitted." - sendcooldown = 1 - spawn(3000) // three minute cooldown. might mess with this number a bit as time goes on + + if(dpt == "Central Command") + Centcomm_fax(tofax.info, tofax.name, usr) + sendcooldown = 1800 + + else + SendFax(tofax.info, tofax.name, usr, dpt) + sendcooldown = 600 + + usr << "Message transmitted successfully." + + spawn(sendcooldown) // cooldown time sendcooldown = 0 if(href_list["remove"]) @@ -107,6 +132,9 @@ scan = I authenticated = 0 + if(href_list["dept"]) + dpt = input(usr, "Which department?", "Choose a department", "") as null|anything in alldepartments + if(href_list["auth"]) if ( (!( authenticated ) && (scan)) ) if (check_access(scan)) @@ -148,3 +176,20 @@ var/msg = "\blue CENTCOMM FAX: [key_name(Sender, 1)] (PP) (VV) (SM) (JMP) (CA) (RPLY): Receiving '[sentname]' via secure connection ... view message" admins << msg + +proc/SendFax(var/sent, var/sentname, var/mob/Sender, var/dpt) + + for(var/obj/machinery/faxmachine/F in allfaxes) + if( F.department == dpt ) + if(! (F.stat & (BROKEN|NOPOWER) ) ) + + flick("faxreceive", F) + + // give the sprite some time to flick + spawn(20) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( F.loc ) + P.name = "[sentname]" + P.info = "[sent]" + P.update_icon() + + playsound(F.loc, "sound/items/polaroid1.ogg", 50, 1) diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index 8370e717ba4..a40746f52f6 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -11,8 +11,6 @@ Attach to transfer valve and open. BOOM. */ - - //Some legacy definitions so fires can be started. atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) return null @@ -21,160 +19,164 @@ atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) - turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) - if(fire_protection > world.time-300) return - var/datum/gas_mixture/air_contents = return_air(1) - if(!air_contents) + if(fire_protection > world.time-300) return 0 - - /*if(active_hotspot) - if(soh) - if(air_contents.toxins > 0.5 && air_contents.oxygen > 0.5) - if(active_hotspot.temperature < exposed_temperature) - active_hotspot.temperature = exposed_temperature - if(active_hotspot.volume < exposed_volume) - active_hotspot.volume = exposed_volume - return 1*/ - var/igniting = 0 if(locate(/obj/fire) in src) return 1 - var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases + var/datum/gas_mixture/air_contents = return_air() + if(!air_contents || exposed_temperature < PLASMA_MINIMUM_BURN_TEMPERATURE) + return 0 + + var/igniting = 0 var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in src - if(air_contents.calculate_firelevel(liquid) > vsc.IgnitionLevel && (fuel || liquid || air_contents.toxins > 0.5)) + + if(air_contents.check_combustability(liquid)) igniting = 1 - if(air_contents.oxygen < 0.5) - return 0 if(! (locate(/obj/fire) in src)) - var/obj/fire/F = new(src,1000) - F.temperature = exposed_temperature - F.volume = CELL_VOLUME - //active_hotspot.just_spawned = (current_cycle < air_master.current_cycle) - //remove just_spawned protection if no longer processing this cell + new /obj/fire(src,1000) return igniting -obj - fire - //Icon for fire on turfs. +/obj/fire + //Icon for fire on turfs. - anchored = 1 - mouse_opacity = 0 + anchored = 1 + mouse_opacity = 0 - //luminosity = 3 + //luminosity = 3 - icon = 'icons/effects/fire.dmi' + icon = 'icons/effects/fire.dmi' + icon_state = "1" + + layer = TURF_LAYER + + var/firelevel = 10000 //Calculated by gas_mixture.calculate_firelevel() + +/obj/fire/process() + . = 1 + + //get location and check if it is in a proper ZAS zone + var/turf/simulated/S = loc + + if(!istype(S)) + del src + + if(!S.zone) + del src + + var/datum/gas_mixture/air_contents = S.return_air() + //get liquid fuels on the ground. + var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S + //and the volatile stuff from the air + var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases + + //since the air is processed in fractions, we need to make sure not to have any minuscle residue or + //the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour + if(air_contents.oxygen < 0.001) + air_contents.oxygen = 0 + if(air_contents.toxins < 0.001) + air_contents.toxins = 0 + if(fuel) + if(fuel.moles < 0.001) + air_contents.trace_gases.Remove(fuel) + + //check if there is something to combust + if(!air_contents.check_recombustability(liquid)) + //del src + RemoveFire() + + //get a firelevel and set the icon + firelevel = air_contents.calculate_firelevel(liquid) + + if(firelevel > 6) + icon_state = "3" + SetLuminosity(7) + else if(firelevel > 2.5) + icon_state = "2" + SetLuminosity(5) + else icon_state = "1" + SetLuminosity(3) - var - volume = CELL_VOLUME - temperature = PLASMA_MINIMUM_BURN_TEMPERATURE - firelevel = 10000 //Calculated by gas_mixture.calculate_firelevel() - archived_firelevel = 0 + //im not sure how to implement a version that works for every creature so for now monkeys are firesafe + for(var/mob/living/carbon/human/M in loc) + M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure() ) //Burn the humans! + for(var/atom/A in loc) + A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume()) + //spread + for(var/direction in cardinal) + if(S.air_check_directions&direction) //Grab all valid bordering tiles - process() - . = 1 + var/turf/simulated/enemy_tile = get_step(S, direction) - if(firelevel > vsc.IgnitionLevel) + if(istype(enemy_tile)) + var/datum/gas_mixture/acs = enemy_tile.return_air() + var/obj/effect/decal/cleanable/liquid_fuel/liq = locate() in enemy_tile + if(!acs) continue + if(!acs.check_recombustability(liq)) continue + //If extinguisher mist passed over the turf it's trying to spread to, don't spread and + //reduce firelevel. + if(enemy_tile.fire_protection > world.time-30) + firelevel -= 1.5 + continue - var/turf/simulated/floor/S = loc - if(!S.zone) del src //Cannot exist where zones are broken. + //Spread the fire. + if(!(locate(/obj/fire) in enemy_tile)) + if( prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0)) + new/obj/fire(enemy_tile,firelevel) - if(istype(S)) - var - datum/gas_mixture/air_contents = S.return_air() - //Get whatever trace fuels are in the area - datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases - //Also get liquid fuels on the ground. - obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S + //seperate part of the present gas + //this is done to prevent the fire burning all gases in a single pass + var/datum/gas_mixture/flow = air_contents.remove_ratio(vsc.fire_consuption_rate) +///////////////////////////////// FLOW HAS BEEN CREATED /// DONT DELETE THE FIRE UNTIL IT IS MERGED BACK OR YOU WILL DELETE AIR /////////////////////////////////////////////// - var/datum/gas_mixture/flow = air_contents.remove_ratio(0.25) - //The reason we're taking a part of the air instead of all of it is so that it doesn't jump to - //the fire's max temperature instantaneously. + if(flow) - firelevel = air_contents.calculate_firelevel(liquid) + if(flow.check_recombustability(liquid)) + //Ensure flow temperature is higher than minimum fire temperatures. + //this creates some energy ex nihilo but is necessary to get a fire started + //lets just pretend this energy comes from the ignition source and dont mention this again + //flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) - //Ensure that there is an appropriate amount of fuel and O2 here. - if(firelevel > 0.25 && flow.oxygen > 0.3 && (air_contents.toxins || fuel || liquid)) + //burn baby burn! - for(var/direction in cardinal) - if(S.air_check_directions&direction) //Grab all valid bordering tiles + flow.zburn(liquid,1) + //merge the air back + S.assume_air(flow) - var/turf/simulated/enemy_tile = get_step(S, direction) - - if(istype(enemy_tile)) - //If extinguisher mist passed over the turf it's trying to spread to, don't spread and - //reduce firelevel. - if(enemy_tile.fire_protection > world.time-30) - firelevel -= 1.5 - continue - - //Spread the fire. - if(!(locate(/obj/fire) in enemy_tile)) - if( prob( firelevel*10 ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0)) - new/obj/fire(enemy_tile,firelevel) - - if(flow) - - //Ensure adequate oxygen and fuel. - if(flow.oxygen > 0.3 && (flow.toxins || fuel || liquid)) - - //Change icon depending on the fuel, and thus temperature. - if(firelevel > 6) - icon_state = "3" - else if(firelevel > 2.5) - icon_state = "2" - else - icon_state = "1" - - //Ensure flow temperature is higher than minimum fire temperatures. - flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) - - //Burn the gas mixture. - flow.zburn(liquid) - if(fuel && fuel.moles <= 0.00001) - del fuel - - else - - del src +///////////////////////////////// FLOW HAS BEEN REMERGED /// feel free to delete the fire again from here on ////////////////////////////////////////////////////////////////// - S.assume_air(flow) //Then put it back where you found it. +/obj/fire/New(newLoc,fl) + ..() - else - del src - else - del src - else - del src + if(!istype(loc, /turf)) + del src + + dir = pick(cardinal) + SetLuminosity(3) + firelevel = fl + air_master.active_hotspots.Add(src) - for(var/mob/living/carbon/human/M in loc) - M.FireBurn(temperature, min(max(0.1,firelevel / 20),10)) //Burn the humans! +/obj/fire/Del() + if (istype(loc, /turf/simulated)) + SetLuminosity(0) + loc = null + air_master.active_hotspots.Remove(src) - New(newLoc,fl) - ..() + ..() - if(!istype(loc, /turf)) - del src +/obj/fire/proc/RemoveFire() + if (istype(loc, /turf/simulated)) + SetLuminosity(0) + loc = null + air_master.active_hotspots.Remove(src) - dir = pick(cardinal) - //sd_SetLuminosity(3,2,0) - firelevel = fl - air_master.active_hotspots.Add(src) - - Del() - if (istype(loc, /turf/simulated)) - //sd_SetLuminosity(0) - - loc = null - air_master.active_hotspots.Remove(src) - - ..() turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again. @@ -182,22 +184,19 @@ turf/proc/apply_fire_protection() turf/simulated/apply_fire_protection() fire_protection = world.time -datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid) - //This proc is similar to fire(), but uses a simple logarithm to calculate temp, and is thus more stable with ZAS. - if(temperature > PLASMA_FLASHPOINT && !reacting) - reacting = 1 +datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn) + var/value = 0 - if(temperature > PLASMA_MINIMUM_BURN_TEMPERATURE && reacting) - var - total_fuel = toxins - fuel_sources = 0 //We'll divide by this later so that fuel is consumed evenly. - datum/gas/volatile_fuel/fuel = locate() in trace_gases + if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid)) + var/total_fuel = 0 + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + + total_fuel += toxins if(fuel) //Volatile Fuel total_fuel += fuel.moles - fuel_sources++ if(liquid) //Liquid Fuel @@ -205,72 +204,126 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid) del liquid else total_fuel += liquid.amount - fuel_sources++ - //Toxins - if(toxins > 0.3) fuel_sources++ + //Calculate the firelevel. + var/firelevel = calculate_firelevel(liquid) - if(!fuel_sources) return 0 //If there's no fuel, there's no burn. Can't divide by zero anyway. + //get the current inner energy of the gas mix + //this must be taken here to prevent the addition or deletion of energy by a changing heat capacity + var/starting_energy = temperature * heat_capacity() - if(oxygen > 0.3) + //determine the amount of oxygen used + var/total_oxygen = min(oxygen, 2 * total_fuel) - //Calculate the firelevel. - var/firelevel = calculate_firelevel(liquid) + //determine the amount of fuel actually used + var/used_fuel_ratio = min(oxygen / 2 , total_fuel) / total_fuel + total_fuel = total_fuel * used_fuel_ratio - //Reaches a maximum practical temperature of around 4500. + var/total_reactants = total_fuel + total_oxygen - //Increase temperature. - temperature = max( 1700*log(0.4*firelevel + 1.23) , temperature ) + //determine the amount of reactants actually reacting + var/used_reactants_ratio = min( max(total_reactants * firelevel / vsc.fire_firelevel_multiplier, 0.2), total_reactants) / total_reactants - //Consume some gas. - var/consumed_gas = min(oxygen,0.05*firelevel,total_fuel) / fuel_sources + //remove and add gasses as calculated + oxygen -= min(oxygen, total_oxygen * used_reactants_ratio ) - oxygen = max(0,oxygen-consumed_gas) + toxins -= min(toxins, (toxins * used_fuel_ratio * used_reactants_ratio ) * 3) + if(toxins < 0) + toxins = 0 - toxins = max(0,toxins-consumed_gas) + carbon_dioxide += max(2 * total_fuel, 0) - carbon_dioxide += consumed_gas*2 + if(fuel) + fuel.moles -= (fuel.moles * used_fuel_ratio * used_reactants_ratio) * 5 //Fuel burns 5 times as quick + if(fuel.moles <= 0) del fuel - if(fuel) - fuel.moles -= consumed_gas - if(fuel.moles <= 0) del fuel + if(liquid) + liquid.amount -= (liquid.amount * used_fuel_ratio * used_reactants_ratio) * 5 // liquid fuel burns 5 times as quick - if(liquid) - liquid.amount -= consumed_gas - if(liquid.amount <= 0) del liquid + if(liquid.amount <= 0) del liquid - update_values() - return consumed_gas*fuel_sources + //calculate the energy produced by the reaction and then set the new temperature of the mix + temperature = (starting_energy + vsc.fire_fuel_energy_release * total_fuel) / heat_capacity() - else - reacting = 0 + update_values() + value = total_reactants * used_reactants_ratio + return value + +datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_fuel/liquid) + //this is a copy proc to continue a fire after its been started. + + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + + if(oxygen && (toxins || fuel || liquid)) + if(liquid) + return 1 + if (toxins) + return 1 + if(fuel) + return 1 return 0 +datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid) + //this check comes up very often and is thus centralized here to ease adding stuff + + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + + if(oxygen && (toxins || fuel || liquid)) + if(liquid) + return 1 + if (toxins >= 0.7) + return 1 + if(fuel && fuel.moles >= 1.4) + return 1 + + return 0 datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid) - //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas. - var - datum/gas/volatile_fuel/fuel = locate() in trace_gases - liquid_concentration = 0 + //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas. - oxy_concentration = oxygen / volume - tox_concentration = toxins / volume - fuel_concentration = 0 + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + var/total_fuel = 0 + var/firelevel = 0 - if(fuel) fuel_concentration = (fuel.moles) / volume - if(liquid) liquid_concentration = (liquid.amount*15) / volume - return (oxy_concentration + tox_concentration + liquid_concentration + fuel_concentration)*100 + if(check_recombustability(liquid)) -/mob/living/carbon/human/proc/FireBurn(last_temperature, mx as num) + total_fuel += toxins + + if(liquid) + total_fuel += liquid.amount + + if(fuel) + total_fuel += fuel.moles + + var/total_combustables = (total_fuel + oxygen) + + if(total_fuel > 0 && oxygen > 0) + + //slows down the burning when the concentration of the reactants is low + var/dampening_multiplier = total_combustables / (total_combustables + nitrogen + carbon_dioxide) + //calculates how close the mixture of the reactants is to the optimum + var/mix_multiplier = 1 / (1 + (5 * ((oxygen / total_combustables) ** 2))) + //toss everything together + firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier + + return max( 0, firelevel) + + +/mob/living/proc/FireBurn(var/firelevel, var/last_temperature, var/pressure) + var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1) + apply_damage(2.5*mx, BURN) + + +/mob/living/carbon/human/FireBurn(var/firelevel, var/last_temperature, var/pressure) //Burns mobs due to fire. Respects heat transfer coefficients on various body parts. + //Due to TG reworking how fireprotection works, this is kinda less meaningful. - var - head_exposure = 1 - chest_exposure = 1 - groin_exposure = 1 - legs_exposure = 1 - arms_exposure = 1 + var/head_exposure = 1 + var/chest_exposure = 1 + var/groin_exposure = 1 + var/legs_exposure = 1 + var/arms_exposure = 1 //Get heat transfer coefficients for clothing. @@ -289,6 +342,8 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue legs_exposure = 0 if(C.body_parts_covered & ARMS) arms_exposure = 0 + //minimize this for low-pressure enviroments + var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1) //Always check these damage procs first if fire damage isn't working. They're probably what's wrong. @@ -299,5 +354,3 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue apply_damage(0.6*mx*legs_exposure, BURN, "r_leg", 0, 0, "Fire") apply_damage(0.4*mx*arms_exposure, BURN, "l_arm", 0, 0, "Fire") apply_damage(0.4*mx*arms_exposure, BURN, "r_arm", 0, 0, "Fire") - - //flash_pain() \ No newline at end of file diff --git a/code/ZAS/Plasma.dm b/code/ZAS/Plasma.dm index 9f0e95f6617..716ea216403 100644 --- a/code/ZAS/Plasma.dm +++ b/code/ZAS/Plasma.dm @@ -118,12 +118,12 @@ obj/var/contaminated = 0 /mob/living/carbon/human/proc/burn_eyes() //The proc that handles eye burning. if(prob(20)) src << "\red Your eyes burn!" - eye_stat += 2.5 + var/datum/organ/internal/eyes/E = internal_organs["eyes"] + E.damage += 2.5 eye_blurry = min(eye_blurry+1.5,50) - if (prob(max(0,eye_stat - 20) + 1) &&!eye_blind) + if (prob(max(0,E.damage - 15) + 1) &&!eye_blind) src << "\red You are blinded!" eye_blind += 20 - eye_stat = 0 /mob/living/carbon/human/proc/pl_head_protected() //Checks if the head is adequately sealed. diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index e73d989aff2..5dd951fe52e 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -1,7 +1,7 @@ var/global/vs_control/vsc = new /vs_control -/* var/fire_consuption_rate = 0.25 + var/fire_consuption_rate = 0.25 var/fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" var/fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." @@ -12,7 +12,7 @@ var/global/vs_control/vsc = new var/fire_fuel_energy_release = 397000 var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" -*/ + var/IgnitionLevel = 0.5 var/IgnitionLevel_DESC = "Determines point at which fire can ignite" diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index d4bc832506b..cd77fbbbf21 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -519,7 +519,7 @@ proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) for(var/datum/gas/G in B.trace_gases) var/datum/gas/H = locate(G.type) in A.trace_gases - if(H) + if(!H) H = new G.type A.trace_gases += H var/G_avg = (G.moles*size) / (size+share_size) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 20bb1bedebc..b0d609c78e9 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -16,6 +16,7 @@ var/global/list/chemical_reactions_list //list of all /datum/chemical_reactio var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff var/global/list/landmarks_list = list() //list of all landmarks created var/global/list/surgery_steps = list() //list of all surgery steps |BS12 +var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12 var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking. //Languages/species/whitelist. @@ -76,6 +77,13 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al surgery_steps += S sort_surgeries() + //Medical side effects. List all effects by their names + paths = typesof(/datum/medical_effect)-/datum/medical_effect + for(var/T in paths) + var/datum/medical_effect/M = new T + side_effects[M.name] = T + + //Languages and species. paths = typesof(/datum/language)-/datum/language for(var/T in paths) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 5ece365899c..5ce15be96e7 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -55,7 +55,7 @@ if(modifiers["ctrl"]) CtrlClickOn(A) return - + if(stat || paralysis || stunned || weakened) return @@ -65,6 +65,8 @@ return if(istype(loc,/obj/mecha)) + if(!locate(/turf) in list(A,A.loc)) // Prevents inventory from being drilled + return var/obj/mecha/M = loc return M.click_action(A,src) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 54a7974d586..a0dcfb9ae9c 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -47,7 +47,7 @@ return 1 if(usr.next_move >= world.time) return - usr.next_move = world.time + 10 + usr.next_move = world.time + 6 if(usr.stat || usr.restrained() || usr.stunned || usr.lying) return 1 @@ -86,6 +86,8 @@ return 1 if(usr.stat || usr.paralysis || usr.stunned || usr.weakened) return 1 + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return 1 if(master) var/obj/item/I = usr.get_active_hand() if(I) @@ -207,6 +209,8 @@ usr.hud_used.hidden_inventory_update() if("equip") + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return 1 if(ishuman(usr)) var/mob/living/carbon/human/H = usr H.quick_equip() @@ -421,6 +425,8 @@ return 1 if(usr.stat || usr.paralysis || usr.stunned || usr.weakened) return 1 + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return 1 switch(name) if("r_hand") if(iscarbon(usr)) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 912ab59b8c6..42ac1cdc97f 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -28,7 +28,7 @@ var/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default) var/vote_period = 600 // length of voting period (deciseconds, default 1 minute) var/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called - var/vote_autotransfer_interval = 3600 // length of time before next sequential autotransfer vote + var/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi) var/vote_no_dead = 0 // dead people can't vote (tbi) // var/enable_authentication = 0 // goon authentication diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index f857a276bb0..452c174b356 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -48,6 +48,7 @@ datum/controller/vote proc/autotransfer() initiate_vote("crew_transfer","the server") + log_debug("The server has called an Autotransfer") proc/reset() @@ -206,14 +207,16 @@ datum/controller/vote return 0 choices.Add(config.votable_modes) if("crew_transfer") - if(check_rights(R_ADMIN) || check_rights(R_MOD)) + if(check_rights(R_ADMIN|R_MOD, 0)) question = "End the shift?" choices.Add("Initiate Crew Transfer", "Continue The Round") else if (get_security_level() == "red" || get_security_level() == "delta") + initiator_key << "The current alert status is too high to call for a crew transfer!" return 0 if(ticker.current_state <= 2) return 0 + initiator_key << "The crew transfer button has been disabled!" question = "End the shift?" choices.Add("Initiate Crew Transfer", "Continue The Round") if("custom") diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 75f2d5f3e5f..346ba7ce299 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -173,11 +173,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin sparks.start() if(smoke_spread) if(smoke_spread == 1) - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is smoke.start() else if(smoke_spread == 2) - var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() + var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is smoke.start() diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 297bdb890da..664b065d1cb 100755 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -456,6 +456,14 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee containername = "fuel tank crate" group = "Engineering" +/datum/supply_packs/coolanttank + name = "Coolant tank crate" + contains = list(/obj/structure/reagent_dispensers/coolanttank) + cost = 16 + containertype = /obj/structure/largecrate + containername = "coolant tank crate" + group = "Medical / Science" + /datum/supply_packs/solar name = "Solar Pack crate" contains = list(/obj/item/solar_assembly, @@ -945,6 +953,25 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Engineering" access = access_ce +/datum/supply_packs/smbig + name = "Supermatter Core" + contains = list(/obj/machinery/power/supermatter) + cost = 50 + containertype = /obj/structure/closet/crate/secure/plasma + containername = "Supermatter crate (CAUTIION)" + access = access_ce + group = "Engineering" + + +/datum/supply_packs/smsmall + name = "Supermatter Shard" + contains = list(/obj/machinery/power/supermatter/shard) + cost = 25 + containertype = /obj/structure/closet/crate/secure/plasma + containername = "Supermatter crate (CAUTIION)" + access = access_ce + group = "Engineering" + /datum/supply_packs/shield_cap contains = list(/obj/item/weapon/circuitboard/shield_cap) name = "Experimental shield capacitor circuitry" diff --git a/code/defines/obj/hydro.dm b/code/defines/obj/hydro.dm index 7cb2439cc68..2b57dbeffa5 100644 --- a/code/defines/obj/hydro.dm +++ b/code/defines/obj/hydro.dm @@ -132,6 +132,40 @@ plant_type = 0 growthstages = 1 +/obj/item/seeds/shandseed + name = "pack of s'rendarr's hand seeds" + desc = "These seeds grow into a helpful herb called S'Rendarr's Hand, native to Ahdomai." + icon_state = "seed-shand" + mypath = "/obj/item/seeds/shandseed" + species = "shand" + plantname = "S'Rendarr's Hand" + productname = "/obj/item/stack/medical/bruise_pack/tajaran" + lifespan = 50 + endurance = 25 + maturation = 3 + production = 5 + yield = 4 + potency = 10 + plant_type = 0 + growthstages = 3 + +/obj/item/seeds/mtearseed + name = "pack of messa's tear seeds" + desc = "These seeds grow into a helpful herb called Messa's Tear, native to Ahdomai." + icon_state = "seed-mtear" + mypath = "/obj/item/seeds/mtearseed" + species = "mtear" + plantname = "Messa's Tear" + productname = "/obj/item/stack/medical/ointment/tajaran" + lifespan = 50 + endurance = 25 + maturation = 3 + production = 5 + yield = 4 + potency = 10 + plant_type = 0 + growthstages = 3 + /obj/item/seeds/berryseed name = "pack of berry seeds" desc = "These seeds grow into berry bushes." diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 9133753e4ee..9ba221c64d6 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -1322,6 +1322,10 @@ proc/process_ghost_teleport_locs() name = "\improper Miscellaneous Research" icon_state = "toxmisc" +/area/toxins/telesci + name = "\improper Telescience Lab" + icon_state = "toxmisc" + /area/toxins/server name = "\improper Server Room" icon_state = "server" diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 45a6c52a259..28598b175bb 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -52,7 +52,7 @@ /obj/machinery/dna_scannernew/proc/eject_occupant() src.go_out() for(var/obj/O in src) - if((!istype(O,/obj/item/weapon/circuitboard/clonescanner)) && (!istype(O,/obj/item/weapon/stock_parts)) && (!istype(O,/obj/item/weapon/cable_coil))) + if((!istype(O,/obj/item/weapon/reagent_containers)) && (!istype(O,/obj/item/weapon/circuitboard/clonescanner)) && (!istype(O,/obj/item/weapon/stock_parts)) && (!istype(O,/obj/item/weapon/cable_coil))) O.loc = get_turf(src)//Ejects items that manage to get in there (exluding the components) if(!occupant) for(var/mob/M in src)//Failsafe so you can get mobs out diff --git a/code/game/gamemodes/events/ninja_abilities.dm b/code/game/gamemodes/events/ninja_abilities.dm index 9245c740e07..641bdf77ce6 100644 --- a/code/game/gamemodes/events/ninja_abilities.dm +++ b/code/game/gamemodes/events/ninja_abilities.dm @@ -57,7 +57,7 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo if(!ninjacost(,2)) var/mob/living/carbon/human/U = affecting U << "\blue There are [s_bombs] smoke bombs remaining." - var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() + var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() smoke.set_up(10, 0, U.loc) smoke.start() playsound(U.loc, 'sound/effects/bamf.ogg', 50, 2) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 7480555d694..b8faeeef976 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -8,6 +8,8 @@ var/bomb_set density = 1 var/deployable = 0.0 var/extended = 0.0 + var/lighthack = 0 + var/opened = 0.0 var/timeleft = 60.0 var/timing = 0.0 var/r_code = "ADMIN" @@ -15,15 +17,36 @@ var/bomb_set var/yes_code = 0.0 var/safety = 1.0 var/obj/item/weapon/disk/nuclear/auth = null + var/list/wires = list() + var/light_wire + var/safety_wire + var/timing_wire var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, // 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. flags = FPRINT use_power = 0 + + /obj/machinery/nuclearbomb/New() ..() r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. + src.wires["Red"] = 0 + src.wires["Blue"] = 0 + src.wires["Green"] = 0 + src.wires["Marigold"] = 0 + src.wires["Fuschia"] = 0 + src.wires["Black"] = 0 + src.wires["Pearl"] = 0 + var/list/w = list("Red","Blue","Green","Marigold","Black","Fuschia","Pearl") + src.light_wire = pick(w) + w -= src.light_wire + src.timing_wire = pick(w) + w -= src.timing_wire + src.safety_wire = pick(w) + w -= src.safety_wire + /obj/machinery/nuclearbomb/process() if (src.timing) bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed. @@ -36,6 +59,30 @@ var/bomb_set return /obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob) + + if (istype(O, /obj/item/weapon/screwdriver)) + src.add_fingerprint(user) + if (src.auth) + if (src.opened == 0) + src.opened = 1 + overlays += image(icon, "npanel_open") + user << "You unscrew the control panel of [src]." + + else + src.opened = 0 + overlays -= image(icon, "npanel_open") + user << "You screw the control panel of [src] back on." + else + if (src.opened == 0) + user << "The [src] emits a buzzing noise, the panel staying locked in." + if (src.opened == 1) + src.opened = 0 + overlays -= image(icon, "npanel_open") + user << "You screw the control panel of [src] back on." + flick("nuclearbombc", src) + + return + if (src.extended) if (istype(O, /obj/item/weapon/disk/nuclear)) usr.drop_item() @@ -119,6 +166,8 @@ var/bomb_set /obj/machinery/nuclearbomb/attack_hand(mob/user as mob) if (src.extended) + if (src.opened) + nukehack_win(user,50) user.set_machine(src) var/dat = text("Nuclear Fission Explosive
\nAuth. Disk: []
", src, (src.auth ? "++++++++++" : "----------")) if (src.auth) @@ -145,11 +194,23 @@ var/bomb_set visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring!") else visible_message("\red \The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") - flick("nuclearbombc", src) - src.icon_state = "nuclearbomb1" + if(!src.lighthack) + flick("nuclearbombc", src) + src.icon_state = "nuclearbomb1" src.extended = 1 return +obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) + var/dat as text + dat += "Nuclear Fission Explosive
\nNuclear Device Wires:
" + for(var/wire in src.wires) + dat += text("[wire] Wire: [src.wires[wire] ? "Mend" : "Cut"] Pulse
") + dat += text("
The device is [src.timing ? "shaking!" : "still"]
") + dat += text("The device is [src.safety ? "quiet" : "whirring"].
") + dat += text("The lights are [src.lighthack ? "static" : "functional"].
") + user << browse("Bomb Defusion[dat]","window=nukebomb_hack") + onclose(user, "nukebomb_hack") + /obj/machinery/nuclearbomb/verb/make_deployable() set category = "Object" set name = "Make Deployable" @@ -161,16 +222,57 @@ var/bomb_set else usr << "\red You adjust some panels to make [src] deployable." src.deployable = 1 + return + /obj/machinery/nuclearbomb/Topic(href, href_list) ..() if (!usr.canmove || usr.stat || usr.restrained()) return - if (!ishuman(usr)) - usr << "\red You don't have the dexterity to do this!" - return 1 if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) usr.set_machine(src) + if(href_list["act"]) + var/temp_wire = href_list["wire"] + if(href_list["act"] == "pulse") + if (!istype(usr.get_active_hand(), /obj/item/device/multitool)) + usr << "You need a multitool!" + else + if(src.wires[temp_wire]) + usr << "You can't pulse a cut wire." + else + if(src.light_wire == temp_wire) + src.lighthack = !src.lighthack + spawn(100) src.lighthack = !src.lighthack + if(src.timing_wire == temp_wire) + if(src.timing) + explode() + if(src.safety_wire == temp_wire) + src.safety = !src.safety + spawn(100) src.safety = !src.safety + if(src.safety == 1) + visible_message("\blue The [src] quiets down.") + if(!src.lighthack) + if (src.icon_state == "nuclearbomb2") + src.icon_state = "nuclearbomb1" + else + visible_message("\blue The [src] emits a quiet whirling noise!") + if(href_list["act"] == "wire") + if (!istype(usr.get_active_hand(), /obj/item/weapon/wirecutters)) + usr << "You need wirecutters!" + else + wires[temp_wire] = !wires[temp_wire] + if(src.safety_wire == temp_wire) + if(src.timing) + explode() + if(src.timing_wire == temp_wire) + if(!src.lighthack) + if (src.icon_state == "nuclearbomb2") + src.icon_state = "nuclearbomb1" + src.timing = 0 + bomb_set = 0 + if(src.light_wire == temp_wire) + src.lighthack = !src.lighthack + if (href_list["auth"]) if (src.auth) src.auth.loc = src.loc @@ -211,14 +313,16 @@ var/bomb_set return src.timing = !( src.timing ) if (src.timing) - src.icon_state = "nuclearbomb2" + if(!src.lighthack) + src.icon_state = "nuclearbomb2" if(!src.safety) bomb_set = 1//There can still be issues with this reseting when there are multiple bombs. Not a big deal tho for Nuke/N else bomb_set = 0 else - src.icon_state = "nuclearbomb1" bomb_set = 0 + if(!src.lighthack) + src.icon_state = "nuclearbomb1" if (href_list["safety"]) src.safety = !( src.safety ) if(safety) @@ -266,7 +370,8 @@ var/bomb_set src.timing = -1.0 src.yes_code = 0 src.safety = 1 - src.icon_state = "nuclearbomb3" + if(!src.lighthack) + src.icon_state = "nuclearbomb3" playsound(src,'sound/machines/Alarm.ogg',100,0,5) if (ticker && ticker.mode) ticker.mode.explosion_in_progress = 1 diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index c50767d2f55..f1a0fd2e260 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -26,6 +26,7 @@ supervisors = "your laws and the AI" //Nodrak selection_color = "#ddffdd" minimal_player_age = 21 + alt_titles = list("Android", "Robot") equip(var/mob/living/carbon/human/H) if(!H) return 0 diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 93d87635dad..7eb8fa096e9 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -11,6 +11,13 @@ density = 1 var/orient = "LEFT" // "RIGHT" changes the dir suffix to "-r" + +/obj/machinery/sleep_console/process() + if(stat & (NOPOWER|BROKEN)) + return + src.updateUsrDialog() + return + /obj/machinery/sleep_console/ex_act(severity) switch(severity) if(1.0) @@ -71,22 +78,25 @@ if(occupant.reagents) for(var/chemical in connected.available_chemicals) dat += "[connected.available_chemicals[chemical]]: [occupant.reagents.get_reagent_amount(chemical)] units
" - dat += "
Refresh meter readings each second
" - if(src.connected.beaker) - if(src.connected.filtering) - dat += "
Stop Dialysis
" - dat += text("Output Beaker has [] units of free space remaining

", src.connected.beaker.reagents.maximum_volume - src.connected.beaker.reagents.total_volume) - else - dat += "
Start Dialysis
" - dat += text("Output Beaker has [] units of free space remaining

", src.connected.beaker.reagents.maximum_volume - src.connected.beaker.reagents.total_volume) - else - dat += "
No Dialysis Output Beaker is present.

" - + dat += "Refresh Meter Readings
" + if(src.connected.beaker) + dat += "
Remove Beaker
" + if(src.connected.filtering) + dat += "Stop Dialysis
" + dat += text("Output Beaker has [] units of free space remaining

", src.connected.beaker.reagents.maximum_volume - src.connected.beaker.reagents.total_volume) + else + dat += "
Start Dialysis
" + dat += text("Output Beaker has [] units of free space remaining

", src.connected.beaker.reagents.maximum_volume - src.connected.beaker.reagents.total_volume) + else + dat += "
No Dialysis Output Beaker is present.

" + for(var/chemical in connected.available_chemicals) dat += "Inject [connected.available_chemicals[chemical]]: " for(var/amount in connected.amounts) - dat += "[amount] units " - dat += "
" + dat += "[amount] units
" + + + dat += "
Eject Patient" else dat += "The sleeper is empty." dat += text("

Close", user) @@ -108,19 +118,21 @@ src.connected.inject_chemical(usr,href_list["chemical"],text2num(href_list["amount"])) else usr << "\red \b This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!" + src.updateUsrDialog() if (href_list["refresh"]) src.updateUsrDialog() - if (href_list["togglefilter"]) - src.connected.toggle_filter() - src.updateUsrDialog() + if (href_list["removebeaker"]) + src.connected.remove_beaker() + src.updateUsrDialog() + if (href_list["togglefilter"]) + src.connected.toggle_filter() + src.updateUsrDialog() + if (href_list["ejectify"]) + src.connected.eject() + src.updateUsrDialog() src.add_fingerprint(usr) return -/obj/machinery/sleep_console/process() - if(stat & (NOPOWER|BROKEN)) - return - src.updateUsrDialog() - return /obj/machinery/sleep_console/power_change() return @@ -143,15 +155,15 @@ density = 1 anchored = 1 var/orient = "LEFT" // "RIGHT" changes the dir suffix to "-r" - var/mob/living/carbon/human/occupant = null - var/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "dermaline" = "Dermaline", "bicaridine" = "Bicaridine", "dexalin" = "Dexalin") + var/mob/living/carbon/human/occupant = null + var/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "paracetamol" = "Paracetamol", "anti_toxin" = "Dylovene", "dexalin" = "Dexalin") var/amounts = list(5, 10) - var/obj/item/weapon/reagent_containers/glass/beaker = null - var/filtering = 0 + var/obj/item/weapon/reagent_containers/glass/beaker = null + var/filtering = 0 New() ..() - beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large() + beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large() spawn( 5 ) if(orient == "RIGHT") icon_state = "sleeper_0-r" @@ -164,15 +176,14 @@ process() - if(filtering > 0) - if(beaker) - if(beaker.reagents.total_volume < beaker.reagents.maximum_volume) - src.occupant.vessel.trans_to(beaker, 1) - for(var/datum/reagent/x in src.occupant.reagents.reagent_list) -// world << "FILTERING CHEMS" - src.occupant.reagents.trans_to(beaker, 3) - src.occupant.vessel.trans_to(beaker, 1) - src.updateDialog() + if(filtering > 0) + if(beaker) + if(beaker.reagents.total_volume < beaker.reagents.maximum_volume) + src.occupant.vessel.trans_to(beaker, 1) + for(var/datum/reagent/x in src.occupant.reagents.reagent_list) + src.occupant.reagents.trans_to(beaker, 3) + src.occupant.vessel.trans_to(beaker, 1) + src.updateUsrDialog() return @@ -184,59 +195,60 @@ del(src) return - attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) - if(istype(G, /obj/item/weapon/reagent_containers/glass)) - if(!beaker) - beaker = G - user.drop_item() - G.loc = src - user.visible_message("[user] adds \a [G] to \the [src]!", "You add \a [G] to \the [src]!") - return - else - user << "\red The sleeper has a beaker already." + attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) + if(istype(G, /obj/item/weapon/reagent_containers/glass)) + if(!beaker) + beaker = G + user.drop_item() + G.loc = src + user.visible_message("[user] adds \a [G] to \the [src]!", "You add \a [G] to \the [src]!") + src.updateUsrDialog() + return + else + user << "\red The sleeper has a beaker already." return - else if(istype(G, /obj/item/weapon/grab)) - if(!ismob(G:affecting)) - return + else if(istype(G, /obj/item/weapon/grab)) + if(!ismob(G:affecting)) + return if(src.occupant) user << "\blue The sleeper is already occupied!" return - for(var/mob/living/carbon/slime/M in range(1,G:affecting)) - if(M.Victim == G:affecting) - usr << "[G:affecting.name] will not fit into the sleeper because they have a slime latched onto their head." - return - - visible_message("[user] starts putting [G:affecting:name] into the sleeper.", 3) - - if(do_after(user, 20)) - if(src.occupant) - user << "\blue The sleeper is already occupied!" - return - if(!G || !G:affecting) return - var/mob/M = G:affecting - if(M.client) - M.client.perspective = EYE_PERSPECTIVE - M.client.eye = src - M.loc = src - src.occupant = M - src.icon_state = "sleeper_1" - if(orient == "RIGHT") - icon_state = "sleeper_1-r" - - M << "\blue You feel cool air surround you. You go numb as your senses turn inward." - - src.add_fingerprint(user) - del(G) + for(var/mob/living/carbon/slime/M in range(1,G:affecting)) + if(M.Victim == G:affecting) + usr << "[G:affecting.name] will not fit into the sleeper because they have a slime latched onto their head." + return + + visible_message("[user] starts putting [G:affecting:name] into the sleeper.", 3) + + if(do_after(user, 20)) + if(src.occupant) + user << "\blue The sleeper is already occupied!" + return + if(!G || !G:affecting) return + var/mob/M = G:affecting + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.loc = src + src.occupant = M + src.icon_state = "sleeper_1" + if(orient == "RIGHT") + icon_state = "sleeper_1-r" + + M << "\blue You feel cool air surround you. You go numb as your senses turn inward." + + src.add_fingerprint(user) + del(G) return return ex_act(severity) - if(filtering) - toggle_filter() + if(filtering) + toggle_filter() switch(severity) if(1.0) for(var/atom/movable/A as mob|obj in src) @@ -260,8 +272,8 @@ return return emp_act(severity) - if(filtering) - toggle_filter() + if(filtering) + toggle_filter() if(stat & (BROKEN|NOPOWER)) ..(severity) return @@ -286,15 +298,15 @@ if (M:reagents.get_reagent_amount("inaprovaline") < 5) M:reagents.add_reagent("inaprovaline", 5) return - proc/toggle_filter() - if(filtering) - filtering = 0 - else - filtering = 1 + proc/toggle_filter() + if(filtering) + filtering = 0 + else + filtering = 1 proc/go_out() - if(filtering) - toggle_filter() + if(filtering) + toggle_filter() if(!src.occupant) return if(src.occupant.client) @@ -337,10 +349,10 @@ user << text("[]\t -Burn Severity %: []", (src.occupant.getFireLoss() < 60 ? "\blue " : "\red "), src.occupant.getFireLoss()) user << "\blue Expected time till occupant can safely awake: (note: If health is below 20% these times are inaccurate)" user << text("\blue \t [] second\s (if around 1 or 2 the sleeper is keeping them asleep.)", src.occupant.paralysis / 5) - if(src.beaker) - user << text("\blue \t Dialysis Output Beaker has [] of free space remaining.", src.beaker.reagents.maximum_volume - src.beaker.reagents.total_volume) - else - user << "\blue No Dialysis Output Beaker loaded." + if(src.beaker) + user << text("\blue \t Dialysis Output Beaker has [] of free space remaining.", src.beaker.reagents.maximum_volume - src.beaker.reagents.total_volume) + else + user << "\blue No Dialysis Output Beaker loaded." else user << "\blue There is no one inside!" return @@ -359,19 +371,19 @@ add_fingerprint(usr) return - verb/remove_beaker() - set name = "Remove Beaker" - set category = "Object" - set src in oview(1) - if(usr.stat != 0) - return - if(beaker) - filtering = 0 - beaker.loc = usr.loc - beaker = null - add_fingerprint(usr) - return - + verb/remove_beaker() + set name = "Remove Beaker" + set category = "Object" + set src in oview(1) + if(usr.stat != 0) + return + if(beaker) + filtering = 0 + beaker.loc = usr.loc + beaker = null + add_fingerprint(usr) + return + verb/move_inside() set name = "Enter Sleeper" set category = "Object" @@ -402,10 +414,10 @@ if(orient == "RIGHT") icon_state = "sleeper_1-r" - usr << "\blue You feel cool air surround you. You go numb as your senses turn inward." - + usr << "\blue You feel cool air surround you. You go numb as your senses turn inward." + for(var/obj/O in src) del(O) src.add_fingerprint(usr) return - return + return diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 3f17fe7299a..4b2fb50c54e 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -281,6 +281,7 @@ var/infected = "" var/imp = "" var/bled = "" + var/robot = "" var/splint = "" var/internal_bleeding = "" var/lung_ruptured = "" @@ -295,6 +296,8 @@ bled = "Bleeding:" if(e.status & ORGAN_BROKEN) AN = "[e.broken_description]:" + if(e.status & ORGAN_ROBOT) + robot = "Prosthetic:" if(e.open) open = "Open:" var/unknown_body = 0 @@ -308,16 +311,25 @@ if(!AN && !open && !infected & !imp) AN = "None:" if(!(e.status & ORGAN_DESTROYED)) - dat += "[e.display_name][e.burn_dam][e.brute_dam][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]" + dat += "[e.display_name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]" else dat += "[e.display_name]--Not Found" dat += "" for(var/organ_name in occupant.internal_organs) var/datum/organ/internal/i = occupant.internal_organs[organ_name] + var/mech = "" + if(i.robotic == 1) + mech = "Assisted:" + if(i.robotic == 2) + mech = "Mechanical:" dat += "" - dat += "[i.name]N/A[i.damage]None:" + dat += "[i.name]N/A[i.damage]None:[mech]" dat += "" dat += "" + if(occupant.sdisabilities & BLIND) + dat += text("Cataracts detected.
") + if(occupant.sdisabilities & NEARSIGHTED) + dat += text("Retinal misalignment detected.
") else dat += "\The [src] is empty." else diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index ae75617ccf6..f2a069c4543 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -1511,7 +1511,7 @@ FIRE ALARM pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24) pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0 - if(z == 1) + if(z == 1 || z == 5) if(security_level) src.overlays += image('icons/obj/monitors.dmi', "overlay_[get_security_level()]") else diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 2db4c1594eb..477fd67cab0 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -28,6 +28,7 @@ var/global/list/autolathe_recipes = list( \ new /obj/item/weapon/surgicaldrill(),\ new /obj/item/weapon/retractor(),\ new /obj/item/weapon/cautery(),\ + new /obj/item/weapon/hemostat(),\ new /obj/item/weapon/reagent_containers/glass/beaker(), \ new /obj/item/weapon/reagent_containers/glass/beaker/large(), \ new /obj/item/weapon/reagent_containers/glass/beaker/vial(), \ diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm index d0345f60905..aa274e505eb 100644 --- a/code/game/machinery/bots/cleanbot.dm +++ b/code/game/machinery/bots/cleanbot.dm @@ -298,6 +298,7 @@ text("[src.oddbutton ? "Yes" : "No" target_types += /obj/effect/decal/cleanable/robot_debris target_types += /obj/effect/decal/cleanable/crayon target_types += /obj/effect/decal/cleanable/liquid_fuel + target_types += /obj/effect/decal/cleanable/mucus if(src.blood) target_types += /obj/effect/decal/cleanable/xenoblood/ diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 2392eed9944..46b9b22d2a7 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -200,4 +200,10 @@ name = "Engineering Cameras" desc = "Used to monitor fires and breaches." icon_state = "engineeringcameras" - network = list("Engineering","Power Alarms","Atmosphere Alarms","Fire Alarms") + network = list("Engineering","Power Alarms","Atmosphere Alarms","Fire Alarms") + +/obj/machinery/computer/security/nuclear + name = "Mission Monitor" + desc = "Used to access the built-in cameras in helmets." + icon_state = "syndicam" + network = list("NUKE") diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 8cee9f811c4..911ccace956 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -152,7 +152,7 @@ carddesc += "" carddesc += "" carddesc += "Stored account number: " - carddesc += "" + carddesc += "" carddesc += "" carddesc += "Assignment: " diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index ae0dc3c5c36..c47eb1f9136 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -27,7 +27,7 @@ for(var/x in verbs) verbs -= x set_broken() - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(5, 0, src) smoke.start() return diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 9de6b2c6aa8..303e814ef11 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -79,13 +79,15 @@ continue O.Weaken(strength) - if ((O.eye_stat > 15 && prob(O.eye_stat + 50))) - flick("e_flash", O:flash) - O.eye_stat += rand(1, 2) + if (istype(O, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = O + var/datum/organ/internal/eyes/E = H.internal_organs["eyes"] + if ((E.damage > E.min_bruised_damage && prob(E.damage + 50))) + flick("e_flash", O:flash) + E.damage += rand(1, 5) else if(!O.blinded) flick("flash", O:flash) - O.eye_stat += rand(0, 2) /obj/machinery/flasher/emp_act(severity) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 1476b13d0a8..d7bb61c0be4 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -148,6 +148,14 @@ else if(istype(W, /obj/item/weapon/card) && currently_vending) var/obj/item/weapon/card/I = W scan_card(I) + + else if(src.panel_open) + + for(var/datum/data/vending_product/R in product_records) + if(istype(W, R.product_path)) + stock(R, user) + del(W) + else ..() @@ -407,6 +415,13 @@ src.updateUsrDialog() +/obj/machinery/vending/proc/stock(var/datum/data/vending_product/R, var/mob/user) + if(src.panel_open) + user << "\blue You stock the [src] with \a [R.product_name]" + R.amount++ + + src.updateUsrDialog() + /obj/machinery/vending/process() if(stat & (BROKEN|NOPOWER)) return @@ -759,8 +774,8 @@ /obj/item/seeds/poppyseed = 3,/obj/item/seeds/ambrosiavulgarisseed = 3,/obj/item/seeds/whitebeetseed = 3,/obj/item/seeds/watermelonseed = 3,/obj/item/seeds/limeseed = 3, /obj/item/seeds/lemonseed = 3,/obj/item/seeds/orangeseed = 3,/obj/item/seeds/grassseed = 3,/obj/item/seeds/cocoapodseed = 3,/obj/item/seeds/plumpmycelium = 2, /obj/item/seeds/cabbageseed = 3,/obj/item/seeds/grapeseed = 3,/obj/item/seeds/pumpkinseed = 3,/obj/item/seeds/cherryseed = 3,/obj/item/seeds/plastiseed = 3,/obj/item/seeds/riceseed = 3) - contraband = list(/obj/item/seeds/amanitamycelium = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/libertymycelium = 2, - /obj/item/seeds/nettleseed = 2,/obj/item/seeds/reishimycelium = 2) + contraband = list(/obj/item/seeds/amanitamycelium = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/libertymycelium = 2,/obj/item/seeds/mtearseed = 2, + /obj/item/seeds/nettleseed = 2,/obj/item/seeds/reishimycelium = 2,/obj/item/seeds/reishimycelium = 2,/obj/item/seeds/shandseed = 2,) premium = list(/obj/item/toy/waterflower = 1) diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index fdce02f5d2e..cdb3645c62d 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -14,7 +14,7 @@ var/smoke = 5 var/smoke_ready = 1 var/smoke_cooldown = 100 - var/datum/effect/effect/system/harmless_smoke_spread/smoke_system = new + var/datum/effect/effect/system/smoke_spread/smoke_system = new operation_req_access = list(access_cent_specops) wreckage = /obj/effect/decal/mecha_wreckage/marauder add_req_access = 0 diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index c0f783c52d6..8d2d69a654f 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -21,15 +21,6 @@ would spawn and follow the beaker, even if it is carried or thrown. flags = TABLEPASS mouse_opacity = 0 -/obj/effect/effect/smoke - name = "smoke" - icon = 'icons/effects/water.dmi' - icon_state = "smoke" - opacity = 1 - anchored = 0.0 - mouse_opacity = 0 - var/amount = 8.0 - /obj/effect/proc/delete() loc = null if(reagents) @@ -222,196 +213,186 @@ steam.start() -- spawns the effect ///////////////////////////////////////////// -/obj/effect/effect/harmless_smoke +/obj/effect/effect/smoke name = "smoke" icon_state = "smoke" opacity = 1 anchored = 0.0 mouse_opacity = 0 var/amount = 6.0 + var/time_to_live = 100 + //Remove this bit to use the old smoke icon = 'icons/effects/96x96.dmi' pixel_x = -32 pixel_y = -32 -/obj/effect/effect/harmless_smoke/New() +/obj/effect/effect/smoke/New() ..() - spawn (100) + spawn (time_to_live) delete() return -/obj/effect/effect/harmless_smoke/Move() +/obj/effect/effect/smoke/HasEntered(mob/living/carbon/M as mob ) ..() - return - -/datum/effect/effect/system/harmless_smoke_spread - var/total_smoke = 0 // To stop it being spammed and lagging! - var/direction - - set_up(n = 5, c = 0, loca, direct) - if(n > 10) - n = 10 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/harmless_smoke/smoke = new /obj/effect/effect/harmless_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 20) - n = 20 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct +/datum/effect/effect/system/smoke_spread/set_up(n = 5, c = 0, loca, direct) + if(n > 10) + n = 10 + number = n + cardinals = c + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + if(direct) + direction = direct - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/bad_smoke/smoke = new /obj/effect/effect/bad_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 20) + return + spawn(0) + if(holder) + src.location = get_turf(holder) + var/obj/effect/effect/smoke/smoke = new smoke_type(src.location) + src.total_smoke++ + var/direction = src.direction + if(!direction) + if(src.cardinals) + direction = pick(cardinal) + else + direction = pick(alldirs) + for(i=0, i 20) - n = 20 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/sleep_smoke/smoke = new /obj/effect/effect/sleep_smoke(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i 20) - n = 20 - number = n - cardinals = c - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - - start() - var/i = 0 - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/mustard_gas/smoke = new /obj/effect/effect/mustard_gas(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - for(i=0, i= eyes.min_bruised_damage) + if(M.stat != 2) + if(eyes.robotic <= 1) //robot eyes bleeding might be a bit silly + M << "\red Your eyes start to bleed profusely!" + if(prob(50)) + if(M.stat != 2) + M << "\red You drop what you're holding and clutch at your eyes!" + M.drop_item() + M.eye_blurry += 10 + M.Paralyse(1) + M.Weaken(4) + if (eyes.damage >= eyes.min_broken_damage) + if(M.stat != 2) + M << "\red You go blind!" var/datum/organ/external/affecting = M:get_organ("head") if(affecting.take_damage(7)) M:UpdateDamageIcon() else M.take_organ_damage(7) M.eye_blurry += rand(3,4) - M.eye_stat += rand(2,4) - if (M.eye_stat >= 10) - M.eye_blurry += 15+(0.1*M.eye_blurry) - M.disabilities |= NEARSIGHTED - if(M.stat != 2) - M << "\red Your eyes start to bleed profusely!" - if(prob(50)) - if(M.stat != 2) - M << "\red You drop what you're holding and clutch at your eyes!" - M.drop_item() - M.eye_blurry += 10 - M.Paralyse(1) - M.Weaken(4) - if (prob(M.eye_stat - 10 + 1)) - if(M.stat != 2) - M << "\red You go blind!" - M.sdisabilities |= BLIND return /obj/item/clean_blood() diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index c1ccb4aa6ca..a89a4573eab 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -78,6 +78,7 @@ if(M.stat == DEAD || M.sdisabilities & BLIND) //mob is dead or fully blind user << "[M] pupils does not react to the light!" else if(XRAY in M.mutations) //mob has X-RAY vision + flick("flash", M.flash) //Yes, you can still get flashed wit X-Ray. user << "[M] pupils give an eerie glow!" else //they're okay! if(!M.blinded) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index ccc00290db1..47175e20d19 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -65,24 +65,31 @@ var/mob/living/carbon/human/H = M var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) - if(!affecting.bandage()) - user << "\red The wounds on [M]'s [affecting.display_name] have already been bandaged." - return 1 + if(affecting.open == 0) + if(!affecting.bandage()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been bandaged." + return 1 + else + for (var/datum/wound/W in affecting.wounds) + if (W.internal) + continue + if (W.current_stage <= W.max_bleeding_stage) + user.visible_message( "\blue [user] bandages [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You bandage [W.desc] on [M]'s [affecting.display_name]." ) + //H.add_side_effect("Itch") + else if (istype(W,/datum/wound/bruise)) + user.visible_message( "\blue [user] places bruise patch over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You place bruise patch over [W.desc] on [M]'s [affecting.display_name]." ) + else + user.visible_message( "\blue [user] places bandaid over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You place bandaid over [W.desc] on [M]'s [affecting.display_name]." ) + use(1) else - for (var/datum/wound/W in affecting.wounds) - if (W.internal) - continue - if (W.current_stage <= W.max_bleeding_stage) - user.visible_message( "\blue [user] bandages [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You bandage [W.desc] on [M]'s [affecting.display_name]." ) - //H.add_side_effect("Itch") - else if (istype(W,/datum/wound/bruise)) - user.visible_message( "\blue [user] places bruise patch over [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You place bruise patch over [W.desc] on [M]'s [affecting.display_name]." ) - else - user.visible_message( "\blue [user] places bandaid over [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You place bandaid over [W.desc] on [M]'s [affecting.display_name]." ) - use(1) + if (can_operate(H)) //Checks if mob is lying down on table for surgery + if (do_surgery(H,user,src)) + return + else + user << "The [affecting.display_name] is cut open, you'll need more than a bandage!" /obj/item/stack/medical/ointment name = "ointment" @@ -101,30 +108,38 @@ var/mob/living/carbon/human/H = M var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) - if(!affecting.salve()) - user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." - return 1 + if(affecting.open == 0) + if(!affecting.salve()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." + return 1 + else + user.visible_message( "\blue [user] salves wounds on [M]'s [affecting.display_name].", \ + "\blue You salve wounds on [M]'s [affecting.display_name]." ) + use(1) else - user.visible_message( "\blue [user] salves wounds on [M]'s [affecting.display_name].", \ - "\blue You salve wounds on [M]'s [affecting.display_name]." ) - use(1) + if (can_operate(H)) //Checks if mob is lying down on table for surgery + if (do_surgery(H,user,src)) + return + else + user << "The [affecting.display_name] is cut open, you'll need more than a bandage!" /obj/item/stack/medical/bruise_pack/tajaran name = "\improper S'rendarr's Hand leaf" singular_name = "S'rendarr's Hand leaf" - desc = "A soft leaf that is rubbed on bruises." + desc = "A poultice made of soft leaves that is rubbed on bruises." icon = 'icons/obj/harvest.dmi' - icon_state = "cabbage" + icon_state = "shandp" heal_brute = 7 /obj/item/stack/medical/ointment/tajaran - name = "\improper Messa's Tear leaf" - singular_name = "Messa's Tear leaf" - desc = "A cold leaf that is rubbed on burns." + name = "\improper Messa's Tear petals" + singular_name = "Messa's Tear petals" + desc = "A poultice made of cold, blue petals that is rubbed on burns." icon = 'icons/obj/harvest.dmi' - icon_state = "ambrosiavulgaris" + icon_state = "mtearp" heal_burn = 7 + /obj/item/stack/medical/advanced/bruise_pack name = "advanced trauma kit" singular_name = "advanced trauma kit" @@ -141,25 +156,32 @@ var/mob/living/carbon/human/H = M var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) - if(!affecting.bandage()) - user << "\red The wounds on [M]'s [affecting.display_name] have already been treated." - return 1 + if(affecting.open == 0) + if(!affecting.bandage()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been treated." + return 1 + else + for (var/datum/wound/W in affecting.wounds) + if (W.internal) + continue + if (W.current_stage <= W.max_bleeding_stage) + user.visible_message( "\blue [user] cleans [W.desc] on [M]'s [affecting.display_name] and seals edges with bioglue.", \ + "\blue You clean and seal [W.desc] on [M]'s [affecting.display_name]." ) + //H.add_side_effect("Itch") + else if (istype(W,/datum/wound/bruise)) + user.visible_message( "\blue [user] places medicine patch over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You place medicine patch over [W.desc] on [M]'s [affecting.display_name]." ) + else + user.visible_message( "\blue [user] smears some bioglue over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You smear some bioglue over [W.desc] on [M]'s [affecting.display_name]." ) + affecting.heal_damage(heal_brute,0) + use(1) else - for (var/datum/wound/W in affecting.wounds) - if (W.internal) - continue - if (W.current_stage <= W.max_bleeding_stage) - user.visible_message( "\blue [user] cleans [W.desc] on [M]'s [affecting.display_name] and seals edges with bioglue.", \ - "\blue You clean and seal [W.desc] on [M]'s [affecting.display_name]." ) - //H.add_side_effect("Itch") - else if (istype(W,/datum/wound/bruise)) - user.visible_message( "\blue [user] places medicine patch over [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You place medicine patch over [W.desc] on [M]'s [affecting.display_name]." ) - else - user.visible_message( "\blue [user] smears some bioglue over [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You smear some bioglue over [W.desc] on [M]'s [affecting.display_name]." ) - affecting.heal_damage(heal_brute,0) - use(1) + if (can_operate(H)) //Checks if mob is lying down on table for surgery + if (do_surgery(H,user,src)) + return + else + user << "The [affecting.display_name] is cut open, you'll need more than a bandage!" /obj/item/stack/medical/advanced/ointment name = "advanced burn kit" @@ -178,14 +200,21 @@ var/mob/living/carbon/human/H = M var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) - if(!affecting.salve()) - user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." - return 1 + if(affecting.open == 0) + if(!affecting.salve()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." + return 1 + else + user.visible_message( "\blue [user] covers wounds on [M]'s [affecting.display_name] with regenerative membrane.", \ + "\blue You cover wounds on [M]'s [affecting.display_name] with regenerative membrane." ) + affecting.heal_damage(0,heal_burn) + use(1) else - user.visible_message( "\blue [user] covers wounds on [M]'s [affecting.display_name] with regenerative membrane.", \ - "\blue You cover wounds on [M]'s [affecting.display_name] with regenerative membrane." ) - affecting.heal_damage(0,heal_burn) - use(1) + if (can_operate(H)) //Checks if mob is lying down on table for surgery + if (do_surgery(H,user,src)) + return + else + user << "The [affecting.display_name] is cut open, you'll need more than a bandage!" /obj/item/stack/medical/splint name = "medical splints" diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index 026ddb77f5f..db0ab6b0884 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -26,12 +26,20 @@ if (istype(M,/mob/living/carbon/human)) //Repairing robolimbs var/mob/living/carbon/human/H = M var/datum/organ/external/S = H.get_organ(user.zone_sel.selecting) - if (S && (S.status & ORGAN_ROBOT)) - if(S.get_damage()) - S.heal_damage(15, 15, robo_repair = 1) - H.updatehealth() - use(1) - user.visible_message("\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " \the"][S.display_name] with \the [src].",\ - "You apply some nanite paste at [user == M ? "your" : "[M]'s"] [S.display_name].") + + if(S.open == 1) + if (S && (S.status & ORGAN_ROBOT)) + if(S.get_damage()) + S.heal_damage(15, 15, robo_repair = 1) + H.updatehealth() + use(1) + user.visible_message("\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " \the"][S.display_name] with \the [src].",\ + "You apply some nanite paste at [user == M ? "your" : "[M]'s"] [S.display_name].") + else + user << "Nothing to fix here." + else + if (can_operate(H)) + if (do_surgery(H,user,src)) + return else - user << "Nothing to fix here." + user << "Nothing to fix in here." \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index a7e6d57bb37..30fcfbdd494 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -2,6 +2,8 @@ * Contains: * Glass sheets * Reinforced glass sheets + * Plasma Glass Sheets + * Reinforced Plasma Glass Sheets (AKA Holy fuck strong windows) * Glass shards - TODO: Move this into code/game/object/item/weapons */ @@ -15,6 +17,7 @@ icon_state = "sheet-glass" g_amt = 3750 origin_tech = "materials=1" + var/created_window = /obj/structure/window/basic /obj/item/stack/sheet/glass/attack_self(mob/user as mob) @@ -81,9 +84,8 @@ if(!found) dir_to_set = direction break - var/obj/structure/window/W - W = new /obj/structure/window/basic( user.loc, 0 ) + W = new created_window( user.loc, 0 ) W.dir = dir_to_set W.ini_dir = W.dir W.anchored = 0 @@ -98,7 +100,7 @@ user << "\red There is a window in the way." return 1 var/obj/structure/window/W - W = new /obj/structure/window/basic( user.loc, 0 ) + W = new created_window( user.loc, 0 ) W.dir = SOUTHWEST W.ini_dir = SOUTHWEST W.anchored = 0 @@ -293,3 +295,54 @@ H.UpdateDamageIcon() H.updatehealth() ..() + + + + +/* + * Plasma Glass sheets + */ +/obj/item/stack/sheet/glass/plasmaglass + name = "plasma glass" + desc = "A very strong and very resistant sheet of a plasma-glass alloy." + singular_name = "glass sheet" + icon_state = "sheet-plasmaglass" + g_amt = 7500 + origin_tech = "materials=3;plasma=2" + created_window = /obj/structure/window/plasmabasic + +/obj/item/stack/sheet/glass/plasmaglass/attack_self(mob/user as mob) + construct_window(user) + +/obj/item/stack/sheet/glass/plasmaglass/attackby(obj/item/W, mob/user) + ..() + if( istype(W, /obj/item/stack/rods) ) + var/obj/item/stack/rods/V = W + var/obj/item/stack/sheet/glass/plasmarglass/RG = new (user.loc) + RG.add_fingerprint(user) + RG.add_to_stacks(user) + V.use(1) + var/obj/item/stack/sheet/glass/G = src + src = null + var/replace = (user.get_inactive_hand()==G) + G.use(1) + if (!G && !RG && replace) + user.put_in_hands(RG) + else + return ..() + +/* + * Reinforced plasma glass sheets + */ +/obj/item/stack/sheet/glass/plasmarglass + name = "reinforced plasma glass" + desc = "Plasma glass which seems to have rods or something stuck in them." + singular_name = "reinforced plasma glass sheet" + icon_state = "sheet-plasmarglass" + g_amt = 7500 + m_amt = 1875 + origin_tech = "materials=4;plasma=2" + created_window = /obj/structure/window/plasmareinforced + +/obj/item/stack/sheet/glass/plasmarglass/attack_self(mob/user as mob) + construct_window(user) \ No newline at end of file diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index c0339639955..2ca53be3ee7 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -127,7 +127,7 @@ icon_state = "id" item_state = "card-id" var/access = list() - var/registered_name = null // The name registered_name on the card + var/registered_name = "Unknown" // The name registered_name on the card slot_flags = SLOT_ID var/blood_type = "\[UNSET\]" @@ -280,4 +280,4 @@ assignment = "General" New() access = get_all_centcom_access() - ..() \ No newline at end of file + ..() diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 1a50e9ad05c..4024e5275e9 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -48,7 +48,6 @@ //Flashing everyone if(eye_safety < 1) flick("e_flash", M.flash) - M.eye_stat += rand(1, 3) M.Stun(2) M.Weaken(10) @@ -80,13 +79,14 @@ M.ear_deaf = max(M.ear_deaf,5) //This really should be in mob not every check - if (M.eye_stat >= 20) - M << "\red Your eyes start to burn badly!" - M.disabilities |= NEARSIGHTED - if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) - if (prob(M.eye_stat - 20 + 1)) - M << "\red You can't see anything!" - M.sdisabilities |= BLIND + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/datum/organ/internal/eyes/E = H.internal_organs["eyes"] + if (E.damage >= E.min_bruised_damage) + M << "\red Your eyes start to burn badly!" + if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) + if (E.damage >= E.min_broken_damage) + M << "\red You can't see anything!" if (M.ear_damage >= 15) M << "\red Your ears start to ring badly!" if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index 27a2d0580e2..d518567a5dc 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -7,11 +7,11 @@ item_state = "flashbang" flags = FPRINT | TABLEPASS slot_flags = SLOT_BELT - var/datum/effect/effect/system/bad_smoke_spread/smoke + var/datum/effect/effect/system/smoke_spread/bad/smoke New() ..() - src.smoke = new /datum/effect/effect/system/bad_smoke_spread + src.smoke = new /datum/effect/effect/system/smoke_spread/bad src.smoke.attach(src) prime() diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm index ee6f96161a8..937e22975ef 100644 --- a/code/game/objects/items/weapons/manuals.dm +++ b/code/game/objects/items/weapons/manuals.dm @@ -122,7 +122,8 @@ Step eight: Put in the new, full power cell - if you don't have one, continue with step 15.
Step nine: Quickly put on a Radiation suit.
Step ten: Check if the singularity field generators withstood the down-time - if they didn't, continue with step 15.
- Step eleven: Since disaster was averted you now have to ensure it doesn't repeat. If it was a powersink which caused it and if the engineering apc is wired to the same powernet, which the powersink is on, you have to remove the piece of wire which links the apc to the powernet. If it wasn't a powersink which caused it, then skip to step 14.
+ Step eleven: Since disaster was averted you now have to ensure it doesn't repeat. If it was a powersink which caused it and if the engineering apc is wired to the same powernet, + which the powersink is on, you have to remove the piece of wire which links the apc to the powernet. If it wasn't a powersink which caused it, then skip to step 14.
Step twelve: Grab your crowbar and pry away the tile closest to the APC.
Step thirteen: Use the wirecutters to cut the wire which is conecting the grid to the terminal.
Step fourteen: Go to the bar and tell the guys how you saved them all. Stop reading this guide here.
@@ -189,7 +190,9 @@

How to Clone People

- So there’s 50 dead people lying on the floor, chairs are spinning like no tomorrow and you haven’t the foggiest idea of what to do? Not to worry! This guide is intended to teach you how to clone people and how to do it right, in a simple step-by-step process! If at any point of the guide you have a mental meltdown, genetics probably isn’t for you and you should get a job-change as soon as possible before you’re sued for malpractice. + So there’s 50 dead people lying on the floor, chairs are spinning like no tomorrow and you haven’t the foggiest idea of what to do? Not to worry! + This guide is intended to teach you how to clone people and how to do it right, in a simple step-by-step process! If at any point of the guide you have a mental meltdown, + genetics probably isn’t for you and you should get a job-change as soon as possible before you’re sued for malpractice.
  1. Acquire body
  2. @@ -209,34 +212,48 @@ This is pretty much vital for the process because without a body, you cannot clone it. Usually, bodies will be brought to you, so you do not need to worry so much about this step. If you already have a body, great! Move on to the next step.

    Step 2: Strip body

    - The cloning machine does not like abiotic items. What this means is you can’t clone anyone if they’re wearing clothes, so take all of it off. If it’s just one person, it’s courteous to put their possessions in the closet. If you have about seven people awaiting cloning, just leave the piles where they are, but don’t mix them around and for God’s sake don’t let people in to steal them. + The cloning machine does not like abiotic items. What this means is you can’t clone anyone if they’re wearing clothes, so take all of it off. If it’s just one person, it’s courteous to put their possessions in the closet. + If you have about seven people awaiting cloning, just leave the piles where they are, but don’t mix them around and for God’s sake don’t let people in to steal them.

    Step 3: Put body in cloning machine

    Grab the body and then put it inside the DNA modifier. If you cannot do this, then you messed up at Step 2. Go back and check you took EVERYTHING off - a commonly missed item is their headset.

    Step 4: Scan body

    - Go onto the computer and scan the body by pressing ‘Scan - ’. If you’re successful, they will be added to the records (note that this can be done at any time, even with living people, so that they can be cloned without a body in the event that they are lying dead on port solars and didn‘t turn on their suit sensors)! If not, and it says “Error: Mental interface failure.”, then they have left their bodily confines and are one with the spirits. If this happens, just shout at them to get back in their body, click ‘Refresh‘ and try scanning them again. If there’s no success, threaten them with gibbing. Still no success? Skip over to Step 7 and don‘t continue after it, as you have an unresponsive body and it cannot be cloned. If you got “Error: Unable to locate valid genetic data.“, you are trying to clone a monkey - start over. + Go onto the computer and scan the body by pressing ‘Scan - ’. If you’re successful, they will be added to the records (note that this can be done at any time, even with living people, + so that they can be cloned without a body in the event that they are lying dead on port solars and didn‘t turn on their suit sensors)! + If not, and it says “Error: Mental interface failure.”, then they have left their bodily confines and are one with the spirits. If this happens, just shout at them to get back in their body, + click ‘Refresh‘ and try scanning them again. If there’s no success, threaten them with gibbing. + Still no success? Skip over to Step 7 and don‘t continue after it, as you have an unresponsive body and it cannot be cloned. + If you got “Error: Unable to locate valid genetic data.“, you are trying to clone a monkey - start over.

    Step 5: Clone body

    - Now that the body has a record, click ’View Records’, click the subject’s name, and then click ‘Clone’ to start the cloning process. Congratulations! You’re halfway there. Remember not to ‘Eject’ the cloning pod as this will kill the developing clone and you’ll have to start the process again. + Now that the body has a record, click ’View Records’, click the subject’s name, and then click ‘Clone’ to start the cloning process. Congratulations! You’re halfway there. + Remember not to ‘Eject’ the cloning pod as this will kill the developing clone and you’ll have to start the process again.

    Step 6: Get clean SEs for body

    - Cloning is a finicky and unreliable process. Whilst it will most certainly bring someone back from the dead, they can have any number of nasty disabilities given to them during the cloning process! For this reason, you need to prepare a clean, defect-free Structural Enzyme (SE) injection for when they’re done. If you’re a competent Geneticist, you will already have one ready on your working computer. If, for any reason, you do not, then eject the body from the DNA modifier (NOT THE CLONING POD) and take it next door to the Genetics research room. Put the body in one of those DNA modifiers and then go onto the console. Go into View/Edit/Transfer Buffer, find an open slot and click “SE“ to save it. Then click ‘Injector’ to get the SEs in syringe form. Put this in your pocket or something for when the body is done. + Cloning is a finicky and unreliable process. Whilst it will most certainly bring someone back from the dead, they can have any number of nasty disabilities given to them during the cloning process! + For this reason, you need to prepare a clean, defect-free Structural Enzyme (SE) injection for when they’re done. If you’re a competent Geneticist, you will already have one ready on your working computer. + If, for any reason, you do not, then eject the body from the DNA modifier (NOT THE CLONING POD) and take it next door to the Genetics research room. Put the body in one of those DNA modifiers and then go onto the console. + Go into View/Edit/Transfer Buffer, find an open slot and click “SE“ to save it. Then click ‘Injector’ to get the SEs in syringe form. Put this in your pocket or something for when the body is done.

    Step 7: Put body in morgue

    - Now that the cloning process has been initiated and you have some clean Structural Enzymes, you no longer need the body! Drag it to the morgue and tell the Chef over the radio that they have some fresh meat waiting for them in there. To put a body in a morgue bed, simply open the tray, grab the body, put it on the open tray, then close the tray again. Use one of the nearby pens to label the bed “CHEF MEAT” in order to avoid confusion. + Now that the cloning process has been initiated and you have some clean Structural Enzymes, you no longer need the body! Drag it to the morgue and tell the Chef over the radio that they have some fresh meat waiting for them in there. + To put a body in a morgue bed, simply open the tray, grab the body, put it on the open tray, then close the tray again. Use one of the nearby pens to label the bed “CHEF MEAT” in order to avoid confusion.

    Step 8: Await cloned body

    Now go back to the lab and wait for your patient to be cloned. It won’t be long now, I promise.

    Step 9: Cyo and clean clean SE injector on person

    - Has your body been cloned yet? Great! As soon as the guy pops out, grab them and stick them in cryo. Clonexadone and Cryoxadone help rebuild their genetic material. Then grab your cleanr SE injector and jab it in them. Once you’ve injected them, they now have clean Structural Enzymes and their defects, if any, will disappear in a short while. + Has your body been cloned yet? Great! As soon as the guy pops out, grab them and stick them in cryo. Clonexadone and Cryoxadone help rebuild their genetic material. Then grab your cleanr SE injector and jab it in them. Once you’ve injected them, + they now have clean Structural Enzymes and their defects, if any, will disappear in a short while.

    Step 10: Give person clothes back

    - Obviously the person will be naked after they have been cloned. Provided you weren’t an irresponsible little shit, you should have protected their possessions from thieves and should be able to give them back to the patient. No matter how cruel you are, it’s simply against protocol to force your patients to walk outside naked. + Obviously the person will be naked after they have been cloned. Provided you weren’t an irresponsible little shit, you should have protected their possessions from thieves and should be able to give them back to the patient. + No matter how cruel you are, it’s simply against protocol to force your patients to walk outside naked.

    Step 11: Send person on their way

    - Give the patient one last check-over - make sure they don’t still have any defects and that they have all their possessions. Ask them how they died, if they know, so that you can report any foul play over the radio. Once you’re done, your patient is ready to go back to work! Chances are they do not have Medbay access, so you should let them out of Genetics and the Medbay main entrance. + Give the patient one last check-over - make sure they don’t still have any defects and that they have all their possessions. Ask them how they died, if they know, so that you can report any foul play over the radio. + Once you’re done, your patient is ready to go back to work! Chances are they do not have Medbay access, so you should let them out of Genetics and the Medbay main entrance.

    If you’ve gotten this far, congratulations! You have mastered the art of cloning. Now, the real problem is how to resurrect yourself after that traitor had his way with you for cloning his target. @@ -248,7 +265,7 @@ /obj/item/weapon/book/manual/ripley_build_and_repair name = "APLU \"Ripley\" Construction and Operation Manual" icon_state ="book" - author = "Weyland-Yutani Corp" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned + author = "Randall Varn, Einstein Engines Senior Mechanic" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned title = "APLU \"Ripley\" Construction and Operation Manual" dat = {" @@ -347,23 +364,38 @@ Those are the basic steps to furthing science. What do you do science with, however? Well, you have four major tools: R&D Console, the Destructive Analyzer, the Protolathe, and the Circuit Imprinter.

    The R&D Console

    - The R&D console is the cornerstone of any research lab. It is the central system from which the Destructive Analyzer, Protolathe, and Circuit Imprinter (your R&D systems) are controled. More on those systems in their own sections. On its own, the R&D console acts as a database for all your technological gains and new devices you discover. So long as the R&D console remains intact, you'll retain all that SCIENCE you've discovered. Protect it though, because if it gets damaged, you'll lose your data! In addition to this important purpose, the R&D console has a disk menu that lets you transfer data from the database onto disk or from the disk into the database. It also has a settings menu that lets you re-sync with nearby R&D devices (if they've become disconnected), lock the console from the unworthy, upload the data to all other R&D consoles in the network (all R&D consoles are networked by default), connect/disconnect from the network, and purge all data from the database. + The R&D console is the cornerstone of any research lab. It is the central system from which the Destructive Analyzer, Protolathe, and Circuit Imprinter (your R&D systems) are controled. More on those systems in their own sections. + On its own, the R&D console acts as a database for all your technological gains and new devices you discover. So long as the R&D console remains intact, you'll retain all that SCIENCE you've discovered. Protect it though, + because if it gets damaged, you'll lose your data! + In addition to this important purpose, the R&D console has a disk menu that lets you transfer data from the database onto disk or from the disk into the database. + It also has a settings menu that lets you re-sync with nearby R&D devices (if they've become disconnected), lock the console from the unworthy, + upload the data to all other R&D consoles in the network (all R&D consoles are networked by default), connect/disconnect from the network, and purge all data from the database. NOTE: The technology list screen, circuit imprinter, and protolathe menus are accessible by non-scientists. This is intended to allow 'public' systems for the plebians to utilize some new devices.

    Destructive Analyzer

    - This is the source of all technology. Whenever you put a handheld object in it, it analyzes it and determines what sort of technological advancements you can discover from it. If the technology of the object is equal or higher then your current knowledge, you can destroy the object to further those sciences. Some devices (notably, some devices made from the protolathe and circuit imprinter) aren't 100% reliable when you first discover them. If these devices break down, you can put them into the Destructive Analyzer and improve their reliability rather then futher science. If their reliability is high enough ,it'll also advance their related technologies. + This is the source of all technology. Whenever you put a handheld object in it, it analyzes it and determines what sort of technological advancements you can discover from it. If the technology of the object is equal or higher then your current knowledge, + you can destroy the object to further those sciences. + Some devices (notably, some devices made from the protolathe and circuit imprinter) aren't 100% reliable when you first discover them. If these devices break down, you can put them into the Destructive Analyzer and improve their reliability rather then futher science. + If their reliability is high enough ,it'll also advance their related technologies.

    Circuit Imprinter

    This machine, along with the Protolathe, is used to actually produce new devices. The Circuit Imprinter takes glass and various chemicals (depends on the design) to produce new circuit boards to build new machines or computers. It can even be used to print AI modules.

    Protolathe

    - This machine is an advanced form of the Autolathe that produce non-circuit designs. Unlike the Autolathe, it can use processed metal, glass, solid plasma, silver, gold, and diamonds along with a variety of chemicals to produce devices. The downside is that, again, not all devices you make are 100% reliable when you first discover them. + This machine is an advanced form of the Autolathe that produce non-circuit designs. Unlike the Autolathe, it can use processed metal, glass, solid plasma, silver, gold, and diamonds along with a variety of chemicals to produce devices. + The downside is that, again, not all devices you make are 100% reliable when you first discover them.

    Reliability and You

    - As it has been stated, many devices when they're first discovered do not have a 100% reliablity when you first discover them. Instead, the reliablity of the device is dependent upon a base reliability value, whatever improvements to the design you've discovered through the Destructive Analyzer, and any advancements you've made with the device's source technologies. To be able to improve the reliability of a device, you have to use the device until it breaks beyond repair. Once that happens, you can analyze it in a Destructive Analyzer. Once the device reachs a certain minimum reliability, you'll gain tech advancements from it. + As it has been stated, many devices when they're first discovered do not have a 100% reliablity when you first discover them. Instead, + the reliablity of the device is dependent upon a base reliability value, whatever improvements to the design you've discovered through the Destructive Analyzer, + and any advancements you've made with the device's source technologies. To be able to improve the reliability of a device, you have to use the device until it breaks beyond repair. Once that happens, you can analyze it in a Destructive Analyzer. + Once the device reachs a certain minimum reliability, you'll gain tech advancements from it.

    Building a Better Machine

    - Many machines produces from circuit boards and inserted into a machine frame require a variety of parts to construct. These are parts like capacitors, batteries, matter bins, and so forth. As your knowledge of science improves, more advanced versions are unlocked. If you use these parts when constructing something, its attributes may be improved. For example, if you use an advanced matter bin when constructing an autolathe (rather then a regular one), it'll hold more materials. Experiment around with stock parts of various qualities to see how they affect the end results! Be warned, however: Tier 3 and higher stock parts don't have 100% reliability and their low reliability may affect the reliability of the end machine. + Many machines produces from circuit boards and inserted into a machine frame require a variety of parts to construct. These are parts like capacitors, batteries, matter bins, and so forth. As your knowledge of science improves, more advanced versions are unlocked. + If you use these parts when constructing something, its attributes may be improved. + For example, if you use an advanced matter bin when constructing an autolathe (rather then a regular one), it'll hold more materials. Experiment around with stock parts of various qualities to see how they affect the end results! Be warned, however: + Tier 3 and higher stock parts don't have 100% reliability and their low reliability may affect the reliability of the end machine. "} @@ -796,4 +828,170 @@ Disk, Code, Safety, Timer, Disk, RUN!
    Intelligence Analysts believe that normal Nanotrasen procedure is for the Captain to secure the nuclear authorisation disk.
    Good luck! - "} \ No newline at end of file + "} + +/obj/item/weapon/book/manual/atmospipes + name = "Pipes and You: Getting To Know Your Scary Tools" + icon_state = "pipingbook" + author = "Maria Crash, Senior Atmospherics Technician" + title = "Pipes and You: Getting To Know Your Scary Tools" + dat = {" + + + + + + +

    Contents

    +
      +
    1. Author's Forward
    2. +
    3. Basic Piping
    4. +
    5. Insulated Pipes
    6. +
    7. Atmospherics Devices
    8. +
    9. Heat Exchange Systems
    10. +
    11. Final Checks
    12. +
    +

    + +

    HOW TO NOT SUCK QUITE SO HARD AT ATMOSPHERICS


    + Or: What the fuck does a "passive gate" do?

    + + Alright. It has come to my attention that a variety of people are unsure of what a "pipe" is and what it does. + Apparently there is an unnatural fear of these arcane devices and their "gases". Spooky, spooky. So, + this will tell you what every device constructable by an ordinary pipe dispenser within atmospherics actually does. + You are not going to learn what to do with them to be the super best person ever, or how to play guitar with passive gates, + or something like that. Just what stuff does.

    + + +

    Basic Pipes


    + The boring ones.
    + TMost ordinary pipes are pretty straightforward. They hold gas. If gas is moving in a direction for some reason, gas will flow in that direction. + That's about it. Even so, here's all of your wonderful pipe options.
    + +
  3. Straight pipes: They're pipes. One-meter sections. Straight line. Pretty simple. Just about every pipe and device is based around this + standard one-meter size, so most things will take up as much space as one of these.
  4. +
  5. Bent pipes: Pipes with a 90 degree bend at the half-meter mark. My goodness.
  6. +
  7. Pipe manifolds: Pipes that are essentially a "T" shape, allowing you to connect three things at one point.
  8. +
  9. 4-way manifold: A four-way junction.
  10. +
  11. Pipe cap: Caps off the end of a pipe. Open ends don't actually vent air, because of the way the pipes are assembled, so, uh. Use them to decorate your house or something.
  12. +
  13. Manual Valve: A valve that will block off airflow when turned. Can't be used by the AI or cyborgs, because they don't have hands.
  14. +<
  15. Manual T-Valve: Like a manual valve, but at the center of a manifold instead of a straight pipe.


  16. + +

    Insulated Pipes


    + Special Public Service Announcement.
    + Our regular pipes are already insulated. These are completely worthless. Punch anyone who uses them.

    + +

    Devices:


    + They actually do something.
    + This is usually where people get frightened,
    afraid, and start calling on their gods and/or cowering in fear. Yes, I can see you doing that right now. + Stop it. It's unbecoming. Most of these are fairly straightforward.
    + +
  17. Gas Pump: Take a wild guess. It moves gas in the direction it's pointing (marked by the red line on one end). It moves it based on pressure, the maximum output being 4500 kPa (kilopascals). + Ordinary atmospheric pressure, for comparison, is 101.3 kPa, and the minimum pressure of room-temperature pure oxygen needed to not suffocate in a matter of minutes is 16 kPa + (though 18 is preferred using internals, for various reasons).
  18. +
  19. Volume pump: This pump goes based on volume, instead of pressure, and the possible maximum pressure it can create in the pipe on the recieving end is double the gas pump because of this, + clocking in at an incredible 9000 kPa. If a pipe with this is destroyed or damaged, and this pressure of gas escapes, it can be incredibly dangerous depending on the size of the pipe filled. + Don't hook this to the distribution loop, or you will make babies cry and the Chief Engineer brutally beat you.
  20. +
  21. Passive gate: This is essentially a cap on the pressure of gas allowed to flow in a specific direction. + When turned on, instead of actively pumping gas, it measures the pressure flowing through it, and whatever pressure you set is the maximum: it'll cap after that. + In addition, it only lets gas flow one way. The direction the gas flows is opposite the red handle on it, which is confusing to people used to the red stripe on pumps pointing the way.
  22. +
  23. Unary vent: The basic vent used in rooms. It pumps gas into the room, but can't suck it back out. Controlled by the room's air alarm system.
  24. +
  25. Scrubber: The other half of room equipment. Filters air, and can suck it in entirely in what's called a "panic siphon". Actvating a panic siphon without very good reason will kill someone. Don't do it.
  26. +
  27. Meter: A little box with some gagues and numbers. Fasten it to any pipe or manifold, and it'll read you the pressure in it. Very useful.
  28. +
  29. Gas mixer: Two sides are input, one side is output. Mixes the gases pumped into it at the ratio defined. The side perpendicular to the other two is "node 2", for reference. + Can output this gas at pressures from 0-4500 kPa.
  30. +
  31. Gas filter: Essentially the opposite of a gas mixer. One side is input. The other two sides are output. One gas type will be filtered into the perpendicular output pipe, + the rest will continue out the other side. Can also output from 0-4500 kPa.
  32. + +

    Heat Exchange Systems


    + Will not set you on fire.
    + These systems are used to transfer heat only between two pipes. They will not move gases or any other element, but will equalize the temperature (eventually). Note that because of how gases work (remember: pv=nRt), + a higher temperature will raise pressure, and a lower one will lower temperature.
    + +
  33. Pipe: This is a pipe that will exchange heat with the surrounding atmosphere. Place in fire for superheating. Place in space for supercooling.
  34. +
  35. Bent Pipe: Take a wild guess.
  36. +
  37. Junction:Junction:The point where you connect your normal pipes to heat exchange pipes. Not necessary for heat exchangers, but necessary for H/E pipes/bent pipes.
  38. +
  39. Heat Exchanger: These funky-looking bits attach to an open pipe end. Put another heat exchanger directly across from it, and you can transfer heat across two pipes without having to have the gases touch. + This normally shouldn't exchange with the ambient air, despite being totally exposed. Just don't ask questions...

  40. + + + That's about it for pipes. Go forth, armed with this knowledge, and try not to break, burn down, or kill anything. Please.
    + + + + "} + +/obj/item/weapon/book/manual/evaguide + name = "EVA Gear and You: Not Spending All Day Inside" + icon_state = "evabook" + author = "Maria Crash, Senior Atmospherics Technician" + title = "EVA Gear and You: Not Spending All Day Inside" + dat = {" + + + + + + +

    Contents

    +
      +
    1. A forward on using EVA gear
    2. +
    3. Donning a Civilian Suits
    4. +
    5. Putting on a Hardsuit
    6. +
    7. Final Checks
    8. +
    +

    + +

    EVA Gear and You: Not Spending All Day Inside


    + Or: How not to suffocate because there's a hole in your shoes

    + + EVA gear. Wonderful to use. It's useful for mining, engineering, and occasionally just surviving, if things are that bad. Most people have EVA training, + but apparently there are some on a space station who don't. This guide should give you a basic idea of how to use this gear, safely. It's split into two sections: + Civilian suits and hardsuits.

    + +

    Civilian Suits


    + The bulkiest things this side of Alpha Centauri
    + These suits are the grey ones that are stored in EVA. They're the more simple to get on, but are also a lot bulkier, and provide less protection from environmental hazards such as radiaion or physical impact. + As Medical, Engineering, Security, and Mining all have hardsuits of their own, these don't see much use, but knowing how to put them on is quite useful anyways.

    + + First, take the suit. It should be in three pieces: A top, a bottom,
    and a helmet. Put the bottom on first, shoes and the like will fit in it. If you have magnetic boots, however, + put them on on top of the suit's feet. Next, get the top on, as you would a shirt. It can be somewhat awkward putting these pieces on, due to the makeup of the suit, + but to an extent they will adjust to you. You can then find the snaps and seals around the waist, where the two pieces meet. Fasten these, and double-check their tightness. + The red indicators around the waist of the lower half will turn green when this is done correctly. Next, put on whatever breathing apparatus you're using, be it a gas mask or a breath mask. Make sure the oxygen tube is fastened into it. + Put on the helmet now, straight forward, and make sure the tube goes into the small opening specifically for internals. Again, fasten seals around the neck, a small indicator light in the inside of the helmet should go from red to off when all is fastened. + There is a small slot on the side of the suit where an emergency oxygen tank or extended emergency oxygen tank will fit, + but it is reccomended to have a full-sized tank on your back for EVA.

    + +

    Hardsuits


    + Heavy, uncomfortable, still the best option.
    + These suits come in Engineering, Mining, and the Armory. There's also a couple Medical Hardsuits in EVA. These provide a lot more protection than the standard suits.

    + + Similarly to the other suits, these are split into three parts. Fastening the pant and top are mostly the same as the other spacesuits, with the exception that these are a bit heavier, + though not as bulky. The helmet goes on differently, with the air tube feeing into the suit and out a hole near the left shoulder, while the helmet goes on turned ninety degrees counter-clockwise, + and then is screwed in for one and a quarter full rotations clockwise, leaving the faceplate directly in front of you. There is a small button on the right side of the helmet that activates the helmet light. + The tanks that fasten onto the side slot are emergency tanks, as
    well as full-sized oxygen tanks, leaving your back free for a backpack or satchel.

    + +

    FINAL CHECKS:


    +
  41. Are all seals fastened correctly?
  42. +
  43. Do you either have shoes on under the suit, or magnetic boots on over it?
  44. +
  45. Do you have a mask on and internals on the suit or your back?
  46. +
  47. Do you have a way to communicate with the station in case something goes wrong?
  48. +
  49. Do you have a second person watching if this is a training session?

  50. + + If you don't have any further issues, go out and do whatever is necessary.
    + + + + "} \ No newline at end of file diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm index e0d3697c3a6..fbaab9a3015 100644 --- a/code/game/objects/items/weapons/scrolls.dm +++ b/code/game/objects/items/weapons/scrolls.dm @@ -50,7 +50,7 @@ if(!((user == loc || (in_range(src, user) && istype(src.loc, /turf))))) return - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(5, 0, user.loc) smoke.attach(user) smoke.start() diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 5fea401da19..9ad77255dc4 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -27,6 +27,9 @@ if (ishuman(usr) || ismonkey(usr)) //so monkeys can take off their backpacks -- Urist var/mob/M = usr + if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech + return + if(over_object == M && Adjacent(M)) // this must come before the screen objects only block orient2hud(M) // dunno why it wasn't before if(M.s_active) @@ -206,6 +209,8 @@ break if(!ok) if(!stop_messages) + if (istype(W, /obj/item/weapon/hand_labeler)) + return 0 usr << "[src] cannot hold [W]." return 0 @@ -311,7 +316,7 @@ return 1 //Robots can't interact with storage items. if(!can_be_inserted(W)) - return 1 + return 0 if(istype(W, /obj/item/weapon/tray)) var/obj/item/weapon/tray/T = W diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 90da67076b2..5c50973691a 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -354,33 +354,36 @@ /obj/item/weapon/weldingtool/proc/eyecheck(mob/user as mob) if(!iscarbon(user)) return 1 var/safety = user:eyecheck() - switch(safety) - if(1) - usr << "\red Your eyes sting a little." - user.eye_stat += rand(1, 2) - if(user.eye_stat > 12) - user.eye_blurry += rand(3,6) - if(0) - usr << "\red Your eyes burn." - user.eye_stat += rand(2, 4) - if(user.eye_stat > 10) - user.eye_blurry += rand(4,10) - if(-1) - usr << "\red Your thermals intensify the welder's glow. Your eyes itch and burn severely." - user.eye_blurry += rand(12,20) - user.eye_stat += rand(12, 16) - if(user.eye_stat > 10 && safety < 2) - user << "\red Your eyes are really starting to hurt. This can't be good for you!" - if (prob(user.eye_stat - 25 + 1)) - user << "\red You go blind!" - user.sdisabilities |= BLIND - else if (prob(user.eye_stat - 15 + 1)) - user << "\red You go blind!" - user.eye_blind = 5 - user.eye_blurry = 5 - user.disabilities |= NEARSIGHTED - spawn(100) - user.disabilities &= ~NEARSIGHTED + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + var/datum/organ/internal/eyes/E = H.internal_organs["eyes"] + switch(safety) + if(1) + usr << "\red Your eyes sting a little." + E.damage += rand(1, 2) + if(E.damage > 12) + user.eye_blurry += rand(3,6) + if(0) + usr << "\red Your eyes burn." + E.damage += rand(2, 4) + if(E.damage > 10) + E.damage += rand(4,10) + if(-1) + usr << "\red Your thermals intensify the welder's glow. Your eyes itch and burn severely." + user.eye_blurry += rand(12,20) + E.damage += rand(12, 16) + if(E.damage > 10 && safety < 2) + user << "\red Your eyes are really starting to hurt. This can't be good for you!" + if (E.damage >= E.min_broken_damage) + user << "\red You go blind!" + user.sdisabilities |= BLIND + else if (E.damage >= E.min_bruised_damage) + user << "\red You go blind!" + user.eye_blind = 5 + user.eye_blurry = 5 + user.disabilities |= NEARSIGHTED + spawn(100) + user.disabilities &= ~NEARSIGHTED return @@ -406,7 +409,6 @@ m_amt = 70 g_amt = 120 origin_tech = "engineering=4;plasma=3" - icon_state = "ewelder" var/last_gen = 0 diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 58ed13b9d9d..16c5be21a88 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -48,29 +48,30 @@ /obj/structure/table/update_icon() - if(flipped) - var/type = 0 - var/tabledirs = 0 - for(var/direction in list(turn(dir,90), turn(dir,-90)) ) - var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,direction)) - if (T && T.flipped) - type++ - tabledirs |= direction - var/base = "table" - if (istype(src, /obj/structure/table/woodentable)) - base = "wood" - if (istype(src, /obj/structure/table/reinforced)) - base = "rtable" - - icon_state = "[base]flip[type]" - if (type==1) - if (tabledirs & turn(dir,90)) - icon_state = icon_state+"-" - if (tabledirs & turn(dir,-90)) - icon_state = icon_state+"+" - return 1 - spawn(2) //So it properly updates when deleting + + if(flipped) + var/type = 0 + var/tabledirs = 0 + for(var/direction in list(turn(dir,90), turn(dir,-90)) ) + var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,direction)) + if (T && T.flipped && T.dir == src.dir) + type++ + tabledirs |= direction + var/base = "table" + if (istype(src, /obj/structure/table/woodentable)) + base = "wood" + if (istype(src, /obj/structure/table/reinforced)) + base = "rtable" + + icon_state = "[base]flip[type]" + if (type==1) + if (tabledirs & turn(dir,90)) + icon_state = icon_state+"-" + if (tabledirs & turn(dir,-90)) + icon_state = icon_state+"+" + return 1 + var/dir_sum = 0 for(var/direction in list(1,2,4,8,5,6,9,10)) var/skip_sum = 0 @@ -393,29 +394,36 @@ return /obj/structure/table/proc/straight_table_check(var/direction) - var/turf/left = get_step(src,turn(direction,90)) - var/turf/right = get_step(src,turn(direction,-90)) - var/turf/next = get_step(src,direction) - if(locate(/obj/structure/table,left) || locate(/obj/structure/table,right)) - return 0 - var/obj/structure/table/T = locate(/obj/structure/table, next) + var/obj/structure/table/T + for(var/angle in list(-90,90)) + T = locate() in get_step(src.loc,turn(direction,angle)) + if(T && !T.flipped) + return 0 + T = locate() in get_step(src.loc,direction) + if (!T || T.flipped) + return 1 if (istype(T,/obj/structure/table/reinforced/)) var/obj/structure/table/reinforced/R = T if (R.status == 2) return 0 - if (!T) - return 1 - else - return T.straight_table_check(direction) + return T.straight_table_check(direction) + +/obj/structure/table/verb/can_touch(var/mob/user) + if (!user) + return 0 + if (user.stat) //zombie goasts go away + return 0 + if (issilicon(user)) + user << "You need hands for this." + return 0 + return 1 /obj/structure/table/verb/do_flip() set name = "Flip table" set desc = "Flips a non-reinforced table" set category = "Object" set src in oview(1) - - if (issilicon(usr)) - usr << "You need hands for this." + if (!can_touch(usr)) return if(!flip(get_cardinal_dir(usr,src))) usr << "It won't budge." @@ -423,21 +431,38 @@ usr.visible_message("[usr] flips \the [src]!") return +/obj/structure/table/proc/unflipping_check(var/direction) + for(var/mob/M in oview(src,0)) + return 0 + + var/list/L = list() + if(direction) + L.Add(direction) + else + L.Add(turn(src.dir,-90)) + L.Add(turn(src.dir,90)) + for(var/new_dir in L) + var/obj/structure/table/T = locate() in get_step(src.loc,new_dir) + if(T) + if(T.flipped && T.dir == src.dir && !T.unflipping_check(new_dir)) + return 0 + return 1 + /obj/structure/table/proc/do_put() set name = "Put table back" set desc = "Puts flipped table back" set category = "Object" set src in oview(1) - if (!unflip()) - usr << "It won't budge." + if (!can_touch(usr)) return + if (!unflipping_check()) + usr << "It won't budge." + return + unflip() /obj/structure/table/proc/flip(var/direction) - if (flipped) - return 0 - if( !straight_table_check(turn(direction,90)) || !straight_table_check(turn(direction,-90)) ) return 0 @@ -456,8 +481,8 @@ flipped = 1 flags |= ON_BORDER for(var/D in list(turn(direction, 90), turn(direction, -90))) - if(locate(/obj/structure/table,get_step(src,D))) - var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,D)) + var/obj/structure/table/T = locate() in get_step(src,D) + if(T && !T.flipped) T.flip(direction) update_icon() update_adjacent() @@ -465,16 +490,6 @@ return 1 /obj/structure/table/proc/unflip() - if (!flipped) - return 0 - - var/can_flip = 1 - for (var/mob/A in oview(src,0))//src.loc) - if (istype(A)) - can_flip = 0 - if (!can_flip) - return 0 - verbs -=/obj/structure/table/proc/do_put verbs +=/obj/structure/table/verb/do_flip @@ -482,8 +497,8 @@ flipped = 0 flags &= ~ON_BORDER for(var/D in list(turn(dir, 90), turn(dir, -90))) - if(locate(/obj/structure/table,get_step(src,D))) - var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,D)) + var/obj/structure/table/T = locate() in get_step(src.loc,D) + if(T && T.flipped && T.dir == src.dir) T.unflip() update_icon() update_adjacent() @@ -646,4 +661,4 @@ del(src) /obj/structure/rack/attack_tk() // no telehulk sorry - return + return \ No newline at end of file diff --git a/code/game/objects/structures/transit_tubes.dm b/code/game/objects/structures/transit_tubes.dm index 54630d3c4a3..d1435d383d9 100644 --- a/code/game/objects/structures/transit_tubes.dm +++ b/code/game/objects/structures/transit_tubes.dm @@ -99,6 +99,16 @@ obj/structure/ex_act(severity) +/obj/structure/transit_tube/Bumped(mob/AM as mob|obj) + var/obj/structure/transit_tube/T = locate() in AM.loc + if(T) + AM << "The tube's support pylons block your way." + return ..() + else + AM.loc = src.loc + AM << "You slip under the tube." + + /obj/structure/transit_tube/station/New(loc) ..(loc) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 24a9866a545..7d1041aaab3 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -11,6 +11,8 @@ var/ini_dir = null var/state = 0 var/reinf = 0 + var/basestate + var/shardtype = /obj/item/weapon/shard // var/silicate = 0 // number of units of silicate // var/icon/silicateIcon = null // the silicated icon @@ -219,11 +221,11 @@ var/index = null index = 0 while(index < 2) - new /obj/item/weapon/shard(loc) + new shardtype(loc) if(reinf) new /obj/item/stack/rods(loc) index++ else - new /obj/item/weapon/shard(loc) + new shardtype(loc) if(reinf) new /obj/item/stack/rods(loc) del(src) return @@ -282,19 +284,9 @@ /obj/structure/window/New(Loc,re=0) ..() - if(re) reinf = re +// if(re) reinf = re ini_dir = dir - if(reinf) - icon_state = "rwindow" - desc = "A reinforced window." - name = "reinforced window" - state = 2*anchored - health = 40 - if(opacity) - icon_state = "twindow" - else - icon_state = "window" update_nearby_tiles(need_rebuild=1) update_nearby_icons() @@ -354,12 +346,12 @@ if(abs(x-W.x)-abs(y-W.y) ) //doesn't count windows, placed diagonally to src junction |= get_dir(src,W) if(opacity) - icon_state = "twindow[junction]" + icon_state = "[basestate][junction]" else if(reinf) - icon_state = "rwindow[junction]" + icon_state = "[basestate][junction]" else - icon_state = "window[junction]" + icon_state = "[basestate][junction]" return @@ -371,18 +363,53 @@ /obj/structure/window/basic + desc = "It looks thin and flimsy. A few knocks with... anything, really should shatter it." icon_state = "window" + basestate = "window" + +/obj/structure/window/plasmabasic + name = "plasma window" + desc = "A plasma-glass alloy window. It looks insanely tough to break. It appears it's also insanely tough to burn through." + basestate = "plasmawindow" + icon_state = "plasmawindow" + shardtype = /obj/item/weapon/shard/plasma + health = 120 + +/obj/structure/window/plasmabasic/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > T0C + 32000) + hit(round(exposed_volume / 1000), 0) + ..() + +/obj/structure/window/plasmareinforced + name = "reinforced plasma window" + desc = "A plasma-glass alloy window, with rods supporting it. It looks hopelessly tough to break. It also looks completely fireproof, considering how basic plasma windows are insanely fireproof." + basestate = "plasmarwindow" + icon_state = "plasmarwindow" + shardtype = /obj/item/weapon/shard/plasma + reinf = 1 + health = 160 + +/obj/structure/window/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return /obj/structure/window/reinforced name = "reinforced window" + desc = "It looks rather strong. Might take a few good hits to shatter it." icon_state = "rwindow" + basestate = "rwindow" + health = 40 reinf = 1 /obj/structure/window/reinforced/tinted name = "tinted window" + desc = "It looks rather strong and opaque. Might take a few good hits to shatter it." icon_state = "twindow" + basestate = "twindow" opacity = 1 /obj/structure/window/reinforced/tinted/frosted name = "frosted window" - icon_state = "fwindow" \ No newline at end of file + desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window." + icon_state = "fwindow" + basestate = "fwindow" + health = 30 \ No newline at end of file diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index ccfbd30e1ba..1b708d91070 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -46,6 +46,8 @@ var/global/normal_ooc_colour = "#002eb8" display_colour = "#0099cc" //light blue if(holder.rights & R_MOD && !(holder.rights & R_ADMIN)) display_colour = "#184880" //dark blue + if(holder.rights & R_DEBUG && !(holder.rights & R_ADMIN)) + display_colour = "#1b521f" //dark green else if(holder.rights & R_ADMIN) if(config.allow_admin_ooccolor) display_colour = src.prefs.ooccolor diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index ad60ecf4960..804116fedea 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -1,7 +1,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null) - if(!check_rights(R_BAN)) return + if(!check_rights(R_MOD,0) && !check_rights(R_BAN)) return establish_db_connection() if(!dbcon.IsConnected()) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 5664ff20d82..018d0fe8824 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -807,7 +807,7 @@ var/global/floorIsLava = 0 set desc="Delay the game start/end" set name="Delay" - if(!check_rights(R_ADMIN)) return + if(!check_rights(R_SERVER)) return if (!ticker || ticker.current_state != GAME_STATE_PREGAME) ticker.delay_end = !ticker.delay_end log_admin("[key_name(usr)] [ticker.delay_end ? "delayed the round end" : "has made the round end normally"].") diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index dd330ec00c0..606a6e82ffc 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -69,7 +69,8 @@ var/list/admin_verbs_admin = list( /client/proc/check_customitem_activity, /client/proc/man_up, /client/proc/global_man_up, - /client/proc/response_team // Response Teams admin verb + /client/proc/response_team, // Response Teams admin verb + /client/proc/allow_character_respawn /* Allows a ghost to respawn */ ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, @@ -139,7 +140,9 @@ var/list/admin_verbs_debug = list( /client/proc/restart_controller, /client/proc/enable_debug_verbs, /client/proc/callproc, - /client/proc/toggledebuglogs + /client/proc/toggledebuglogs, + /client/proc/SDQL_query, + /client/proc/SDQL2_query ) var/list/admin_verbs_possess = list( /proc/possess, diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 813a0bfbd79..0b6ab51ce34 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -685,6 +685,7 @@ if(notbannedlist.len) //at least 1 unbanned job exists in joblist so we have stuff to ban. switch(alert("Temporary Ban?",,"Yes","No", "Cancel")) if("Yes") + if(!check_rights(R_MOD,0) && !check_rights(R_BAN)) return if(config.ban_legacy_system) usr << "\red Your server is using the legacy banning system, which does not support temporary job bans. Consider upgrading. Aborting ban." return @@ -846,7 +847,7 @@ del(M.client) //del(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends. if("No") - if(check_rights(R_BAN)) return + if(!check_rights(R_BAN)) return var/reason = input(usr,"Reason?","reason","Griefer") as text|null if(!reason) return diff --git a/code/modules/admin/verbs/SDQL.dm b/code/modules/admin/verbs/SDQL.dm new file mode 100644 index 00000000000..d8626da403a --- /dev/null +++ b/code/modules/admin/verbs/SDQL.dm @@ -0,0 +1,497 @@ + +//Structured Datum Query Language. Basically SQL meets BYOND objects. + +//Note: For use in BS12, need text_starts_with proc, and to modify the action on select to use BS12's object edit command(s). + +/client/proc/SDQL_query(query_text as message) + set category = "Admin" + if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe. + message_admins("\red ERROR: Non-admin [usr.key] attempted to execute a SDQL query!") + log_admin("Non-admin [usr.key] attempted to execute a SDQL query!") + + var/list/query_list = SDQL_tokenize(query_text) + + if(query_list.len < 2) + if(query_list.len > 0) + usr << "\red SDQL: Too few discrete tokens in query \"[query_text]\". Please check your syntax and try again." + return + + if(!(lowertext(query_list[1]) in list("select", "delete", "update"))) + usr << "\red SDQL: Unknown query type: \"[query_list[1]]\" in query \"[query_text]\". Please check your syntax and try again." + return + + var/list/types = list() + + var/i + for(i = 2; i <= query_list.len; i += 2) + types += query_list[i] + + if(i + 1 >= query_list.len || query_list[i + 1] != ",") + break + + i++ + + var/list/from = list() + + if(i <= query_list.len) + if(lowertext(query_list[i]) in list("from", "in")) + for(i++; i <= query_list.len; i += 2) + from += query_list[i] + + if(i + 1 >= query_list.len || query_list[i + 1] != ",") + break + + i++ + + if(from.len < 1) + from += "world" + + var/list/set_vars = list() + + if(lowertext(query_list[1]) == "update") + if(i <= query_list.len && lowertext(query_list[i]) == "set") + for(i++; i <= query_list.len; i++) + if(i + 2 <= query_list.len && query_list[i + 1] == "=") + set_vars += query_list[i] + set_vars[query_list[i]] = query_list[i + 2] + + else + usr << "\red SDQL: Invalid set parameter in query \"[query_text]\". Please check your syntax and try again." + return + + i += 3 + + if(i >= query_list.len || query_list[i] != ",") + break + + if(set_vars.len < 1) + usr << "\red SDQL: Invalid or missing set in query \"[query_text]\". Please check your syntax and try again." + return + + var/list/where = list() + + if(i <= query_list.len && lowertext(query_list[i]) == "where") + where = query_list.Copy(i + 1) + + var/list/from_objs = list() + if("world" in from) + from_objs += world + else + for(var/f in from) + if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"") + from_objs += locate(copytext(f, 2, length(f))) + else if(copytext(f, 1, 2) != "/") + from_objs += locate(f) + else + var/f2 = text2path(f) + if(text_starts_with(f, "/mob")) + for(var/mob/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/space")) + for(var/turf/space/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/simulated")) + for(var/turf/simulated/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf/unsimulated")) + for(var/turf/unsimulated/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/turf")) + for(var/turf/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/area")) + for(var/area/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/obj/item")) + for(var/obj/item/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/obj/machinery")) + for(var/obj/machinery/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/obj")) + for(var/obj/m in world) + if(istype(m, f2)) + from_objs += m + + else if(text_starts_with(f, "/atom")) + for(var/atom/m in world) + if(istype(m, f2)) + from_objs += m +/* + else + for(var/datum/m in world) + if(istype(m, f2)) + from_objs += m +*/ + + var/list/objs = list() + + for(var/from_obj in from_objs) + if("*" in types) + objs += from_obj:contents + else + for(var/f in types) + if(copytext(f, 1, 2) == "'" || copytext(f, 1, 2) == "\"") + objs += locate(copytext(f, 2, length(f))) in from_obj + else if(copytext(f, 1, 2) != "/") + objs += locate(f) in from_obj + else + var/f2 = text2path(f) + if(text_starts_with(f, "/mob")) + for(var/mob/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/space")) + for(var/turf/space/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/simulated")) + for(var/turf/simulated/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf/unsimulated")) + for(var/turf/unsimulated/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/turf")) + for(var/turf/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/area")) + for(var/area/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/obj/item")) + for(var/obj/item/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/obj/machinery")) + for(var/obj/machinery/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/obj")) + for(var/obj/m in from_obj) + if(istype(m, f2)) + objs += m + + else if(text_starts_with(f, "/atom")) + for(var/atom/m in from_obj) + if(istype(m, f2)) + objs += m + + else + for(var/datum/m in from_obj) + if(istype(m, f2)) + objs += m + + + for(var/datum/t in objs) + var/currently_false = 0 + for(i = 1, i - 1 < where.len, i++) + var/v = where[i++] + var/compare_op = where[i++] + if(!(compare_op in list("==", "=", "<>", "<", ">", "<=", ">=", "!="))) + usr << "\red SDQL: Unknown comparison operator [compare_op] in where clause following [v] in query \"[query_text]\". Please check your syntax and try again." + return + + var/j + for(j = i, j <= where.len, j++) + if(lowertext(where[j]) in list("and", "or", ";")) + break + + if(!currently_false) + var/value = SDQL_text2value(t, v) + var/result = SDQL_evaluate(t, where.Copy(i, j)) + + switch(compare_op) + if("=", "==") + currently_false = !(value == result) + + if("!=", "<>") + currently_false = !(value != result) + + if("<") + currently_false = !(value < result) + + if(">") + currently_false = !(value > result) + + if("<=") + currently_false = !(value <= result) + + if(">=") + currently_false = !(value >= result) + + + if(j > where.len || lowertext(where[j]) == ";") + break + else if(lowertext(where[j]) == "or") + if(currently_false) + currently_false = 0 + else + break + + i = j + + if(currently_false) + objs -= t + + + + usr << "\blue SQDL Query: [query_text]" + message_admins("[usr] executed SDQL query: \"[query_text]\".") +/* + for(var/t in types) + usr << "Type: [t]" + + for(var/t in from) + usr << "From: [t]" + + for(var/t in set_vars) + usr << "Set: [t] = [set_vars[t]]" + + if(where.len) + var/where_str = "" + for(var/t in where) + where_str += "[t] " + + usr << "Where: [where_str]" + + usr << "From objects:" + for(var/datum/t in from_objs) + usr << t + + usr << "Objects:" + for(var/datum/t in objs) + usr << t +*/ + switch(lowertext(query_list[1])) + if("delete") + for(var/datum/t in objs) + del t + + if("update") + for(var/datum/t in objs) + objs[t] = list() + for(var/v in set_vars) + if(v in t.vars) + objs[t][v] = SDQL_text2value(t, set_vars[v]) + + for(var/datum/t in objs) + for(var/v in objs[t]) + t.vars[v] = objs[t][v] + + if("select") + var/text = "" + for(var/datum/t in objs) + if(istype(t, /atom)) + var/atom/a = t + + if(a.x) + text += "\ref[t]: [t] at ([a.x], [a.y], [a.z])
    " + + else if(a.loc && a.loc.x) + text += "\ref[t]: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
    " + + else + text += "\ref[t]: [t]
    " + + else + text += "\ref[t]: [t]
    " + + //text += "[t]
    " + usr << browse(text, "window=sdql_result") + + +/client/Topic(href,href_list[],hsrc) + if(href_list["SDQL_select"]) + debug_variables(locate(href_list["SDQL_select"])) + + ..() + + +/proc/SDQL_evaluate(datum/object, list/equation) + if(equation.len == 0) + return null + + else if(equation.len == 1) + return SDQL_text2value(object, equation[1]) + + else if(equation[1] == "!") + return !SDQL_evaluate(object, equation.Copy(2)) + + else if(equation[1] == "-") + return -SDQL_evaluate(object, equation.Copy(2)) + + + else + usr << "\red SDQL: Sorry, equations not yet supported :(" + return null + + +/proc/SDQL_text2value(datum/object, text) + if(text2num(text) != null) + return text2num(text) + else if(text == "null") + return null + else if(copytext(text, 1, 2) == "'" || copytext(text, 1, 2) == "\"" ) + return copytext(text, 2, length(text)) + else if(copytext(text, 1, 2) == "/") + return text2path(text) + else + if(findtext(text, ".")) + var/split = findtext(text, ".") + var/v = copytext(text, 1, split) + + if((v in object.vars) && istype(object.vars[v], /datum)) + return SDQL_text2value(object.vars[v], copytext(text, split + 1)) + else + return null + + else + if(text in object.vars) + return object.vars[text] + else + return null + + +/proc/text_starts_with(text, start) + if(copytext(text, 1, length(start) + 1) == start) + return 1 + else + return 0 + + + + + +/proc/SDQL_tokenize(query_text) + + var/list/whitespace = list(" ", "\n", "\t") + var/list/single = list("(", ")", ",", "+", "-") + var/list/multi = list( + "=" = list("", "="), + "<" = list("", "=", ">"), + ">" = list("", "="), + "!" = list("", "=")) + + var/word = "" + var/list/query_list = list() + var/len = length(query_text) + + for(var/i = 1, i <= len, i++) + var/char = copytext(query_text, i, i + 1) + + if(char in whitespace) + if(word != "") + query_list += word + word = "" + + else if(char in single) + if(word != "") + query_list += word + word = "" + + query_list += char + + else if(char in multi) + if(word != "") + query_list += word + word = "" + + var/char2 = copytext(query_text, i + 1, i + 2) + + if(char2 in multi[char]) + query_list += "[char][char2]" + i++ + + else + query_list += char + + else if(char == "'") + if(word != "") + usr << "\red SDQL: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again." + return null + + word = "'" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "'") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "'" + i++ + + else + break + + else + word += char + + if(i > len) + usr << "\red SDQL: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again." + return null + + query_list += "[word]'" + word = "" + + else if(char == "\"") + if(word != "") + usr << "\red SDQL: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again." + return null + + word = "\"" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "\"") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "\"" + i++ + + else + break + + else + word += char + + if(i > len) + usr << "\red SDQL: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again." + return null + + query_list += "[word]\"" + word = "" + + else + word += char + + if(word != "") + query_list += word + + return query_list diff --git a/code/modules/admin/verbs/SDQL_2.dm b/code/modules/admin/verbs/SDQL_2.dm new file mode 100644 index 00000000000..549447da117 --- /dev/null +++ b/code/modules/admin/verbs/SDQL_2.dm @@ -0,0 +1,426 @@ + + +/client/proc/SDQL2_query(query_text as message) + set category = "Admin" + if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe. + message_admins("\red ERROR: Non-admin [usr.key] attempted to execute a SDQL query!") + log_admin("Non-admin [usr.key] attempted to execute a SDQL query!") + + if(!query_text || length(query_text) < 1) + return + + //world << query_text + + var/list/query_list = SDQL2_tokenize(query_text) + + if(!query_list || query_list.len < 1) + return + + var/list/query_tree = SDQL_parse(query_list) + + if(query_tree.len < 1) + return + + var/list/from_objs = list() + var/list/select_types = list() + + switch(query_tree[1]) + if("explain") + SDQL_testout(query_tree["explain"]) + return + + if("call") + if("on" in query_tree) + select_types = query_tree["on"] + else + return + + if("select", "delete", "update") + select_types = query_tree[query_tree[1]] + + from_objs = SDQL_from_objs(query_tree["from"]) + + var/list/objs = list() + + for(var/type in select_types) + var/char = copytext(type, 1, 2) + + if(char == "/" || char == "*") + for(var/from in from_objs) + objs += SDQL_get_all(type, from) + + else if(char == "'" || char == "\"") + objs += locate(copytext(type, 2, length(type))) + + if("where" in query_tree) + var/objs_temp = objs + objs = list() + for(var/datum/d in objs_temp) + if(SDQL_expression(d, query_tree["where"])) + objs += d + + //usr << "Query: [query_text]" + message_admins("[usr] executed SDQL query: \"[query_text]\".") + + switch(query_tree[1]) + if("delete") + for(var/datum/d in objs) + del d + + if("select") + var/text = "" + for(var/datum/t in objs) + if(istype(t, /atom)) + var/atom/a = t + + if(a.x) + text += "\ref[t]: [t] at ([a.x], [a.y], [a.z])
    " + + else if(a.loc && a.loc.x) + text += "\ref[t]: [t] in [a.loc] at ([a.loc.x], [a.loc.y], [a.loc.z])
    " + + else + text += "\ref[t]: [t]
    " + + else + text += "\ref[t]: [t]
    " + + usr << browse(text, "window=SDQL-result") + + if("update") + if("set" in query_tree) + var/list/set_list = query_tree["set"] + for(var/datum/d in objs) + var/list/vals = list() + for(var/v in set_list) + if(v in d.vars) + vals += v + vals[v] = SDQL_expression(d, set_list[v]) + + if(istype(d, /turf)) + for(var/v in vals) + if(v == "x" || v == "y" || v == "z") + continue + + d.vars[v] = vals[v] + + else + for(var/v in vals) + d.vars[v] = vals[v] + + + + + +/proc/SDQL_parse(list/query_list) + var/datum/SDQL_parser/parser = new(query_list) + var/list/query_tree = parser.parse() + + del(parser) + + return query_tree + + + +/proc/SDQL_testout(list/query_tree, indent = 0) + var/spaces = "" + for(var/s = 0, s < indent, s++) + spaces += " " + + for(var/item in query_tree) + if(istype(item, /list)) + world << "[spaces](" + SDQL_testout(item, indent + 1) + world << "[spaces])" + + else + world << "[spaces][item]" + + if(!isnum(item) && query_tree[item]) + + if(istype(query_tree[item], /list)) + world << "[spaces] (" + SDQL_testout(query_tree[item], indent + 2) + world << "[spaces] )" + + else + world << "[spaces] [query_tree[item]]" + + + +/proc/SDQL_from_objs(list/tree) + if("world" in tree) + return list(world) + + var/list/out = list() + + for(var/type in tree) + var/char = copytext(type, 1, 2) + + if(char == "/") + out += SDQL_get_all(type, world) + + else if(char == "'" || char == "\"") + out += locate(copytext(type, 2, length(type))) + + return out + + +/proc/SDQL_get_all(type, location) + var/list/out = list() + + if(type == "*") + for(var/datum/d in location) + out += d + + return out + + type = text2path(type) + + if(ispath(type, /mob)) + for(var/mob/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /turf)) + for(var/turf/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /obj)) + for(var/obj/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /area)) + for(var/area/d in location) + if(istype(d, type)) + out += d + + else if(ispath(type, /atom)) + for(var/atom/d in location) + if(istype(d, type)) + out += d + + else + for(var/datum/d in location) + if(istype(d, type)) + out += d + + return out + + +/proc/SDQL_expression(datum/object, list/expression, start = 1) + var/result = 0 + var/val + + for(var/i = start, i <= expression.len, i++) + var/op = "" + + if(i > start) + op = expression[i] + i++ + + var/list/ret = SDQL_value(object, expression, i) + val = ret["val"] + i = ret["i"] + + if(op != "") + switch(op) + if("+") + result += val + if("-") + result -= val + if("*") + result *= val + if("/") + result /= val + if("&") + result &= val + if("|") + result |= val + if("^") + result ^= val + if("=", "==") + result = (result == val) + if("!=", "<>") + result = (result != val) + if("<") + result = (result < val) + if("<=") + result = (result <= val) + if(">") + result = (result > val) + if(">=") + result = (result >= val) + if("and", "&&") + result = (result && val) + if("or", "||") + result = (result || val) + else + usr << "\red SDQL2: Unknown op [op]" + result = null + else + result = val + + return result + +/proc/SDQL_value(datum/object, list/expression, start = 1) + var/i = start + var/val = null + + if(i > expression.len) + return list("val" = null, "i" = i) + + if(istype(expression[i], /list)) + val = SDQL_expression(object, expression[i]) + + else if(expression[i] == "!") + var/list/ret = SDQL_value(object, expression, i + 1) + val = !ret["val"] + i = ret["i"] + + else if(expression[i] == "~") + var/list/ret = SDQL_value(object, expression, i + 1) + val = ~ret["val"] + i = ret["i"] + + else if(expression[i] == "-") + var/list/ret = SDQL_value(object, expression, i + 1) + val = -ret["val"] + i = ret["i"] + + else if(expression[i] == "null") + val = null + + else if(isnum(expression[i])) + val = expression[i] + + else if(copytext(expression[i], 1, 2) in list("'", "\"")) + val = copytext(expression[i], 2, length(expression[i])) + + else + val = SDQL_var(object, expression, i) + i = expression.len + + return list("val" = val, "i" = i) + +/proc/SDQL_var(datum/object, list/expression, start = 1) + + if(expression[start] in object.vars) + + if(start < expression.len && expression[start + 1] == ".") + return SDQL_var(object.vars[expression[start]], expression[start + 2]) + + else + return object.vars[expression[start]] + + else + return null + +/proc/SDQL2_tokenize(query_text) + + var/list/whitespace = list(" ", "\n", "\t") + var/list/single = list("(", ")", ",", "+", "-", ".") + var/list/multi = list( + "=" = list("", "="), + "<" = list("", "=", ">"), + ">" = list("", "="), + "!" = list("", "=")) + + var/word = "" + var/list/query_list = list() + var/len = length(query_text) + + for(var/i = 1, i <= len, i++) + var/char = copytext(query_text, i, i + 1) + + if(char in whitespace) + if(word != "") + query_list += word + word = "" + + else if(char in single) + if(word != "") + query_list += word + word = "" + + query_list += char + + else if(char in multi) + if(word != "") + query_list += word + word = "" + + var/char2 = copytext(query_text, i + 1, i + 2) + + if(char2 in multi[char]) + query_list += "[char][char2]" + i++ + + else + query_list += char + + else if(char == "'") + if(word != "") + usr << "\red SDQL2: You have an error in your SDQL syntax, unexpected ' in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again." + return null + + word = "'" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "'") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "'" + i++ + + else + break + + else + word += char + + if(i > len) + usr << "\red SDQL2: You have an error in your SDQL syntax, unmatched ' in query: \"[query_text]\". Please check your syntax, and try again." + return null + + query_list += "[word]'" + word = "" + + else if(char == "\"") + if(word != "") + usr << "\red SDQL2: You have an error in your SDQL syntax, unexpected \" in query: \"[query_text]\" following \"[word]\". Please check your syntax, and try again." + return null + + word = "\"" + + for(i++, i <= len, i++) + char = copytext(query_text, i, i + 1) + + if(char == "\"") + if(copytext(query_text, i + 1, i + 2) == "'") + word += "\"" + i++ + + else + break + + else + word += char + + if(i > len) + usr << "\red SDQL2: You have an error in your SDQL syntax, unmatched \" in query: \"[query_text]\". Please check your syntax, and try again." + return null + + query_list += "[word]\"" + word = "" + + else + word += char + + if(word != "") + query_list += word + + return query_list diff --git a/code/modules/admin/verbs/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL_2_parser.dm new file mode 100644 index 00000000000..d1d30b33b5e --- /dev/null +++ b/code/modules/admin/verbs/SDQL_2_parser.dm @@ -0,0 +1,531 @@ +//I'm pretty sure that this is a recursive [s]descent[/s] ascent parser. + + + +//Spec + +////////// +// +// query : select_query | delete_query | update_query | call_query | explain +// explain : 'EXPLAIN' query +// +// select_query : 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +// delete_query : 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +// update_query : 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] +// call_query : 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] +// +// select_list : select_item [',' select_list] +// select_item : '*' | select_function | object_type +// select_function : count_function +// count_function : 'COUNT' '(' '*' ')' | 'COUNT' '(' object_types ')' +// +// from_list : from_item [',' from_list] +// from_item : 'world' | object_type +// +// call_function : ['(' [arguments] ')'] +// arguments : expression [',' arguments] +// +// object_type : | string +// +// assignments : assignment, [',' assignments] +// assignment : '=' expression +// variable : | '.' variable +// +// bool_expression : expression comparitor expression [bool_operator bool_expression] +// expression : ( unary_expression | '(' expression ')' | value ) [binary_operator expression] +// unary_expression : unary_operator ( unary_expression | value | '(' expression ')' ) +// comparitor : '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' +// value : variable | string | number | 'null' +// unary_operator : '!' | '-' | '~' +// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' +// bool_operator : 'AND' | '&&' | 'OR' | '||' +// +// string : ''' ''' | '"' '"' +// number : +// +////////// + +/datum/SDQL_parser + var/query_type + var/error = 0 + + var/list/query + var/list/tree + + var/list/select_functions = list("count") + var/list/boolean_operators = list("and", "or", "&&", "||") + var/list/unary_operators = list("!", "-", "~") + var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^") + var/list/comparitors = list("=", "==", "!=", "<>", "<", "<=", ">", ">=") + + + +/datum/SDQL_parser/New(query_list) + query = query_list + + + +/datum/SDQL_parser/proc/parse_error(error_message) + error = 1 + usr << "\red SQDL2 Parsing Error: [error_message]" + return query.len + 1 + +/datum/SDQL_parser/proc/parse() + tree = list() + query(1, tree) + + if(error) + return list() + else + return tree + +/datum/SDQL_parser/proc/token(i) + if(i <= query.len) + return query[i] + + else + return null + +/datum/SDQL_parser/proc/tokens(i, num) + if(i + num <= query.len) + return query.Copy(i, i + num) + + else + return null + +/datum/SDQL_parser/proc/tokenl(i) + return lowertext(token(i)) + + + +/datum/SDQL_parser/proc + +//query: select_query | delete_query | update_query + query(i, list/node) + query_type = tokenl(i) + + switch(query_type) + if("select") + select_query(i, node) + + if("delete") + delete_query(i, node) + + if("update") + update_query(i, node) + + if("call") + call_query(i, node) + + if("explain") + node += "explain" + node["explain"] = list() + query(i + 1, node["explain"]) + + +// select_query: 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] + select_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) + + node += "select" + node["select"] = select + + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" + + node += "from" + node["from"] = from + + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + + node += "where" + node["where"] = where + + return i + + +//delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] + delete_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) + + node += "delete" + node["delete"] = select + + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" + + node += "from" + node["from"] = from + + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + + node += "where" + node["where"] = where + + return i + + +//update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] + update_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) + + node += "update" + node["update"] = select + + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" + + node += "from" + node["from"] = from + + if(tokenl(i) != "set") + i = parse_error("UPDATE has misplaced SET") + + var/list/set_assignments = list() + i = assignments(i + 1, set_assignments) + + node += "set" + node["set"] = set_assignments + + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + + node += "where" + node["where"] = where + + return i + + +//call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] + call_query(i, list/node) + var/list/func = list() + i = call_function(i + 1, func) + + node += "call" + node["call"] = func + + if(tokenl(i) != "on") + return i + + var/list/select = list() + i = select_list(i + 1, select) + + node += "on" + node["on"] = select + + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" + + node += "from" + node["from"] = from + + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + + node += "where" + node["where"] = where + + return i + + +//select_list: select_item [',' select_list] + select_list(i, list/node) + i = select_item(i, node) + + if(token(i) == ",") + i = select_list(i + 1, node) + + return i + + +//from_list: from_item [',' from_list] + from_list(i, list/node) + i = from_item(i, node) + + if(token(i) == ",") + i = from_list(i + 1, node) + + return i + + +//assignments: assignment, [',' assignments] + assignments(i, list/node) + i = assignment(i, node) + + if(token(i) == ",") + i = assignments(i + 1, node) + + return i + + +//select_item: '*' | select_function | object_type + select_item(i, list/node) + + if(token(i) == "*") + node += "*" + i++ + + else if(tokenl(i) in select_functions) + i = select_function(i, node) + + else + i = object_type(i, node) + + return i + + +//from_item: 'world' | object_type + from_item(i, list/node) + + if(token(i) == "world") + node += "world" + i++ + + else + i = object_type(i, node) + + return i + + +//bool_expression: expression [bool_operator bool_expression] + bool_expression(i, list/node) + + var/list/bool = list() + i = expression(i, bool) + + node[++node.len] = bool + + if(tokenl(i) in boolean_operators) + i = bool_operator(i, node) + i = bool_expression(i, node) + + return i + + +//assignment: '=' expression + assignment(i, list/node) + + node += token(i) + + if(token(i + 1) == "=") + var/varname = token(i) + node[varname] = list() + + i = expression(i + 2, node[varname]) + + else + parse_error("Assignment expected, but no = found") + + return i + + +//variable: | '.' variable + variable(i, list/node) + var/list/L = list(token(i)) + node[++node.len] = L + + if(token(i + 1) == ".") + L += "." + i = variable(i + 2, L) + + else + i++ + + return i + + +//object_type: | string + object_type(i, list/node) + + if(copytext(token(i), 1, 2) == "/") + node += token(i) + + else + i = string(i, node) + + return i + 1 + + +//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' + comparitor(i, list/node) + + if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">=")) + node += token(i) + + else + parse_error("Unknown comparitor [token(i)]") + + return i + 1 + + +//bool_operator: 'AND' | '&&' | 'OR' | '||' + bool_operator(i, list/node) + + if(tokenl(i) in list("and", "or", "&&", "||")) + node += token(i) + + else + parse_error("Unknown comparitor [token(i)]") + + return i + 1 + + +//string: ''' ''' | '"' '"' + string(i, list/node) + + if(copytext(token(i), 1, 2) in list("'", "\"")) + node += token(i) + + else + parse_error("Expected string but found '[token(i)]'") + + return i + 1 + + +//call_function: ['(' [arguments] ')'] + call_function(i, list/node) + + parse_error("Sorry, function calls aren't available yet") + + return i + + +//select_function: count_function + select_function(i, list/node) + + parse_error("Sorry, function calls aren't available yet") + + return i + + +//expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression] + expression(i, list/node) + + if(token(i) in unary_operators) + i = unary_expression(i, node) + + else if(token(i) == "(") + var/list/expr = list() + + i = expression(i + 1, expr) + + if(token(i) != ")") + parse_error("Missing ) at end of expression.") + + else + i++ + + node[++node.len] = expr + + else + i = value(i, node) + + if(token(i) in binary_operators) + i = binary_operator(i, node) + i = expression(i, node) + + else if(token(i) in comparitors) + i = binary_operator(i, node) + + var/list/rhs = list() + i = expression(i, rhs) + + node[++node.len] = rhs + + + return i + + +//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' ) + unary_expression(i, list/node) + + if(token(i) in unary_operators) + var/list/unary_exp = list() + + unary_exp += token(i) + i++ + + if(token(i) in unary_operators) + i = unary_expression(i, unary_exp) + + else if(token(i) == "(") + var/list/expr = list() + + i = expression(i + 1, expr) + + if(token(i) != ")") + parse_error("Missing ) at end of expression.") + + else + i++ + + unary_exp[++unary_exp.len] = expr + + else + i = value(i, unary_exp) + + node[++node.len] = unary_exp + + + else + parse_error("Expected unary operator but found '[token(i)]'") + + return i + + +//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' + binary_operator(i, list/node) + + if(token(i) in (binary_operators + comparitors)) + node += token(i) + + else + parse_error("Unknown binary operator [token(i)]") + + return i + 1 + + +//value: variable | string | number | 'null' + value(i, list/node) + + if(token(i) == "null") + node += "null" + i++ + + else if(isnum(text2num(token(i)))) + node += text2num(token(i)) + i++ + + else if(copytext(token(i), 1, 2) in list("'", "\"")) + i = string(i, node) + + else + i = variable(i, node) + + return i + + + + +/*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/ \ No newline at end of file diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 2f1178dfbae..3447d70e677 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -221,6 +221,50 @@ proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0) message_admins("\blue [key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste].", 1) return 1 +/* +Allow admins to set players to be able to respawn/bypass 30 min wait, without the admin having to edit variables directly +Ccomp's first proc. +*/ + +/client/proc/allow_character_respawn() + set category = "Special Verbs" + set name = "Allow player to respawn" + set desc = "Let's the player bypass the 30 minute wait to respawn." + if(!holder) + src << "Only administrators may use this command." + var/any = 0 + var/list/mobs = list() + var/list/ghosts = list() + var/list/sortmob = sortAtom(mob_list) // get the mob list. + for(var/mob/dead/observer/M in sortmob) + mobs.Add(M) //filter it where it's only ghosts + any = 1 //if no ghosts show up, any will just be 0 + if(!any) + src << "There doesn't appear to be any ghosts for you to select." + return + + for(var/mob/M in mobs) + var/name = M.name + ghosts[name] = M //get the name of the mob for the popup list + + var/target = input("Please, select a ghost!", "COME BACK TO LIFE!", null, null) as null|anything in ghosts + if(!target) + src << "Hrm, appears you didn't select a ghost" // Sanity check, if no ghosts in the list we don't want to edit a null variable and cause a runtime error. + return + + var/mob/M = ghosts[target] + M.timeofdeath=-19999 /* time of death is checked in /mob/verb/abandon_mob() which is the Respawn verb. + timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure + there won't be an autopsy. + */ + M:show_message(text("\blue You may now respawn. You should roleplay as if you learned nothing about the round during your time with the dead."), 1) + log_admin("[key_name(usr)] allowed [key_name(M)] to bypass the 30 minute respawn limit") + message_admins("Admin [key_name_admin(usr)] allowed [key_name_admin(M)] to bypass the 30 minute respawn limit", 1) + + + + + /* If a guy was gibbed and you want to revive him, this is a good way to do so. Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. diff --git a/code/modules/admin/verbs/vox_raiders.dm b/code/modules/admin/verbs/vox_raiders.dm index 7359a026b46..f1e6204d223 100644 --- a/code/modules/admin/verbs/vox_raiders.dm +++ b/code/modules/admin/verbs/vox_raiders.dm @@ -66,7 +66,7 @@ var/global/vox_tick = 1 C.registered_user = src var/obj/item/weapon/storage/wallet/W = new(src) W.handle_item_insertion(C) - spawn_money(rand(100,300)*5,W) + spawn_money(rand(50,150)*10,W) equip_to_slot_or_del(W, slot_wear_id) var/obj/item/weapon/implant/cortical/I = new(src) diff --git a/code/modules/awaymissions/trigger.dm b/code/modules/awaymissions/trigger.dm index 7080179b9a6..65ad8f543d6 100644 --- a/code/modules/awaymissions/trigger.dm +++ b/code/modules/awaymissions/trigger.dm @@ -31,11 +31,11 @@ s.start() if(entersmoke) - var/datum/effect/effect/system/harmless_smoke_spread/s = new /datum/effect/effect/system/harmless_smoke_spread + var/datum/effect/effect/system/smoke_spread/s = new /datum/effect/effect/system/smoke_spread s.set_up(4, 1, src, 0) s.start() if(exitsmoke) - var/datum/effect/effect/system/harmless_smoke_spread/s = new /datum/effect/effect/system/harmless_smoke_spread + var/datum/effect/effect/system/smoke_spread/s = new /datum/effect/effect/system/smoke_spread s.set_up(4, 1, dest, 0) s.start() diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 9db503f93ae..2abfe0f4fc0 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -251,6 +251,7 @@ 'nano/css/icons.css', 'nano/templates/chem_dispenser.tmpl', 'nano/templates/cryo.tmpl', + 'nano/templates/geoscanner.tmpl', 'nano/templates/dna_modifier.tmpl', 'nano/images/uiBackground.png', 'nano/images/uiIcons16.png', @@ -298,9 +299,5 @@ 'icons/spideros_icons/sos_11.png', 'icons/spideros_icons/sos_12.png', 'icons/spideros_icons/sos_13.png', - 'icons/spideros_icons/sos_14.png', - 'icons/xenoarch_icons/chart1.jpg', - 'icons/xenoarch_icons/chart2.jpg', - 'icons/xenoarch_icons/chart3.jpg', - 'icons/xenoarch_icons/chart4.jpg' + 'icons/spideros_icons/sos_14.png' ) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index ca9b23ef3d3..51d8bb92da0 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -262,6 +262,7 @@ datum/preferences //dat += "Skin pattern: Adjust
    " dat += "Needs Glasses: [disabilities == 0 ? "No" : "Yes"]
    " dat += "Limbs: Adjust
    " + dat += "Internal Organs: Adjust
    " //display limbs below var/ind = 0 @@ -286,6 +287,10 @@ datum/preferences organ_name = "left hand" if("r_hand") organ_name = "right hand" + if("heart") + organ_name = "heart" + if("eyes") + organ_name = "eyes" if(status == "cyborg") ++ind @@ -297,6 +302,24 @@ datum/preferences if(ind > 1) dat += ", " dat += "\tAmputated [organ_name]" + else if(status == "mechanical") + ++ind + if(ind > 1) + dat += ", " + dat += "\tMechanical [organ_name]" + else if(status == "assisted") + ++ind + if(ind > 1) + dat += ", " + switch(organ_name) + if("heart") + dat += "\tPacemaker-assisted [organ_name]" + if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements + dat += "\tSurgically altered [organ_name]" + if("eyes") + dat += "\tRetinal overlayed [organ_name]" + else + dat += "\tMechanically assisted [organ_name]" if(!ind) dat += "\[...\]

    " else @@ -1048,6 +1071,28 @@ datum/preferences if(second_limb) organ_data[second_limb] = "cyborg" + if("organs") + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") + if(!organ_name) return + + var/organ = null + switch(organ_name) + if("Heart") + organ = "heart" + if("Eyes") + organ = "eyes" + + var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") + if(!new_state) return + + switch(new_state) + if("Normal") + organ_data[organ] = null + if("Assisted") + organ_data[organ] = "assisted" + if("Mechanical") + organ_data[organ] = "mechanical" + if("skin_style") var/skin_style_name = input(user, "Select a new skin style") as null|anything in list("default1", "default2", "default3") if(!skin_style_name) return @@ -1167,19 +1212,27 @@ datum/preferences character.skills = skills // Destroy/cyborgize organs + for(var/name in organ_data) var/datum/organ/external/O = character.organs_by_name[name] - if(!O) continue - + var/datum/organ/internal/I = character.internal_organs_by_name[name] var/status = organ_data[name] + if(status == "amputated") O.amputated = 1 O.status |= ORGAN_DESTROYED O.destspawn = 1 - else if(status == "cyborg") + if(status == "cyborg") O.status |= ORGAN_ROBOT + if(status == "assisted") + I.mechassist() + else if(status == "mechanical") + I.mechanize() + + else continue + if(underwear > underwear_m.len || underwear < 1) - underwear = 1 //I'm sure this is 100% unnecessary, but I'm paranoid... sue me. + underwear = 0 //I'm sure this is 100% unnecessary, but I'm paranoid... sue me. //HAH NOW NO MORE MAGIC CLONING UNDIES character.underwear = underwear if(backbag > 4 || backbag < 1) diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 57f18d1e36a..b170ea2de6f 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -257,15 +257,6 @@ item_state = "neocoat" flags = FPRINT | TABLEPASS -//actual suits - -/obj/item/clothing/suit/creamsuit - name = "cream suit" - desc = "A cream coloured, genteel suit." - icon_state = "creamsuit" - item_state = "creamsuit" - flags = FPRINT | TABLEPASS - //stripper /obj/item/clothing/under/stripper/stripper_pink diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 382f4c2d108..98331e8fcca 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -478,6 +478,7 @@ siemens_coefficient = 0.30 permeability_coefficient = 0.01 item_color="white" + species_restricted = list("exclude","Unathi") /obj/item/clothing/gloves/fluff/walter_brooks_1 //botanistpower: Walter Brooks name = "mittens" @@ -860,6 +861,7 @@ desc = "Made of a special fiber that gives special protection against biohazards. Has a cross on the chest denoting that the wearer is trained medical personnel and short sleeves." icon = 'icons/obj/custom_items.dmi' icon_state = "medical_short" + item_state = "medical_short" item_color = "medical_short" /obj/item/clothing/suit/storage/labcoat/fluff/red diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm index 07208e5b656..93142e02614 100644 --- a/code/modules/events/event_dynamic.dm +++ b/code/modules/events/event_dynamic.dm @@ -76,7 +76,7 @@ var/list/event_last_fired = list() if(active_with_role["Medical"] > 0) possibleEvents[/datum/event/radiation_storm] = active_with_role["Medical"] * 50 possibleEvents[/datum/event/spontaneous_appendicitis] = active_with_role["Medical"] * 150 - possibleEvents[/datum/event/viral_outbreak] = active_with_role["Medical"] * 10 + possibleEvents[/datum/event/viral_infection] = active_with_role["Medical"] * 10 possibleEvents[/datum/event/organ_failure] = active_with_role["Medical"] * 50 possibleEvents[/datum/event/prison_break] = active_with_role["Security"] * 50 @@ -92,7 +92,7 @@ var/list/event_last_fired = list() var/time_passed = world.time - event_last_fired[event_type] var/full_recharge_after = 60 * 60 * 10 * 3 // 3 hours var/weight_modifier = max(0, (full_recharge_after - time_passed) / 300) - + possibleEvents[event_type] = max(possibleEvents[event_type] - weight_modifier, 0) var/picked_event = pickweight(possibleEvents) diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index 34319c0d91f..54f63f9f9f3 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -99,8 +99,9 @@ new /obj/item/weapon/book/manual/engineering_particle_accelerator(src) new /obj/item/weapon/book/manual/engineering_hacking(src) new /obj/item/weapon/book/manual/engineering_guide(src) + new /obj/item/weapon/book/manual/atmospipes(src) new /obj/item/weapon/book/manual/engineering_singularity_safety(src) - new /obj/item/weapon/book/manual/robotics_cyborgs(src) + new /obj/item/weapon/book/manual/evaguide(src) update_icon() /obj/structure/bookcase/manuals/research_and_development diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index ac206cf1b89..313ae1cf1b2 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -298,9 +298,25 @@ new /obj/item/stack/sheet/mineral/clown(output.loc) else on = 0 + if (selected_glass == 1 && selected_gold == 0 && selected_silver == 0 && selected_diamond == 0 && selected_plasma == 1 && selected_uranium == 0 && selected_iron == 0 && selected_clown == 0) + if (ore_glass > 0 && ore_plasma > 0) + ore_glass--; + ore_plasma--; + new /obj/item/stack/sheet/glass/plasmaglass(output.loc) + else + on = 0 + if (selected_glass == 1 && selected_gold == 0 && selected_silver == 0 && selected_diamond == 0 && selected_plasma == 1 && selected_uranium == 0 && selected_iron == 1 && selected_clown == 0) + if (ore_glass > 0 && ore_plasma > 0 && ore_iron > 0) + ore_glass--; + ore_iron--; + ore_plasma--; + new /obj/item/stack/sheet/glass/plasmarglass(output.loc) + else + on = 0 continue //THESE TWO ARE CODED FOR URIST TO USE WHEN HE GETS AROUND TO IT. //They were coded on 18 Feb 2012. If you're reading this in 2015, then firstly congratulations on the world not ending on 21 Dec 2012 and secondly, Urist is apparently VERY lazy. ~Errorage + //Iamgoofball here, this comment I'm typing right now was made in 11/1/2013. If you're reading this in 2020, then please let me know if the world has gone into a nuclear apocalypse. Also Urist has been tried and hung for how lazy he was. That and he was jaywalking. /*if (selected_glass == 0 && selected_gold == 0 && selected_silver == 0 && selected_diamond == 1 && selected_plasma == 0 && selected_uranium == 1 && selected_iron == 0 && selected_clown == 0) if (ore_uranium >= 2 && ore_diamond >= 1) ore_uranium -= 2 @@ -380,34 +396,42 @@ if (O) if (istype(O,/obj/item/weapon/ore/iron)) ore_iron++; + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/glass)) ore_glass++; + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/diamond)) ore_diamond++; + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/plasma)) ore_plasma++ + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/gold)) ore_gold++ + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/silver)) ore_silver++ + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/uranium)) ore_uranium++ + O.loc = null del(O) continue if (istype(O,/obj/item/weapon/ore/clown)) ore_clown++ + O.loc = null del(O) continue O.loc = src.output.loc diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index 46a37dae549..ccdcc56e642 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -42,6 +42,10 @@ dat += text("Reinforced Glass: [machine.ore_rglass] Release
    ") if(machine.ore_plasma) dat += text("Plasma: [machine.ore_plasma] Release
    ") + if(machine.ore_plasmaglass) + dat += text("Plasma Glass: [machine.ore_plasmaglass] Release
    ") + if(machine.ore_plasmarglass) + dat += text("Reinforced Plasma Glass: [machine.ore_plasmarglass] Release
    ") if(machine.ore_gold) dat += text("Gold: [machine.ore_gold] Release
    ") if(machine.ore_silver) @@ -83,6 +87,18 @@ G.amount = machine.ore_plasma G.loc = machine.output.loc machine.ore_plasma = 0 + if ("plasmaglass") + if (machine.ore_plasmaglass > 0) + var/obj/item/stack/sheet/glass/plasmaglass/G = new /obj/item/stack/sheet/glass/plasmaglass + G.amount = machine.ore_plasmaglass + G.loc = machine.output.loc + machine.ore_plasmaglass = 0 + if ("plasmarglass") + if (machine.ore_plasmarglass > 0) + var/obj/item/stack/sheet/glass/plasmarglass/G = new /obj/item/stack/sheet/glass/plasmarglass + G.amount = machine.ore_plasmarglass + G.loc = machine.output.loc + machine.ore_plasmarglass = 0 if ("uranium") if (machine.ore_uranium > 0) var/obj/item/stack/sheet/mineral/uranium/G = new /obj/item/stack/sheet/mineral/uranium @@ -195,6 +211,8 @@ var/ore_silver = 0; var/ore_diamond = 0; var/ore_plasma = 0; + var/ore_plasmaglass = 0; + var/ore_plasmarglass = 0; var/ore_iron = 0; var/ore_uranium = 0; var/ore_clown = 0; @@ -263,6 +281,14 @@ ore_rglass+= O:amount del(O) continue + if (istype(O,/obj/item/stack/sheet/glass/plasmaglass)) + ore_plasmaglass+= O:amount + del(O) + continue + if (istype(O,/obj/item/stack/sheet/glass/plasmarglass)) + ore_plasmarglass+= O:amount + del(O) + continue if (istype(O,/obj/item/stack/sheet/plasteel)) ore_plasteel+= O:amount del(O) @@ -349,6 +375,18 @@ G.loc = output.loc ore_rglass -= stack_amt return + if (ore_plasmaglass >= stack_amt) + var/obj/item/stack/sheet/glass/plasmaglass/G = new /obj/item/stack/sheet/glass/plasmaglass + G.amount = stack_amt + G.loc = output.loc + ore_plasmaglass -= stack_amt + return + if (ore_plasmarglass >= stack_amt) + var/obj/item/stack/sheet/glass/plasmarglass/G = new /obj/item/stack/sheet/glass/plasmarglass + G.amount = stack_amt + G.loc = output.loc + ore_plasmarglass -= stack_amt + return if (ore_plasteel >= stack_amt) var/obj/item/stack/sheet/plasteel/G = new /obj/item/stack/sheet/plasteel G.amount = stack_amt diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 0eb859083ad..83077154a84 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -4,6 +4,8 @@ #define XENOARCH_SPREAD_CHANCE 15 #define ARTIFACT_SPAWN_CHANCE 20 +/datum/controller/game_controller/var/list/artifact_spawning_turfs = list() + /turf/simulated/mineral //wall piece name = "Rock" icon = 'icons/turf/walls.dmi' @@ -127,7 +129,7 @@ //dont create artifact machinery in animal or plant digsites, or if we already have one if(!artifact_find && digsite != 1 && digsite != 2 && prob(ARTIFACT_SPAWN_CHANCE)) artifact_find = new() - artifact_spawning_turfs.Add(src) + master_controller.artifact_spawning_turfs.Add(src) if(!src.geological_data) src.geological_data = new/datum/geosample(src) @@ -369,29 +371,25 @@ commented out in r5061, I left it because of the shroom thingies //just pull the surrounding rock out excavate_find(0, F) - if( src.excavation_level + P.excavation_amount >= 100 || (!finds.len && !excavation_minerals.len) ) - //if players have been excavating this turf, have a chance to leave some rocky debris behind - var/boulder_prob = 0 + if( src.excavation_level + P.excavation_amount >= 100 ) + //if players have been excavating this turf, leave some rocky debris behind var/obj/structure/boulder/B - - if(src.excavation_level > 15) - boulder_prob = 10 if(artifact_find) - boulder_prob += 25 - if(src.excavation_level >= 100) - boulder_prob += 40 - else if(src.excavation_level > 95) - boulder_prob += 25 - else if(src.excavation_level > 90) - boulder_prob += 10 - if(prob(boulder_prob)) + if( src.excavation_level > 0 || prob(15) ) + //boulder with an artifact inside + B = new(src) + if(artifact_find) + B.artifact_find = artifact_find + else + artifact_debris(1) + else if(prob(15)) + //empty boulder B = new(src) - if(artifact_find) - B.artifact_find = artifact_find - else if(artifact_find && src.excavation_level + P.excavation_amount >= 100) - artifact_debris(1) - gets_drilled(B ? 0 : 1) + if(B) + gets_drilled(0) + else + gets_drilled(1) return else src.excavation_level += P.excavation_amount @@ -475,7 +473,7 @@ commented out in r5061, I left it because of the shroom thingies if(prob(50)) pain = 1 for(var/mob/living/M in range(src, 200)) - M << "[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fadaing away!" + M << "[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fading away!" if(pain) flick("pain",M.pain) if(prob(50)) diff --git a/code/modules/mob/living/carbon/alien/humanoid/life.dm b/code/modules/mob/living/carbon/alien/humanoid/life.dm index c2e9eb786f0..943e7d9ac90 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/life.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/life.dm @@ -128,7 +128,7 @@ breath = loc.remove_air(breath_moles) // Handle chem smoke effect -- Doohl - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) smoke.reagents.reaction(src, INGEST) spawn(5) diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm index c617d615f01..b820e0f51a0 100644 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -103,7 +103,7 @@ breath = loc.remove_air(breath_moles) // Handle chem smoke effect -- Doohl - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) smoke.reagents.reaction(src, INGEST) spawn(5) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 4ca6efea54c..6b597920ff3 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -180,7 +180,7 @@ This function restores the subjects blood to max. /mob/living/carbon/human/proc/restore_blood() var/blood_volume = vessel.get_reagent_amount("blood") vessel.add_reagent("blood",560.0-blood_volume) - + /* This function restores all organs. @@ -252,8 +252,9 @@ This function restores all organs. W.loc = src else if(istype(used_weapon,/obj/item/projectile)) //We don't want to use the actual projectile item, so we spawn some shrapnel. - if(prob(75) && damagetype == BRUTE) - var/obj/item/projectile/P = used_weapon + + var/obj/item/projectile/P = used_weapon + if(prob(75) && P.embed) var/obj/item/weapon/shard/shrapnel/S = new() S.name = "[P.name] shrapnel" S.desc = "[S.desc] It looks like it was fired from [P.shot_from]." diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 4044c0aae1f..2d06c5fee77 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -159,6 +159,9 @@ emp_act for(var/datum/organ/external/O in organs) if(O.status & ORGAN_DESTROYED) continue O.emp_act(severity) + for(var/datum/organ/internal/I in O.internal_organs) + if(I.robotic == 0) continue + I.emp_act(severity) ..() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 315b3f40915..104e60fff89 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -21,7 +21,7 @@ var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup var/age = 30 //Player's age (pure fluff) - var/b_type = "A+" //Player's bloodtype (Not currently used, just character fluff) + var/b_type = "A+" //Player's bloodtype var/underwear = 1 //Which underwear the player wants var/backbag = 2 //Which backpack type the player has chosen. Nothing, Satchel or Backpack. diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 19d00be7004..d9354dccd63 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -359,7 +359,7 @@ if(!block) - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) smoke.reagents.reaction(src, INGEST) spawn(5) @@ -960,6 +960,9 @@ var/datum/organ/internal/liver/liver = internal_organs["liver"] liver.process() + var/datum/organ/internal/eyes/eyes = internal_organs["eyes"] + eyes.process() + updatehealth() return //TODO: DEFERRED @@ -1335,10 +1338,6 @@ if(!O.up && tinted_weldhelh) client.screen += global_hud.darkMask - if(eye_stat > 20) - if(eye_stat > 30) client.screen += global_hud.darkMask - else client.screen += global_hud.vimpaired - if(machine) if(!machine.check_eye(src)) reset_view(null) else @@ -1433,7 +1432,7 @@ else if(health < config.health_threshold_softcrit) shock_stage = max(shock_stage, 61) else - shock_stage = min(shock_stage, 100) + shock_stage = min(shock_stage, 160) shock_stage = max(shock_stage-1, 0) return @@ -1450,15 +1449,26 @@ if (shock_stage >= 60) if(shock_stage == 60) emote("me",1,"'s body becomes limp.") + if (prob(2)) + src << ""+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!") + Weaken(20) + + if(shock_stage >= 80) if (prob(5)) - Stun(20) - lying = 1 + src << ""+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!") + Weaken(20) - if(shock_stage == 80) - src << ""+pick("You see a light at the end of the tunnel!", "You feel like you could die any moment now.", "You're about to lose consciousness.") + if(shock_stage >= 120) + if (prob(2)) + src << ""+pick("You black out!", "You feel like you could die any moment now.", "You're about to lose consciousness.") + Paralyse(5) - if(shock_stage > 80) - Paralyse(rand(15,28)) + if(shock_stage == 150) + emote("me",1,"can no longer stand, collapsing!") + Weaken(20) + + if(shock_stage >= 150) + Weaken(20) proc/handle_pulse() if(life_tick % 5) return pulse //update pulse every 5 life ticks (~1 tick/sec, depending on server load) @@ -1485,6 +1495,15 @@ if(temp <= PULSE_FAST && temp >= PULSE_NONE) temp++ break + for(var/datum/reagent/R in reagents.reagent_list) //To avoid using fakedeath + if(R.id in heartstopper) + temp = PULSE_NONE + break + for(var/datum/reagent/R in reagents.reagent_list) //Conditional heart-stoppage + if(R.id in cheartstopper) + if(R.volume >= R.overdose) + temp = PULSE_NONE + break return temp diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 7d76cc91b42..ebca69ecca8 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -123,7 +123,6 @@ Please contact me on #coderbus IRC. ~Carn x ////////////////////////////////// /mob/living/carbon/human - var/list/overlays_lying[TOTAL_LAYERS] var/list/overlays_standing[TOTAL_LAYERS] var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed var/icon/race_icon @@ -137,28 +136,32 @@ Please contact me on #coderbus IRC. ~Carn x update_hud() //TODO: remove the need for this overlays.Cut() - if(lying) //can't be cloaked when lying. (for now) - icon = lying_icon - for(var/image/I in overlays_lying) - overlays += I + var/stealth = 0 + //cloaking devices. //TODO: get rid of this :< + for(var/obj/item/weapon/cloaking_device/S in list(l_hand,r_hand,belt,l_store,r_store)) + if(S.active) + stealth = 1 + break + if(stealth) + icon = 'icons/mob/human.dmi' + icon_state = "body_cloaked" + var/image/I = overlays_standing[L_HAND_LAYER] + if(istype(I)) overlays += I + I = overlays_standing[R_HAND_LAYER] + if(istype(I)) overlays += I else - var/stealth = 0 - //cloaking devices. //TODO: get rid of this :< - for(var/obj/item/weapon/cloaking_device/S in list(l_hand,r_hand,belt,l_store,r_store)) - if(S.active) - stealth = 1 - break - if(stealth) - icon = 'icons/mob/human.dmi' - icon_state = "body_cloaked" - var/image/I = overlays_standing[L_HAND_LAYER] - if(istype(I)) overlays += I - I = overlays_standing[R_HAND_LAYER] - if(istype(I)) overlays += I - else - icon = stand_icon - for(var/image/I in overlays_standing) - overlays += I + icon = stand_icon + for(var/image/I in overlays_standing) + overlays += I + + if(lying) + var/matrix/M = matrix() + M.Turn(90) + M.Translate(1,-6) + src.transform = M + else + var/matrix/M = matrix() + src.transform = M var/global/list/damage_icon_parts = list() proc/get_damage_icon_part(damage_state, body_part) @@ -188,10 +191,8 @@ proc/get_damage_icon_part(damage_state, body_part) previous_damage_appearance = damage_appearance var/icon/standing = new /icon('icons/mob/dam_human.dmi', "00") - var/icon/lying = new /icon('icons/mob/dam_human.dmi', "00-2") var/image/standing_image = new /image("icon" = standing) - var/image/lying_image = new /image("icon" = lying) // blend the individual damage states with our icons @@ -204,19 +205,14 @@ proc/get_damage_icon_part(damage_state, body_part) standing_image.overlays += DI - DI = get_damage_icon_part("[O.damage_state]-2", "[O.icon_name]2") - lying_image.overlays += DI - overlays_standing[DAMAGE_LAYER] = standing_image - overlays_lying[DAMAGE_LAYER] = lying_image if(update_icons) update_icons() //BASE MOB SPRITE /mob/living/carbon/human/proc/update_body(var/update_icons=1) if(stand_icon) del(stand_icon) - if(lying_icon) del(lying_icon) var/husk_color_mod = rgb(96,88,80) var/hulk_color_mod = rgb(48,224,40) @@ -252,9 +248,6 @@ proc/get_damage_icon_part(damage_state, body_part) else temp = part.get_icon() - if(part.status & ORGAN_ROBOT) - temp.GrayScale() - if(part.status & ORGAN_DEAD) temp.ColorTone(necrosis_color_mod) temp.SetIntensity(0.7) @@ -316,8 +309,6 @@ proc/get_damage_icon_part(damage_state, body_part) if(!fat && !skeleton) stand_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY) - lying_icon = stand_icon.MakeLying() - if(update_icons) update_icons() @@ -328,7 +319,6 @@ proc/get_damage_icon_part(damage_state, body_part) //HAIR OVERLAY /mob/living/carbon/human/proc/update_hair(var/update_icons=1) //Reset our hair - overlays_lying[HAIR_LAYER] = null overlays_standing[HAIR_LAYER] = null var/datum/organ/external/head/head_organ = get_organ("head") @@ -343,33 +333,25 @@ proc/get_damage_icon_part(damage_state, body_part) //base icons var/icon/face_standing = new /icon('icons/mob/human_face.dmi',"bald_s") - var/icon/face_lying = new /icon('icons/mob/human_face.dmi',"bald_l") if(f_style) var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] if(facial_hair_style && src.species.name in facial_hair_style.species_allowed) var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - var/icon/facial_l = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_l") if(facial_hair_style.do_colouration) facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) - facial_l.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) face_standing.Blend(facial_s, ICON_OVERLAY) - face_lying.Blend(facial_l, ICON_OVERLAY) if(h_style && !(head && (head.flags & BLOCKHEADHAIR))) var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] if(hair_style && src.species.name in hair_style.species_allowed) var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") - var/icon/hair_l = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_l") if(hair_style.do_colouration) hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) - hair_l.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) face_standing.Blend(hair_s, ICON_OVERLAY) - face_lying.Blend(hair_l, ICON_OVERLAY) - overlays_lying[HAIR_LAYER] = image(face_lying) overlays_standing[HAIR_LAYER] = image(face_standing) if(update_icons) update_icons() @@ -379,7 +361,6 @@ proc/get_damage_icon_part(damage_state, body_part) if(FAT in mutations) fat = "fat" - var/image/lying = image("icon" = 'icons/effects/genetics.dmi') var/image/standing = image("icon" = 'icons/effects/genetics.dmi') var/add_image = 0 var/g = "m" @@ -388,29 +369,22 @@ proc/get_damage_icon_part(damage_state, body_part) switch(mut) if(HULK) if(fat) - lying.underlays += "hulk_[fat]_l" standing.underlays += "hulk_[fat]_s" else - lying.underlays += "hulk_[g]_l" standing.underlays += "hulk_[g]_s" add_image = 1 if(COLD_RESISTANCE) - lying.underlays += "fire[fat]_l" standing.underlays += "fire[fat]_s" add_image = 1 if(TK) - lying.underlays += "telekinesishead[fat]_l" standing.underlays += "telekinesishead[fat]_s" add_image = 1 if(LASER) - lying.overlays += "lasereyes_l" standing.overlays += "lasereyes_s" add_image = 1 if(add_image) - overlays_lying[MUTATIONS_LAYER] = lying overlays_standing[MUTATIONS_LAYER] = standing else - overlays_lying[MUTATIONS_LAYER] = null overlays_standing[MUTATIONS_LAYER] = null if(update_icons) update_icons() @@ -433,10 +407,8 @@ proc/get_damage_icon_part(damage_state, body_part) if(dna) switch(dna.mutantrace) if("golem","slime","shadow","adamantine") - overlays_lying[MUTANTRACE_LAYER] = image("icon" = 'icons/effects/genetics.dmi', "icon_state" = "[dna.mutantrace][fat]_[gender]_l") overlays_standing[MUTANTRACE_LAYER] = image("icon" = 'icons/effects/genetics.dmi', "icon_state" = "[dna.mutantrace][fat]_[gender]_s") else - overlays_lying[MUTANTRACE_LAYER] = null overlays_standing[MUTANTRACE_LAYER] = null if(!dna || !(dna.mutantrace in list("golem","metroid"))) @@ -448,12 +420,10 @@ proc/get_damage_icon_part(damage_state, body_part) //Call when target overlay should be added/removed /mob/living/carbon/human/update_targeted(var/update_icons=1) if (targeted_by && target_locked) - overlays_lying[TARGETED_LAYER] = target_locked overlays_standing[TARGETED_LAYER] = target_locked else if (!targeted_by && target_locked) del(target_locked) if (!targeted_by) - overlays_lying[TARGETED_LAYER] = null overlays_standing[TARGETED_LAYER] = null if(update_icons) update_icons() @@ -495,27 +465,20 @@ proc/get_damage_icon_part(damage_state, body_part) w_uniform.screen_loc = ui_iclothing var/t_color = w_uniform.item_color if(!t_color) t_color = icon_state - var/image/lying = image("icon_state" = "[t_color]_l") var/image/standing = image("icon_state" = "[t_color]_s") - - lying.icon = 'icons/mob/uniform.dmi' standing.icon = 'icons/mob/uniform.dmi' if(w_uniform.blood_DNA) - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "uniformblood2") standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "uniformblood") if(w_uniform:hastie) //WE CHECKED THE TYPE ABOVE. THIS REALLY SHOULD BE FINE. var/tie_color = w_uniform:hastie.item_color if(!tie_color) tie_color = w_uniform:hastie.icon_state - lying.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]2") standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]") - overlays_lying[UNIFORM_LAYER] = lying overlays_standing[UNIFORM_LAYER] = standing else - overlays_lying[UNIFORM_LAYER] = null overlays_standing[UNIFORM_LAYER] = null // Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY for( var/obj/item/thing in list(r_store, l_store, wear_id, belt) ) // @@ -534,13 +497,10 @@ proc/get_damage_icon_part(damage_state, body_part) if(wear_id) wear_id.screen_loc = ui_id //TODO if(w_uniform && w_uniform:displays_id) - overlays_lying[ID_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "id2") overlays_standing[ID_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "id") else - overlays_lying[ID_LAYER] = null overlays_standing[ID_LAYER] = null else - overlays_lying[ID_LAYER] = null overlays_standing[ID_LAYER] = null if(update_icons) update_icons() @@ -548,57 +508,43 @@ proc/get_damage_icon_part(damage_state, body_part) if(gloves) var/t_state = gloves.item_state if(!t_state) t_state = gloves.icon_state - var/image/lying = image("icon" = 'icons/mob/hands.dmi', "icon_state" = "[t_state]2") var/image/standing = image("icon" = 'icons/mob/hands.dmi', "icon_state" = "[t_state]") if(gloves.blood_DNA) - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands2") standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands") gloves.screen_loc = ui_gloves - overlays_lying[GLOVES_LAYER] = lying overlays_standing[GLOVES_LAYER] = standing else if(blood_DNA) - overlays_lying[GLOVES_LAYER] = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands2") overlays_standing[GLOVES_LAYER] = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands") else - overlays_lying[GLOVES_LAYER] = null overlays_standing[GLOVES_LAYER] = null if(update_icons) update_icons() /mob/living/carbon/human/update_inv_glasses(var/update_icons=1) if(glasses) - overlays_lying[GLASSES_LAYER] = image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]2") overlays_standing[GLASSES_LAYER] = image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]") else - overlays_lying[GLASSES_LAYER] = null overlays_standing[GLASSES_LAYER] = null if(update_icons) update_icons() /mob/living/carbon/human/update_inv_ears(var/update_icons=1) if(l_ear || r_ear) if(l_ear) - overlays_lying[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[l_ear.icon_state]2") overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[l_ear.icon_state]") if(r_ear) - overlays_lying[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[r_ear.icon_state]2") overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[r_ear.icon_state]") else - overlays_lying[EARS_LAYER] = null overlays_standing[EARS_LAYER] = null if(update_icons) update_icons() /mob/living/carbon/human/update_inv_shoes(var/update_icons=1) if(shoes) - var/image/lying = image("icon" = 'icons/mob/feet.dmi', "icon_state" = "[shoes.icon_state]2") var/image/standing = image("icon" = 'icons/mob/feet.dmi', "icon_state" = "[shoes.icon_state]") if(shoes.blood_DNA) - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "shoeblood2") standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "shoeblood") - overlays_lying[SHOES_LAYER] = lying overlays_standing[SHOES_LAYER] = standing else - overlays_lying[SHOES_LAYER] = null overlays_standing[SHOES_LAYER] = null if(update_icons) update_icons() @@ -606,11 +552,9 @@ proc/get_damage_icon_part(damage_state, body_part) if(s_store) var/t_state = s_store.item_state if(!t_state) t_state = s_store.icon_state - overlays_lying[SUIT_STORE_LAYER] = image("icon" = 'icons/mob/belt_mirror.dmi', "icon_state" = "[t_state]2") overlays_standing[SUIT_STORE_LAYER] = image("icon" = 'icons/mob/belt_mirror.dmi', "icon_state" = "[t_state]") s_store.screen_loc = ui_sstore1 //TODO else - overlays_lying[SUIT_STORE_LAYER] = null overlays_standing[SUIT_STORE_LAYER] = null if(update_icons) update_icons() @@ -618,21 +562,15 @@ proc/get_damage_icon_part(damage_state, body_part) /mob/living/carbon/human/update_inv_head(var/update_icons=1) if(head) head.screen_loc = ui_head //TODO - var/image/lying var/image/standing if(istype(head,/obj/item/clothing/head/kitty)) - lying = image("icon" = head:mob2) standing = image("icon" = head:mob) else - lying = image("icon" = 'icons/mob/head.dmi', "icon_state" = "[head.icon_state]2") standing = image("icon" = 'icons/mob/head.dmi', "icon_state" = "[head.icon_state]") if(head.blood_DNA) - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood2") standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood") - overlays_lying[HEAD_LAYER] = lying overlays_standing[HEAD_LAYER] = standing else - overlays_lying[HEAD_LAYER] = null overlays_standing[HEAD_LAYER] = null if(update_icons) update_icons() @@ -641,10 +579,8 @@ proc/get_damage_icon_part(damage_state, body_part) belt.screen_loc = ui_belt //TODO var/t_state = belt.item_state if(!t_state) t_state = belt.icon_state - overlays_lying[BELT_LAYER] = image("icon" = 'icons/mob/belt.dmi', "icon_state" = "[t_state]2") overlays_standing[BELT_LAYER] = image("icon" = 'icons/mob/belt.dmi', "icon_state" = "[t_state]") else - overlays_lying[BELT_LAYER] = null overlays_standing[BELT_LAYER] = null if(update_icons) update_icons() @@ -652,7 +588,6 @@ proc/get_damage_icon_part(damage_state, body_part) /mob/living/carbon/human/update_inv_wear_suit(var/update_icons=1) if( wear_suit && istype(wear_suit, /obj/item/clothing/suit) ) //TODO check this wear_suit.screen_loc = ui_oclothing //TODO - var/image/lying = image("icon" = 'icons/mob/suit.dmi', "icon_state" = "[wear_suit.icon_state]2") var/image/standing = image("icon" = 'icons/mob/suit.dmi', "icon_state" = "[wear_suit.icon_state]") if( istype(wear_suit, /obj/item/clothing/suit/straight_jacket) ) @@ -662,16 +597,13 @@ proc/get_damage_icon_part(damage_state, body_part) if(wear_suit.blood_DNA) var/obj/item/clothing/suit/S = wear_suit - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[S.blood_overlay_type]blood2") standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[S.blood_overlay_type]blood") - overlays_lying[SUIT_LAYER] = lying overlays_standing[SUIT_LAYER] = standing update_tail_showing(0) else - overlays_lying[SUIT_LAYER] = null overlays_standing[SUIT_LAYER] = null update_tail_showing(0) @@ -687,15 +619,11 @@ proc/get_damage_icon_part(damage_state, body_part) /mob/living/carbon/human/update_inv_wear_mask(var/update_icons=1) if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/tie) ) ) wear_mask.screen_loc = ui_mask //TODO - var/image/lying = image("icon" = 'icons/mob/mask.dmi', "icon_state" = "[wear_mask.icon_state]2") var/image/standing = image("icon" = 'icons/mob/mask.dmi', "icon_state" = "[wear_mask.icon_state]") if( !istype(wear_mask, /obj/item/clothing/mask/cigarette) && wear_mask.blood_DNA ) - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "maskblood2") standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "maskblood") - overlays_lying[FACEMASK_LAYER] = lying overlays_standing[FACEMASK_LAYER] = standing else - overlays_lying[FACEMASK_LAYER] = null overlays_standing[FACEMASK_LAYER] = null if(update_icons) update_icons() @@ -703,10 +631,8 @@ proc/get_damage_icon_part(damage_state, body_part) /mob/living/carbon/human/update_inv_back(var/update_icons=1) if(back) back.screen_loc = ui_back //TODO - overlays_lying[BACK_LAYER] = image("icon" = 'icons/mob/back.dmi', "icon_state" = "[back.icon_state]2") overlays_standing[BACK_LAYER] = image("icon" = 'icons/mob/back.dmi', "icon_state" = "[back.icon_state]") else - overlays_lying[BACK_LAYER] = null overlays_standing[BACK_LAYER] = null if(update_icons) update_icons() @@ -723,16 +649,13 @@ proc/get_damage_icon_part(damage_state, body_part) drop_r_hand() drop_l_hand() stop_pulling() //TODO: should be handled elsewhere - overlays_lying[HANDCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "handcuff2") overlays_standing[HANDCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "handcuff1") else - overlays_lying[HANDCUFF_LAYER] = null overlays_standing[HANDCUFF_LAYER] = null if(update_icons) update_icons() /mob/living/carbon/human/update_inv_legcuffed(var/update_icons=1) if(legcuffed) - overlays_lying[LEGCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "legcuff2") overlays_standing[LEGCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "legcuff1") if(src.m_intent != "walk") src.m_intent = "walk" @@ -740,7 +663,6 @@ proc/get_damage_icon_part(damage_state, body_part) src.hud_used.move_intent.icon_state = "walking" else - overlays_lying[LEGCUFF_LAYER] = null overlays_standing[LEGCUFF_LAYER] = null if(update_icons) update_icons() @@ -769,12 +691,10 @@ proc/get_damage_icon_part(damage_state, body_part) if(update_icons) update_icons() /mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1) - overlays_lying[TAIL_LAYER] = null overlays_standing[TAIL_LAYER] = null if(species.tail && species.flags & HAS_TAIL) if(!wear_suit || !(wear_suit.flags_inv & HIDEJUMPSUIT) && !istype(wear_suit, /obj/item/clothing/suit/space)) - overlays_lying[TAIL_LAYER] = image("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_l") overlays_standing[TAIL_LAYER] = image("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_s") if(update_icons) diff --git a/code/modules/mob/living/carbon/monkey/diona.dm b/code/modules/mob/living/carbon/monkey/diona.dm index 3780cdb6836..1d80763fdc8 100644 --- a/code/modules/mob/living/carbon/monkey/diona.dm +++ b/code/modules/mob/living/carbon/monkey/diona.dm @@ -6,7 +6,7 @@ name = "diona nymph" voice_name = "diona nymph" speak_emote = list("chirrups") - ico = "nymph" + icon_state = "nymph1" var/list/donors = list() var/ready_evolve = 0 diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index 49fea7308ae..6c28acc72b5 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -250,7 +250,7 @@ block = 1 if(!block) - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) smoke.reagents.reaction(src, INGEST) spawn(5) diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index d7add5b0888..fe3aeae8ba5 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -10,28 +10,27 @@ var/obj/item/weapon/card/id/wear_id = null // Fix for station bounced radios -- Skie var/greaterform = "Human" // Used when humanizing a monkey. - var/ico = "monkey" // Used when updating icons. var/uni_append = "12C4E2" // Small appearance modifier for different species. /mob/living/carbon/monkey/tajara name = "farwa" voice_name = "farwa" speak_emote = list("mews") - ico = "tajkey" + icon_state = "tajkey1" uni_append = "0A0E00" /mob/living/carbon/monkey/skrell name = "neaera" voice_name = "neaera" speak_emote = list("squicks") - ico = "skrellkey" + icon_state = "skrellkey1" uni_append = "01CC92" /mob/living/carbon/monkey/unathi name = "stok" voice_name = "stok" speak_emote = list("hisses") - ico = "stokkey" + icon_state = "stokkey1" uni_append = "044C5D" /mob/living/carbon/monkey/New() diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm index 660f7f4b839..284f9e288fc 100644 --- a/code/modules/mob/living/carbon/monkey/update_icons.dm +++ b/code/modules/mob/living/carbon/monkey/update_icons.dm @@ -28,25 +28,25 @@ update_hud() lying_prev = lying //so we don't update overlays for lying/standing unless our stance changes again overlays.Cut() + for(var/image/I in overlays_standing) + overlays += I if(lying) - icon_state = ico + "0" - for(var/image/I in overlays_lying) - overlays += I + var/matrix/M = matrix() + M.Turn(90) + M.Translate(1,-6) + src.transform = M else - icon_state = ico + "1" - for(var/image/I in overlays_standing) - overlays += I + var/matrix/M = matrix() + src.transform = M //////// /mob/living/carbon/monkey/update_inv_wear_mask(var/update_icons=1) if( wear_mask && istype(wear_mask, /obj/item/clothing/mask) ) - overlays_lying[M_MASK_LAYER] = image("icon" = 'icons/mob/monkey.dmi', "icon_state" = "[wear_mask.icon_state]2") overlays_standing[M_MASK_LAYER] = image("icon" = 'icons/mob/monkey.dmi', "icon_state" = "[wear_mask.icon_state]") wear_mask.screen_loc = ui_monkey_mask else - overlays_lying[M_MASK_LAYER] = null overlays_standing[M_MASK_LAYER] = null if(update_icons) update_icons() @@ -77,11 +77,9 @@ /mob/living/carbon/monkey/update_inv_back(var/update_icons=1) if(back) - overlays_lying[M_BACK_LAYER] = image("icon" = 'icons/mob/back.dmi', "icon_state" = "[back.icon_state]2") overlays_standing[M_BACK_LAYER] = image("icon" = 'icons/mob/back.dmi', "icon_state" = "[back.icon_state]") back.screen_loc = ui_monkey_back else - overlays_lying[M_BACK_LAYER] = null overlays_standing[M_BACK_LAYER] = null if(update_icons) update_icons() @@ -91,10 +89,8 @@ drop_r_hand() drop_l_hand() stop_pulling() - overlays_lying[M_HANDCUFF_LAYER] = image("icon" = 'icons/mob/monkey.dmi', "icon_state" = "handcuff2") overlays_standing[M_HANDCUFF_LAYER] = image("icon" = 'icons/mob/monkey.dmi', "icon_state" = "handcuff1") else - overlays_lying[M_HANDCUFF_LAYER] = null overlays_standing[M_HANDCUFF_LAYER] = null if(update_icons) update_icons() @@ -106,12 +102,10 @@ //Call when target overlay should be added/removed /mob/living/carbon/monkey/update_targeted(var/update_icons=1) if (targeted_by && target_locked) - overlays_lying[TARGETED_LAYER] = target_locked overlays_standing[TARGETED_LAYER] = target_locked else if (!targeted_by && target_locked) del(target_locked) if (!targeted_by) - overlays_lying[TARGETED_LAYER] = null overlays_standing[TARGETED_LAYER] = null if(update_icons) update_icons() diff --git a/code/modules/mob/living/carbon/shock.dm b/code/modules/mob/living/carbon/shock.dm index fd2356be26d..9ea65574857 100644 --- a/code/modules/mob/living/carbon/shock.dm +++ b/code/modules/mob/living/carbon/shock.dm @@ -5,20 +5,24 @@ /mob/living/carbon/proc/updateshock() src.traumatic_shock = \ 1 * src.getOxyLoss() + \ - 0.5 * src.getToxLoss() + \ - 2.5 * src.getFireLoss() + \ - 1.5 * src.getBruteLoss() + \ - 2 * src.getCloneLoss() + \ - 1 * src.halloss + 0.7 * src.getToxLoss() + \ + 1.5 * src.getFireLoss() + \ + 1.2 * src.getBruteLoss() + \ + 1.7 * src.getCloneLoss() + \ + 2 * src.halloss if(reagents.has_reagent("alkysine")) src.traumatic_shock -= 10 if(reagents.has_reagent("inaprovaline")) src.traumatic_shock -= 25 + if(reagents.has_reagent("synaptizine")) + src.traumatic_shock -= 40 + if(reagents.has_reagent("paracetamol")) + src.traumatic_shock -= 50 if(reagents.has_reagent("tramadol")) - src.traumatic_shock -= 80 // make synaptizine function as good painkiller + src.traumatic_shock -= 80 if(reagents.has_reagent("oxycodone")) - src.traumatic_shock -= 200 // make synaptizine function as good painkiller + src.traumatic_shock -= 200 if(src.slurring) src.traumatic_shock -= 20 if(src.analgesic) @@ -35,7 +39,7 @@ else if(organ.status & ORGAN_BROKEN || organ.open) src.traumatic_shock += 30 if(organ.status & ORGAN_SPLINTED) - src.traumatic_shock -= 20 + src.traumatic_shock -= 25 if(src.traumatic_shock < 0) src.traumatic_shock = 0 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 828b952ece5..a677bd2445e 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -280,7 +280,6 @@ blinded = 0 eye_blind = 0 eye_blurry = 0 - eye_stat = 0 ear_deaf = 0 ear_damage = 0 heal_overall_damage(getBruteLoss(), getFireLoss()) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 4c51e5f474a..c6a6f508bb4 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -302,6 +302,7 @@ var/list/department_radio_keys = list( var/list/listening listening = get_mobs_in_view(message_range, src) + var/list/onscreen = get_mobs_in_view(7, src) for(var/mob/M in player_list) if (!M.client) continue //skip monkeys and leavers @@ -370,16 +371,19 @@ var/list/department_radio_keys = list( for(var/mob/M in hearers(5, src)) if(M != src && is_speaking_radio) M:show_message("[src] talks into [used_radios.len ? used_radios[1] : "radio"]") - + var/rendered = null + if (length(heard_a)) var/message_a = say_quote(message,speaking) if (italics) message_a = "[message_a]" + var/message_ghost = "[message_a]" // bold so ghosts know the person is in view. rendered = "[GetVoice()][alt_name] [message_a]" - for (var/M in heard_a) + var/rendered_ghost = "[GetVoice()][alt_name] [message_ghost]" + for (var/mob/M in heard_a) if(hascall(M,"show_message")) var/deaf_message = "" var/deaf_type = 1 @@ -388,7 +392,10 @@ var/list/department_radio_keys = list( else deaf_message = "You cannot hear yourself!" deaf_type = 2 // Since you should be able to hear yourself without looking - M:show_message(rendered, 2, deaf_message, deaf_type) + if (M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTEARS) && M in onscreen) + M:show_message(rendered_ghost, 2, deaf_message, deaf_type) + else + M:show_message(rendered, 2, deaf_message, deaf_type) M << speech_bubble if (length(heard_b)) diff --git a/code/modules/mob/living/simple_animal/bees.dm b/code/modules/mob/living/simple_animal/bees.dm index 9f1a8cc50d1..e78e818eccd 100644 --- a/code/modules/mob/living/simple_animal/bees.dm +++ b/code/modules/mob/living/simple_animal/bees.dm @@ -80,7 +80,7 @@ //smoke, water and steam calms us down var/calming = 0 - var/list/calmers = list(/obj/effect/effect/chem_smoke, \ + var/list/calmers = list(/obj/effect/effect/smoke/chem, \ /obj/effect/effect/water, \ /obj/effect/effect/foam, \ /obj/effect/effect/steam, \ diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index c7f0cd845ba..423486499c9 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -76,7 +76,7 @@ New() ..() - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(5, 0, src.loc) smoke.start() visible_message("\red The [src] warps in!") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 648dfa309b4..8f9623565f3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -240,6 +240,8 @@ var/list/slot_equipment_priority = list( \ set category = "Object" set src = usr + if(istype(loc,/obj/mecha)) return + if(hand) var/obj/item/W = l_hand if (W) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index fd0f6be9013..f8d82287187 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -81,7 +81,6 @@ var/lying = 0 var/lying_prev = 0 var/canmove = 1 - var/eye_stat = null//Living, potentially Carbon var/lastpuke = 0 var/unacidable = 0 var/small = 0 diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index caa104a98a5..d23c2407c9a 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -114,6 +114,11 @@ name = "Ponytail 3" icon_state = "hair_ponytail3" + sideponytail + name = "Side Ponytail" + icon_state = "hair_stail" + gender = FEMALE + parted name = "Parted" icon_state = "hair_parted" @@ -241,6 +246,11 @@ icon_state = "hair_gelled" gender = FEMALE + gentle + name = "Gentle" + icon_state = "hair_gentle" + gender = FEMALE + spiky name = "Spiky" icon_state = "hair_spikey" @@ -264,6 +274,11 @@ icon_state = "hair_braid" gender = FEMALE + braid2 + name = "Long Braid" + icon_state = "hair_hbraid" + gender = FEMALE + odango name = "Odango" icon_state = "hair_odango" @@ -469,6 +484,18 @@ species_allowed = list("Tajaran") do_colouration = 0 + taj_ears_bangs + name = "Tajara Bangs" + icon_state = "hair_bangs" + species_allowed = list("Tajaran") + do_colouration = 0 + + taj_ears_braid + name = "Tajara Braid" + icon_state = "hair_tbraid" + species_allowed = list("Tajaran") + do_colouration = 0 + taj_ears_shaggy name = "Tajara Shaggy" icon_state = "hair_shaggy" diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index e5101faf896..59917edd52b 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -235,9 +235,14 @@ O.loc = loc O.job = "Cyborg" - - O.mmi = new /obj/item/device/mmi(O) - O.mmi.transfer_identity(src)//Does not transfer key/client. + if(O.mind.assigned_role == "Cyborg") + if(O.mind.role_alt_title == "Android") + O.mmi = new /obj/item/device/mmi/posibrain(O) + if(O.mind.role_alt_title == "Robot") + O.mmi = new /obj/item/device/mmi/posibrain(O) //Ravensdale wants a circuit based brain for another robot class, this is a placeholder. + else + O.mmi = new /obj/item/device/mmi(O) + O.mmi.transfer_identity(src)//Does not transfer key/client. O.Namepick() diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index dd31d28ac76..a0a88e21209 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -55,11 +55,11 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 // being pumped properly anymore. var/datum/organ/internal/heart/heart = internal_organs["heart"] switch(heart.damage) - if(5 to 10) + if(1 to heart.min_bruised_damage) blood_volume *= 0.8 - if(11 to 20) - blood_volume *= 0.5 - if(21 to INFINITY) + if(heart.min_bruised_damage to heart.min_broken_damage) + blood_volume *= 0.6 + if(heart.min_broken_damage to INFINITY) blood_volume *= 0.3 //Effects of bloodloss @@ -93,7 +93,7 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 src << "\red You feel extremely [word]" if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD) oxyloss += 5 - toxloss += 5 + toxloss += 3 if(prob(15)) var/word = pick("dizzy","woosey","faint") src << "\red You feel extremely [word]" diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 45828edc2aa..89f66c17202 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -35,6 +35,7 @@ /mob/living/carbon/human/var/list/organs = list() /mob/living/carbon/human/var/list/organs_by_name = list() // map organ names to organs +/mob/living/carbon/human/var/list/internal_organs_by_name = list() // so internal organs have less ickiness too //Creates and initializes and connects external and internal organs /mob/living/carbon/human/proc/make_organs() @@ -51,11 +52,12 @@ organs_by_name["l_foot"] = new/datum/organ/external/l_foot(organs_by_name["l_leg"]) organs_by_name["r_foot"] = new/datum/organ/external/r_foot(organs_by_name["r_leg"]) - new/datum/organ/internal/heart(src) - new/datum/organ/internal/lungs(src) - new/datum/organ/internal/liver(src) - new/datum/organ/internal/kidney(src) - new/datum/organ/internal/brain(src) + internal_organs_by_name["heart"] = new/datum/organ/internal/heart(src) + internal_organs_by_name["lungs"] = new/datum/organ/internal/lungs(src) + internal_organs_by_name["liver"] = new/datum/organ/internal/liver(src) + internal_organs_by_name["kidney"] = new/datum/organ/internal/kidney(src) + internal_organs_by_name["brain"] = new/datum/organ/internal/brain(src) + internal_organs_by_name["eyes"] = new/datum/organ/internal/eyes(src) for(var/name in organs_by_name) organs += organs_by_name[name] @@ -91,7 +93,7 @@ I.take_damage(rand(3,5)) //Special effects for limbs. - if(E.name in list("l_hand","l_arm","r_hand","r_arm")) + if(E.name in list("l_hand","l_arm","r_hand","r_arm") && (broken||malfunction)) var/obj/item/c_hand //Getting what's in this hand if(E.name == "l_hand" || E.name == "l_arm") c_hand = l_hand @@ -99,8 +101,7 @@ c_hand = r_hand if (c_hand) - if (broken||malfunction) - u_equip(c_hand) + u_equip(c_hand) if(broken) emote("me", 1, "screams in pain and drops what they were holding in their [E.display_name?"[E.display_name]":"[E]"]!") @@ -124,35 +125,11 @@ paralysis = 10 //Check arms and legs for existence - var/canstand_l = 1 //Can stand on left leg - var/canstand_r = 1 //Can stand on right leg - var/hasleg_l = 1 //Have left leg - var/hasleg_r = 1 //Have right leg - var/hasarm_l = 1 //Have left arm - var/hasarm_r = 1 //Have right arm - var/datum/organ/external/E - E = get_organ("l_leg") - if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED)) - canstand_l = 0 - hasleg_l = 0 - E = get_organ("r_leg") - if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED)) - canstand_r = 0 - hasleg_r = 0 - E = get_organ("l_foot") - if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED)) - canstand_l = 0 - E = get_organ("r_foot") - if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED)) - canstand_r = 0 - E = get_organ("l_arm") - if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED)) - hasarm_l = 0 - E = get_organ("r_arm") - if(E.status & ORGAN_DESTROYED && !(E.status & ORGAN_SPLINTED)) - hasarm_r = 0 + can_stand = 2 //can stand on both legs + var/datum/organ/external/E = organs_by_name["l_foot"] + if(E.status & ORGAN_DESTROYED) + can_stand-- - // Can stand if have at least one full leg (with leg and foot parts present) - // Has limbs to move around if at least one arm or leg is at least partially there - can_stand = canstand_l||canstand_r - has_limbs = hasleg_l||hasleg_r||hasarm_l||hasarm_r + E = organs_by_name["r_foot"] + if(E.status & ORGAN_DESTROYED) + can_stand-- diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index bbf17280840..4c96749e878 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -45,6 +45,7 @@ // how often wounds should be updated, a higher number means less often var/wound_update_accuracy = 1 + /datum/organ/external/New(var/datum/organ/external/P) if(P) parent = P @@ -181,7 +182,7 @@ var/result = update_icon() return result - + /* This function completely restores a damaged organ to perfect condition. */ @@ -191,21 +192,20 @@ This function completely restores a damaged organ to perfect condition. perma_injury = 0 brute_dam = 0 burn_dam = 0 - + // handle internal organs for(var/datum/organ/internal/current_organ in internal_organs) current_organ.rejuvenate() - + // remove embedded objects and drop them on the floor for(var/obj/implanted_object in implants) if(!istype(implanted_object,/obj/item/weapon/implant)) // We don't want to remove REAL implants. Just shrapnel etc. implanted_object.loc = owner.loc implants -= implanted_object - + owner.updatehealth() - update_icon() - - + + /datum/organ/external/proc/createwound(var/type = CUT, var/damage) if(damage == 0) return @@ -290,7 +290,6 @@ This function completely restores a damaged organ to perfect condition. perma_injury = 0 update_germs() - update_icon() return //Updating germ levels. Handles organ germ levels and necrosis. @@ -299,6 +298,11 @@ This function completely restores a damaged organ to perfect condition. #define GANGREN_LEVEL_TERMINAL 2500 #define GERM_TRANSFER_AMOUNT germ_level/500 /datum/organ/external/proc/update_germs() + + if(status & ORGAN_ROBOT|ORGAN_DESTROYED) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. + germ_level = 0 + return + if(germ_level > 0 && owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs //Syncing germ levels with external wounds for(var/datum/wound/W in wounds) @@ -338,8 +342,9 @@ This function completely restores a damaged organ to perfect condition. for(var/datum/wound/W in wounds) // wounds can disappear after 10 minutes at the earliest - if(W.damage == 0 && W.created + 10 * 10 * 60 <= world.time) + if(W.damage <= 0 && W.created + 10 * 10 * 60 <= world.time) wounds -= W + continue // let the GC handle the deletion of the wound // Internal wounds get worse over time. Low temperatures (cryo) stop them. @@ -347,17 +352,17 @@ This function completely restores a damaged organ to perfect condition. if(!owner.reagents.has_reagent("bicaridine")) //bicard stops internal wounds from growing bigger with time, and also stop bleeding W.open_wound(0.1 * wound_update_accuracy) owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy) + if(!owner.reagents.has_reagent("inaprovaline")) //This little copypaste will allow inaprovaline to work too, giving it a much needed buff to help medical. + W.open_wound(0.1 * wound_update_accuracy) + owner.vessel.remove_reagent("blood",0.05 * W.damage * wound_update_accuracy) + owner.vessel.remove_reagent("blood",0.02 * W.damage * wound_update_accuracy)//Bicaridine slows Internal Bleeding if(prob(1 * wound_update_accuracy)) owner.custom_pain("You feel a stabbing pain in your [display_name]!",1) - //overdose of bicaridine begins healing IB - if(owner.reagents.has_reagent("bicaridine") && (owner.reagents.get_reagent_amount("bicaridine") >= 30)) - var/healinternal = 0.2 - if(W.damage <= healinternal) - W.damage = 0 - else - W.damage -= healinternal + //overdose of bicaridine begins healing IB + if(owner.reagents.get_reagent_amount("bicaridine") >= 30) + W.damage = max(0, W.damage - 0.2) // slow healing var/heal_amt = 0 @@ -385,6 +390,8 @@ This function completely restores a damaged organ to perfect condition. // sync the organ's damage with its wounds src.update_damages() + if (update_icon()) + owner.UpdateDamageIcon(1) //Updates brute_damn and burn_damn from wound damages. Updates BLEEDING status. /datum/organ/external/proc/update_damages() @@ -417,7 +424,6 @@ This function completely restores a damaged organ to perfect condition. var/n_is = damage_state_text() if (n_is != damage_state) damage_state = n_is - owner.update_body(1) return 1 return 0 @@ -549,7 +555,7 @@ This function completely restores a damaged organ to perfect condition. var/lol = pick(cardinal) step(organ,lol) - owner.regenerate_icons() + owner.update_body(1) /**************************************************** @@ -619,10 +625,13 @@ This function completely restores a damaged organ to perfect condition. return 0 /datum/organ/external/get_icon(gender="") + if (status & ORGAN_ROBOT) + return new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]") + if (status & ORGAN_MUTATED) return new /icon(owner.deform_icon, "[icon_name][gender ? "_[gender]" : ""]") - else - return new /icon(owner.race_icon, "[icon_name][gender ? "_[gender]" : ""]") + + return new /icon(owner.race_icon, "[icon_name][gender ? "_[gender]" : ""]") /datum/organ/external/proc/is_usable() @@ -886,17 +895,17 @@ obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob) switch(brain_op_stage) if(0) for(var/mob/O in (oviewers(brainmob) - user)) - O.show_message("\red [brainmob] is beginning to have \his head cut open with [src] by [user].", 1) - brainmob << "\red [user] begins to cut open your head with [src]!" - user << "\red You cut [brainmob]'s head open with [src]!" + O.show_message("\red [brainmob] is beginning to have \his head cut open with [W] by [user].", 1) + brainmob << "\red [user] begins to cut open your head with [W]!" + user << "\red You cut [brainmob]'s head open with [W]!" brain_op_stage = 1 if(2) for(var/mob/O in (oviewers(brainmob) - user)) - O.show_message("\red [brainmob] is having \his connections to the brain delicately severed with [src] by [user].", 1) - brainmob << "\red [user] begins to cut open your head with [src]!" - user << "\red You cut [brainmob]'s head open with [src]!" + O.show_message("\red [brainmob] is having \his connections to the brain delicately severed with [W] by [user].", 1) + brainmob << "\red [user] begins to cut open your head with [W]!" + user << "\red You cut [brainmob]'s head open with [W]!" brain_op_stage = 3.0 else @@ -905,20 +914,20 @@ obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob) switch(brain_op_stage) if(1) for(var/mob/O in (oviewers(brainmob) - user)) - O.show_message("\red [brainmob] has \his skull sawed open with [src] by [user].", 1) - brainmob << "\red [user] begins to saw open your head with [src]!" - user << "\red You saw [brainmob]'s head open with [src]!" + O.show_message("\red [brainmob] has \his skull sawed open with [W] by [user].", 1) + brainmob << "\red [user] begins to saw open your head with [W]!" + user << "\red You saw [brainmob]'s head open with [W]!" brain_op_stage = 2 if(3) for(var/mob/O in (oviewers(brainmob) - user)) - O.show_message("\red [brainmob] has \his spine's connection to the brain severed with [src] by [user].", 1) - brainmob << "\red [user] severs your brain's connection to the spine with [src]!" - user << "\red You sever [brainmob]'s brain's connection to the spine with [src]!" + O.show_message("\red [brainmob] has \his spine's connection to the brain severed with [W] by [user].", 1) + brainmob << "\red [user] severs your brain's connection to the spine with [W]!" + user << "\red You sever [brainmob]'s brain's connection to the spine with [W]!" - user.attack_log += "\[[time_stamp()]\] Debrained [brainmob.name] ([brainmob.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" - brainmob.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" - msg_admin_attack("[brainmob] ([brainmob.ckey]) debrained [user] ([user.ckey]) (INTENT: [uppertext(user.a_intent)]) (JMP)") + user.attack_log += "\[[time_stamp()]\] Debrained [brainmob.name] ([brainmob.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])" + brainmob.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])" + msg_admin_attack("[user] ([user.ckey]) debrained [brainmob] ([brainmob.ckey]) (INTENT: [uppertext(user.a_intent)]) (JMP)") var/obj/item/brain/B = new(loc) B.transfer_identity(brainmob) diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 43d0a180d88..35be9ba4e87 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -5,15 +5,15 @@ /mob/living/carbon/human/var/list/internal_organs = list() /datum/organ/internal - // amount of damage to the organ - var/damage = 0 + var/damage = 0 // amount of damage to the organ var/min_bruised_damage = 10 var/min_broken_damage = 30 var/parent_organ = "chest" + var/robotic = 0 //For being a robot /datum/organ/internal/proc/rejuvenate() damage=0 - + /datum/organ/internal/proc/is_bruised() return damage >= min_bruised_damage @@ -31,12 +31,51 @@ src.owner = H /datum/organ/internal/proc/take_damage(amount, var/silent=0) - src.damage += amount + if(src.robotic == 2) + src.damage += (amount * 0.8) + else + src.damage += amount var/datum/organ/external/parent = owner.get_organ(parent_organ) if (!silent) owner.custom_pain("Something inside your [parent.display_name] hurts a lot.", 1) + +/datum/organ/internal/proc/emp_act(severity) + switch(robotic) + if(0) + return + if(1) + switch (severity) + if (1.0) + take_damage(20,0) + return + if (2.0) + take_damage(7,0) + return + if(3.0) + take_damage(3,0) + return + if(2) + switch (severity) + if (1.0) + take_damage(40,0) + return + if (2.0) + take_damage(15,0) + return + if(3.0) + take_damage(10,0) + return + +/datum/organ/internal/proc/mechanize() //Being used to make robutt hearts, etc + robotic = 2 + +/datum/organ/internal/proc/mechassist() //Used to add things like pacemakers, etc + robotic = 1 + min_bruised_damage = 15 + min_broken_damage = 35 + /**************************************************** INTERNAL ORGANS DEFINES ****************************************************/ @@ -102,4 +141,14 @@ /datum/organ/internal/brain name = "brain" - parent_organ = "head" \ No newline at end of file + parent_organ = "head" + +/datum/organ/internal/eyes + name = "eyes" + parent_organ = "head" + + process() //Eye damage replaces the old eye_stat var. + if(is_bruised()) + owner.eye_blurry = 20 + if(is_broken()) + owner.eye_blind = 20 diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm index 718abbe2726..987e7d026cf 100644 --- a/code/modules/organs/pain.dm +++ b/code/modules/organs/pain.dm @@ -9,6 +9,8 @@ mob/var/next_pain_time = 0 // amount is a num from 1 to 100 mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0) if(stat >= 2) return + if(reagents.has_reagent("paracetamol")) + return if(reagents.has_reagent("tramadol")) return if(reagents.has_reagent("oxycodone")) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7a68873fd1e..599d2517236 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -962,7 +962,7 @@ cell.corrupt() src.malfhack = 1 update_icon() - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(3, 0, src.loc) smoke.attach(src) smoke.start() diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index ecc7acb8173..86e2351d50d 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -303,7 +303,7 @@ for(var/mob/M in viewers(src)) M.show_message("\red The [src.name] is making strange noises!", 3, "\red You hear sizzling electronics.", 2) sleep(10*pick(4,5,6,7,10,14)) - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(3, 0, src.loc) smoke.attach(src) smoke.start() @@ -321,7 +321,7 @@ emp_act(2) if(prob(5)) //smoke only world << "\red SMES smoke in [src.loc.loc]" - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(3, 0, src.loc) smoke.attach(src) smoke.start() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 7bcfecfa46f..13c1a0888f2 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -136,6 +136,14 @@ in_chamber.current = curloc in_chamber.yo = targloc.y - curloc.y in_chamber.xo = targloc.x - curloc.x + if(istype(user, /mob/living/carbon)) + var/mob/living/carbon/mob = user + if(mob.shock_stage > 120) + in_chamber.yo += rand(-2,2) + in_chamber.xo += rand(-2,2) + else if(mob.shock_stage > 70) + in_chamber.yo += rand(-1,1) + in_chamber.xo += rand(-1,1) if(params) var/list/mouse_control = params2list(params) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 9dbcabc47d9..97fa5b1dbd1 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -50,6 +50,7 @@ var/drowsy = 0 var/agony = 0 + var/embed = 0 // whether or not the projectile can embed itself in the mob proc/on_hit(var/atom/target, var/blocked = 0) if(blocked >= 2) return 0//Full block diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 36e456285ab..a88381b2a03 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -5,16 +5,18 @@ damage_type = BRUTE nodamage = 0 flag = "bullet" + embed = 1 on_hit(var/atom/target, var/blocked = 0) if (..(target, blocked)) var/mob/living/L = target shake_camera(L, 3, 2) -/obj/item/projectile/bullet/weakbullet +/obj/item/projectile/bullet/weakbullet // "rubber" bullets damage = 10 stun = 5 weaken = 5 + embed = 0 /obj/item/projectile/bullet/midbullet @@ -48,6 +50,7 @@ stun = 10 weaken = 10 stutter = 10 + embed = 0 /obj/item/projectile/bullet/a762 damage = 25 \ No newline at end of file diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm index 364ad53370b..2fab1a4da18 100644 --- a/code/modules/projectiles/projectile/force.dm +++ b/code/modules/projectiles/projectile/force.dm @@ -4,6 +4,7 @@ icon_state = "ice_1" damage = 20 flag = "energy" + embed = 1 /obj/item/projectile/forcebolt/strong name = "force bolt" diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 8b5400fa40e..a42b3c1d9bc 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -15,9 +15,12 @@ var/amount = 30 var/beaker = null var/recharged = 0 + var/hackedcheck = 0 var/list/dispensable_reagents = list("hydrogen","lithium","carbon","nitrogen","oxygen","fluorine", "sodium","aluminum","silicon","phosphorus","sulfur","chlorine","potassium","iron", "copper","mercury","radium","water","ethanol","sugar","sacid","tungsten") + var/list/broken_requirements = list() + var/broken_on_spawn = 0 /obj/machinery/chem_dispenser/proc/recharge() if(stat & (BROKEN|NOPOWER)) return @@ -49,6 +52,28 @@ recharge() dispensable_reagents = sortList(dispensable_reagents) + if(broken_on_spawn) + var/amount = pick(1,2,2,3,4) + var/list/options = list() + options[/obj/item/weapon/stock_parts/capacitor/adv] = "Add an advanced capacitor to fix it." + options[/obj/item/weapon/stock_parts/console_screen] = "Replace the console screen to fix it." + options[/obj/item/weapon/stock_parts/manipulator/pico] = "Upgrade to a pico manipulator to fix it." + options[/obj/item/weapon/stock_parts/matter_bin/adv] = "Give it an advanced matter bin to fix it." + options[/obj/item/stack/sheet/mineral/diamond] = "Line up a cut diamond with the nozzle to fix it." + options[/obj/item/stack/sheet/mineral/uranium] = "Position a uranium sheet inside to fix it." + options[/obj/item/stack/sheet/mineral/plasma] = "Enter a block of plasma to fix it." + options[/obj/item/stack/sheet/mineral/silver] = "Cover the internals with a silver lining to fix it." + options[/obj/item/stack/sheet/mineral/gold] = "Wire a golden filament to fix it." + options[/obj/item/stack/sheet/plasteel] = "Surround the outside with a plasteel cover to fix it." + options[/obj/item/stack/sheet/rglass] = "Insert a pane of reinforced glass to fix it." + + while(amount > 0) + amount -= 1 + + var/index = pick(options) + broken_requirements[index] = options[index] + options -= index + /obj/machinery/chem_dispenser/ex_act(severity) switch(severity) if(1.0) @@ -74,14 +99,17 @@ * * @param user /mob The mob who is interacting with this ui * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main") - * @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui * * @return nothing */ -/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) +/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main") if(stat & (BROKEN|NOPOWER)) return if(user.stat || user.restrained()) return + if(broken_requirements.len) + user << "[src] is broken. [broken_requirements[broken_requirements[1]]]" + return + // this is the data which will be sent to the ui var/data[0] data["amount"] = amount @@ -111,13 +139,10 @@ 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 - if (!ui) // no ui has been passed, so we'll search for one - { - ui = nanomanager.get_open_ui(user, src, ui_key) - } + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key) if (!ui) // the ui does not exist, so we'll create a new one - ui = new(user, src, ui_key, "chem_dispenser.tmpl", "Chem Dispenser 5000", 374, 640) + ui = new(user, src, ui_key, "chem_dispenser.tmpl", "Chem Dispenser 5000", 370, 605) // When the UI is first opened this is the data it will use ui.set_initial_data(data) ui.open() @@ -159,18 +184,26 @@ if(isrobot(user)) return - if(!istype(B, /obj/item/weapon/reagent_containers/glass)) + if(broken_requirements.len && B.type == broken_requirements[1]) + broken_requirements -= broken_requirements[1] + user << "You fix [src]." + if(istype(B,/obj/item/stack)) + var/obj/item/stack/S = B + S.use(1) + else + user.drop_item() + del(B) return - if(src.beaker) - user << "A beaker is already loaded into the machine." + user << "Something is already loaded into the machine." + return + if(istype(B, /obj/item/weapon/reagent_containers/glass||/obj/item/weapon/reagent_containers/food)) + src.beaker = B + user.drop_item() + B.loc = src + user << "You set [B] on the machine." + nanomanager.update_uis(src) // update all UIs attached to src return - - src.beaker = B - user.drop_item() - B.loc = src - user << "You add the beaker to the machine!" - nanomanager.update_uis(src) // update all UIs attached to src /obj/machinery/chem_dispenser/attack_ai(mob/user as mob) return src.attack_hand(user) @@ -184,6 +217,50 @@ ui_interact(user) +/obj/machinery/chem_dispenser/soda + icon_state = "soda_dispenser" + name = "soda fountain" + desc = "A drink fabricating machine, capable of producing many sugary drinks with just one touch." + energy = 100 + max_energy = 100 + dispensable_reagents = list("water","ice","coffee","tea","icetea","space_cola","spacemountainwind","dr_gibb","space_up","tonic","sodawater","lemon_lime","sugar","orangejuice","limejuice") + + /obj/machinery/chem_dispenser/soda/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob) + ..() + if(istype(B, /obj/item/device/multitool)) + if(hackedcheck == 0) + user << "You change the mode from 'McNano' to 'Pizza King'." + dispensable_reagents += list("thirteenloko","grapesoda") + hackedcheck = 1 + return + + else + user << "You change the mode from 'Pizza King' to 'McNano'." + dispensable_reagents -= list("thirteenloko") + hackedcheck = 0 + return +/obj/machinery/chem_dispenser/beer + icon_state = "booze_dispenser" + name = "booze dispenser" + energy = 100 + max_energy = 100 + desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one." + dispensable_reagents = list("water","ice","coffee","tea","cream","lemon_lime","sugar","orangejuice","limejuice","cola","sodawater","tonic","beer","kahlua","whiskey","wine","vodka","gin","rum","tequila","vermouth","cognac","ale","mead") + + /obj/machinery/chem_dispenser/beer/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob) + ..() + if(istype(B, /obj/item/device/multitool)) + if(hackedcheck == 0) + user << "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes." + dispensable_reagents += list("goldschlager","patron","watermelonjuice","berryjuice") + hackedcheck = 1 + return + + else + user << "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes." + dispensable_reagents -= list("goldschlager","patron","watermelonjuice","berryjuice") + hackedcheck = 0 + return ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -347,15 +424,15 @@ reagents.clear_reagents() icon_state = "mixer0" else if (href_list["createpill"] || href_list["createpill_multiple"]) + var/name = reject_bad_text(input(usr,"Name:","Name your pill!",reagents.get_master_reagent_name())) var/count = 1 if (href_list["createpill_multiple"]) count = isgoodnumber(input("Select the number of pills to make.", 10, pillamount) as num) if (count > 20) count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines? var/amount_per_pill = reagents.total_volume/count if (amount_per_pill > 50) amount_per_pill = 50 - var/name = reject_bad_text(input(usr,"Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill] units)")) while (count--) var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.loc) - if(!name) name = "[reagents.get_master_reagent_name()] ([amount_per_pill] units)" + if(!name) name = reagents.get_master_reagent_name() P.name = "[name] pill" P.pixel_x = rand(-7, 7) //random position P.pixel_y = rand(-7, 7) @@ -367,9 +444,9 @@ src.updateUsrDialog() else if (href_list["createbottle"]) if(!condi) - var/name = reject_bad_text(input(usr,"Name:","Name your bottle!","[reagents.get_master_reagent_name()] ([reagents.total_volume] units)")) + var/name = reject_bad_text(input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name())) var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) - if(!name) name = "[reagents.get_master_reagent_name()] ([reagents.total_volume] units)" + if(!name) name = reagents.get_master_reagent_name() P.name = "[name] bottle" P.pixel_x = rand(-7, 7) //random position P.pixel_y = rand(-7, 7) diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 8f162524556..bf29dc863ff 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -31,7 +31,7 @@ datum var/datum/reagent/self = src src = null //of the reagent to the mob on TOUCHING it. - if(!istype(self.holder.my_atom, /obj/effect/effect/chem_smoke)) + if(!istype(self.holder.my_atom, /obj/effect/effect/smoke/chem)) // If the chemicals are in a smoke cloud, do not try to let the chemicals "penetrate" into the mob's system (balance station 13) -- Doohl if(method == TOUCH) @@ -731,13 +731,29 @@ datum ..() return + paracetamol + name = "Paracetamol" + id = "paracetamol" + description = "Most probably know this as Tylenol, but this chemical is a mild, simple painkiller." + reagent_state = LIQUID + color = "#C855DC" + overdose = 60 + + on_mob_life(var/mob/living/M as mob) + if (volume > overdose) + M.hallucination = max(M.hallucination, 2) + tramadol name = "Tramadol" id = "tramadol" description = "A simple, yet effective painkiller." reagent_state = LIQUID color = "#C8A5DC" - overdose = REAGENTS_OVERDOSE + overdose = 30 + + on_mob_life(var/mob/living/M as mob) + if (volume > overdose) + M.hallucination = max(M.hallucination, 2) oxycodone name = "Oxycodone" @@ -745,7 +761,13 @@ datum description = "An effective and very addictive painkiller." reagent_state = LIQUID color = "#C805DC" - overdose = REAGENTS_OVERDOSE + overdose = 20 + + on_mob_life(var/mob/living/M as mob) + if (volume > overdose) + M.druggy = max(M.druggy, 10) + M.hallucination = max(M.hallucination, 3) + virus_food name = "Virus Food" @@ -1025,7 +1047,7 @@ datum if(M.stat == 2.0) return if(!M) M = holder.my_atom - if(M.getOxyLoss() && prob(80)) M.adjustOxyLoss(-1*REM) + if(M.getOxyLoss()) M.adjustOxyLoss(-1*REM) if(M.getBruteLoss() && prob(80)) M.heal_organ_damage(1*REM,0) if(M.getFireLoss() && prob(80)) M.heal_organ_damage(0,1*REM) if(M.getToxLoss() && prob(80)) M.adjustToxLoss(-1*REM) @@ -1069,7 +1091,6 @@ datum M.sdisabilities = 0 M.eye_blurry = 0 M.eye_blind = 0 - M.eye_stat = 0 M.SetWeakened(0) M.SetStunned(0) M.SetParalysis(0) @@ -1189,9 +1210,31 @@ datum if(!M) M = holder.my_atom M.eye_blurry = max(M.eye_blurry-5 , 0) M.eye_blind = max(M.eye_blind-5 , 0) - M.disabilities &= ~NEARSIGHTED - M.eye_stat = max(M.eye_stat-5, 0) -// M.sdisabilities &= ~1 Replaced by eye surgery + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/datum/organ/internal/eyes/E = H.internal_organs["eyes"] + if(istype(E)) + if(E.damage > 0) + E.damage -= 1 + ..() + return + + peridaxon + name = "Peridaxon" + id = "peridaxon" + description = "Used to encourage recovery of internal organs and nervous systems. Medicate cautiously." + reagent_state = LIQUID + color = "#C8A5DC" // rgb: 200, 165, 220 + overdose = 10 + + on_mob_life(var/mob/living/M as mob) + if(!M) M = holder.my_atom + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/datum/organ/external/chest/C = H.get_organ("chest") + for(var/datum/organ/internal/I in C.internal_organs) + if(I.damage > 0) + I.damage -= 0.20 ..() return @@ -1658,10 +1701,12 @@ datum if(prob(5)) M.emote("yawn") if(12 to 15) M.eye_blurry = max(M.eye_blurry, 10) - if(15 to 25) + if(15 to 49) + if(prob(50)) + M.Weaken(2) M.drowsyness = max(M.drowsyness, 20) - if(25 to INFINITY) - M.Paralyse(20) + if(50 to INFINITY) + M.Weaken(20) M.drowsyness = max(M.drowsyness, 30) data++ ..() @@ -1673,9 +1718,10 @@ datum description = "A powerful sedative." reagent_state = SOLID color = "#000067" // rgb: 0, 0, 103 - toxpwr = 0 + toxpwr = 1 custom_metabolism = 0.1 //Default 0.2 - overdose = REAGENTS_OVERDOSE/2 + overdose = 15 + overdose_dam = 5 on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom @@ -1685,11 +1731,50 @@ datum if(1) M.confused += 2 M.drowsyness += 2 - if(2 to 50) + if(2 to 199) + M.Weaken(30) + if(200 to INFINITY) M.sleeping += 1 - if(51 to INFINITY) - M.sleeping += 1 - M.adjustToxLoss((data - 50)*REM) + ..() + return + + toxin/potassium_chloride + name = "Potassium Chloride" + id = "potassium_chloride" + description = "A delicious salt that stops the heart when injected into cardiac muscle." + reagent_state = SOLID + color = "#FFFFFF" // rgb: 255,255,255 + toxpwr = 0 + overdose = 30 + + on_mob_life(var/mob/living/carbon/M as mob) + var/mob/living/carbon/human/H = M + if(H.stat != 1) + if (volume >= overdose) + if(H.losebreath >= 10) + H.losebreath = max(10, H.losebreath-10) + H.adjustOxyLoss(2) + H.Weaken(10) + ..() + return + + toxin/potassium_chlorophoride + name = "Potassium Chlorophoride" + id = "potassium_chlorophoride" + description = "A specific chemical based on Potassium Chloride to stop the heart for surgery. Not safe to eat!" + reagent_state = SOLID + color = "#FFFFFF" // rgb: 255,255,255 + toxpwr = 2 + overdose = 20 + + on_mob_life(var/mob/living/carbon/M as mob) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.stat != 1) + if(H.losebreath >= 10) + H.losebreath = max(10, M.losebreath-10) + H.adjustOxyLoss(2) + H.Weaken(10) ..() return @@ -2348,6 +2433,13 @@ datum description = "It's grrrrrape!" color = "#863333" // rgb: 134, 51, 51 + drink/grapesoda + name = "Grape Soda" + id = "grapesoda" + description = "Grapes made into a fine drank." + color = "#421C52" // rgb: 98, 57, 53 + adj_drowsy = -3 + drink/poisonberryjuice name = "Poison Berry Juice" id = "poisonberryjuice" @@ -3047,29 +3139,29 @@ datum switch(data) if(1 to 25) if (!M.stuttering) M.stuttering = 1 - M.make_dizzy(10) + M.make_dizzy(1) M.hallucination = max(M.hallucination, 3) if(prob(1)) M.emote(pick("twitch","giggle")) if(25 to 75) if (!M.stuttering) M.stuttering = 1 M.hallucination = max(M.hallucination, 10) - M.make_jittery(20) - M.make_dizzy(20) + M.make_jittery(2) + M.make_dizzy(2) M.druggy = max(M.druggy, 45) if(prob(5)) M.emote(pick("twitch","giggle")) if (75 to 150) if (!M.stuttering) M.stuttering = 1 M.hallucination = max(M.hallucination, 60) - M.make_jittery(40) - M.make_dizzy(40) + M.make_jittery(4) + M.make_dizzy(4) M.druggy = max(M.druggy, 60) if(prob(10)) M.emote(pick("twitch","giggle")) if(prob(30)) M.adjustToxLoss(2) if (150 to 300) if (!M.stuttering) M.stuttering = 1 M.hallucination = max(M.hallucination, 60) - M.make_jittery(40) - M.make_dizzy(40) + M.make_jittery(4) + M.make_dizzy(4) M.druggy = max(M.druggy, 60) if(prob(10)) M.emote(pick("twitch","giggle")) if(prob(30)) M.adjustToxLoss(2) @@ -3084,7 +3176,7 @@ datum var/datum/organ/internal/heart/L = H.internal_organs["heart"] if (istype(L)) L.take_damage(100, 0) - + holder.remove_reagent(src.id, FOOD_METABOLISM) ethanol/deadrum name = "Deadrum" @@ -3460,7 +3552,7 @@ datum id = "aloe" description = "So very, very, very good." color = "#664300" // rgb: 102, 67, 0 - boozepwr = 35 + boozepwr = 3 ethanol/andalusia name = "Andalusia" diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 07c1c778690..bb168446d56 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -105,11 +105,19 @@ datum required_reagents = list("inaprovaline" = 1, "ethanol" = 1, "oxygen" = 1) result_amount = 3 + paracetamol + name = "Paracetamol" + id = "paracetamol" + result = "paracetamol" + required_reagents = list("tramadol" = 1, "sugar" = 1, "water" = 1) + result_amount = 3 + oxycodone name = "Oxycodone" id = "oxycodone" result = "oxycodone" - required_reagents = list("ethanol" = 1, "tramadol" = 1, "plasma" = 1) + required_reagents = list("ethanol" = 1, "tramadol" = 1) + required_catalysts = list("plasma" = 1) result_amount = 1 //cyanide @@ -119,6 +127,13 @@ datum // required_reagents = list("hydrogen" = 1, "carbon" = 1, "nitrogen" = 1) // result_amount = 1 + water //I can't believe we never had this. + name = "Water" + id = "water" + result = null + required_reagents = list("oxygen" = 2, "hydrogen" = 1) + result_amount = 1 + thermite name = "Thermite" id = "thermite" @@ -189,6 +204,14 @@ datum required_reagents = list("silicon" = 1, "carbon" = 1) result_amount = 2 + peridaxon + name = "Peridaxon" + id = "peridaxon" + result = "peridaxon" + required_reagents = list("bicaridine" = 2, "clonexadone" = 2) + required_catalysts = list("plasma" = 5) + result_amount = 2 + virus_food name = "Virus Food" id = "virusfood" @@ -433,7 +456,7 @@ datum secondary = 1 on_reaction(var/datum/reagents/holder, var/created_volume) var/location = get_turf(holder.my_atom) - var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread + var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem S.attach(location) S.set_up(holder, 10, 0, location) playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) @@ -451,6 +474,27 @@ datum required_reagents = list("ethanol" = 1, "chlorine" = 3, "water" = 1) result_amount = 1 + potassium_chloride + name = "Potassium Chloride" + id = "potassium_chloride" + id = "potassium_chloride" + required_reagents = list("sodiumchloride" = 1, "potassium" = 1) + result_amount = 2 + + potassium_chlorophoride + name = "Potassium Chlorophoride" + id = "potassium_chlorophoride" + id = "potassium_chlorophoride" + required_reagents = list("potassium_chloride" = 1, "plasma" = 1, "chloral_hydrate" = 1) + result_amount = 4 + + stoxin + name = "Sleep Toxin" + id = "stoxin" + result = "stoxin" + required_reagents = list("chloralhydrate" = 1, "sugar" = 4) + result_amount = 5 + zombiepowder name = "Zombie Powder" id = "zombiepowder" @@ -1791,6 +1835,14 @@ datum required_reagents = list("berryjuice" = 1, "cream" = 1, "vermouth" = 1) result_amount = 3 + grapesoda //Allows Grape Soda to be made + name = "Grape Soda" + id = "grapesoda" + result = "grapesoda" + required_reagents = list("grapejuice" = 2, "cola" = 1) + result_amount = 3 + + ////DRINKS THAT REQUIRED IMPROVED SPRITES BELOW:: -Agouri///// diff --git a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm index 2aec56dc0aa..2c08c1ce600 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm @@ -1,5 +1,5 @@ - - + + /obj/item/weapon/reagent_containers/food/drinks/drinkingglass name = "glass" desc = "Your standard drinking glass." @@ -434,6 +434,10 @@ icon_state = "grapejuice" name = "Glass of grape juice" desc = "It's grrrrrape!" + if("grapesoda") + icon_state = "grapesoda" + name = "Can of Grape Soda" + desc = "Looks like a delicious drank!" if("icetea") icon_state = "icedteaglass" name = "Iced Tea" @@ -499,4 +503,4 @@ New() ..() reagents.add_reagent("cola", 50) - on_reagent_change() \ No newline at end of file + on_reagent_change() diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index bdb8d913c47..771d49a2da8 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -118,7 +118,7 @@ if(istype(W,/obj/item/weapon/storage)) ..() // -> item/attackby() if((slices_num <= 0 || !slices_num) || !slice_path) - return 1 + return 0 var/inaccurate = 0 if( \ istype(W, /obj/item/weapon/kitchenknife) || \ diff --git a/code/modules/reagents/reagent_containers/food/snacks/grown.dm b/code/modules/reagents/reagent_containers/food/snacks/grown.dm index c47103e2821..b8be5cf0bd3 100644 --- a/code/modules/reagents/reagent_containers/food/snacks/grown.dm +++ b/code/modules/reagents/reagent_containers/food/snacks/grown.dm @@ -243,6 +243,50 @@ reagents.add_reagent("plasticide", 1+round((potency / 10), 1)) bitesize = 1+round(reagents.total_volume / 2, 1) + +/obj/item/weapon/reagent_containers/food/snacks/grown/shand + seed = "/obj/item/seeds/shandseed" + name = "S'rendarr's Hand leaf" + desc = "A leaf sample from a lowland thicket shrub, often hid in by prey and predator to staunch their wounds and conceal their scent, allowing the plant to spread far on it's native Ahdomai. Smells strongly like wax." + icon_state = "shand" + New() + ..() + spawn(5) //So potency can be set in the proc that creates these crops + reagents.add_reagent("bicaridine", round((potency / 10), 1)) + bitesize = 1+round(reagents.total_volume / 2, 1) + +/obj/item/weapon/reagent_containers/food/snacks/grown/mtear + seed = "/obj/item/seeds/mtearseed" + name = "sprig of Messa's Tear" + desc = "A mountain climate herb with a soft, cold blue flower, known to contain an abundance of chemicals in it's flower useful to treating burns- Bad for the allergic to pollen." + icon_state = "mtear" + New() + ..() + spawn(5) //So potency can be set in the proc that creates these crops + reagents.add_reagent("honey", 1+round((potency / 10), 1)) + reagents.add_reagent("kelotane", 3+round((potency / 5), 1)) + bitesize = 1+round(reagents.total_volume / 2, 1) + +/obj/item/weapon/reagent_containers/food/snacks/grown/mtear/attack_self(mob/user as mob) + if(istype(user.loc,/turf/space)) + return + var/obj/item/stack/medical/ointment/tajaran/poultice = new /obj/item/stack/medical/ointment/tajaran(user.loc) + + poultice.heal_burn = potency + del(src) + + user << "You mash the petals into a poultice." + +/obj/item/weapon/reagent_containers/food/snacks/grown/shand/attack_self(mob/user as mob) + if(istype(user.loc,/turf/space)) + return + var/obj/item/stack/medical/bruise_pack/tajaran/poultice = new /obj/item/stack/medical/bruise_pack/tajaran(user.loc) + + poultice.heal_brute = potency + del(src) + + user << "You mash the leaves into a poultice." + /obj/item/weapon/reagent_containers/food/snacks/grown/glowberries seed = "/obj/item/seeds/glowberryseed" name = "bunch of glow-berries" diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index ad68c27b67c..b4a7ecf2095 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -1,318 +1,337 @@ - -//////////////////////////////////////////////////////////////////////////////// -/// (Mixing)Glass. -//////////////////////////////////////////////////////////////////////////////// -/obj/item/weapon/reagent_containers/glass - name = " " - var/base_name = " " - desc = " " - icon = 'icons/obj/chemical.dmi' - icon_state = "null" - item_state = "null" - amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(5,10,15,25,30,50) - volume = 50 - flags = FPRINT | TABLEPASS | OPENCONTAINER - - var/label_text = "" - - var/list/can_be_placed_into = list( - /obj/machinery/chem_master/, - /obj/machinery/chem_dispenser/, - /obj/machinery/reagentgrinder, - /obj/structure/table, - /obj/structure/closet, - /obj/structure/sink, - /obj/item/weapon/storage, - /obj/machinery/atmospherics/unary/cryo_cell, - /obj/machinery/dna_scannernew, - /obj/item/weapon/grenade/chem_grenade, - /obj/machinery/bot/medbot, - /obj/machinery/computer/pandemic, - /obj/item/weapon/storage/secure/safe, - /obj/machinery/iv_drip, - /obj/machinery/disease2/incubator, - /obj/machinery/disposal, - /obj/machinery/apiary, - /mob/living/simple_animal/cow, - /mob/living/simple_animal/hostile/retaliate/goat, + +//////////////////////////////////////////////////////////////////////////////// +/// (Mixing)Glass. +//////////////////////////////////////////////////////////////////////////////// +/obj/item/weapon/reagent_containers/glass + name = " " + var/base_name = " " + desc = " " + icon = 'icons/obj/chemical.dmi' + icon_state = "null" + item_state = "null" + amount_per_transfer_from_this = 10 + possible_transfer_amounts = list(5,10,15,25,30,50) + volume = 50 + flags = FPRINT | TABLEPASS | OPENCONTAINER + + var/label_text = "" + + var/list/can_be_placed_into = list( + /obj/machinery/chem_master/, + /obj/machinery/chem_dispenser/, + /obj/machinery/reagentgrinder, + /obj/structure/table, + /obj/structure/closet, + /obj/structure/sink, + /obj/item/weapon/storage, + /obj/machinery/atmospherics/unary/cryo_cell, + /obj/machinery/dna_scannernew, + /obj/item/weapon/grenade/chem_grenade, + /obj/machinery/bot/medbot, + /obj/machinery/computer/pandemic, + /obj/item/weapon/storage/secure/safe, + /obj/machinery/iv_drip, + /obj/machinery/disease2/incubator, + /obj/machinery/disposal, + /obj/machinery/apiary, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/hostile/retaliate/goat, /obj/machinery/computer/centrifuge, /obj/machinery/sleeper ) - - New() - ..() - base_name = name - - examine() - set src in view() - ..() - if (!(usr in view(2)) && usr!=src.loc) return - usr << "\blue It contains:" - if(reagents && reagents.reagent_list.len) - usr << "\blue [src.reagents.total_volume] units of liquid." - else - usr << "\blue Nothing." - if (!is_open_container()) - usr << "\blue Airtight lid seals it completely." - - attack_self() - ..() - if (is_open_container()) - usr << "You put the lid on \the [src]." - flags ^= OPENCONTAINER - else - usr << "You take the lid off \the [src]." - flags |= OPENCONTAINER - update_icon() - - afterattack(obj/target, mob/user, proximity) - if(!proximity) return - if (!is_open_container()) - return - - for(var/type in src.can_be_placed_into) - if(istype(target, type)) - return - - if(ismob(target) && target.reagents && reagents.total_volume) - user << "\blue You splash the solution onto [target]." - - var/mob/living/M = target - var/list/injected = list() - for(var/datum/reagent/R in src.reagents.reagent_list) - injected += R.name - var/contained = english_list(injected) - M.attack_log += text("\[[time_stamp()]\] Has been splashed with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to splash [M.name] ([M.key]). Reagents: [contained]") - msg_admin_attack("[user.name] ([user.ckey]) splashed [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") - - for(var/mob/O in viewers(world.view, user)) - O.show_message(text("\red [] has been splashed with something by []!", target, user), 1) - src.reagents.reaction(target, TOUCH) - spawn(5) src.reagents.clear_reagents() - return - else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. - - if(!target.reagents.total_volume && target.reagents) - user << "\red [target] is empty." - return - - if(reagents.total_volume >= reagents.maximum_volume) - user << "\red [src] is full." - return - - var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this) - user << "\blue You fill [src] with [trans] units of the contents of [target]." - - else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it. - if(!reagents.total_volume) - user << "\red [src] is empty." - return - - if(target.reagents.total_volume >= target.reagents.maximum_volume) - user << "\red [target] is full." - return - - var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) - user << "\blue You transfer [trans] units of the solution to [target]." - - //Safety for dumping stuff into a ninja suit. It handles everything through attackby() and this is unnecessary. - else if(istype(target, /obj/item/clothing/suit/space/space_ninja)) - return - - else if(istype(target, /obj/machinery/bunsen_burner)) - return - - else if(istype(target, /obj/machinery/anomaly)) - return - - else if(reagents.total_volume) - user << "\blue You splash the solution onto [target]." - src.reagents.reaction(target, TOUCH) - spawn(5) src.reagents.clear_reagents() - return - - attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen)) - var/tmp_label = sanitize(input(user, "Enter a label for [src.name]","Label",src.label_text)) - if(length(tmp_label) > 10) - user << "\red The label can be at most 10 characters long." - else - user << "\blue You set the label to \"[tmp_label]\"." - src.label_text = tmp_label - src.update_name_label() - - proc/update_name_label() - if(src.label_text == "") - src.name = src.base_name - else - src.name = "[src.base_name] ([src.label_text])" - -/obj/item/weapon/reagent_containers/glass/beaker - name = "beaker" - desc = "A beaker. Can hold up to 50 units." - icon = 'icons/obj/chemical.dmi' - icon_state = "beaker" - item_state = "beaker" - m_amt = 0 - g_amt = 500 - - on_reagent_change() - update_icon() - - pickup(mob/user) - ..() - update_icon() - - dropped(mob/user) - ..() - update_icon() - - attack_hand() - ..() - update_icon() - - update_icon() - overlays.Cut() - - if(reagents.total_volume) - var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") - - var/percent = round((reagents.total_volume / volume) * 100) - switch(percent) - if(0 to 9) filling.icon_state = "[icon_state]-10" - if(10 to 24) filling.icon_state = "[icon_state]10" - if(25 to 49) filling.icon_state = "[icon_state]25" - if(50 to 74) filling.icon_state = "[icon_state]50" - if(75 to 79) filling.icon_state = "[icon_state]75" - if(80 to 90) filling.icon_state = "[icon_state]80" - if(91 to INFINITY) filling.icon_state = "[icon_state]100" - - filling.icon += mix_color_from_reagents(reagents.reagent_list) - overlays += filling - - if (!is_open_container()) - var/image/lid = image(icon, src, "lid_[initial(icon_state)]") - overlays += lid - -/obj/item/weapon/reagent_containers/glass/beaker/large - name = "large beaker" - desc = "A large beaker. Can hold up to 100 units." - icon_state = "beakerlarge" - g_amt = 5000 - volume = 100 - amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(5,10,15,25,30,50,100) - flags = FPRINT | TABLEPASS | OPENCONTAINER - -/obj/item/weapon/reagent_containers/glass/beaker/vial - name = "vial" - desc = "A small glass vial. Can hold up to 25 units." - icon_state = "vial" - g_amt = 250 - volume = 25 - amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(5,10,15,25) - flags = FPRINT | TABLEPASS | OPENCONTAINER - -/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone - New() - ..() - reagents.add_reagent("cryoxadone", 30) - update_icon() - -/obj/item/weapon/reagent_containers/glass/beaker/sulphuric - New() - ..() - reagents.add_reagent("sacid", 50) - update_icon() - -/obj/item/weapon/reagent_containers/glass/beaker/slime - New() - ..() - reagents.add_reagent("slimejelly", 50) - update_icon() - -/obj/item/weapon/reagent_containers/glass/bucket - desc = "It's a bucket." - name = "bucket" - icon = 'icons/obj/janitor.dmi' - icon_state = "bucket" - item_state = "bucket" - m_amt = 200 - g_amt = 0 - w_class = 3.0 - amount_per_transfer_from_this = 20 - possible_transfer_amounts = list(10,20,30,50,70) - volume = 70 - flags = FPRINT | OPENCONTAINER - - attackby(var/obj/D, mob/user as mob) - if(isprox(D)) - user << "You add [D] to [src]." - del(D) - user.put_in_hands(new /obj/item/weapon/bucket_sensor) - user.drop_from_inventory(src) - del(src) - -// vials are defined twice, what? -/* -/obj/item/weapon/reagent_containers/glass/beaker/vial - name = "vial" - desc = "Small glass vial. Looks fragile." - icon_state = "vial" - g_amt = 500 - volume = 15 - amount_per_transfer_from_this = 5 - possible_transfer_amounts = list(1,5,15) - flags = FPRINT | TABLEPASS | OPENCONTAINER */ - -/* -/obj/item/weapon/reagent_containers/glass/blender_jug - name = "Blender Jug" - desc = "A blender jug, part of a blender." - icon = 'icons/obj/kitchen.dmi' - icon_state = "blender_jug_e" - volume = 100 - - on_reagent_change() - switch(src.reagents.total_volume) - if(0) - icon_state = "blender_jug_e" - if(1 to 75) - icon_state = "blender_jug_h" - if(76 to 100) - icon_state = "blender_jug_f" - -/obj/item/weapon/reagent_containers/glass/canister //not used apparantly - desc = "It's a canister. Mainly used for transporting fuel." - name = "canister" - icon = 'icons/obj/tank.dmi' - icon_state = "canister" - item_state = "canister" - m_amt = 300 - g_amt = 0 - w_class = 4.0 - - amount_per_transfer_from_this = 20 - possible_transfer_amounts = list(10,20,30,60) - volume = 120 - flags = FPRINT - -/obj/item/weapon/reagent_containers/glass/dispenser - name = "reagent glass" - desc = "A reagent glass." - icon = 'icons/obj/chemical.dmi' - icon_state = "beaker0" - amount_per_transfer_from_this = 10 - flags = FPRINT | TABLEPASS | OPENCONTAINER - -/obj/item/weapon/reagent_containers/glass/dispenser/surfactant - name = "reagent glass (surfactant)" - icon_state = "liquid" - - New() - ..() - reagents.add_reagent("fluorosurfactant", 20) - -*/ + + New() + ..() + base_name = name + + examine() + set src in view() + ..() + if (!(usr in view(2)) && usr!=src.loc) return + usr << "\blue It contains:" + if(reagents && reagents.reagent_list.len) + usr << "\blue [src.reagents.total_volume] units of liquid." + else + usr << "\blue Nothing." + if (!is_open_container()) + usr << "\blue Airtight lid seals it completely." + + attack_self() + ..() + if (is_open_container()) + usr << "You put the lid on \the [src]." + flags ^= OPENCONTAINER + else + usr << "You take the lid off \the [src]." + flags |= OPENCONTAINER + update_icon() + + afterattack(obj/target, mob/user , flag) + if (!is_open_container()) + return + + for(var/type in src.can_be_placed_into) + if(istype(target, type)) + return + + if(ismob(target) && target.reagents && reagents.total_volume) + user << "\blue You splash the solution onto [target]." + + var/mob/living/M = target + var/list/injected = list() + for(var/datum/reagent/R in src.reagents.reagent_list) + injected += R.name + var/contained = english_list(injected) + M.attack_log += text("\[[time_stamp()]\] Has been splashed with [src.name] by [user.name] ([user.ckey]). Reagents: [contained]") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to splash [M.name] ([M.key]). Reagents: [contained]") + msg_admin_attack("[user.name] ([user.ckey]) splashed [M.name] ([M.key]) with [src.name]. Reagents: [contained] (INTENT: [uppertext(user.a_intent)]) (JMP)") + + for(var/mob/O in viewers(world.view, user)) + O.show_message(text("\red [] has been splashed with something by []!", target, user), 1) + src.reagents.reaction(target, TOUCH) + spawn(5) src.reagents.clear_reagents() + return + else if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. + + if(!target.reagents.total_volume && target.reagents) + user << "\red [target] is empty." + return + + if(reagents.total_volume >= reagents.maximum_volume) + user << "\red [src] is full." + return + + var/trans = target.reagents.trans_to(src, target:amount_per_transfer_from_this) + user << "\blue You fill [src] with [trans] units of the contents of [target]." + + else if(target.is_open_container() && target.reagents) //Something like a glass. Player probably wants to transfer TO it. + if(!reagents.total_volume) + user << "\red [src] is empty." + return + + if(target.reagents.total_volume >= target.reagents.maximum_volume) + user << "\red [target] is full." + return + + var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + user << "\blue You transfer [trans] units of the solution to [target]." + + //Safety for dumping stuff into a ninja suit. It handles everything through attackby() and this is unnecessary. + else if(istype(target, /obj/item/clothing/suit/space/space_ninja)) + return + + else if(istype(target, /obj/machinery/bunsen_burner)) + return + + else if(istype(target, /obj/machinery/radiocarbon_spectrometer)) + return + + else if(reagents.total_volume) + user << "\blue You splash the solution onto [target]." + src.reagents.reaction(target, TOUCH) + spawn(5) src.reagents.clear_reagents() + return + + attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen)) + var/tmp_label = sanitize(input(user, "Enter a label for [src.name]","Label",src.label_text)) + if(length(tmp_label) > 10) + user << "\red The label can be at most 10 characters long." + else + user << "\blue You set the label to \"[tmp_label]\"." + src.label_text = tmp_label + src.update_name_label() + + proc/update_name_label() + if(src.label_text == "") + src.name = src.base_name + else + src.name = "[src.base_name] ([src.label_text])" + +/obj/item/weapon/reagent_containers/glass/beaker + name = "beaker" + desc = "A beaker. Can hold up to 50 units." + icon = 'icons/obj/chemical.dmi' + icon_state = "beaker" + item_state = "beaker" + m_amt = 0 + g_amt = 500 + + on_reagent_change() + update_icon() + + pickup(mob/user) + ..() + update_icon() + + dropped(mob/user) + ..() + update_icon() + + attack_hand() + ..() + update_icon() + + update_icon() + overlays.Cut() + + if(reagents.total_volume) + var/image/filling = image('icons/obj/reagentfillings.dmi', src, "[icon_state]10") + + var/percent = round((reagents.total_volume / volume) * 100) + switch(percent) + if(0 to 9) filling.icon_state = "[icon_state]-10" + if(10 to 24) filling.icon_state = "[icon_state]10" + if(25 to 49) filling.icon_state = "[icon_state]25" + if(50 to 74) filling.icon_state = "[icon_state]50" + if(75 to 79) filling.icon_state = "[icon_state]75" + if(80 to 90) filling.icon_state = "[icon_state]80" + if(91 to INFINITY) filling.icon_state = "[icon_state]100" + + filling.icon += mix_color_from_reagents(reagents.reagent_list) + overlays += filling + + if (!is_open_container()) + var/image/lid = image(icon, src, "lid_[initial(icon_state)]") + overlays += lid + +/obj/item/weapon/reagent_containers/glass/beaker/large + name = "large beaker" + desc = "A large beaker. Can hold up to 100 units." + icon_state = "beakerlarge" + g_amt = 5000 + volume = 100 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = list(5,10,15,25,30,50,100) + flags = FPRINT | TABLEPASS | OPENCONTAINER + +/obj/item/weapon/reagent_containers/glass/beaker/noreact + name = "cryostasis beaker" + desc = "A cryostasis beaker that allows for chemical storage without reactions. Can hold up to 50 units." + icon_state = "beakernoreact" + g_amt = 500 + volume = 50 + amount_per_transfer_from_this = 10 + flags = FPRINT | TABLEPASS | OPENCONTAINER | NOREACT + +/obj/item/weapon/reagent_containers/glass/beaker/bluespace + name = "bluespace beaker" + desc = "A bluespace beaker, powered by experimental bluespace technology and Element Cuban combined with the Compound Pete. Can hold up to 300 units." + icon_state = "beakerbluespace" + g_amt = 5000 + volume = 300 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = list(5,10,15,25,30,50,100,300) + flags = FPRINT | TABLEPASS | OPENCONTAINER + + +/obj/item/weapon/reagent_containers/glass/beaker/vial + name = "vial" + desc = "A small glass vial. Can hold up to 25 units." + icon_state = "vial" + g_amt = 250 + volume = 25 + amount_per_transfer_from_this = 10 + possible_transfer_amounts = list(5,10,15,25) + flags = FPRINT | TABLEPASS | OPENCONTAINER + +/obj/item/weapon/reagent_containers/glass/beaker/cryoxadone + New() + ..() + reagents.add_reagent("cryoxadone", 30) + update_icon() + +/obj/item/weapon/reagent_containers/glass/beaker/sulphuric + New() + ..() + reagents.add_reagent("sacid", 50) + update_icon() + +/obj/item/weapon/reagent_containers/glass/beaker/slime + New() + ..() + reagents.add_reagent("slimejelly", 50) + update_icon() + +/obj/item/weapon/reagent_containers/glass/bucket + desc = "It's a bucket." + name = "bucket" + icon = 'icons/obj/janitor.dmi' + icon_state = "bucket" + item_state = "bucket" + m_amt = 200 + g_amt = 0 + w_class = 3.0 + amount_per_transfer_from_this = 20 + possible_transfer_amounts = list(10,20,30,50,70) + volume = 70 + flags = FPRINT | OPENCONTAINER + + attackby(var/obj/D, mob/user as mob) + if(isprox(D)) + user << "You add [D] to [src]." + del(D) + user.put_in_hands(new /obj/item/weapon/bucket_sensor) + user.drop_from_inventory(src) + del(src) + +// vials are defined twice, what? +/* +/obj/item/weapon/reagent_containers/glass/beaker/vial + name = "vial" + desc = "Small glass vial. Looks fragile." + icon_state = "vial" + g_amt = 500 + volume = 15 + amount_per_transfer_from_this = 5 + possible_transfer_amounts = list(1,5,15) + flags = FPRINT | TABLEPASS | OPENCONTAINER */ + +/* +/obj/item/weapon/reagent_containers/glass/blender_jug + name = "Blender Jug" + desc = "A blender jug, part of a blender." + icon = 'icons/obj/kitchen.dmi' + icon_state = "blender_jug_e" + volume = 100 + + on_reagent_change() + switch(src.reagents.total_volume) + if(0) + icon_state = "blender_jug_e" + if(1 to 75) + icon_state = "blender_jug_h" + if(76 to 100) + icon_state = "blender_jug_f" + +/obj/item/weapon/reagent_containers/glass/canister //not used apparantly + desc = "It's a canister. Mainly used for transporting fuel." + name = "canister" + icon = 'icons/obj/tank.dmi' + icon_state = "canister" + item_state = "canister" + m_amt = 300 + g_amt = 0 + w_class = 4.0 + + amount_per_transfer_from_this = 20 + possible_transfer_amounts = list(10,20,30,60) + volume = 120 + flags = FPRINT + +/obj/item/weapon/reagent_containers/glass/dispenser + name = "reagent glass" + desc = "A reagent glass." + icon = 'icons/obj/chemical.dmi' + icon_state = "beaker0" + amount_per_transfer_from_this = 10 + flags = FPRINT | TABLEPASS | OPENCONTAINER + +/obj/item/weapon/reagent_containers/glass/dispenser/surfactant + name = "reagent glass (surfactant)" + icon_state = "liquid" + + New() + ..() + reagents.add_reagent("fluorosurfactant", 20) + +*/ diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 076e769d8b3..74ea366c253 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -131,6 +131,14 @@ ..() reagents.add_reagent("kelotane", 15) +/obj/item/weapon/reagent_containers/pill/paracetamol + name = "Paracetamol pill" + desc = "Tylenol! A painkiller for the ages. Chewables!" + icon_state = "pill8" + New() + ..() + reagents.add_reagent("paracetamol", 15) + /obj/item/weapon/reagent_containers/pill/tramadol name = "Tramadol pill" desc = "A simple painkiller." diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 9ba14f5d74d..52f37b9dd2c 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -211,6 +211,10 @@ // attack with hand, switch position /obj/machinery/conveyor_switch/attack_hand(mob/user) + if(!allowed(user)) + user << "Access denied." + return + if(position == 0) if(last_pos < 0) position = 1 diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index f3b3709d86a..02289aacf8f 100755 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -157,7 +157,7 @@ /obj/item/device/destTagger name = "destination tagger" desc = "Used to set the destination of properly wrapped packages." - icon_state = "forensic0-old" + icon_state = "dest_tagger" var/currTag = 0 //The whole system for the sorttype var is determined based on the order of this list, //disposals must always be 1, since anything that's untagged will automatically go to disposals, or sorttype = 1 --Superxpdude diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm index 8f3a765a48e..6fa91b4aaf3 100644 --- a/code/modules/research/circuitprinter.dm +++ b/code/modules/research/circuitprinter.dm @@ -101,7 +101,7 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis). user << "\The [name] must be linked to an R&D console first!" return 1 if (O.is_open_container()) - return 1 + return 0 if (!istype(O, /obj/item/stack/sheet/glass) && !istype(O, /obj/item/stack/sheet/mineral/gold) && !istype(O, /obj/item/stack/sheet/mineral/diamond) && !istype(O, /obj/item/stack/sheet/mineral/uranium)) user << "\red You cannot insert this item into the [name]!" return 1 diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index ac144533166..e861826e0f2 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -1340,6 +1340,28 @@ datum/design/nanopaste build_type = PROTOLATHE materials = list("$metal" = 7000, "$glass" = 7000) build_path = "/obj/item/stack/nanopaste" + +datum/design/bluespacebeaker + name = "bluespace beaker" + desc = "A bluespace beaker, powered by experimental bluespace technology and Element Cuban combined with the Compound Pete. Can hold up to 300 units." + id = "bluespacebeaker" + req_tech = list("bluespace" = 2, "materials" = 6) + build_type = PROTOLATHE + materials = list("$metal" = 3000, "$plasma" = 3000, "$diamond" = 500) + reliability_base = 76 + build_path = "/obj/item/weapon/reagent_containers/glass/beaker/bluespace" + category = "Misc" + +datum/design/noreactbeaker + name = "cryostasis beaker" + desc = "A cryostasis beaker that allows for chemical storage without reactions. Can hold up to 50 units." + id = "splitbeaker" + req_tech = list("materials" = 2) + build_type = PROTOLATHE + materials = list("$metal" = 3000) + reliability_base = 76 + build_path = "/obj/item/weapon/reagent_containers/glass/beaker/noreact" + category = "Misc" ///////////////////////////////////////// /////////////////Weapons///////////////// ///////////////////////////////////////// diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm index 72430976b84..15aafd77e98 100644 --- a/code/modules/research/destructive_analyzer.dm +++ b/code/modules/research/destructive_analyzer.dm @@ -99,6 +99,7 @@ Note: Must be placed within 3 tiles of the R&D Console spawn(10) icon_state = "d_analyzer_l" busy = 0 + return 1 return //For testing purposes only. diff --git a/code/modules/research/xenoarchaeology/artifact/artifact.dm b/code/modules/research/xenoarchaeology/artifact/artifact.dm index 1ff8a220f32..6300a6d71a4 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact.dm @@ -35,6 +35,7 @@ icon_state = "boulder1" density = 1 opacity = 1 + anchored = 1 var/excavation_level = 0 var/datum/geosample/geological_data var/datum/artifact_find/artifact_find @@ -75,17 +76,14 @@ user << "\blue You finish [P.drill_verb] [src]." excavation_level += P.excavation_amount - var/reveal_prob = 1 - if(excavation_level >= 95) - reveal_prob = 50 + (excavation_level - 90) * (excavation_level - 90) - else if(excavation_level >= 90) - reveal_prob = 5 - if(excavation_level >= 100) + if(excavation_level > 100) //failure user.visible_message("[src] suddenly crumbles away.",\ - "\red [src] has disintegrated under your onslaught, any secrets it was holding long gone.") + "\red [src] has disintegrated under your onslaught, any secrets it was holding are long gone.") del(src) - else if(prob(reveal_prob)) + return + + if(prob(excavation_level)) //success if(artifact_find) var/spawn_type = artifact_find.artifact_find_type diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_unknown_old.dm b/code/modules/research/xenoarchaeology/artifact/artifact_unknown_old.dm deleted file mode 100644 index 3c779caa967..00000000000 --- a/code/modules/research/xenoarchaeology/artifact/artifact_unknown_old.dm +++ /dev/null @@ -1,242 +0,0 @@ -//Part of ISaidNo's public release around July 2011(ish), multiple changes -//many thanks - -#define PLASMA_SPAWN 1 -#define N2_SPAWN 2 -#define CO2_SPAWN 3 -#define RADIATE 4 -#define VIRUS 5 -#define HEAT 6 -#define COLD 7 - -/obj/machinery/artifact - name = "alien artifact" - desc = "A large alien device." - icon = 'icons/obj/xenoarchaeology.dmi' - icon_state = "ano00" - var/icon_num = 0 - anchored = 0 - density = 1 - var/origin = null // Used in the randomisation/research of the artifact. - var/activated = 0 // Whether or not the artifact has been unlocked. - var/charged = 1 // Whether the artifact is ready to have it's effect. - var/chargetime = 0 // How much time until the artifact is charged. - var/recharge = 5 // How long does it take this artifact to recharge? - var/display_id = "" // Artifact ID to display once successfully scanned - var/datum/artifact_effect/my_effect = null - var/being_used = 0 - -/obj/machinery/artifact/New() - ..() - // Origin and appearance randomisation - - my_effect = new() - - - icon_num = rand(0,5) - icon_state = "ano[icon_num]0" - - // Power randomisation - my_effect.trigger = pick("force","energy","chemical","heat","touch","presence") - if (my_effect.trigger == "chemical") - my_effect.triggerX = pick("hydrogen","corrosive","volatile","toxic") - - my_effect.effecttype = pick("healing","injure","stun","roboheal","robohurt","cellcharge","celldrain","planthelper","forcefield","teleport","dnaswitch","emp","sleepy") - - // Select range based on the power - var/canworldpulse = 1 - switch(my_effect.effecttype) - if("healing") - my_effect.effectmode = pick("aura","pulse","contact") - if("injure") - my_effect.effectmode = pick("aura","pulse","contact") - if("stun") - my_effect.effectmode = pick("aura","pulse","contact") - if("roboheal") - my_effect.effectmode = pick("aura","pulse","contact") - if("robohurt") - my_effect.effectmode = pick("aura","pulse","contact") - if("sleepy") - my_effect.effectmode = pick("aura","pulse","contact") - if("cellcharge") - my_effect.effectmode = pick("aura","pulse") - if("celldrain") - my_effect.effectmode = pick("aura","pulse") - if("planthelper") - my_effect.effectmode = pick("aura","pulse") - canworldpulse = 0 - if("forcefield") - my_effect.effectmode = "contact" - canworldpulse = 0 - if("teleport") - my_effect.effectmode = pick("pulse","contact") - if("genderswitch") - my_effect.effectmode = pick("pulse","contact") - if("emp") - my_effect.effectmode = pick("pulse","contact") - - // Recharge timer & range setup - if (my_effect.effectmode == "aura") - my_effect.aurarange = rand(1,4) - if (my_effect.effectmode == "contact") - src.recharge = rand(5,15) - if (my_effect.effectmode == "pulse") - my_effect.aurarange = rand(2,14) - src.recharge = rand(5,20) - if (canworldpulse == 1 && prob(1)) - my_effect.effectmode = "worldpulse" - src.recharge = rand(40,120) - - /* - display_id += pick("kappa","sigma","antaeres","beta","lorard","omicron","iota","upsilon","omega","gamma","delta") - display_id += "-" - display_id += num2text(rand(100,999)) - */ - -/obj/machinery/artifact/Del() - ..() - my_effect.HaltEffect() - -/obj/machinery/artifact/attack_hand(var/mob/user as mob) - if (istype(user, /mob/living/silicon/ai) || istype(user, /mob/dead/)) return - if (istype(user, /mob/living/silicon/robot)) - if (get_dist(user, src) > 1) - user << "\red You can't reach [src] from here." - return - if(ishuman(user) && istype(user:gloves,/obj/item/clothing/gloves)) - return ..() - for(var/mob/O in viewers(src, null)) - O.show_message(text("[] touches [].", user, src), 1) - src.add_fingerprint(user) - src.Artifact_Contact(user) - -/obj/machinery/artifact/attackby(obj/item/weapon/W as obj, mob/living/user as mob) - /*if (istype(W, /obj/item/weapon/cargotele)) - W:cargoteleport(src, user) - return*/ - if (my_effect.trigger == "chemical" && istype(W, /obj/item/weapon/reagent_containers/)) - switch(my_effect.triggerX) - if("hydrogen") - if (W.reagents.has_reagent("hydrogen", 1) || W.reagents.has_reagent("water", 1)) - src.Artifact_Activate() - return - if("corrosive") - if (W.reagents.has_reagent("acid", 1) || W.reagents.has_reagent("pacid", 1) || W.reagents.has_reagent("diethylamine", 1)) - src.Artifact_Activate() - return - if("volatile") - if (W.reagents.has_reagent("plasma", 1) || W.reagents.has_reagent("thermite", 1)) - src.Artifact_Activate() - return - if("toxic") - if (W.reagents.has_reagent("toxin", 1) || W.reagents.has_reagent("cyanide", 1) || W.reagents.has_reagent("amanitin", 1) || W.reagents.has_reagent("neurotoxin", 1)) - src.Artifact_Activate() - return - ..() - if (my_effect.trigger == "force" && W.force >= 10 && !src.activated) src.Artifact_Activate() - if (my_effect.trigger == "energy") - if (istype(W,/obj/item/weapon/melee/baton) && W:status) src.Artifact_Activate() - if (istype(W,/obj/item/weapon/melee/energy)) src.Artifact_Activate() - if (istype(W,/obj/item/weapon/melee/cultblade)) src.Artifact_Activate() - if (istype(W,/obj/item/weapon/gun/energy/)) src.Artifact_Activate() - if (istype(W,/obj/item/device/multitool)) src.Artifact_Activate() - if (istype(W,/obj/item/weapon/card/emag)) src.Artifact_Activate() - if (my_effect.trigger == "heat") - if (istype(W,/obj/item/weapon/match) && W:lit) src.Artifact_Activate() - if (istype(W, /obj/item/weapon/weldingtool) && W:welding) src.Artifact_Activate() - if (istype(W, /obj/item/weapon/lighter) && W:lit) src.Artifact_Activate() - - //Bump(atom/A) - -/obj/machinery/artifact/Bumped(M as mob|obj) - if (istype(M,/obj/item/weapon/) && my_effect.trigger == "force" && M:throwforce >= 10) src.Artifact_Activate() - -/obj/machinery/artifact/bullet_act(var/obj/item/projectile/P) - if (my_effect.trigger == "force") - if(istype(P,/obj/item/projectile/bullet)) src.Artifact_Activate() - else if(istype(P,/obj/item/projectile/hivebotbullet)) src.Artifact_Activate() - if (my_effect.trigger == "energy") - if(istype(P,/obj/item/projectile/beam)) src.Artifact_Activate() - else if(istype(P,/obj/item/projectile/ion)) src.Artifact_Activate() - else if(istype(P,/obj/item/projectile/energy)) src.Artifact_Activate() - if (my_effect.trigger == "heat") - if(istype(P,/obj/item/projectile/temp)) src.Artifact_Activate() - -/obj/machinery/artifact/ex_act(severity) - switch(severity) - if(1.0) del src - if(2.0) - if (prob(50)) del src - if (my_effect.trigger == "force") src.Artifact_Activate() - if (my_effect.trigger == "heat") src.Artifact_Activate() - if(3.0) - if (my_effect.trigger == "force") src.Artifact_Activate() - if (my_effect.trigger == "heat") src.Artifact_Activate() - return - -/obj/machinery/artifact/temperature_expose(null, temp, volume) - if (my_effect.trigger == "heat") src.Artifact_Activate() - -/obj/machinery/artifact/process() - if (!src.activated) - return - if (chargetime > 0) - chargetime -= 1 - else - src.charged = 1 - - my_effect.UpdateEffect(src.loc) - - //activate - if( (my_effect.effectmode == "pulse" || my_effect.effecttype == "worldpulse") && activated) - if(src.charged && my_effect.DoEffect(src)) - src.charged = 0 - src.chargetime = src.recharge - -/obj/machinery/artifact/proc/Artifact_Activate() - src.activated = !src.activated - var/display_msg = "" - if(activated) - if(prob(30)) - switch(rand(4)) - if(0) - display_msg = "momentarily glows brightly!" - if(1) - display_msg = "distorts slightly for a moment!" - if(2) - display_msg = "makes a slightly clicking noise!" - if(3) - display_msg = "flickers slightly!" - if(4) - display_msg = "vibrates!" - else - my_effect.HaltEffect() - if(prob(30)) - switch(rand(2)) - if(0) - display_msg = "grows dull!" - if(1) - display_msg = "fades in intensity!" - if(2) - display_msg = "suddenly becomes very quiet!" - - icon_state = "ano[icon_num][activated]" - for(var/mob/O in viewers(src, null)) - O.show_message(text("[] [display_msg]", src), 1) - -/obj/machinery/artifact/proc/Artifact_Contact(var/mob/user as mob) - // Trigger Code - if (istype (user,/mob/living/carbon/) && my_effect.trigger == "touch" && !src.activated) src.Artifact_Activate() - else if (my_effect.trigger != "touch" && !src.activated) user << "Nothing happens." - - if (my_effect.effectmode == "contact" && src.activated && src.charged) - my_effect.DoEffect(user) - src.charged = 0 - src.chargetime = src.recharge - -// this was used in QM for a time but it fell into disuse and wasn't removed, the purpose being to check if an artifact -// was benevolent or malicious, to determine whether QMs would be paid or punished for shipping it - -/obj/machinery/artifact/Move() - ..() - my_effect.update_move(src, src.loc) diff --git a/code/modules/research/xenoarchaeology/artifact/effect_old.dm b/code/modules/research/xenoarchaeology/artifact/effect_old.dm deleted file mode 100644 index 092cb0d0f58..00000000000 --- a/code/modules/research/xenoarchaeology/artifact/effect_old.dm +++ /dev/null @@ -1,542 +0,0 @@ -// - -/datum/artifact_effect - var/artifact_id = "" // Display ID of the spawning artifact - var/trigger = "touch" // What activates it? - var/triggerX = "none" // Used for more varied triggers - var/effecttype = "healing" // What does it do? - var/effectmode = "aura" // How does it carry out the effect? - var/aurarange = 4 // How far the artifact will extend an aura effect. - var/list/created_field - var/archived_loc - -/datum/artifact_effect/New() - // - created_field = new() - -/datum/artifact_effect/proc/GetOriginString(var/origin) - -/datum/artifact_effect/proc/GetEffectString(var/effect) - -/datum/artifact_effect/proc/GetTriggerString(var/trigger) - -/datum/artifact_effect/proc/GetRangeString(var/range) - switch(effectmode) - if("aura") return "Constant Short-Range Energy Field" - if("pulse") - if(aurarange > 7) return "Long Range Energy Pulses" - else return "Medium Range Energy Pulses" - if("worldpulse") return "Extreme Range Energy Pulses" - if("contact") return "Requires contact with subject" - else return "Unknown Range" - -/datum/artifact_effect/proc/HaltEffect() - for(var/obj/effect/energy_field/F in created_field) - created_field.Remove(F) - del F - -/datum/artifact_effect/proc/UpdateEffect(var/atom/originator) - /*for(var/obj/effect/energy_field/F in created_field) - created_field.Remove(F) - del F*/ - if(originator.loc != archived_loc) - archived_loc = originator.loc - update_move(originator) - - for(var/obj/effect/energy_field/E in created_field) - if(E.strength < 5) - E.Strengthen(0.2) - -/datum/artifact_effect/proc/DoEffect(var/atom/originator) - archived_loc = originator.loc - if (src.effectmode == "contact") - var/mob/living/user = originator - if(!user) - return - switch(src.effecttype) - if("healing") - //caeltodo - if (istype(user, /mob/living/carbon/human/)) - user << "\blue You feel a soothing energy invigorate you." - - var/mob/living/carbon/human/H = user - for(var/datum/organ/external/affecting in H.organs) - if(!affecting) continue - if(!istype(affecting, /datum/organ/external)) continue - affecting.heal_damage(25, 25) //fixes getting hit after ingestion, killing you when game updates organ health - //user:heal_organ_damage(25, 25) - // - user.adjustOxyLoss(-25) - user.adjustToxLoss(-25) - user.adjustBruteLoss(-25) - user.adjustFireLoss(-25) - user.adjustBrainLoss(-25) - user.radiation -= min(user.radiation, 25) - user.nutrition += 50 - H.bodytemperature = initial(H.bodytemperature) - // - H.vessel.add_reagent("blood",50) - spawn(1) - H.fixblood() - H.regenerate_icons() - return 1 - // - if (istype(user, /mob/living/carbon/monkey/)) - user << "\blue You feel a soothing energy invigorate you." - user.adjustOxyLoss(-25) - user.adjustToxLoss(-25) - user.adjustBruteLoss(-25) - user.adjustFireLoss(-25) - user.adjustBrainLoss(-25) - return 1 - else user << "Nothing happens." - if("injure") - if (istype(user, /mob/living/carbon/)) - user << "\red A painful discharge of energy strikes you!" - user.adjustOxyLoss(rand(5,25)) - user.adjustToxLoss(rand(5,25)) - user.adjustBruteLoss(rand(5,25)) - user.adjustFireLoss(rand(5,25)) - user.adjustBrainLoss(rand(5,25)) - user.radiation += 25 - user.nutrition -= min(50, user.nutrition) - user.make_dizzy(6) - user.weakened += 6 - return 1 - else user << "Nothing happens." - if("stun") - if (istype(user, /mob/living/carbon/)) - user << "\red A powerful force overwhelms your consciousness." - user.weakened += 45 - user.stuttering += 45 - if(prob(50)) - user.stunned += rand(1,10) - return 1 - else user << "Nothing happens." - if("roboheal") - if (istype(user, /mob/living/silicon/robot)) - user << "\blue Your systems report damaged components mending by themselves!" - user.adjustBruteLoss(rand(-10,-30)) - user.adjustFireLoss(rand(-10,-30)) - return 1 - else user << "Nothing happens." - if("robohurt") - if (istype(user, /mob/living/silicon/robot)) - user << "\red Your systems report severe damage has been inflicted!" - user.adjustBruteLoss(rand(10,50)) - user.adjustFireLoss(rand(10,50)) - return 1 - else user << "Nothing happens." - if("forcefield") - while(created_field.len < 16) - var/obj/effect/energy_field/E = new (locate(user.x,user.y,user.z)) - created_field.Add(E) - E.strength = 1 - E.density = 1 - E.anchored = 1 - E.invisibility = 0 - return 1 - if("teleport") - var/list/randomturfs = new/list() - for(var/turf/T in orange(user, 50)) - if(!istype(T, /turf/simulated/floor) || T.density) - continue - randomturfs.Add(T) - if(randomturfs.len > 0) - user << "\red You are suddenly zapped away elsewhere!" - if (user.buckled) - user.buckled.unbuckle() - user.loc = pick(randomturfs) - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is - sparks.start() - return 1 - if("sleepy") - user << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.") - user.drowsyness = min(user.drowsyness + rand(5,25), 50) - user.eye_blurry = min(user.eye_blurry + rand(1,3), 50) - return 1 - else if (src.effectmode == "aura") - switch(src.effecttype) - //caeltodo - if("healing") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - if(prob(10)) M << "\blue You feel a soothing energy radiating from something nearby." - M.adjustBruteLoss(-1) - M.adjustFireLoss(-1) - M.adjustToxLoss(-1) - M.adjustOxyLoss(-1) - M.adjustBrainLoss(-1) - M.updatehealth() - return 1 - if("injure") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - if(prob(10)) M << "\red You feel a painful force radiating from something nearby." - M.adjustBruteLoss(1) - M.adjustFireLoss(1) - M.adjustToxLoss(1) - M.adjustOxyLoss(1) - M.adjustBrainLoss(1) - M.updatehealth() - return 1 - if("stun") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - if(prob(10)) M << "\red Energy radiating from the [originator] is making you feel numb." - if(prob(20)) - M << "\red Your body goes numb for a moment." - M.stunned += 2 - M.weakened += 2 - M.stuttering += 2 - return 1 - if("roboheal") - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - if(prob(10)) M << "\blue SYSTEM ALERT: Beneficial energy field detected!" - M.adjustBruteLoss(-1) - M.adjustFireLoss(-1) - M.updatehealth() - return 1 - if("robohurt") - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - if(prob(10)) M << "\red SYSTEM ALERT: Harmful energy field detected!" - M.adjustBruteLoss(1) - M.adjustFireLoss(1) - M.updatehealth() - return 1 - if("cellcharge") - for (var/obj/machinery/power/apc/C in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/B in C.contents) - B.charge += 10 - for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) S.charge += 20 - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/D in M.contents) - D.charge += 10 - if(prob(10)) M << "\blue SYSTEM ALERT: Energy boosting field detected!" - return 1 - if("celldrain") - for (var/obj/machinery/power/apc/C in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/B in C.contents) - B.charge = max(B.charge-10,0) - for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) - S.charge = max(S.charge-20,0) - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/D in M.contents) - D.charge = max(D.charge-10,0) - if(prob(10)) M << "\red SYSTEM ALERT: Energy draining field detected!" - return 1 - if("planthelper") - for (var/obj/machinery/hydroponics/H in range(src.aurarange,originator)) - //makes weeds and shrooms and stuff more potent too - if(H.planted) - H.waterlevel += 2 - H.nutrilevel += 2 - if(H.toxic > 0) - H.toxic -= 1 - H.health += 1 - if(H.pestlevel > 0) - H.pestlevel -= 1 - if(H.weedlevel > 0) - H.weedlevel -= 1 - H.lastcycle += 5 - return 1 - if("sleepy") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(prob(10)) - M << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.") - M.drowsyness = min(M.drowsyness + 1, 25) - M.eye_blurry = min(M.eye_blurry + 1, 25) - return 1 - else if (src.effectmode == "pulse") - for(var/mob/O in viewers(originator, null)) - O.show_message(text("[] emits a pulse of energy!", originator), 1) - switch(src.effecttype) - //caeltodo - if("healing") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - M << "\blue A wave of energy invigorates you." - M.adjustBruteLoss(-5) - M.adjustFireLoss(-5) - M.adjustToxLoss(-5) - M.adjustOxyLoss(-5) - M.adjustBrainLoss(-5) - M.updatehealth() - return 1 - if("injure") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - M << "\red A wave of energy causes you great pain!" - M.adjustBruteLoss(5) - M.adjustFireLoss(5) - M.adjustToxLoss(5) - M.adjustOxyLoss(5) - M.adjustBrainLoss(5) - M.make_dizzy(6) - M.weakened += 3 - M.updatehealth() - return 1 - if("stun") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - M << "\red A wave of energy overwhelms your senses!" - M.paralysis += 3 - M.weakened += 4 - M.stuttering += 4 - return 1 - if("roboheal") - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!" - M.adjustBruteLoss(-10) - M.adjustFireLoss(-10) - M.updatehealth() - return 1 - if("robohurt") - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!" - M.adjustBruteLoss(10) - M.adjustFireLoss(10) - M.updatehealth() - return 1 - if("cellcharge") - for (var/obj/machinery/power/apc/C in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/B in C.contents) - B.charge += 250 - for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) S.charge += 400 - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/D in M.contents) - D.charge += 250 - M << "\blue SYSTEM ALERT: Large energy boost detected!" - return 1 - if("celldrain") - for (var/obj/machinery/power/apc/C in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/B in C.contents) - B.charge = max(B.charge-500,0) - for (var/obj/machinery/power/smes/S in range (src.aurarange,originator)) - S.charge = max(S.charge-400,0) - for (var/mob/living/silicon/robot/M in range(src.aurarange,originator)) - for (var/obj/item/weapon/cell/D in M.contents) - D.charge = max(D.charge-500,0) - M << "\red SYSTEM ALERT: Severe energy drain detected!" - return 1 - if("planthelper") - //makes weeds and shrooms and stuff more potent too - for (var/obj/machinery/hydroponics/H in range(src.aurarange,originator)) - if(H.planted) - H.dead = 0 - H.waterlevel = 200 - H.nutrilevel = 200 - H.toxic = 0 - H.health = 100 - H.pestlevel = 0 - H.weedlevel = 0 - H.lastcycle = H.cycledelay - return 1 - if("teleport") - for (var/mob/living/M in range(src.aurarange,originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - var/list/randomturfs = new/list() - for(var/turf/T in orange(M, 30)) - if(!istype(T, /turf/simulated/floor) || T.density) - continue - randomturfs.Add(T) - if(randomturfs.len > 0) - M << "\red You are displaced by a strange force!" - if(M.buckled) - M.buckled.unbuckle() - M.loc = pick(randomturfs) - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is - sparks.start() - return 1 - if("dnaswitch") - for(var/mob/living/H in range(src.aurarange,originator)) - if(ishuman(H) && istype(H:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(H:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - - if(prob(30)) - H << pick("\green You feel a little different.","\green You feel strange.","\green You feel different.") - //todo - if (H.gender == FEMALE) - H.gender = MALE - else - H.gender = FEMALE - /*H.dna.ready_dna(H) - H.update_body() - H.update_face()*/ - return 1 - if("emp") - empulse(get_turf(originator), aurarange/2, aurarange) - return 1 - if("sleepy") - for (var/mob/living/carbon/M in range(src.aurarange,originator)) - if(prob(30)) - M << pick("\blue You feel like taking a nap.","\blue You feel a yawn coming on.","\blue You feel a little tired.") - if(prob(50)) - M.drowsyness = min(M.drowsyness + rand(1,5), 25) - if(prob(50)) - M.eye_blurry = min(M.eye_blurry + rand(1,5), 25) - return 1 - else if (src.effectmode == "worldpulse") - for(var/mob/O in viewers(originator, null)) - O.show_message(text("[] emits a powerful burst of energy!", originator), 1) - switch(src.effecttype) - if("healing") - for (var/mob/living/carbon/M in range(200, originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - M << "\blue Waves of soothing energy wash over you." - M.adjustBruteLoss(-3) - M.adjustFireLoss(-3) - M.adjustToxLoss(-3) - M.adjustOxyLoss(-3) - M.adjustBrainLoss(-3) - M.updatehealth() - return 1 - if("injure") - for (var/mob/living/carbon/human/M in range(200, originator)) - M << "\red A wave of painful energy strikes you!" - M.adjustBruteLoss(3) - M.adjustFireLoss(3) - M.adjustToxLoss(3) - M.adjustOxyLoss(3) - M.adjustBrainLoss(3) - M.updatehealth() - return 1 - if("stun") - for (var/mob/living/carbon/M in range(200, originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - M << "\red A powerful force causes you to black out momentarily." - M.paralysis += 5 - M.weakened += 8 - M.stuttering += 8 - return 1 - if("roboheal") - for (var/mob/living/silicon/robot/M in range(200, originator)) - M << "\blue SYSTEM ALERT: Structural damage has been repaired by energy pulse!" - M.adjustBruteLoss(-5) - M.adjustFireLoss(-5) - M.updatehealth() - return 1 - if("robohurt") - for (var/mob/living/silicon/robot/M in range(200, originator)) - M << "\red SYSTEM ALERT: Structural damage inflicted by energy pulse!" - M.adjustBruteLoss(5) - M.adjustFireLoss(5) - M.updatehealth() - return 1 - if("cellcharge") - for (var/obj/machinery/power/apc/C in range(200, originator)) - for (var/obj/item/weapon/cell/B in C.contents) - B.charge += 100 - for (var/obj/machinery/power/smes/S in range (src.aurarange,src)) S.charge += 250 - for (var/mob/living/silicon/robot/M in world) - for (var/obj/item/weapon/cell/D in M.contents) - D.charge += 100 - M << "\blue SYSTEM ALERT: Energy boost detected!" - return 1 - if("celldrain") - for (var/obj/machinery/power/apc/C in range(200, originator)) - for (var/obj/item/weapon/cell/B in C.contents) - B.charge = max(B.charge-250,0) - for (var/obj/machinery/power/smes/S in range (src.aurarange,src)) - S.charge = max(S.charge-250,0) - for (var/mob/living/silicon/robot/M in world) - for (var/obj/item/weapon/cell/D in M.contents) - D.charge = max(D.charge-250,0) - M << "\red SYSTEM ALERT: Energy drain detected!" - return 1 - if("teleport") - for (var/mob/living/M in range(200, originator)) - if(ishuman(M) && istype(M:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(M:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - var/list/randomturfs = new/list() - for(var/turf/T in orange(M, 15)) - if(!istype(T, /turf/simulated/floor) || T.density) - continue - randomturfs.Add(T) - if(randomturfs.len > 0) - M << "\red You are displaced by a strange force!" - if(M.buckled) - M.buckled.unbuckle() - M.loc = pick(randomturfs) - var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() - sparks.set_up(3, 0, get_turf(originator)) //no idea what the 0 is - sparks.start() - return 1 - if("dnaswitch") - for(var/mob/living/H in range(200, originator)) - if(ishuman(H) && istype(H:wear_suit,/obj/item/clothing/suit/bio_suit/anomaly) && istype(H:head,/obj/item/clothing/head/bio_hood/anomaly)) - continue - - if(prob(30)) - H << pick("\green You feel a little different.","\green You feel strange.","\green You feel different.") - //todo - if (H.gender == FEMALE) - H.gender = MALE - else - H.gender = FEMALE - /*H.dna.ready_dna(H) - H.update_body() - H.update_face()*/ - return 1 - if("sleepy") - for(var/mob/living/H in range(200, originator)) - H.drowsyness = min(H.drowsyness + rand(5,15), 50) - H.eye_blurry = min(H.eye_blurry + rand(5,15), 50) - return 1 - -//initially for the force field artifact -/datum/artifact_effect/proc/update_move(var/atom/originator) - switch(effecttype) - if("forcefield") - while(created_field.len < 16) - //for now, just instantly respawn the fields when they get destroyed - var/obj/effect/energy_field/E = new (locate(originator.x,originator.y,originator)) - created_field.Add(E) - E.strength = 1 - E.density = 1 - E.anchored = 1 - E.invisibility = 0 - - var/obj/effect/energy_field/E = created_field[1] - E.loc = locate(originator.x + 2,originator.y + 2,originator.z) - E = created_field[2] - E.loc = locate(originator.x + 2,originator.y + 1,originator.z) - E = created_field[3] - E.loc = locate(originator.x + 2,originator.y,originator.z) - E = created_field[4] - E.loc = locate(originator.x + 2,originator.y - 1,originator.z) - E = created_field[5] - E.loc = locate(originator.x + 2,originator.y - 2,originator.z) - E = created_field[6] - E.loc = locate(originator.x + 1,originator.y + 2,originator.z) - E = created_field[7] - E.loc = locate(originator.x + 1,originator.y - 2,originator.z) - E = created_field[8] - E.loc = locate(originator.x,originator.y + 2,originator.z) - E = created_field[9] - E.loc = locate(originator.x,originator.y - 2,originator.z) - E = created_field[10] - E.loc = locate(originator.x - 1,originator.y + 2,originator.z) - E = created_field[11] - E.loc = locate(originator.x - 1,originator.y - 2,originator.z) - E = created_field[12] - E.loc = locate(originator.x - 2,originator.y + 2,originator.z) - E = created_field[13] - E.loc = locate(originator.x - 2,originator.y + 1,originator.z) - E = created_field[14] - E.loc = locate(originator.x - 2,originator.y,originator.z) - E = created_field[15] - E.loc = locate(originator.x - 2,originator.y - 1,originator.z) - E = created_field[16] - E.loc = locate(originator.x - 2,originator.y - 2,originator.z) diff --git a/code/modules/research/xenoarchaeology/finds/finds.dm b/code/modules/research/xenoarchaeology/finds/finds.dm index 7464e7c8b06..0b776ca91f6 100644 --- a/code/modules/research/xenoarchaeology/finds/finds.dm +++ b/code/modules/research/xenoarchaeology/finds/finds.dm @@ -324,26 +324,27 @@ if(26) //energy gun var/spawn_type = pick(\ - /obj/item/weapon/gun/energy/laser/practice;100,\ - /obj/item/weapon/gun/energy/laser;75,\ - /obj/item/weapon/gun/energy/xray;50,\ - /obj/item/weapon/gun/energy/laser/captain;25,\ - ) - var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc) - new_item = new_gun - new_item.icon_state = "egun[rand(1,6)]" + /obj/item/weapon/gun/energy/laser/practice,\ + /obj/item/weapon/gun/energy/laser,\ + /obj/item/weapon/gun/energy/xray,\ + /obj/item/weapon/gun/energy/laser/captain) + if(spawn_type) + var/obj/item/weapon/gun/energy/new_gun = new spawn_type(src.loc) + new_item = new_gun + new_item.icon_state = "egun[rand(1,6)]" + new_gun.desc = "This is an antique energy weapon, you're not sure if it will fire or not." - //5% chance to explode when first fired - //10% chance to have an unchargeable cell - //15% chance to gain a random amount of starting energy, otherwise start with an empty cell - if(prob(5)) - new_gun.power_supply.rigged = 1 - if(prob(10)) - new_gun.power_supply.maxcharge = 0 - if(prob(15)) - new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge) - else - new_gun.power_supply.charge = 0 + //5% chance to explode when first fired + //10% chance to have an unchargeable cell + //15% chance to gain a random amount of starting energy, otherwise start with an empty cell + if(prob(5)) + new_gun.power_supply.rigged = 1 + if(prob(10)) + new_gun.power_supply.maxcharge = 0 + if(prob(15)) + new_gun.power_supply.charge = rand(0, new_gun.power_supply.maxcharge) + else + new_gun.power_supply.charge = 0 item_type = "gun" if(27) diff --git a/code/modules/research/xenoarchaeology/finds/finds_defines.dm b/code/modules/research/xenoarchaeology/finds/finds_defines.dm index b9649d074b3..6de9b4c8061 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_defines.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_defines.dm @@ -206,6 +206,28 @@ ) return find_type +var/list/responsive_carriers = list( \ + "carbon", \ + "potassium", \ + "hydrogen", \ + "nitrogen", \ + "mercury", \ + "iron", \ + "chlorine", \ + "phosphorus", \ + "plasma") + +var/list/finds_as_strings = list( \ + "Trace organic cells", \ + "Long exposure particles", \ + "Trace water particles", \ + "Crystalline structures", \ + "Metallic derivative", \ + "Metallic composite", \ + "Metamorphic/igneous rock composite", \ + "Metamorphic/sedimentary rock composite", \ + "Anomalous material" ) + #undef ARCHAEO_BOWL #undef ARCHAEO_URN #undef ARCHAEO_CUTLERY diff --git a/code/modules/research/xenoarchaeology/finds/finds_misc.dm b/code/modules/research/xenoarchaeology/finds/finds_misc.dm index 64184ec0b6f..0c626b85810 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_misc.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_misc.dm @@ -1,8 +1,10 @@ /obj/item/weapon/shard/plasma name = "plasma shard" + desc = "A shard of plasma glass. Considerably tougher then normal glass shards. Apparently not tough enough to be a window." + force = 8.0 + throwforce = 15.0 icon_state = "plasmalarge" - /obj/item/weapon/shard/plasma/New() src.icon_state = pick("plasmalarge", "plasmamedium", "plasmasmall") @@ -24,14 +26,14 @@ if ( istype(W, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/WT = W if(WT.remove_fuel(0, user)) - var/obj/item/stack/sheet/mineral/plasma/NG = new (user.loc) - for (var/obj/item/stack/sheet/mineral/plasma/G in user.loc) + var/obj/item/stack/sheet/glass/plasmaglass/NG = new (user.loc) + for (var/obj/item/stack/sheet/glass/plasmaglass/G in user.loc) if(G==NG) continue if(G.amount>=G.max_amount) continue G.attackby(NG, user) - usr << "You add the newly-formed plasma to the stack. It now contains [NG.amount] sheets." + usr << "You add the newly-formed plasma glass to the stack. It now contains [NG.amount] sheets." //SN src = null del(src) return diff --git a/code/modules/research/xenoarchaeology/geosample.dm b/code/modules/research/xenoarchaeology/geosample.dm index 91d5f1bd62c..47a5bd3da1a 100644 --- a/code/modules/research/xenoarchaeology/geosample.dm +++ b/code/modules/research/xenoarchaeology/geosample.dm @@ -29,30 +29,6 @@ pixel_x = rand(0,16)-8 pixel_y = rand(0,8)-8 -var/list/responsive_carriers = list( \ - "carbon", \ - "potassium", \ - "hydrogen", \ - "nitrogen", \ - "mercury", \ - "iron", \ - "chlorine", \ - "phosphorus", \ - "plasma") - -var/list/finds_as_strings = list( \ - "Trace organic cells", \ - "Long exposure particles", \ - "Trace water particles", \ - "Crystalline structures", \ - "Metallic derivative", \ - "Metallic composite", \ - "Metamorphic/igneous rock composite", \ - "Metamorphic/sedimentary rock composite", \ - "Anomalous material" ) - -var/list/artifact_spawning_turfs = list() - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Geosample datum @@ -64,7 +40,6 @@ var/list/artifact_spawning_turfs = list() var/artifact_id = "" //id of a nearby artifact, if there is one var/artifact_distance = -1 //proportional to distance var/source_mineral = "chlorine" //machines will pop up a warning telling players that the sample may be confused - var/total_spread = 0 // //var/source_mineral //all potential finds are initialised to null, so nullcheck before you access them @@ -76,11 +51,11 @@ var/list/artifact_spawning_turfs = list() //this should only need to be called once /datum/geosample/proc/UpdateTurf(var/turf/simulated/mineral/container) + set background = 1 if(!container || !istype(container)) return age = rand(1,999) - total_spread = 0 switch(container.mineralName) if("Uranium") @@ -132,8 +107,15 @@ var/list/artifact_spawning_turfs = list() var/responsive_reagent = get_responsive_reagent(F.find_type) find_presence[responsive_reagent] = F.dissonance_spread - for(var/entry in find_presence) - total_spread += find_presence[entry] + //loop over again to reset values to percentages + var/total_presence = 0 + for(var/carrier in find_presence) + total_presence += find_presence[carrier] + for(var/carrier in find_presence) + find_presence[carrier] = find_presence[carrier] / total_presence + + /*for(var/entry in find_presence) + total_spread += find_presence[entry]*/ //have this separate from UpdateTurf() so that we dont have a billion turfs being updated (redundantly) every time an artifact spawns /datum/geosample/proc/UpdateNearbyArtifactInfo(var/turf/simulated/mineral/container) @@ -144,14 +126,14 @@ var/list/artifact_spawning_turfs = list() artifact_distance = rand() artifact_id = container.artifact_find.artifact_id else - for(var/turf/simulated/mineral/holder in artifact_spawning_turfs) - if(holder.artifact_find) - var/dist = get_dist(container, holder) - if(dist < holder.artifact_find.artifact_detect_range && dist < src.artifact_distance) - src.artifact_distance = dist - src.artifact_id = holder.artifact_find.artifact_id + for(var/turf/simulated/mineral/T in master_controller.artifact_spawning_turfs) + if(T.artifact_find) + var/cur_dist = get_dist(container, T) * 2 + if( (artifact_distance < 0 || cur_dist < artifact_distance) && cur_dist <= T.artifact_find.artifact_detect_range ) + artifact_distance = cur_dist + rand() * 2 - 1 + artifact_id = T.artifact_find.artifact_id else - artifact_spawning_turfs.Remove(holder) + master_controller.artifact_spawning_turfs.Remove(T) /* #undef FIND_PLANT diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_accelerator.dm b/code/modules/research/xenoarchaeology/machinery/analysis_accelerator.dm deleted file mode 100644 index 74ac904dc9b..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_accelerator.dm +++ /dev/null @@ -1,44 +0,0 @@ - -// This machine shows the age for extremely old finds - -obj/machinery/anomaly/accelerator - name = "Accelerator spectrometer" - -obj/machinery/anomaly/accelerator/ScanResults() - var/results = "The scan was inconclusive. Check sample integrity and carrier consistency." - - var/datum/geosample/scanned_sample - var/carrier_name - var/num_reagents = 0 - - for(var/datum/reagent/A in held_container.reagents.reagent_list) - var/datum/reagent/R = A - if(istype(R, /datum/reagent/analysis_sample)) - scanned_sample = R.data - else - carrier_name = R.id - num_reagents++ - - if(num_reagents == 2 && scanned_sample && carrier_name) - var/specifity = GetResultSpecifity(scanned_sample, carrier_name) - results = "Kinetic acceleration of carrier ([carrier_name]) indicates age ([100 * specifity]% accuracy):

    " - - if(scanned_sample.age_billion) - var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0) - var/displayed_age_billions = scanned_sample.age_billion + max(scanned_sample.age_billion * ((1 - specifity) * (2 * rand() - 1)), 0) - results += "[displayed_age_billions + displayed_age_millions / 1000] billion years.
    " - else if(scanned_sample.age_million) - var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - specifity) * (4 * rand() - 2)), 0) - var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - specifity) * (2 * rand() - 1)), 0) - results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.
    " - else if(scanned_sample.age_thousand) - var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0) - var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age * ((1 - specifity) * (4 * rand() - 2)), 0) - results += "[displayed_age_thousands + displayed_age / 1000] thousand years.
    " - else - var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - specifity) * (8 * rand() - 4)), 0) - results += "[displayed_age] years.
    " - - results += "
    Warning, results only valid for ages on the scale of billions of years." - - return results diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_base.dm b/code/modules/research/xenoarchaeology/machinery/analysis_base.dm deleted file mode 100644 index a462bd98fa0..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_base.dm +++ /dev/null @@ -1,203 +0,0 @@ -//Handles how much the temperature changes on power use. (Joules/Kelvin) -//Equates to as much heat energy per kelvin as a quarter tile of air. -#define XENOARCH_HEAT_CAPACITY 5000 - -//Handles heat transfer to the air. (In watts) -//Can heat a single tile 2 degrees per tick. -#define XENOARCH_MAX_ENERGY_TRANSFER 4000 - -//How many joules of electrical energy produce how many joules of heat energy? -#define XENOARCH_HEAT_COEFFICIENT 3 - - -/obj/machinery/anomaly - name = "Analysis machine" - desc = "A specialised, complex analysis machine." - anchored = 1 - density = 1 - icon = 'icons/obj/virology.dmi' - icon_state = "analyser" - - idle_power_usage = 20 //watts - active_power_usage = 300 //Because I need to make up numbers~ - - var/obj/item/weapon/reagent_containers/glass/held_container - var/obj/item/weapon/tank/fuel_container - var/target_scan_ticks = 30 - var/report_num = 0 - var/scan_process = 0 - var/temperature = 273 //measured in kelvin, if this exceeds 1200, the machine is damaged and requires repairs - //if this exceeds 600 and safety is enabled it will shutdown - //temp greater than 600 also requires a safety prompt to initiate scanning - var/max_temp = 450 - -/obj/machinery/anomaly/New() - ..() - - //for analysis debugging - /*var/obj/item/weapon/reagent_containers/glass/solution_tray/S = new(src.loc) - var/turf/simulated/mineral/diamond/D - for(var/turf/simulated/mineral/diamond/M in world) - D = M - break - S.reagents.add_reagent("analysis_sample", 1, D.geological_data) - S.reagents.add_reagent("chlorine", 1, null)*/ - -/obj/machinery/anomaly/process() - //not sure if everything needs to heat up, or just the GLPC - var/datum/gas_mixture/env = loc.return_air() - var/environmental_temp = env.temperature - if(scan_process) - if(scan_process++ > target_scan_ticks) - FinishScan() - else if(temperature > 400) - src.visible_message("\blue \icon[src] shuts down from the heat!", 2) - scan_process = 0 - else if(temperature > 350 && prob(10)) - src.visible_message("\blue \icon[src] bleets plaintively.", 2) - if(temperature > 400) - scan_process = 0 - - //show we're busy - if(prob(5)) - src.visible_message("\blue \icon[src] [pick("whirrs","chuffs","clicks")][pick(" quietly"," softly"," sadly"," excitedly"," energetically"," angrily"," plaintively")].", 2) - - use_power = 2 - - else - use_power = 1 - - auto_use_power() - - //Add 3000 joules when active. This is about 0.6 degrees per tick. - //May need adjustment - if(use_power == 1) - var/heat_added = active_power_usage *XENOARCH_HEAT_COEFFICIENT - - if(temperature < max_temp) - temperature += heat_added/XENOARCH_HEAT_CAPACITY - - var/temperature_difference = abs(environmental_temp-temperature) - var/datum/gas_mixture/removed = loc.remove_air(env.total_moles*0.25) - var/heat_capacity = removed.heat_capacity() - - heat_added = max(temperature_difference*heat_capacity, XENOARCH_MAX_ENERGY_TRANSFER) - - if(temperature > environmental_temp) - //cool down to match the air - temperature = max(TCMB, temperature - heat_added/XENOARCH_HEAT_CAPACITY) - removed.temperature = max(TCMB, removed.temperature + heat_added/heat_capacity) - - if(temperature_difference > 10 && prob(5)) - src.visible_message("\blue \icon[src] hisses softly.", 2) - - else - //heat up to match the air - temperature = max(TCMB, temperature + heat_added/XENOARCH_HEAT_CAPACITY) - removed.temperature = max(TCMB, removed.temperature - heat_added/heat_capacity) - - if(temperature_difference > 10 && prob(5)) - src.visible_message("\blue \icon[src] plinks quietly.", 2) - - env.merge(removed) - - -//this proc should be overriden by each individual machine -/obj/machinery/anomaly/attack_hand(var/mob/user as mob) - if(stat & (NOPOWER|BROKEN)) - return - user.machine = src - var/dat = "[src.name]
    " - dat += "Module heat level: [temperature] kelvin
    " - dat += "Safeties set at 350k, shielding failure at 400k. Failure to maintain safe heat levels may result in equipment damage.
    " - dat += "
    " - if(scan_process) - dat += "Scan in progress


    " - else - dat += "[held_container ? "Eject beaker" : "No beaker inserted."]
    " - //dat += "[fuel_container ? "Eject fuel tank" : "No fuel tank inserted."]
    " - dat += "[held_container ? "Begin scanning" : ""]" - dat += "
    " - dat += "Refresh
    " - dat += "Close
    " - user << browse(dat, "window=anomaly;size=450x500") - onclose(user, "anomaly") - -obj/machinery/anomaly/attackby(obj/item/weapon/W as obj, mob/living/user as mob) - if(istype(W, /obj/item/weapon/reagent_containers/glass)) - //var/obj/item/weapon/reagent_containers/glass/G = W - if(held_container) - user << "\red You must remove the [held_container] first." - else - user << "\blue You put the [W] into the [src]." - user.drop_item(W) - held_container = W - held_container.loc = src - updateDialog() - - /*else if(istype(W, /obj/item/weapon/tank)) - //var/obj/item/weapon/reagent_containers/glass/G = W - if(fuel_container) - user << "\red You must remove the [fuel_container] first." - else - user << "\blue You put the [fuel_container] into the [src]." - user.drop_item(W) - fuel_container.loc = src - fuel_container = W - updateDialog()*/ - else - return ..() - -obj/machinery/anomaly/proc/ScanResults() - //instantiate in children to produce unique scan behaviour - return "\red Error initialising scanning components." - -obj/machinery/anomaly/proc/FinishScan() - scan_process = 0 - updateDialog() - - //determine the results and print a report - if(held_container) - src.visible_message("\blue \icon[src] makes an insistent chime.", 2) - var/obj/item/weapon/paper/P = new(src.loc) - P.name = "[src] report #[++report_num]" - P.info = "[src] analysis report #[report_num]

    " + ScanResults() - P.stamped = list(/obj/item/weapon/stamp) - P.overlays = list("paper_stamped") - else - src.visible_message("\blue \icon[src] makes a low buzzing noise.", 2) - -obj/machinery/anomaly/Topic(href, href_list) - ..() - usr.set_machine(src) - if(href_list["close"]) - usr << browse(null, "window=anomaly") - usr.machine = null - if(href_list["eject_beaker"]) - held_container.loc = src.loc - held_container = null - if(href_list["eject_fuel"]) - fuel_container.loc = src.loc - fuel_container = null - if(href_list["begin"]) - if(temperature >= 350) - var/proceed = input("Unsafe internal temperature detected, enter YES below to continue.","Warning") - if(proceed == "YES" && get_dist(src, usr) <= 1) - scan_process = 1 - else - scan_process = 1 - - updateUsrDialog() - -//whether the carrier sample matches the possible finds -//results greater than a threshold of 0.6 means a positive result -obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample, var/carrier_name) - var/specifity = 0 - if(scanned_sample && carrier_name) - - if(scanned_sample.find_presence.Find(carrier_name)) - specifity = 0.75 * (scanned_sample.find_presence[carrier_name] / scanned_sample.total_spread) + 0.25 - else - specifity = rand(0, 0.5) - - return specifity diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_fourier_transform.dm b/code/modules/research/xenoarchaeology/machinery/analysis_fourier_transform.dm deleted file mode 100644 index 98c49b2372a..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_fourier_transform.dm +++ /dev/null @@ -1,34 +0,0 @@ - -// This machine tells the distance to a nearby artifact, if there is one - -obj/machinery/anomaly/fourier_transform - name = "Fourier Transform spectroscope" - -obj/machinery/anomaly/fourier_transform/ScanResults() - var/results = "The scan was inconclusive. Check sample integrity and carrier consistency." - - var/datum/geosample/scanned_sample - var/carrier - var/num_reagents = 0 - - for(var/datum/reagent/A in held_container.reagents.reagent_list) - var/datum/reagent/R = A - if(istype(R, /datum/reagent/analysis_sample)) - scanned_sample = R.data - else - carrier = R.id - num_reagents++ - - if(num_reagents == 2 && scanned_sample && carrier) - //all necessary components are present - var/specifity = GetResultSpecifity(scanned_sample, carrier) - var/distance = scanned_sample.artifact_distance - if(distance > 0) - distance += (2 * rand() - 1) * distance * 0.05 - results = "Fourier transform analysis on anomalous energy absorption through carrier ([carrier]) indicates source located inside emission radius ([95 * specifity]% accuracy): [distance]." - else - results = "Energy dispersion detected throughout sample consistent with background readings.
    " - if(carrier == scanned_sample.source_mineral) - results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample." - - return results diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_gas_chromatography.dm b/code/modules/research/xenoarchaeology/machinery/analysis_gas_chromatography.dm deleted file mode 100644 index bd6dbeb9b36..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_gas_chromatography.dm +++ /dev/null @@ -1,39 +0,0 @@ - -// This machine shows the materials that are present - -obj/machinery/anomaly/gas_chromatography - name = "Gas Chromatography spectrometer" - -obj/machinery/anomaly/gas_chromatography/ScanResults() - var/results = "The scan was inconclusive. Check sample integrity and carrier consistency." - - var/datum/geosample/scanned_sample - var/carrier - var/num_reagents = 0 - - for(var/datum/reagent/A in held_container.reagents.reagent_list) - var/datum/reagent/R = A - if(istype(R, /datum/reagent/analysis_sample)) - scanned_sample = R.data - else - carrier = R.id - num_reagents++ - - if(num_reagents == 2 && scanned_sample) - var/specifity = GetResultSpecifity(scanned_sample, carrier) - results = "Chromatography partitioning analysis over carrier ([carrier]) indicates the following elements present ([100 * specifity]% accuracy):

    " - - var/num_found = 0 - for(var/index=1,index <= scanned_sample.find_presence.len, index++) - var/find = scanned_sample.find_presence[index] - if(find && prob(100 * specifity)) - results += " - " + finds_as_strings[index] + "
    " - num_found++ - - if(!num_found) - results = "Chromatography partitioning results over carrier ([carrier]) to determine elemental makeup were inconclusive.
    " - - if(!carrier) - results += "
    No carrier detected, scan accuracy affected.
    " - - return results diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_hyperspectral.dm b/code/modules/research/xenoarchaeology/machinery/analysis_hyperspectral.dm deleted file mode 100644 index a070a61a5d3..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_hyperspectral.dm +++ /dev/null @@ -1,55 +0,0 @@ - -obj/machinery/anomaly/hyperspectral - name = "Hyperspectral Imager" - icon = 'icons/obj/xenoarchaeology.dmi' - icon_state = "scanner" - -obj/machinery/anomaly/hyperspectral/process() - ..() - if(scan_process) - icon_state = "scanner_active" - else if(prob(10)) - icon_state = "scanner" - flick(src, "scanner_active") - -obj/machinery/anomaly/hyperspectral/ScanResults() - var/results = "The scan was inconclusive. Check sample integrity and carrier consistency." - - var/datum/geosample/scanned_sample - var/carrier - var/num_reagents = 0 - - for(var/datum/reagent/A in held_container.reagents.reagent_list) - var/datum/reagent/R = A - if(istype(R, /datum/reagent/analysis_sample)) - scanned_sample = R.data - else - carrier = R.id - num_reagents++ - - if(num_reagents == 2 && scanned_sample && carrier) - //all necessary components are present - var/specifity = GetResultSpecifity(scanned_sample, carrier) - results = "Spectral signature over carrier ([carrier]):
    " - if(specifity <= 0.25) - //results += "
    " - results += "" - else if(specifity <= 0.5) - //results += "
    " - results += "" - else if(specifity <= 0.75) - //results += "
    " - results += "" - else - //results += "
    " - results += "" - - results += "
    " - if(scanned_sample.artifact_id) - results += "Detected energy signatures [100 * (1 - specifity)]% consistent with standard background readings.
    " - if(prob( (specifity + 0.5 * (1 - specifity)) * 100)) - results += "Anomalous exotic energy signature isolated: [scanned_sample.artifact_id]." - else - results += "Detected energy signatures [95 + 5 * (2 * rand() - 1) * (1 - specifity)]% consistent with standard background readings." - - return results diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_ion_mobility.dm b/code/modules/research/xenoarchaeology/machinery/analysis_ion_mobility.dm deleted file mode 100644 index 9b37d20df91..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_ion_mobility.dm +++ /dev/null @@ -1,47 +0,0 @@ - -// This machine shows the amount of a certain material that is present - -obj/machinery/anomaly/ion_mobility - name = "Ion Mobility Spectrometer" - desc = "A specialised, complex analysis machine." - icon = 'icons/obj/virology.dmi' - icon_state = "analyser" - -obj/machinery/anomaly/ion_mobility/ScanResults() - var/results = "The scan was inconclusive. Check sample integrity and carrier consistency." - - var/datum/geosample/scanned_sample - var/carrier - var/num_reagents = 0 - - for(var/datum/reagent/A in held_container.reagents.reagent_list) - var/datum/reagent/R = A - if(istype(R, /datum/reagent/analysis_sample)) - scanned_sample = R.data - else - carrier = R.id - num_reagents++ - - if(num_reagents == 2 && scanned_sample && carrier) - //all necessary components are present - results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) indicates the dissonance spread:

    " - var/found = 0 - if(scanned_sample.find_presence.Find(carrier)) - var/dis_ratio = scanned_sample.find_presence[carrier] - var/desc_index = responsive_carriers.Find(carrier) - results += " - [finds_as_strings[desc_index]]: [dis_ratio]
    " - found++ - /* - for(var/index=1,index <= scanned_sample.find_presence.len, index++) - var/find = scanned_sample.find_presence[index] - //world << "index: [index], find: [find], response: [responsive_carriers[index]], carrier: [carrier]" - if(find && responsive_carriers[index] == carrier) - results += " - [finds_as_strings[index]] [find * 100]%
    " - found++ - */ - if(!found) - results = "Kinetic analysis on sample's ionic residue in carrier ([carrier]) to determine composition were inconclusive.
    " - if(carrier == scanned_sample.source_mineral) - results += "Warning, analysis may be contaminated by high quantities of molecular carrier present throughout sample." - - return results diff --git a/code/modules/research/xenoarchaeology/machinery/analysis_isotope_ratio.dm b/code/modules/research/xenoarchaeology/machinery/analysis_isotope_ratio.dm deleted file mode 100644 index 04efb278ad9..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/analysis_isotope_ratio.dm +++ /dev/null @@ -1,51 +0,0 @@ - -// This machine shows the age for newer finds - -obj/machinery/anomaly/isotope_ratio - name = "Isotope ratio spectrometer" - desc = "A specialised, complex analysis machine." - icon = 'icons/obj/virology.dmi' - icon_state = "analyser" - -obj/machinery/anomaly/isotope_ratio/ScanResults() - var/results = "The scan was inconclusive. Check sample integrity and carrier consistency." - - var/datum/geosample/scanned_sample - var/carrier_name - var/num_reagents = 0 - - for(var/datum/reagent/A in held_container.reagents.reagent_list) - var/datum/reagent/R = A - if(istype(R, /datum/reagent/analysis_sample)) - scanned_sample = R.data - else - carrier_name = R.id - num_reagents++ - - if(num_reagents == 2 && scanned_sample && carrier_name) - var/accuracy = GetResultSpecifity(scanned_sample, carrier_name) - accuracy += 0.5 * (1 - accuracy) / scanned_sample.total_spread - if(!accuracy) - accuracy = rand(0.01, 0.5) - results = "Isotope decay analysis in carrier ([carrier_name]) indicates age ([100 * accuracy]% accuracy):

    " - - if(scanned_sample.age_billion) - //scramble the results - var/displayed_age_thousands = rand(0, 999) - var/displayed_age_millions = rand(0, 999) - results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.
    " - else if(scanned_sample.age_million) - var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0) - var/displayed_age_millions = scanned_sample.age_million + max(scanned_sample.age_million * ((1 - accuracy) * (4 * rand() - 2)), 0) - results += "[displayed_age_millions + displayed_age_thousands / 1000] million years.
    " - else if(scanned_sample.age_thousand) - var/displayed_age = scanned_sample.age + scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1)) - var/displayed_age_thousands = scanned_sample.age_thousand + max(scanned_sample.age_thousand * ((1 - accuracy) * (2 * rand() - 1)), 0) - results += "[displayed_age_thousands + displayed_age / 1000] thousand years.
    " - else - var/displayed_age = scanned_sample.age + max(scanned_sample.age * ((1 - accuracy) * (2 * rand() - 1)), 0) - results += "[displayed_age] years.
    " - - results += "
    Warning, results only valid up to ages of one billion years." - - return results diff --git a/code/modules/research/xenoarchaeology/machinery/artifact_analyser_old.dm b/code/modules/research/xenoarchaeology/machinery/artifact_analyser_old.dm deleted file mode 100644 index ff1415997b1..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/artifact_analyser_old.dm +++ /dev/null @@ -1,318 +0,0 @@ - -//cael - some changes here. the analysis pad is entirely new - -/obj/machinery/artifact_analyser - name = "Artifact Analyser" - desc = "Studies the structure of artifacts to discover their uses." - icon = 'icons/obj/virology.dmi' - icon_state = "analyser" - anchored = 1 - density = 1 - var/working = 0 - var/accuO = 0 - var/accuT = 0 - var/accuE1 = 0 - var/accuE2 = 0 - var/aorigin = "None" - var/atrigger = "None" - var/aeffect1 = "None" - var/aeffect2 = "None" - var/list/origin_bonuses - var/list/trigger_bonuses - var/list/function_bonuses - var/list/range_bonuses - var/cur_id = "" - var/scan_num = 0 - var/obj/machinery/artifact/cur_artifact = null - var/obj/machinery/analyser_pad/owned_pad = null - var/list/allorigins = list("Ancient Robots","Martian","Wizard Federation","Extradimensional","Precursor") - var/list/alltriggers = list("Contact with Living Organism","Heavy Impact","Contact with Energy Source","Contact with Hydrogen","Contact with Corrosive Substance","Contact with Volatile Substance","Contact with Toxins","Exposure to Heat") - var/list/alleffects = list("Healing Device","Anti-biological Weapon","Non-lethal Stunning Trap","Mechanoid Repair Module","Mechanoid Deconstruction Device","Power Generator","Power Drain","Stellar Mineral Attractor","Agriculture Regulator","Shield Generator","Space-Time Displacer") - var/list/allranges = list("Constant Short-Range Energy Field","Medium Range Energy Pulses","Long Range Energy Pulses","Extreme Range Energy Pulses","Requires contact with subject") - -/obj/machinery/artifact_analyser/New() - ..() - origin_bonuses = new/list() - origin_bonuses["ancient"] = 0 - origin_bonuses["martian"] = 0 - origin_bonuses["wizard"] = 0 - origin_bonuses["eldritch"] = 0 - origin_bonuses["precursor"] = 0 - trigger_bonuses = new/list() - trigger_bonuses["ancient"] = 0 - trigger_bonuses["martian"] = 0 - trigger_bonuses["wizard"] = 0 - trigger_bonuses["eldritch"] = 0 - trigger_bonuses["precursor"] = 0 - function_bonuses = new/list() - function_bonuses["ancient"] = 0 - function_bonuses["martian"] = 0 - function_bonuses["wizard"] = 0 - function_bonuses["eldritch"] = 0 - function_bonuses["precursor"] = 0 - range_bonuses = new/list() - range_bonuses["ancient"] = 0 - range_bonuses["martian"] = 0 - range_bonuses["wizard"] = 0 - range_bonuses["eldritch"] = 0 - range_bonuses["precursor"] = 0 - // - spawn(10) - owned_pad = locate() in orange(1, src) - -/obj/machinery/artifact_analyser/attack_hand(var/mob/user as mob) - if(stat & (NOPOWER|BROKEN)) - return - user.machine = src - var/dat = "Artifact Analyser
    " - dat += "

    " - if(!owned_pad) - dat += "Unable to locate analysis pad.
    " - dat += "

    " - else if (!src.working) - dat += "Artifact ID: [cur_id]
    " - dat += "Artifact Origin: [aorigin] ([accuO]%)
    " - dat += "Activation Trigger: [atrigger] ([accuT]%)
    " - dat += "Artifact Function: [aeffect1] ([accuE1]%)
    " - dat += "Artifact Range: [aeffect2] ([accuE2]%)

    " - dat += "

    " - dat += "Artifact ID is determined from unique energy emission signatures.
    " - dat += "Analyse Artifact (Scan number #[scan_num+1])
    " - dat += "Upload/update artifact scan
    " - dat += "Print Page
    " - else - dat += "Please wait. Analysis in progress.
    " - dat += "

    " - // - dat += "Close
    " - user << browse(dat, "window=artanalyser;size=450x500") - onclose(user, "artanalyser") - -/obj/machinery/artifact_analyser/process() - if(stat & (NOPOWER|BROKEN)) - return - use_power(350) - // - if(!owned_pad) - for(var/obj/machinery/analyser_pad/pad in range(1)) - owned_pad = pad - break - -/obj/machinery/artifact_analyser/proc/AA_FailedAnalysis(var/failtype) - switch(failtype) - if(1) - src.aorigin = "Failed to Identify" - if (prob(20)) src.aorigin = pick(src.allorigins) - if(2) - src.atrigger = "Failed to Identify" - if (prob(20)) src.atrigger = pick(src.alltriggers) - if(3) - src.aeffect1 = "Failed to Identify" - if (prob(20)) src.aeffect1 = pick(src.alleffects) - if(4) - src.aeffect2 = "Failed to Identify" - if (prob(20)) src.aeffect2 = pick(src.allranges) - -/obj/machinery/artifact_analyser/proc/AA_Analyse() - if(!cur_artifact) - return - src.accuO = 5 + rand(0,10) + origin_bonuses[cur_artifact.origin] + cur_artifact.activated * 50 - src.accuT = 5 + rand(0,10) + trigger_bonuses[cur_artifact.origin] + cur_artifact.activated * 50 - src.accuE1 = 5 + rand(0,10) + function_bonuses[cur_artifact.origin] + cur_artifact.activated * 50 - src.accuE2 = 5 + rand(0,10) + range_bonuses[cur_artifact.origin] + cur_artifact.activated * 50 - - //keep any correctly determined properties the same - var/origin_correct = 0 - var/trigger_correct = 0 - var/function_correct = 0 - var/range_correct = 0 - if(cur_id == cur_artifact.display_id) - if(src.aorigin == cur_artifact.origin) - origin_correct = 1 - - if(src.atrigger == cur_artifact.my_effect.trigger) - trigger_correct = 1 - else if(src.atrigger == cur_artifact.my_effect.triggerX) - trigger_correct = 1 - - if(src.aeffect1 == cur_artifact.my_effect.effecttype) - function_correct = 1 - - if(src.aeffect2 == cur_artifact.my_effect.effectmode) - range_correct = 1 - - if (src.accuO > 100) src.accuO = 100 - if (src.accuT > 100) src.accuT = 100 - if (src.accuE1 > 100) src.accuE1 = 100 - if (src.accuE2 > 100) src.accuE2 = 100 - // Roll to generate report - if (prob(accuO) || origin_correct) - switch(cur_artifact.origin) - if("ancient") src.aorigin = "Ancient Robots" - if("martian") src.aorigin = "Martian" - if("wizard") src.aorigin = "Wizard Federation" - if("eldritch") src.aorigin = "Extradimensional" - if("precursor") src.aorigin = "Precursor" - else src.aorigin = "Unknown Origin" - origin_bonuses[cur_artifact.origin] += 10 - else - AA_FailedAnalysis(1) - origin_bonuses[cur_artifact.origin] += 5 - if (prob(accuT) || trigger_correct) - switch(cur_artifact.my_effect.trigger) - if("touch") src.atrigger = "Contact with Living Organism" - if("force") src.atrigger = "Heavy Impact" - if("energy") src.atrigger = "Contact with Energy Source" - if("chemical") - switch(cur_artifact.my_effect.triggerX) - if("hydrogen") src.atrigger = "Contact with Hydrogen" - if("corrosive") src.atrigger = "Contact with Corrosive Substance" - if("volatile") src.atrigger = "Contact with Volatile Substance" - if("toxin") src.atrigger = "Contact with Toxins" - if("heat") src.atrigger = "Exposure to Heat" - else src.atrigger = "Unknown Trigger" - trigger_bonuses[cur_artifact.origin] += 5 - else - AA_FailedAnalysis(2) - trigger_bonuses[cur_artifact.origin] += 1 - if (prob(accuE1) || function_correct) - switch(cur_artifact.my_effect.effecttype) - if("healing") src.aeffect1 = "Healing Device" - if("injure") src.aeffect1 = "Anti-biological Weapon" - // if("stun") src.aeffect1 = "Non-lethal Stunning Trap" - if("roboheal") src.aeffect1 = "Mechanoid Repair Module" - if("robohurt") src.aeffect1 = "Mechanoid Deconstruction Device" - if("cellcharge") src.aeffect1 = "Power Generator" - if("celldrain") src.aeffect1 = "Power Drain" - if("planthelper") src.aeffect1 = "Agriculture Regulator" - if("forcefield") src.aeffect1 = "Shield Generator" - if("teleport") src.aeffect1 = "Space-Time Displacer" - else src.aeffect1 = "Unknown Effect" - function_bonuses[cur_artifact.origin] += 5 - else - AA_FailedAnalysis(3) - function_bonuses[cur_artifact.origin] += 1 - if (prob(accuE2) || range_correct) - switch(cur_artifact.my_effect.effectmode) - if("aura") src.aeffect2 = "Constant Short-Range Energy Field" - if("pulse") - if(cur_artifact.my_effect.aurarange > 7) src.aeffect2 = "Long Range Energy Pulses" - else src.aeffect2 = "Medium Range Energy Pulses" - if("worldpulse") src.aeffect2 = "Extreme Range Energy Pulses" - if("contact") src.aeffect2 = "Requires contact with subject" - else src.aeffect2 = "Unknown Range" - range_bonuses[cur_artifact.origin] += 5 - else - AA_FailedAnalysis(4) - range_bonuses[cur_artifact.origin] += 1 - - cur_artifact.name = "alien artifact ([cur_artifact.display_id])" - cur_artifact.desc = "A large alien device. It has a small tag near the bottom that reads \"[cur_artifact.display_id]\"." - cur_id = cur_artifact.display_id - cur_artifact.my_effect.artifact_id = cur_artifact.display_id - -/obj/machinery/artifact_analyser/Topic(href, href_list) - - if(href_list["analyse"]) - if(owned_pad) - var/turf/pad_turf = get_turf(owned_pad) - var/findarti = 0 - for(var/obj/machinery/artifact/A in pad_turf.contents) - findarti++ - cur_artifact = A - if (findarti == 1) - if(cur_artifact && cur_artifact.being_used) - var/message = "[src] states, \"Cannot analyse. Excess energy drain is disrupting signal.\"" - src.visible_message(message, message) - else - cur_artifact.anchored = 1 - cur_artifact.being_used = 1 - src.working = 1 - src.icon_state = "analyser_processing" - var/time = rand(30,50) + max(0, 300 - scan_num * 10) - /*for(var/i = artifact_research.starting_tier, i <= artifact_research.max_tiers, i++) - for(var/datum/artiresearch/R in artifact_research.researched_items[i]) - if (R.bonustype == "analyser") time -= R.bonusTime*/ - time *= 10 - var/message = "[src] states, \"Commencing analysis.\"" - src.visible_message(message, message) - use_power(500) - spawn(time) - src.working = 0 - icon_state = "analyser" - cur_artifact.anchored = 0 - cur_artifact.being_used = 0 - if(cur_artifact.loc == pad_turf) - AA_Analyse() - scan_num++ - message = "[src] states, \"Analysis complete.\"" - src.visible_message(message, message) - use_power(500) - else if (findarti > 1) - var/message = "[src] states, \"Cannot analyse. Error isolating energy signature.\"" - src.visible_message(message, message) - else - var/message = "[src] states, \"Cannot analyse. No noteworthy energy signature isolated.\"" - src.visible_message(message, message) - - if(href_list["upload"] && cur_id != "") - //add new datum to every DB in the world - for(var/obj/machinery/computer/artifact_database/DB in world) - var/update = 0 - for(var/datum/catalogued_artifact/CA in DB.catalogued_artifacts) - if(CA.display_id == cur_id) - //already there, so update it - update = 1 - CA.origin = aorigin + " ([accuO]%)" - CA.trigger = atrigger + " ([accuT]%)" - CA.effecttype = aeffect1 + " ([accuE1]%)" - CA.effectmode = aeffect2 + " ([accuE2]%)" - if(!update) - //not there, so add it - var/datum/catalogued_artifact/CA = new() - CA.display_id = cur_id - CA.origin = aorigin + " ([accuO]%)" - CA.trigger = atrigger + " ([accuT]%)" - CA.effecttype = aeffect1 + " ([accuE1]%)" - CA.effectmode = aeffect2 + " ([accuE2]%)" - DB.catalogued_artifacts.Add(CA) - use_power(100) - - if(href_list["print"]) - var/r = "Artifact Analysis Report (Scan #[scan_num])
    " - r += "Artifact ID: [cur_id] (determined from unique energy emission signatures)
    " - r += "Artifact Origin: [aorigin] ([accuO]%)
    " - r += "Activation Trigger: [atrigger] ([accuT]%)
    " - r += "Artifact Function: [aeffect1] ([accuE1]%)
    " - r += "Artifact Range: [aeffect2] ([accuE2]%)

    " - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src.loc) - P.name = "Artifact Analysis Report #[scan_num]" - P.info = r - for(var/mob/O in hearers(src, null)) - O.show_message("\icon[src] \blue The [src.name] prints a sheet of paper", 3) - use_power(10) - - if(href_list["close"]) - usr << browse(null, "window=artanalyser") - usr.machine = null - - src.updateDialog() - -//stick artifacts onto this then switch the analyser on -/obj/machinery/analyser_pad - name = "artifact analysis pad" - desc = "Studies the structure of artifacts to discover their uses." - icon = 'icons/obj/stationobjs.dmi' - icon_state = "tele0" - anchored = 1 - density = 0 - -/obj/machinery/analyser_pad/New() - ..() - /*spawn(10) - for(var/obj/machinery/artifact_analyser/analyser in orange(1)) - world << "pad found analyser" - if(!analyser.owned_pad) - analyser.owned_pad = src - world << "pad set analyser to self" - break*/ diff --git a/code/modules/research/xenoarchaeology/machinery/artifact_db_old.dm b/code/modules/research/xenoarchaeology/machinery/artifact_db_old.dm deleted file mode 100644 index c6e0d1fb3fa..00000000000 --- a/code/modules/research/xenoarchaeology/machinery/artifact_db_old.dm +++ /dev/null @@ -1,58 +0,0 @@ - -/datum/catalogued_artifact - var/trigger = "touch" // What activates it? - var/effecttype = "healing" // What does it do? - var/effectmode = "aura" // How does it carry out the effect? - var/display_id = "" // Artifact ID to display once successfully scanned - var/origin = "" - -/obj/machinery/computer/artifact_database - name = "Artifact Database" - icon_state = "rdcomp" - var/list/catalogued_artifacts - -/obj/machinery/computer/artifact_database/New() - ..() - catalogued_artifacts = new/list - -/obj/machinery/computer/artifact_database/Topic(href, href_list) - ..() - if( href_list["close"] ) - usr << browse(null, "window=artifact_db") - usr.machine = null - updateDialog() - -/obj/machinery/computer/artifact_database/process() - ..() - updateDialog() - -/obj/machinery/computer/artifact_database/interact(mob/user) - if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) - if (!istype(user, /mob/living/silicon)) - user.machine = null - user << browse(null, "window=artifact_db") - return - var/t = "Artifact Database
    " - t += "
    " - for(var/datum/catalogued_artifact/CA in catalogued_artifacts) - t += "Artifact ID: [CA.display_id] (determined from unique energy emission signatures)
    " - t += "Artifact Origin: [CA.origin]
    " - t += "Activation Trigger: [CA.trigger]
    " - t += "Artifact Function: [CA.effecttype]
    " - t += "Artifact Range: [CA.effectmode]

    " - t += "
    " - t += "
    Refresh Close
    " - user << browse(t, "window=artifact_db;size=500x800") - user.machine = src - -/* -/datum/artifact_effect - var/origin = null // Used in the randomisation/research of the artifact. - var/trigger = "touch" // What activates it? - var/triggerX = "none" // Used for more varied triggers - var/effecttype = "healing" // What does it do? - var/effectmode = "aura" // How does it carry out the effect? - var/aurarange = 4 // How far the artifact will extend an aura effect. - var/display_id = "" // Artifact ID to display once successfully scanned - var/list/created_field -*/ \ No newline at end of file diff --git a/code/modules/research/xenoarchaeology/machinery/coolant.dm b/code/modules/research/xenoarchaeology/machinery/coolant.dm new file mode 100644 index 00000000000..6c0652f4084 --- /dev/null +++ b/code/modules/research/xenoarchaeology/machinery/coolant.dm @@ -0,0 +1,59 @@ + +datum/reagent/coolant + name = "Coolant" + id = "coolant" + description = "Industrial cooling substance." + reagent_state = LIQUID + color = "#C8A5DC" // rgb: 200, 165, 220 + +datum/chemical_reaction/coolant + name = "Coolant" + id = "coolant" + result = "coolant" + required_reagents = list("tungsten" = 1, "oxygen" = 1, "water" = 1) + result_amount = 3 + + + +/obj/structure/reagent_dispensers/coolanttank + name = "coolant tank" + desc = "A tank of industrial coolant" + icon = 'icons/obj/objects.dmi' + icon_state = "coolanttank" + amount_per_transfer_from_this = 10 + New() + ..() + reagents.add_reagent("coolant",1000) + +/obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet)) + if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) + explode() + +/obj/structure/reagent_dispensers/coolanttank/blob_act() + explode() + +/obj/structure/reagent_dispensers/coolanttank/ex_act() + explode() + +/obj/structure/reagent_dispensers/coolanttank/proc/explode() + var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread + //S.attach(src) + S.set_up(5, 0, src.loc) + + playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3) + spawn(0) + S.start() + + var/datum/gas_mixture/env = src.loc.return_air() + if(env) + if (reagents.total_volume > 750) + env.temperature = 0 + else if (reagents.total_volume > 500) + env.temperature -= 100 + else + env.temperature -= 50 + + sleep(10) + if(src) + del(src) diff --git a/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm new file mode 100644 index 00000000000..6dcd45c8255 --- /dev/null +++ b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm @@ -0,0 +1,363 @@ + +/obj/machinery/radiocarbon_spectrometer + name = "Radiocarbon spectrometer" + desc = "A specialised, complex scanner for gleaning information on all manner of small things." + anchored = 1 + density = 1 + icon = 'icons/obj/virology.dmi' + icon_state = "analyser" + + use_power = 1 //1 = idle, 2 = active + idle_power_usage = 20 + active_power_usage = 300 + + //var/obj/item/weapon/reagent_containers/glass/coolant_container + var/scanning = 0 + var/report_num = 0 + // + var/obj/item/scanned_item + var/last_scan_data = "No scans on record." + // + var/last_process_worldtime = 0 + // + var/scanner_progress = 0 + var/scanner_rate = 1.25 //80 seconds per scan + var/scanner_rpm = 0 + var/scanner_rpm_dir = 1 + var/scanner_temperature = 0 + var/scanner_seal_integrity = 100 + // + var/coolant_usage_rate = 0 //measured in u/microsec + var/fresh_coolant = 0 + var/coolant_purity = 0 + var/datum/reagents/coolant_reagents + var/used_coolant = 0 + var/list/coolant_reagents_purity = list() + // + var/maser_wavelength = 0 + var/optimal_wavelength = 0 + var/optimal_wavelength_target = 0 + var/tleft_retarget_optimal_wavelength = 0 + var/maser_efficiency = 0 + // + var/radiation = 0 //0-100 mSv + var/t_left_radspike = 0 + var/rad_shield = 0 + +/obj/machinery/radiocarbon_spectrometer/New() + ..() + create_reagents(500) + coolant_reagents_purity["water"] = 0.5 + coolant_reagents_purity["icecoffee"] = 0.6 + coolant_reagents_purity["icetea"] = 0.6 + coolant_reagents_purity["milkshake"] = 0.6 + coolant_reagents_purity["leporazine"] = 0.7 + coolant_reagents_purity["kelotane"] = 0.7 + coolant_reagents_purity["sterilizine"] = 0.7 + coolant_reagents_purity["dermaline"] = 0.7 + coolant_reagents_purity["hyperzine"] = 0.8 + coolant_reagents_purity["cryoxadone"] = 0.9 + coolant_reagents_purity["coolant"] = 1 + coolant_reagents_purity["adminordrazine"] = 2 + +/obj/machinery/radiocarbon_spectrometer/attack_hand(var/mob/user as mob) + ui_interact(user) + +/obj/machinery/radiocarbon_spectrometer/attackby(var/obj/I as obj, var/mob/user as mob) + if(scanning) + user << "You can't do that while [src] is scanning!" + else + if(istype(I, /obj/item/stack/nanopaste)) + var/choice = alert("What do you want to do with the nanopaste?","Radiometric Scanner","Scan nanopaste","Fix seal integrity") + if(choice == "Fix seal integrity") + var/obj/item/stack/nanopaste/N = I + var/amount_used = min(N.amount, 10 - scanner_seal_integrity / 10) + N.use(amount_used) + scanner_seal_integrity = round(scanner_seal_integrity + amount_used * 10) + return + if(istype(I, /obj/item/weapon/reagent_containers/glass)) + var/choice = alert("What do you want to do with the container?","Radiometric Scanner","Add coolant","Empty coolant","Scan container") + if(choice == "Add coolant") + var/obj/item/weapon/reagent_containers/glass/G = I + var/amount_transferred = min(src.reagents.maximum_volume - src.reagents.total_volume, G.reagents.total_volume) + G.reagents.trans_to(src, amount_transferred) + user << "You empty [amount_transferred]u of coolant into [src]." + update_coolant() + return + else if(choice == "Empty coolant") + var/obj/item/weapon/reagent_containers/glass/G = I + var/amount_transferred = min(G.reagents.maximum_volume - G.reagents.total_volume, src.reagents.total_volume) + src.reagents.trans_to(G, amount_transferred) + user << "You remove [amount_transferred]u of coolant from [src]." + update_coolant() + return + user.drop_item() + I.loc = src + scanned_item = I + +/obj/machinery/radiocarbon_spectrometer/proc/update_coolant() + var/total_purity = 0 + fresh_coolant = 0 + coolant_purity = 0 + var/num_reagent_types = 0 + for (var/datum/reagent/current_reagent in src.reagents.reagent_list) + if (!current_reagent) + continue + var/cur_purity = coolant_reagents_purity[current_reagent.id] + if(!cur_purity) + cur_purity = 0.1 + else if(cur_purity > 1) + cur_purity = 1 + total_purity += cur_purity * current_reagent.volume + fresh_coolant += current_reagent.volume + num_reagent_types += 1 + if(total_purity && fresh_coolant) + coolant_purity = total_purity / fresh_coolant + +/obj/machinery/radiocarbon_spectrometer/ui_interact(mob/user, ui_key = "radio_spectro") + + if(user.stat) + return + + // this is the data which will be sent to the ui + var/data[0] + data["scanned_item"] = (scanned_item ? scanned_item.name : "") + data["scanned_item_desc"] = (scanned_item ? (scanned_item.desc ? scanned_item.desc : "No information on record.") : "") + data["last_scan_data"] = last_scan_data + // + data["scan_progress"] = round(scanner_progress) + data["scanning"] = scanning + // + data["scanner_seal_integrity"] = round(scanner_seal_integrity) + data["scanner_rpm"] = round(scanner_rpm) + data["scanner_temperature"] = round(scanner_temperature) + // + data["coolant_usage_rate"] = "[coolant_usage_rate]" + data["unused_coolant_abs"] = round(fresh_coolant) + data["unused_coolant_per"] = round(fresh_coolant / reagents.maximum_volume * 100) + data["coolant_purity"] = "[coolant_purity * 100]" + // + data["optimal_wavelength"] = round(optimal_wavelength) + data["maser_wavelength"] = round(maser_wavelength) + data["maser_efficiency"] = round(maser_efficiency * 100) + // + data["radiation"] = round(radiation) + data["t_left_radspike"] = round(t_left_radspike) + data["rad_shield_on"] = rad_shield + + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key) + if (!ui) + // the ui does not exist, so we'll create a new one + ui = new(user, src, ui_key, "geoscanner.tmpl", "High Res Radiocarbon Spectrometer", 900, 825) + // When the UI is first opened this is the data it will use + ui.set_initial_data(data) + ui.open() + // Auto update every Master Controller tick + ui.set_auto_update(1) + else + // The UI is already open so push the new data to it + ui.push_data(data) + return + +/obj/machinery/radiocarbon_spectrometer/process() + if(scanning) + if(!scanned_item || scanned_item.loc != src) + scanned_item = null + stop_scanning() + else if(scanner_progress >= 100) + complete_scan() + else + //calculate time difference + var/deltaT = (world.time - last_process_worldtime) * 0.1 + + //modify the RPM over time + //i want 1u to last for 10 sec at 500 RPM, scaling linearly + scanner_rpm += scanner_rpm_dir * 50 * deltaT + if(scanner_rpm > 1000) + scanner_rpm = 1000 + scanner_rpm_dir = -1 * pick(0.5, 2.5, 5.5) + else if(scanner_rpm < 1) + scanner_rpm = 1 + scanner_rpm_dir = 1 * pick(0.5, 2.5, 5.5) + + //heat up according to RPM + //each unit of coolant + scanner_temperature += scanner_rpm * deltaT * 0.05 + + //radiation + t_left_radspike -= deltaT + if(t_left_radspike > 0) + //ordinary radiation + radiation = rand() * 15 + else + //radspike + if(t_left_radspike > -5) + radiation = rand() * 15 + 85 + if(!rad_shield) + //irradiate nearby mobs + for(var/mob/living/M in view(7,src)) + M.apply_effect(radiation / 25, IRRADIATE, 0) + else + t_left_radspike = pick(10,15,25) + + //use some coolant to cool down + if(coolant_usage_rate > 0) + var/coolant_used = min(fresh_coolant, coolant_usage_rate * deltaT) + if(coolant_used > 0) + fresh_coolant -= coolant_used + used_coolant += coolant_used + scanner_temperature = max(scanner_temperature - coolant_used * coolant_purity * 20, 0) + + //modify the optimal wavelength + tleft_retarget_optimal_wavelength -= deltaT + if(tleft_retarget_optimal_wavelength <= 0) + tleft_retarget_optimal_wavelength = pick(4,8,15) + optimal_wavelength_target = rand() * 9900 + 100 + // + if(optimal_wavelength < optimal_wavelength_target) + optimal_wavelength = min(optimal_wavelength + 700 * deltaT, optimal_wavelength_target) + else if(optimal_wavelength > optimal_wavelength_target) + optimal_wavelength = max(optimal_wavelength - 700 * deltaT, optimal_wavelength_target) + // + maser_efficiency = 1 - max(min(10000, abs(optimal_wavelength - maser_wavelength) * 3), 1) / 10000 + + //make some scan progress + if(!rad_shield) + scanner_progress = min(100, scanner_progress + scanner_rate * maser_efficiency * deltaT) + + //degrade the seal over time according to temperature + //i want temperature of 50K to degrade at 1%/sec + scanner_seal_integrity -= (max(scanner_temperature, 1) / 1000) * deltaT + + //emergency stop if seal integrity reaches 0 + if(scanner_seal_integrity <= 0 || (scanner_temperature >= 1273 && !rad_shield)) + stop_scanning() + src.visible_message("\blue \icon[src] buzzes unhappily. It has failed mid-scan!", 2) + + if(prob(5)) + src.visible_message("\blue \icon[src] [pick("whirrs","chuffs","clicks")][pick(" excitedly"," energetically"," busily")].", 2) + else + //gradually cool down over time + if(scanner_temperature > 0) + scanner_temperature = max(scanner_temperature - 5 - 10 * rand(), 0) + if(prob(0.75)) + src.visible_message("\blue \icon[src] [pick("plinks","hisses")][pick(" quietly"," softly"," sadly"," plaintively")].", 2) + last_process_worldtime = world.time + +/obj/machinery/radiocarbon_spectrometer/proc/stop_scanning() + scanning = 0 + scanner_rpm_dir = 1 + scanner_rpm = 0 + optimal_wavelength = 0 + maser_efficiency = 0 + maser_wavelength = 0 + coolant_usage_rate = 0 + radiation = 0 + t_left_radspike = 0 + if(used_coolant) + src.reagents.remove_any(used_coolant) + used_coolant = 0 + +/obj/machinery/radiocarbon_spectrometer/proc/complete_scan() + src.visible_message("\blue \icon[src] makes an insistent chime.", 2) + + if(scanned_item) + //create report + var/obj/item/weapon/paper/P = new(src) + P.name = "[src] report #[++report_num]: [scanned_item.name]" + P.stamped = list(/obj/item/weapon/stamp) + P.overlays = list("paper_stamped") + + //work out data + var/data = " - Mundane object: [scanned_item.desc ? scanned_item.desc : "No information on record."]
    " + var/datum/geosample/G + switch(scanned_item.type) + if(/obj/item/weapon/ore) + var/obj/item/weapon/ore/O = scanned_item + if(O.geological_data) + G = O.geological_data + + if(/obj/item/weapon/rocksliver) + var/obj/item/weapon/rocksliver/O = scanned_item + if(O.geological_data) + G = O.geological_data + + if(/obj/item/weapon/archaeological_find) + data = " - Mundane object (archaic xenos origins)
    " + + var/obj/item/weapon/archaeological_find/A = scanned_item + if(A.speaking_to_players) + data = " - Exhibits properties consistent with sonic reproduction.
    " + if(A.listening_to_players) + data = " - Exhibits properties similar to audio capture technology.
    " + + var/anom_found = 0 + if(G) + data = " - Spectometric analysis on mineral sample has determined type [finds_as_strings[responsive_carriers.Find(G.source_mineral)]]
    " + if(G.age_billion > 0) + data += " - Radiometric dating shows age of [G.age_billion].[G.age_million] billion years
    " + else if(G.age_million > 0) + data += " - Radiometric dating shows age of [G.age_million].[G.age_thousand] million years
    " + else + data += " - Radiometric dating shows age of [G.age_thousand * 1000 + G.age] years
    " + data += " - Chromatographic analysis shows the following materials present:
    " + for(var/carrier in G.find_presence) + if(G.find_presence[carrier]) + var/index = responsive_carriers.Find(carrier) + if(index > 0 && index <= finds_as_strings.len) + data += " > [100 * G.find_presence[carrier]]% [finds_as_strings[index]]
    " + + if(G.artifact_id && G.artifact_distance >= 0) + anom_found = 1 + data += " - Hyperspectral imaging reveals exotic energy wavelength detected with ID: [G.artifact_id]
    " + data += " - Fourier transform analysis on anomalous energy absorption indicates energy source located inside emission radius of [G.artifact_distance]m
    " + + if(!anom_found) + data += " - No anomalous data
    " + + P.info = "[src] analysis report #[report_num]
    " + P.info += "Scanned item: [scanned_item.name]

    " + data + last_scan_data = P.info + P.loc = src.loc + + scanned_item.loc = src.loc + scanned_item = null + +/obj/machinery/radiocarbon_spectrometer/Topic(href, href_list) + if(stat & (NOPOWER|BROKEN)) + return 0 // don't update UIs attached to this object + + if(href_list["scanItem"]) + if(scanning) + stop_scanning() + else + if(scanned_item) + if(scanner_seal_integrity > 0) + scanner_progress = 0 + scanning = 1 + t_left_radspike = pick(5,10,15) + usr << "Scan initiated." + else + usr << "Could not initiate scan, seal requires replacing." + else + usr << "Insert an item to scan." + + if(href_list["maserWavelength"]) + maser_wavelength = max(min(maser_wavelength + 1000 * text2num(href_list["maserWavelength"]), 10000), 1) + + if(href_list["coolantRate"]) + coolant_usage_rate = max(min(coolant_usage_rate + text2num(href_list["coolantRate"]), 10000), 0) + + if(href_list["toggle_rad_shield"]) + if(rad_shield) + rad_shield = 0 + else + rad_shield = 1 + + if(href_list["ejectItem"]) + if(scanned_item) + scanned_item.loc = src.loc + scanned_item = null + + add_fingerprint(usr) + return 1 // update UIs attached to this object diff --git a/code/modules/research/xenoarchaeology/manuals.dm b/code/modules/research/xenoarchaeology/manuals.dm index ceaa3d036ea..99be3a6849c 100644 --- a/code/modules/research/xenoarchaeology/manuals.dm +++ b/code/modules/research/xenoarchaeology/manuals.dm @@ -49,6 +49,8 @@
  51. Core sampler - use this to take core samples from rock faces, which you can then run to the lab for analysis.
  52. Depth scanner - uses x-ray diffraction to locate anomalous densities in rock, indicating archaeological deposits or mineral veins. Comes with a handy reference log containing co-ordinates and time of each scan.
  53. +
  54. Alden-Saraspova counter - uses a patented application of Fourier Transform analysis to determine the difference between background and + exotic radiation. Use it to determine how far you are from anomalous energy sources.
  55. Radio beacon locater - leave a beacon at an item of interest, then track it down later with this handy gadget. Watch for interference from other devices though.
  56. Flashlight or portable light source - Self explanatory, I hope.
  57. @@ -129,51 +131,50 @@

    Contents

    1. A note on terms
    2. -
    3. Isotope ratio spectrometer
    4. -
    5. Accelerator spectrometer
    6. -
    7. Gas chromatography spectrometer
    8. -
    9. Ion mobility spectrometer
    10. +
    11. Analysis progression
    12. +
    13. Heat management
    14. +
    15. Ambient radiation

    A note on terms

    -
  58. Dissonance ratio - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite. - It takes into account volume, density, molecular excitation and isotope spread.
  59. Mass spectrometry - MS is the procedure used used to measure and quantify the components of matter. The most prized tool in the field of 'Materials analysis'
  60. Radiometric dating - MS applied using the right carrier reagents can be used to accurately determine the age of a sample.
  61. -
  62. Sample specifity - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity - (material resonance) indicates that there is much of the carrier reagent present in the sample.
  63. +
  64. Dissonance ratio - This is a pseudoarbitrary value indicating the overal presence of a particular element in a greater composite. + It takes into account volume, density, molecular excitation and isotope spread.
  65. +
  66. Vacuum seal integrity - A reference to how close an airtight seal is to failure.

  67. Contents -

    Isotope ratio spectrometer

    - Isotope ratio mass spectrometers work by coating a small surface with a semiliquid stationary phase consisting of the sample to be - analysed, and recording it's interactions with a gaseous mobile phase comprised of an inert or nonreactive gas such as helium or nitrogen.
    +

    Analysis progression

    + Modern mass spectrometry requires constant attention from the diligant researcher in order to be successul. There are many different elements to juggle, + and later chapters will delve into them. For the spectrometry assistant, the first thing you need to know is that the scanner wavelength is automatically + calculated for you. Just tweak the settings and try to match it with the actual wavelength as closely as possible.

    - IRMS are employed as radiometric daters, extremely accurate but only so up to ages of one billion years.
    Contents -

    Accelerator spectrometer

    - The accelerator mass spectrometer works by accelerating ions to extraordinarily high kinetic energies before mass analysis. The special strength of AMS is - isolate rare or low-strength isotopes, making it able to determine much greater ages with reasonable accuracy.
    +

    Seal integrity

    + In order to maintain sterile and environmentally static procedures, a special chamber is setup inside the spectrometer. It's protected by a proprietary vacuum seal + produced by top tier industrial science. It will only last for a certain number of scans before failing outright, but it can be resealed through use of nanite paste. + Unfortunately, it's susceptible to malforming under heat stress so exposing it to higher temperatures will cause it's operation life to drop significantly.

    - AMS are employed as extreme age radiometric daters, able to determine the age of the sample on a scale of billions of years. - They are commonly located in geology and archaeology laboratories.
    Contents -

    Gas chromatography spectrometer

    - Gas-liquid chromatography mass spectrometers work by coating a small surface with a semiliquid stationary phase consisting of the sample to be - analysed, and recording it's interactions with a gaseous mobile phase comprised of an inert or nonreactive gas such as helium or nitrogen.
    +

    Heat management

    + The scanner relies on a gyro-rotational system that varies in speed and intensity. Over the course of an ordinary scan, the RPMs can change dramatically. Higher RPMs + means greater heat generation, but is necessary for the ongoing continuation of the scan. To offset heat production, spectrometers have an inbuilt cooling system. + Researchers can modify the flow rate of coolant to aid in dropping temperature as necessary, but are advised that frequent coolant replacements may be necessary + depending on coolant purity. Water and substances such as cryoxadone are viable substitutes, but nowhere near as effective as pure coolant itself.

    - GLCS are employed in forensic and geological analysis to determine what elements are present in a sample.
    Contents -

    Ion mobility spectrometer

    - Ion mobility mass spectrometers work by examining the mobility of ionized molecules in an inert carrier gas
    +

    Ambient radiation

    + Researchers are warned that while operational, mass spectrometers emit period bursts of radiation and are thus advised to wear protective gear. In the event of + radiation spikes, there is also a special shield that can be lowered to block emissions. Lowering this, however, will have the effect of blocking the scanner + so use it sparingly.

    - IMS returns a dissonance ratio over the scanned sample and carrier reagent, indicating the average total presence of the sample.
    Contents @@ -197,67 +198,17 @@ -

    Contents

    -
      -
    1. Some useful phrases for you
    2. -
    3. Sample preparation and analysis
    4. -
    5. Fourier transform spectroscope
    6. -
    7. Hyperspectral Imager
    8. -
    - -
    -

    Some useful phrases for you

    - -
  68. Spectroscopy - Spectroscopy is the study of the behaviour of light, commonly used in the 26th century for analysis of anomalous - behaviour of energy or light.
  69. -
  70. Sample specifity - A pseudoarbitrary value used to indicate how well a sample resonates with the employed carrier reagent. Great specifity - (material resonance) indicates that there is much of the carrier reagent present in the sample.
  71. -
  72. Anomalies - Inexplicable or uncategorised occurrences in the cosmos. A fascinating and dangerous study is made to determine the function of - these rare finds, and the term is often applied to describe technology left behind by vastly superior ancient alien forerunners.
  73. -

    - Contents - -

    Sample preparation and analysis

    - When you are readying your spectrometry lab for analysis, you'll need to make sure the sample is in a form the machines can glean data from. - -
  74. Obtain material sample - This should be an ordinary chunk of matter the size of your finger, a good example is a 6mm rock core.
  75. -
  76. Run density separation treatment - Perform the DST procedure on your sample, following generic specifications.
  77. -
  78. Ensure sample purity - DST can sometimes leave behind chemical waste or chunks of matter, make sure there aren't any before proceeding.
  79. -
  80. Prepare analysis tray - A sample tray holds a miniscule amount of liquid (2u), but that's all that our spectrometers require for a good reading.
  81. -
  82. Choose carrier reagent - Standard spectrometers require 1u of the material sample, and 1u of a 'carrier' reagent to provide control comparison - and to enable refraction inferencing.
  83. -
  84. Insert sample tray into machine - And press the 'Go' button. Now go make a cup of coffee.
  85. -
  86. Monitor machine heat levels - The upper end mass spectrometers have quite complex internals, and have a tendency to critically overheat. - Make sure the heat limit isn't exceeded, or there may be potentially disastrous consequences.
  87. -
  88. Examine analysis report - it won't always make sense or provide the information you hoped for, but if you've been careful during DST and ensured - sample integrity, then there's always something to be learnt. Just don't lose the paperwork!
  89. -

    - Contents - -

    Fourier transform spectroscope

    - The FTS measures temporal coherence of radiating energy, then applies time-and-space domain measurements on the collected emission data. The collective - procedure is known as the Fourier Transform Procedure, with the mathematical algorithms dating back to the 19th century on Earth.
    -
    - As well as providing background energy readings, an FTS calculates the approximate distance and direction towards any anomalous energy signatures from - the location the scanned sample was taken from.
    - Contents - -

    Hyperspectral Imager

    - The imager scans and collates spectral energy signatures from across the electromagnetic spectrum. The collected data is then presented to the viewer in - graph form, with any anomalous (uncatalogued or unidentified) energy signatures highlighted.
    -
    - As well as visualising background energy readings, a hyperspectral imager will isolate and identify any anomalous energy signatures in the sample.
    - Contents - - - + It's perhaps one of the most exciting times to be alive, with the recent breakthroughs in understanding and categorisation of things we may one day no longer call + 'anomalies,' but rather 'infrequent or rare occurrences of certain celestial weather or phenomena.' Perhaps a little more long winded, but no less eloquent all the + same! Why, look at the strides we're making in piercing the walls of bluespace or our steadily improving ability to clarify and stabilise subspace emissions; it's + certainly an exciting time to be alive. For the moment the Hydrolian hasn't seen two spatial anomalies alike but the day will come and it is soon, I can feel it. "} /obj/item/weapon/book/manual/materials_chemistry_analysis - name = "Chemical preparation for materials analysis" + name = "Materials analysis and the chemical implications" icon_state = "chemistry" author = "Jasper Pascal, Senior Lecturer in Materials Analysis at the University of Jol'Nar" - title = "Chemical preparation for materials analysis" + title = "Materials analysis and the chemical implications" dat = {"