diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..87eeb862d56 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +#pretending we're C because otherwise ruby will initialize, even with "language: dm". +language: c + +env: + BYOND_MAJOR="503" + BYOND_MINOR="1224" + +before_install: + - sudo apt-get update -qq + - sudo apt-get install libc6:i386 libgcc1:i386 libstdc++6:i386 -qq + +install: + - curl "http://www.byond.com/download/build/${BYOND_MAJOR}/${BYOND_MAJOR}.${BYOND_MINOR}_byond_linux.zip" -o byond.zip + - unzip byond.zip + - cd byond + - sudo make install + - cd .. + +script: + - DreamMaker baystation12.dme diff --git a/COPYING b/COPYING index 5005fcd90f0..77e1d829ffb 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ Baystation12 -Copyright (C) 2010-2013 Baystation12 and tgstation13. +Copyright (C) 2010-2014 Baystation12 and tgstation13. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/baystation12.dme b/baystation12.dme index aaf9eab8aff..227cf0d3122 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -78,6 +78,8 @@ #include "code\controllers\autotransfer.dm" #include "code\controllers\configuration.dm" #include "code\controllers\failsafe.dm" +#include "code\controllers\hooks-defs.dm" +#include "code\controllers\hooks.dm" #include "code\controllers\lighting_controller.dm" #include "code\controllers\master_controller.dm" #include "code\controllers\shuttle_controller.dm" @@ -176,9 +178,14 @@ #include "code\game\area\ai_monitored.dm" #include "code\game\area\areas.dm" #include "code\game\area\Space Station 13 areas.dm" -#include "code\game\dna\dna.dm" -#include "code\game\dna\dna_misc.dm" +#include "code\game\dna\dna2.dm" +#include "code\game\dna\dna2_domutcheck.dm" +#include "code\game\dna\dna2_helpers.dm" #include "code\game\dna\dna_modifier.dm" +#include "code\game\dna\genes\disabilities.dm" +#include "code\game\dna\genes\gene.dm" +#include "code\game\dna\genes\monkey.dm" +#include "code\game\dna\genes\powers.dm" #include "code\game\gamemodes\events.dm" #include "code\game\gamemodes\factions.dm" #include "code\game\gamemodes\game_mode.dm" @@ -223,6 +230,7 @@ #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" #include "code\game\gamemodes\meteor\meteors.dm" +#include "code\game\gamemodes\ninja\ninja.dm" #include "code\game\gamemodes\nuclear\nuclear.dm" #include "code\game\gamemodes\nuclear\nuclearbomb.dm" #include "code\game\gamemodes\nuclear\pinpointer.dm" @@ -264,6 +272,7 @@ #include "code\game\machinery\cloning.dm" #include "code\game\machinery\constructable_frame.dm" #include "code\game\machinery\cryo.dm" +#include "code\game\machinery\cryopod.dm" #include "code\game\machinery\deployable.dm" #include "code\game\machinery\door_control.dm" #include "code\game\machinery\doppler_array.dm" @@ -436,6 +445,7 @@ #include "code\game\objects\effects\decals\Cleanable\humans.dm" #include "code\game\objects\effects\decals\Cleanable\misc.dm" #include "code\game\objects\effects\decals\Cleanable\robots.dm" +#include "code\game\objects\effects\decals\Cleanable\tracks.dm" #include "code\game\objects\effects\spawners\bombspawner.dm" #include "code\game\objects\effects\spawners\gibspawner.dm" #include "code\game\objects\effects\spawners\vaultspawner.dm" @@ -609,6 +619,7 @@ #include "code\game\objects\structures\crates_lockers\closets\secure\cargo.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\engineering.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\freezer.dm" +#include "code\game\objects\structures\crates_lockers\closets\secure\guncabinet.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\hydroponics.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\medical.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\personal.dm" @@ -651,7 +662,6 @@ #include "code\modules\admin\holder2.dm" #include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\NewBan.dm" -#include "code\modules\admin\newbanjob.dm" #include "code\modules\admin\player_notes.dm" #include "code\modules\admin\player_panel.dm" #include "code\modules\admin\topic.dm" @@ -680,6 +690,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" @@ -776,6 +789,7 @@ #include "code\modules\economy\TradeDestinations.dm" #include "code\modules\events\alien_infestation.dm" #include "code\modules\events\blob.dm" +#include "code\modules\events\borers.dm" #include "code\modules\events\brand_intelligence.dm" #include "code\modules\events\carp_migration.dm" #include "code\modules\events\comms_blackout.dm" @@ -817,6 +831,7 @@ #include "code\modules\maps\reader.dm" #include "code\modules\maps\swapmaps.dm" #include "code\modules\maps\writer.dm" +#include "code\modules\mining\abandonedcrates.dm" #include "code\modules\mining\machine_input_output_plates.dm" #include "code\modules\mining\machine_processing.dm" #include "code\modules\mining\machine_stacking.dm" @@ -824,10 +839,12 @@ #include "code\modules\mining\mine_areas.dm" #include "code\modules\mining\mine_items.dm" #include "code\modules\mining\mine_turfs.dm" +#include "code\modules\mining\minerals.dm" #include "code\modules\mining\mint.dm" #include "code\modules\mining\money_bag.dm" #include "code\modules\mining\ores_coins.dm" #include "code\modules\mining\satchel_ore_boxdm.dm" +#include "code\modules\mob\abilities.dm" #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" #include "code\modules\mob\inventory.dm" @@ -1093,6 +1110,7 @@ #include "code\modules\projectiles\guns\projectile\pistol.dm" #include "code\modules\projectiles\guns\projectile\pneumatic.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" +#include "code\modules\projectiles\guns\projectile\rocket.dm" #include "code\modules\projectiles\guns\projectile\shotgun.dm" #include "code\modules\projectiles\projectile\animate.dm" #include "code\modules\projectiles\projectile\beams.dm" @@ -1123,8 +1141,10 @@ #include "code\modules\reagents\reagent_containers\robodropper.dm" #include "code\modules\reagents\reagent_containers\spray.dm" #include "code\modules\reagents\reagent_containers\syringes.dm" +#include "code\modules\reagents\reagent_containers\food\cans.dm" #include "code\modules\reagents\reagent_containers\food\condiment.dm" #include "code\modules\reagents\reagent_containers\food\drinks.dm" +#include "code\modules\reagents\reagent_containers\food\sandwich.dm" #include "code\modules\reagents\reagent_containers\food\snacks.dm" #include "code\modules\reagents\reagent_containers\food\drinks\bottle.dm" #include "code\modules\reagents\reagent_containers\food\drinks\drinkingglass.dm" @@ -1154,7 +1174,6 @@ #include "code\modules\research\xenoarchaeology\geosample.dm" #include "code\modules\research\xenoarchaeology\manuals.dm" #include "code\modules\research\xenoarchaeology\misc.dm" -#include "code\modules\research\xenoarchaeology\readme.dm" #include "code\modules\research\xenoarchaeology\artifact\artifact.dm" #include "code\modules\research\xenoarchaeology\artifact\artifact_autocloner.dm" #include "code\modules\research\xenoarchaeology\artifact\artifact_crystal.dm" @@ -1190,22 +1209,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" @@ -1238,11 +1253,16 @@ #include "code\modules\surgery\eye.dm" #include "code\modules\surgery\face.dm" #include "code\modules\surgery\generic.dm" +#include "code\modules\surgery\headreattach.dm" #include "code\modules\surgery\implant.dm" #include "code\modules\surgery\other.dm" #include "code\modules\surgery\ribcage.dm" #include "code\modules\surgery\robolimbs.dm" #include "code\modules\surgery\surgery.dm" +#include "code\modules\telesci\bscrystal.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" @@ -1291,15 +1311,16 @@ #include "code\WorkInProgress\Cael_Aislinn\ShieldGen\shield_gen.dm" #include "code\WorkInProgress\Cael_Aislinn\ShieldGen\shield_gen_external.dm" #include "code\WorkInProgress\Cael_Aislinn\Supermatter\LaserComputer.dm" -#include "code\WorkInProgress\Cael_Aislinn\Supermatter\SuperMatter.dm" #include "code\WorkInProgress\Cael_Aislinn\Supermatter\ZeroPointLaser.dm" #include "code\WorkInProgress\Chinsky\ashtray.dm" +#include "code\WorkInProgress\Chinsky\guestpass.dm" #include "code\WorkInProgress\Cib\MedicalSideEffects.dm" #include "code\WorkInProgress\kilakk\fax.dm" #include "code\WorkInProgress\Mini\atmos_control.dm" #include "code\WorkInProgress\Ported\policetape.dm" #include "code\WorkInProgress\SkyMarshal\officer_stuff.dm" #include "code\WorkInProgress\SkyMarshal\Ultralight_procs.dm" +#include "code\WorkInProgress\Yinadele\Supermatter.dm" #include "code\ZAS\Airflow.dm" #include "code\ZAS\Connection.dm" #include "code\ZAS\Debug.dm" diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index 4a633030c28..83f8eb7fcf6 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -338,13 +338,13 @@ return /* - Alt-click to ventcrawl - Monkeys, aliens, and slimes + Alt-click to ventcrawl - Monkeys, aliens, slimes and mice. This is a little buggy but somehow that just seems to plague ventcrawl. I am sorry, I don't know why. */ -/obj/machinery/atmospherics/unary/vent_pump/AltClick(var/mob/living/carbon/ML) +/obj/machinery/atmospherics/unary/vent_pump/AltClick(var/mob/living/ML) if(istype(ML)) - var/list/ventcrawl_verbs = list(/mob/living/carbon/monkey/verb/ventcrawl, /mob/living/carbon/alien/verb/ventcrawl, /mob/living/carbon/slime/verb/ventcrawl) + var/list/ventcrawl_verbs = list(/mob/living/carbon/monkey/verb/ventcrawl, /mob/living/carbon/alien/verb/ventcrawl, /mob/living/carbon/slime/verb/ventcrawl,/mob/living/simple_animal/mouse/verb/ventcrawl) if(length(ML.verbs & ventcrawl_verbs)) // alien queens have this removed, an istype would be complicated ML.handle_ventcrawl(src) return diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index 5ade345e08f..3501b606d5a 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -149,10 +149,6 @@ datum/pipeline air.merge(air_sample) //turf_air already modified by equalize_gases() - if(istype(target) && !target.processing) - if(target.air) - if(target.air.check_tile_graphic()) - target.update_visuals(target.air) if(network) network.update = 1 diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index ed755aac990..ace4cd5670a 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) @@ -1130,7 +1130,7 @@ obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/u var/datum/gas_mixture/int_air = return_air() var/datum/gas_mixture/env_air = loc.return_air() if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + user << "You cannot unwrench [src], it is too exerted due to internal pressure." add_fingerprint(user) return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm index 43292f02f2d..20009c0a64b 100644 --- a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm +++ b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm @@ -204,7 +204,7 @@ var/obj/structure/closet/crate/freezer/C = new(src.loc) var/num = rand(2,6) var/new_type = pick( - /obj/item/weapon/reagent_containers/food/drinks/beer, \ + /obj/item/weapon/reagent_containers/food/drinks/cans/beer, \ /obj/item/weapon/reagent_containers/food/drinks/tea, \ /obj/item/weapon/reagent_containers/food/drinks/dry_ramen, \ /obj/item/weapon/reagent_containers/food/snacks/candiedapple, \ diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/areas.dm b/code/WorkInProgress/Cael_Aislinn/Rust/areas.dm index 6183ed04f67..f3a9a4ea1c6 100644 --- a/code/WorkInProgress/Cael_Aislinn/Rust/areas.dm +++ b/code/WorkInProgress/Cael_Aislinn/Rust/areas.dm @@ -10,9 +10,6 @@ construction_storage name = "\improper Construction storage" - locker - name = "\improper Locker room" - atmos_storage name = "\improper Atmos storage" icon_state = "engine_storage" @@ -69,7 +66,11 @@ //icon_state = "engine_portgyro" storage - name = "\improper Engineering hallway" + name = "\improper Engineering Storage" + icon_state = "engine_storage" + + storage_hard + name = "\improper Engineering Hard Storage" icon_state = "engine_storage" hallway 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/Cael_Aislinn/Supermatter/SuperMatter.dm b/code/WorkInProgress/Cael_Aislinn/Supermatter/SuperMatter.dm deleted file mode 100644 index fd3bf8eea6e..00000000000 --- a/code/WorkInProgress/Cael_Aislinn/Supermatter/SuperMatter.dm +++ /dev/null @@ -1,186 +0,0 @@ -#define NITROGEN_RETARDATION_FACTOR 12 //Higher == N2 slows reaction more -#define THERMAL_RELEASE_MODIFIER 0.55 //Percentage of output power given to heat generation. - -#define PLASMA_RELEASE_MODIFIER 0.24 //Percentage of output power given to plasma generation. -#define PLASMA_CONVERSION_FACTOR 50 //How much energy per mole of plasma -#define MAX_PLASMA_RELATIVE_INCREASE 0.3 //Percentage of current plasma amounts that can be added to preexisting plasma. - -#define OXYGEN_RELEASE_MODIFIER 0.13 //Percentage of output power given to oxygen generation. -#define OXYGEN_CONVERSION_FACTOR 150 //How much energy per mole of oxygen. -#define MAX_OXYGEN_RELATIVE_INCREASE 0.2 //Percentage of current oxygen amounts that can be added to preexisting oxygen. - -#define RADIATION_POWER_MODIFIER 0.03 //How much power goes to irradiating the area. -#define RADIATION_FACTOR 10 -#define HALLUCINATION_POWER_MODIFIER 0.05 //How much power goes to hallucinations. -#define HALLUCINATION_FACTOR 20 - -#define REACTION_POWER_MODIFIER 4 //Higher == more overall power - -#define WARNING_DELAY 45 //45 seconds between warnings. - -/obj/machinery/power/supermatter - name = "Supermatter" - desc = "A strangely translucent and iridescent crystal. \red You get headaches just from looking at it." - icon = 'icons/obj/engine.dmi' - icon_state = "darkmatter" - density = 1 - anchored = 0 - - var/gasefficency = 0.25 - - var/base_icon_state = "darkmatter" - - var/damage = 0 - var/damage_archived = 0 - var/safe_alert = "Crystaline hyperstructure returning to safe operating levels." - var/warning_point = 100 - var/warning_alert = "Danger! Crystal hyperstructure instability!" - var/emergency_point = 700 - var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT" - var/explosion_point = 1000 - - var/emergency_issued = 0 - - var/explosion_power = 8 - - var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning - - var/power = 0 - - - shard //Small subtype, less efficient and more sensitive, but less boom. - name = "Supermatter Shard" - desc = "A strangely translucent and iridescent crystal. Looks like it used to be part of a larger structure. \red You get headaches just from looking at it." - icon_state = "darkmatter_shard" - base_icon_state = "darkmatter_shard" - - warning_point = 50 - emergency_point = 500 - explosion_point = 900 - - gasefficency = 0.125 - - explosion_power = 3 //3,6,9,12? Or is that too small? - - - process() - - var/turf/L = loc - - if(!istype(L)) //If we are not on a turf, uh oh. - del src - - //Ok, get the air from the turf - var/datum/gas_mixture/env = L.return_air() - - //Remove gas from surrounding area - var/datum/gas_mixture/removed = env.remove(gasefficency * env.total_moles) - - if (!removed) - return 1 - - if(damage > warning_point) // while the core is still damaged and it's still worth noting its status - if((world.timeofday - lastwarning) / 10 >= WARNING_DELAY) - - if(damage > emergency_point) - //radioalert("states, \"[emergency_alert]\"","Supermatter Monitor") - lastwarning = world.timeofday - else if(damage >= damage_archived) // The damage is still going up - //radioalert("states, \"[warning_alert]\"","Supermatter Monitor") - lastwarning = world.timeofday-150 - else // Phew, we're safe - //radioalert("states, \"[safe_alert]\"","Supermatter Monitor") - lastwarning = world.timeofday - - if(damage > explosion_point) - explosion(loc,explosion_power,explosion_power*2,explosion_power*3,explosion_power*4,1) - del src - - damage_archived = damage - damage = max( damage + ( (removed.temperature - 800) / 150 ) , 0 ) - - if(!removed.total_moles) - damage += max((power-1600)/10,0) - power = max(power,1600) - return 1 - - var/nitrogen_mod = abs((removed.nitrogen / removed.total_moles)) * NITROGEN_RETARDATION_FACTOR - var/oxygen = max(min(removed.oxygen / removed.total_moles - nitrogen_mod, 1), 0) - - var/temp_factor = 0 - if(oxygen > 0.8) - // with a perfect gas mix, make the power less based on heat - temp_factor = 100 - icon_state = "[base_icon_state]_glow" - else - // in normal mode, base the produced energy around the heat - temp_factor = 60 - icon_state = base_icon_state - - //Calculate power released as heat and gas, in as the sqrt of the power. - var/power_factor = (power/500) ** 3 - var/device_energy = oxygen * power_factor - power = max(round((removed.temperature - T0C) / temp_factor) + power - power_factor, 0) //Total laser power plus an overload factor - - //Final energy calcs. - device_energy = max(device_energy * REACTION_POWER_MODIFIER,0) - - //To figure out how much temperature to add each tick, consider that at one atmosphere's worth - //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature - //that the device energy is around 2140. At that stage, we don't want too much heat to be put out - //Since the core is effectively "cold" - - //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock - //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall. - - var/plasma_energy = device_energy * PLASMA_RELEASE_MODIFIER - var/oxygen_energy = device_energy * OXYGEN_RELEASE_MODIFIER - var/other_energy = device_energy * (1- (OXYGEN_RELEASE_MODIFIER + PLASMA_RELEASE_MODIFIER)) - - //Put as much plasma out as is permitted. - if( plasma_energy > removed.total_moles * PLASMA_CONVERSION_FACTOR * MAX_PLASMA_RELATIVE_INCREASE / gasefficency) - removed.toxins += (MAX_PLASMA_RELATIVE_INCREASE * removed.total_moles / gasefficency) - other_energy += plasma_energy - (removed.total_moles * PLASMA_CONVERSION_FACTOR * MAX_PLASMA_RELATIVE_INCREASE / gasefficency) - else - removed.toxins += plasma_energy/PLASMA_CONVERSION_FACTOR - - //Put as much plasma out as is permitted. - if( oxygen_energy > removed.total_moles * OXYGEN_CONVERSION_FACTOR * MAX_OXYGEN_RELATIVE_INCREASE / gasefficency) - removed.oxygen += (MAX_OXYGEN_RELATIVE_INCREASE * removed.total_moles / gasefficency) - other_energy += oxygen_energy - (removed.total_moles * OXYGEN_CONVERSION_FACTOR * MAX_OXYGEN_RELATIVE_INCREASE / gasefficency) - else - removed.oxygen += oxygen_energy/OXYGEN_CONVERSION_FACTOR - - - var/heat_energy = (other_energy*THERMAL_RELEASE_MODIFIER)/(1-(OXYGEN_RELEASE_MODIFIER + PLASMA_RELEASE_MODIFIER)) - var/hallucination_energy = (other_energy*HALLUCINATION_POWER_MODIFIER*HALLUCINATION_FACTOR)/(1-(OXYGEN_RELEASE_MODIFIER + PLASMA_RELEASE_MODIFIER)) - var/rad_energy = (other_energy*RADIATION_POWER_MODIFIER*RADIATION_FACTOR)/(1-(OXYGEN_RELEASE_MODIFIER + PLASMA_RELEASE_MODIFIER)) - - var/heat_applied = max(heat_energy,0) - if(heat_applied + removed.temperature > 800) - removed.temperature = 800 - var/energy_to_reconsider = (heat_applied + removed.temperature - 800) - hallucination_energy += (energy_to_reconsider*HALLUCINATION_POWER_MODIFIER)/(HALLUCINATION_POWER_MODIFIER+RADIATION_POWER_MODIFIER) - rad_energy += (energy_to_reconsider*RADIATION_POWER_MODIFIER)/(HALLUCINATION_POWER_MODIFIER+RADIATION_POWER_MODIFIER) - else - removed.temperature += heat_applied - - removed.update_values() - - env.merge(removed) - - for(var/mob/living/carbon/human/l in view(src, round(hallucination_energy**0.25))) // you have to be seeing the core to get hallucinations - if(prob(10) && !istype(l.glasses, /obj/item/clothing/glasses/meson)) - l.hallucination += hallucination_energy/((get_dist(l,src)**2)) - - for(var/mob/living/l in range(src,round(rad_energy**0.25))) - var/rads = rad_energy/((get_dist(l,src)**2)) - l.apply_effect(rads, IRRADIATE) - - return 1 - - - bullet_act(var/obj/item/projectile/Proj) - if(Proj.flag != "bullet") - power += Proj.damage - return 0 \ No newline at end of file diff --git a/code/WorkInProgress/Chinsky/ashtray.dm b/code/WorkInProgress/Chinsky/ashtray.dm index ab3a6362515..5ec88ac8bdf 100644 --- a/code/WorkInProgress/Chinsky/ashtray.dm +++ b/code/WorkInProgress/Chinsky/ashtray.dm @@ -17,35 +17,34 @@ /obj/item/ashtray/attackby(obj/item/weapon/W as obj, mob/user as mob) if (health < 1) return - if (istype(W,/obj/item/clothing/mask/cigarette) || istype(W, /obj/item/weapon/match)) - if(user) - if (contents.len >= max_butts) - user << "This ashtray is full." - return - user.u_equip(W) - W.loc = src - if ((user.client && user.s_active != src)) - user.client.screen -= W + if (istype(W,/obj/item/weapon/cigbutt) || istype(W,/obj/item/clothing/mask/cigarette) || istype(W, /obj/item/weapon/match)) + if (contents.len >= max_butts) + user << "This ashtray is full." + return + user.u_equip(W) + W.loc = src + + if (istype(W,/obj/item/clothing/mask/cigarette)) var/obj/item/clothing/mask/cigarette/cig = W if (cig.lit == 1) src.visible_message("[user] crushes [cig] in [src], putting it out.") - cig.smoketime = 0 + processing_objects.Remove(cig) + var/obj/item/butt = new cig.type_butt(src) + cig.transfer_fingerprints_to(butt) + del(cig) else if (cig.lit == 0) - if(istype(cig, /obj/item/weapon/match)) - user << "You place [cig] in [src] without even lighting it. Why would you do that?" - else - user << "You place [cig] in [src] without even smoking it. Why would you do that?" - else if (cig.lit == -1) - src.visible_message("[user] places [cig] in [src].") - user.update_inv_l_hand() - user.update_inv_r_hand() - add_fingerprint(user) - if (contents.len == max_butts) - icon_state = icon_full - desc = empty_desc + " It's stuffed full." - else if (contents.len > max_butts/2) - icon_state = icon_half - desc = empty_desc + " It's half-filled." + user << "You place [cig] in [src] without even smoking it. Why would you do that?" + + src.visible_message("[user] places [W] in [src].") + user.update_inv_l_hand() + user.update_inv_r_hand() + add_fingerprint(user) + if (contents.len == max_butts) + icon_state = icon_full + desc = empty_desc + " It's stuffed full." + else if (contents.len > max_butts/2) + icon_state = icon_half + desc = empty_desc + " It's half-filled." else health = max(0,health - W.force) user << "You hit [src] with [W]." @@ -62,7 +61,6 @@ if (contents.len) src.visible_message("\red [src] slams into [hit_atom] spilling its contents!") for (var/obj/item/clothing/mask/cigarette/O in contents) - contents -= O O.loc = src.loc icon_state = icon_empty return ..() @@ -70,7 +68,6 @@ /obj/item/ashtray/proc/die() src.visible_message("\red [src] shatters spilling its contents!") for (var/obj/item/clothing/mask/cigarette/O in contents) - contents -= O O.loc = src.loc icon_state = icon_broken diff --git a/code/WorkInProgress/Chinsky/guestpass.dm b/code/WorkInProgress/Chinsky/guestpass.dm new file mode 100644 index 00000000000..8a959c5b76a --- /dev/null +++ b/code/WorkInProgress/Chinsky/guestpass.dm @@ -0,0 +1,186 @@ +///////////////////////////////////////////// +//Guest pass //////////////////////////////// +///////////////////////////////////////////// +/obj/item/weapon/card/id/guest + name = "guest pass" + desc = "Allows temporary access to station areas." + icon_state = "guest" + + var/temp_access = list() //to prevent agent cards stealing access as permanent + var/expiration_time = 0 + var/reason = "NOT SPECIFIED" + +/obj/item/weapon/card/id/guest/GetAccess() + if (world.time > expiration_time) + return access + else + return temp_access + +/obj/item/weapon/card/id/guest/examine() + ..() + if (world.time < expiration_time) + usr << "\blue This pass expires at [worldtime2text(expiration_time)]." + else + usr << "\red It expired at [worldtime2text(expiration_time)]." + +/obj/item/weapon/card/id/guest/read() + if (world.time > expiration_time) + usr << "This pass expired at [worldtime2text(expiration_time)]." + else + usr << "This pass expires at [worldtime2text(expiration_time)]." + + usr << "It grants access to following areas:" + for (var/A in temp_access) + usr << "[get_access_desc(A)]." + usr << "Issuing reason: [reason]." + return + +///////////////////////////////////////////// +//Guest pass terminal//////////////////////// +///////////////////////////////////////////// + +/obj/machinery/computer/guestpass + name = "guest pass terminal" + icon_state = "guest" + density = 0 + + + var/obj/item/weapon/card/id/giver + var/list/accesses = list() + var/giv_name = "NOT SPECIFIED" + var/reason = "NOT SPECIFIED" + var/duration = 0 + + var/list/internal_log = list() + var/mode = 0 // 0 - making pass, 1 - viewing logs + +/obj/machinery/computer/guestpass/New() + ..() + uid = "[rand(100,999)]-G[rand(10,99)]" + +/obj/machinery/computer/guestpass/attackby(obj/O, mob/user) + if(istype(O, /obj/item/weapon/card/id)) + user.drop_item() + O.loc = src + giver = O + updateUsrDialog() + +/obj/machinery/computer/guestpass/attack_ai(var/mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/guestpass/attack_paw(var/mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/guestpass/attack_hand(var/mob/user as mob) + if(..()) + return + + user.set_machine(src) + var/dat + + if (mode == 1) //Logs + dat += "

Activity log


" + for (var/entry in internal_log) + dat += "[entry]

" + dat += "Print
" + dat += "Back
" + else + dat += "

Guest pass terminal #[uid]


" + dat += "View activity log

" + dat += "Issuing ID: [giver]
" + dat += "Issued to: [giv_name]
" + dat += "Reason: [reason]
" + dat += "Duration (minutes): [duration] m
" + dat += "Access to areas:
" + if (giver && giver.access) + for (var/A in giver.access) + var/area = get_access_desc(A) + if (A in accesses) + area = "[area]" + dat += "[area]
" + dat += "
Issue pass
" + + user << browse(dat, "window=guestpass;size=400x520") + onclose(user, "guestpass") + + +/obj/machinery/computer/guestpass/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + if (href_list["mode"]) + mode = text2num(href_list["mode"]) + + if (href_list["choice"]) + switch(href_list["choice"]) + if ("giv_name") + var/nam = input("Person pass is issued to", "Name", name) + if (nam) + giv_name = nam + if ("reason") + var/reas = input("Reason why pass is issued", "Reason", reason) + reason = reas + if ("duration") + var/dur = input("Duration (in minutes) during which pass is valid.", "Duration") as num + if (dur > 0 && dur < 30) + duration = dur + else + usr << "\red Invalid duration." + if ("access") + var/A = text2num(href_list["access"]) + if (A in accesses) + accesses.Remove(A) + else + accesses.Add(A) + if (href_list["action"]) + switch(href_list["action"]) + if ("id") + if (giver) + if(ishuman(usr)) + giver.loc = usr.loc + if(!usr.get_active_hand()) + usr.put_in_hands(giver) + giver = null + else + giver.loc = src.loc + giver = null + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + giver = I + updateUsrDialog() + + if ("print") + var/dat = "

Activity log of guest pass terminal #[uid]


" + for (var/entry in internal_log) + dat += "[entry]

" + //usr << "Printing the log, standby..." + //sleep(50) + var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc ) + P.name = "activity log" + P.info = dat + + if ("issue") + if (giver) + var/number = add_zero("[rand(0,9999)]", 4) + var/entry = "\[[worldtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: " + for (var/i=1 to accesses.len) + var/A = accesses[i] + if (A) + var/area = get_access_desc(A) + entry += "[i > 1 ? ", [area]" : "[area]"]" + entry += ". Expires at [worldtime2text(world.time + duration*10*60)]." + internal_log.Add(entry) + + var/obj/item/weapon/card/id/guest/pass = new(src.loc) + pass.temp_access = accesses.Copy() + pass.registered_name = giv_name + pass.expiration_time = world.time + duration*10*60 + pass.reason = reason + pass.name = "guest pass #[number]" + else + usr << "\red Cannot issue pass without issuing ID." + updateUsrDialog() + return \ No newline at end of file diff --git a/code/WorkInProgress/Cib/MedicalSideEffects.dm b/code/WorkInProgress/Cib/MedicalSideEffects.dm index 15580c4bd2e..62f9cf75f80 100644 --- a/code/WorkInProgress/Cib/MedicalSideEffects.dm +++ b/code/WorkInProgress/Cib/MedicalSideEffects.dm @@ -83,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) 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/Yinadele/Supermatter.dm b/code/WorkInProgress/Yinadele/Supermatter.dm new file mode 100644 index 00000000000..7765393bb1d --- /dev/null +++ b/code/WorkInProgress/Yinadele/Supermatter.dm @@ -0,0 +1,265 @@ + +#define NITROGEN_RETARDATION_FACTOR 4 //Higher == N2 slows reaction more +#define THERMAL_RELEASE_MODIFIER 10 //Higher == less heat released during reaction +#define PLASMA_RELEASE_MODIFIER 1500 //Higher == less plasma released by reaction +#define OXYGEN_RELEASE_MODIFIER 750 //Higher == less oxygen released at high temperature/power +#define REACTION_POWER_MODIFIER 1.1 //Higher == more overall power + + +//These would be what you would get at point blank, decreases with distance +#define DETONATION_RADS 200 +#define DETONATION_HALLUCINATION 600 + + +#define WARNING_DELAY 60 //45 seconds between warnings. + +/obj/machinery/power/supermatter + name = "Supermatter" + desc = "A strangely translucent and iridescent crystal. \red You get headaches just from looking at it." + icon = 'icons/obj/engine.dmi' + icon_state = "darkmatter" + density = 1 + anchored = 0 + + var/gasefficency = 0.25 + + var/base_icon_state = "darkmatter" + + var/damage = 0 + var/damage_archived = 0 + var/safe_alert = "Crystaline hyperstructure returning to safe operating levels." + var/warning_point = 100 + var/warning_alert = "Danger! Crystal hyperstructure instability!" + var/emergency_point = 700 + var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT." + var/explosion_point = 1000 + + var/emergency_issued = 0 + + var/explosion_power = 8 + + var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning + + var/power = 0 + + //Temporary values so that we can optimize this + //How much the bullets damage should be multiplied by when it is added to the internal variables + var/config_bullet_energy = 2 + //How much of the power is left after processing is finished? +// var/config_power_reduction_per_tick = 0.5 + //How much hallucination should it produce per unit of power? + var/config_hallucination_power = 0.1 + + var/obj/item/device/radio/radio + + shard //Small subtype, less efficient and more sensitive, but less boom. + name = "Supermatter Shard" + desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. \red You get headaches just from looking at it." + icon_state = "darkmatter_shard" + base_icon_state = "darkmatter_shard" + + warning_point = 50 + emergency_point = 500 + explosion_point = 900 + + gasefficency = 0.125 + + explosion_power = 3 //3,6,9,12? Or is that too small? + + +/obj/machinery/power/supermatter/New() + . = ..() + radio = new (src) + + +/obj/machinery/power/supermatter/Del() + del radio + . = ..() + +/obj/machinery/power/supermatter/proc/explode() + explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1) + del src + return + +/obj/machinery/power/supermatter/process() + + var/turf/L = loc + + if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity. + return PROCESS_KILL + + if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now. + return //Yeah just stop. + + if(damage > warning_point) // while the core is still damaged and it's still worth noting its status + if((world.timeofday - lastwarning) / 10 >= WARNING_DELAY) + + if(damage > emergency_point) + radio.autosay(emergency_alert, "Supermatter Monitor") + lastwarning = world.timeofday + + else if(damage >= damage_archived) // The damage is still going up + radio.autosay(warning_alert, "Supermatter Monitor") + lastwarning = world.timeofday - 150 + + else // Phew, we're safe + radio.autosay(safe_alert, "Supermatter Monitor") + lastwarning = world.timeofday + + if(damage > explosion_point) + for(var/mob/living/mob in living_mob_list) + if(istype(mob, /mob/living/carbon/human)) + //Hilariously enough, running into a closet should make you get hit the hardest. + mob:hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) ) + var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(mob, src) + 1) ) + mob.apply_effect(rads, IRRADIATE) + + explode() + + //Ok, get the air from the turf + var/datum/gas_mixture/env = L.return_air() + + //Remove gas from surrounding area + var/datum/gas_mixture/removed = env.remove(gasefficency * env.total_moles) + + if(!removed || !removed.total_moles) + damage += max((power-1600)/10, 0) + power = min(power, 1600) + return 1 + + if (!removed) + return 1 + + damage_archived = damage + damage = max( damage + ( (removed.temperature - 800) / 150 ) , 0 ) + //Ok, 100% oxygen atmosphere = best reaction + //Maxes out at 100% oxygen pressure + var/oxygen = max(min((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / MOLES_CELLSTANDARD, 1), 0) + + var/temp_factor = 100 + + if(oxygen > 0.8) + // with a perfect gas mix, make the power less based on heat + icon_state = "[base_icon_state]_glow" + else + // in normal mode, base the produced energy around the heat + temp_factor = 60 + icon_state = base_icon_state + + power = max( (removed.temperature * temp_factor / T0C) * oxygen + power, 0) //Total laser power plus an overload + + //We've generated power, now let's transfer it to the collectors for storing/usage + transfer_energy() + + var/device_energy = power * REACTION_POWER_MODIFIER + + //To figure out how much temperature to add each tick, consider that at one atmosphere's worth + //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature + //that the device energy is around 2140. At that stage, we don't want too much heat to be put out + //Since the core is effectively "cold" + + //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock + //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall. + removed.temperature += (device_energy / THERMAL_RELEASE_MODIFIER) + + removed.temperature = max(0, min(removed.temperature, 2500)) + + //Calculate how much gas to release + removed.toxins += max(device_energy / PLASMA_RELEASE_MODIFIER, 0) + + removed.oxygen += max((device_energy + removed.temperature - T0C) / OXYGEN_RELEASE_MODIFIER, 0) + + removed.update_values() + + env.merge(removed) + + for(var/mob/living/carbon/human/l in view(src, round(power ** 0.25))) // you have to be seeing the core to get hallucinations + if(!istype(l.glasses, /obj/item/clothing/glasses/meson)) + l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)) ) ) ) + + for(var/mob/living/l in range(src, round((power / 100) ** 0.25))) + var/rads = (power / 10) * sqrt( 1 / get_dist(l, src) ) + l.apply_effect(rads, IRRADIATE) + + power -= (power/500)**3 + + return 1 + + +/obj/machinery/power/supermatter/bullet_act(var/obj/item/projectile/Proj) + if(Proj.flag != "bullet") + power += Proj.damage * config_bullet_energy + else + damage += Proj.damage * config_bullet_energy + return 0 + + +/obj/machinery/power/supermatter/attack_paw(mob/user as mob) + return attack_hand(user) + + +/obj/machinery/power/supermatter/attack_robot(mob/user as mob) + if(Adjacent(user)) + return attack_hand(user) + else + user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update." + return + +/obj/machinery/power/supermatter/attack_ai(mob/user as mob) + user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update." + +/obj/machinery/power/supermatter/attack_hand(mob/user as mob) + user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\ + "You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"",\ + "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") + + Consume(user) + +/obj/machinery/power/supermatter/proc/transfer_energy() + for(var/obj/machinery/power/rad_collector/R in rad_collectors) + if(get_dist(R, src) <= 15) // Better than using orange() every process + R.receive_pulse(power) + return + +/obj/machinery/power/supermatter/attackby(obj/item/weapon/W as obj, mob/living/user as mob) + user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\ + "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\ + "Everything suddenly goes silent.") + + user.drop_from_inventory(W) + Consume(W) + + user.apply_effect(150, IRRADIATE) + + +/obj/machinery/power/supermatter/Bumped(atom/AM as mob|obj) + if(istype(AM, /mob/living)) + AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\ + "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\ + "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.") + else + AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\ + "You hear a loud crack as you are washed with a wave of heat.") + + Consume(AM) + + +/obj/machinery/power/supermatter/proc/Consume(var/mob/living/user) + if(istype(user)) + user.dust() + power += 200 + else + del user + + power += 200 + + //Some poor sod got eaten, go ahead and irradiate people nearby. + for(var/mob/living/l in range(10)) + if(l in view()) + l.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\ + "The unearthly ringing subsides and you notice you have new radiation burns.", 2) + else + l.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2) + var/rads = 500 * sqrt( 1 / (get_dist(l, src) + 1) ) + l.apply_effect(rads, IRRADIATE) + diff --git a/code/WorkInProgress/buildmode.dm b/code/WorkInProgress/buildmode.dm index 28beed7f049..ceb1954a5d8 100644 --- a/code/WorkInProgress/buildmode.dm +++ b/code/WorkInProgress/buildmode.dm @@ -120,7 +120,7 @@ screen_loc = "NORTH,WEST+2" var/varholder = "name" var/valueholder = "derp" - var/objholder = "/obj/structure/closet" + var/objholder = /obj/structure/closet Click(location, control, params) var/list/pa = params2list(params) @@ -145,13 +145,13 @@ if(1) return 1 if(2) - objholder = input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet") - var/list/removed_paths = list("/obj/effect/bhole") - if(objholder in removed_paths) + objholder = text2path(input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet")) + if(!ispath(objholder)) + objholder = /obj/structure/closet alert("That path is not allowed.") - objholder = "/obj/structure/closet" - else if (dd_hasprefix(objholder, "/mob") && !check_rights(R_DEBUG,0)) - objholder = "/obj/structure/closet" + else + if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0)) + objholder = /obj/structure/closet if(3) var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine") @@ -234,8 +234,12 @@ WIN.dir = NORTHWEST if(2) if(pa.Find("left")) - var/obj/A = new holder.buildmode.objholder (get_turf(object)) - A.dir = holder.builddir.dir + if(ispath(holder.buildmode.objholder,/turf)) + var/turf/T = get_turf(object) + T.ChangeTurf(holder.buildmode.objholder) + else + var/obj/A = new holder.buildmode.objholder (get_turf(object)) + A.dir = holder.builddir.dir else if(pa.Find("right")) if(isobj(object)) del(object) diff --git a/code/WorkInProgress/carn/master_controller_semi-seq.dm b/code/WorkInProgress/carn/master_controller_semi-seq.dm index 96e7eacda6e..0f9b4f666d9 100644 --- a/code/WorkInProgress/carn/master_controller_semi-seq.dm +++ b/code/WorkInProgress/carn/master_controller_semi-seq.dm @@ -50,7 +50,7 @@ datum/controller/game_controller/New() if(!syndicate_code_response) syndicate_code_response = generate_code_phrase() if(!ticker) ticker = new /datum/controller/gameticker() if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle() - + if(artifact_spawn) artifact_spawning_turfs = artifact_spawn datum/controller/game_controller/proc/setup() world.tick_lag = config.Ticklag 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..0d8f4cdde1f 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,18 +93,29 @@ /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"]) if(tofax) - tofax.loc = usr.loc - usr.put_in_hands(tofax) - usr << "You take the paper out of \the [src]." - tofax = null + if(!ishuman(usr)) + usr << "You can't do it." + else + tofax.loc = usr.loc + usr.put_in_hands(tofax) + usr << "You take the paper out of \the [src]." + tofax = null if(href_list["scan"]) if (scan) @@ -107,6 +135,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 +179,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/Debug.dm b/code/ZAS/Debug.dm index 5ac704cf9fa..39f5a7caabd 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -134,6 +134,7 @@ zone/proc/DebugDisplay(client/client) client/proc/TestZASRebuild() + set category = "Debug" // var/turf/turf = get_turf(mob) var/zone/current_zone = mob.loc:zone if(!current_zone) @@ -155,7 +156,7 @@ client/proc/TestZASRebuild() for(var/direction in cardinal) var/turf/simulated/adjacent = get_step(current, direction) - if(!current.ZAirPass(adjacent)) + if(!current.ZCanPass(adjacent)) continue if(turfs.Find(adjacent)) current_adjacents += adjacent @@ -210,4 +211,9 @@ client/proc/TestZASRebuild() for(var/turf/current in turfs) current.overlays -= overlays - return final_arrangement \ No newline at end of file + return final_arrangement + +/client/proc/ZASSettings() + set category = "Debug" + + vsc.SetDefault(mob) \ No newline at end of file diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm index 3eccad7e913..9a829633e2b 100644 --- a/code/ZAS/FEA_gas_mixture.dm +++ b/code/ZAS/FEA_gas_mixture.dm @@ -14,6 +14,20 @@ What are the archived variables for? #define QUANTIZE(variable) (round(variable,0.0001)) #define TRANSFER_FRACTION 5 //What fraction (1/#) of the air difference to try and transfer +/hook/startup/proc/createGasOverlays() + plmaster = new /obj/effect/overlay() + plmaster.icon = 'icons/effects/tile_effects.dmi' + plmaster.icon_state = "plasma" + plmaster.layer = FLY_LAYER + plmaster.mouse_opacity = 0 + + slmaster = new /obj/effect/overlay() + slmaster.icon = 'icons/effects/tile_effects.dmi' + slmaster.icon_state = "sleeping_agent" + slmaster.layer = FLY_LAYER + slmaster.mouse_opacity = 0 + return 1 + /datum/gas/sleeping_agent/specific_heat = 40 //These are used for the "Trace Gases" stuff, but is buggy. /datum/gas/oxygen_agent_b/specific_heat = 300 diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index a40746f52f6..ddc06106f38 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -75,12 +75,12 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) //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) + if(air_contents.oxygen < 0.1) air_contents.oxygen = 0 - if(air_contents.toxins < 0.001) + if(air_contents.toxins < 0.1) air_contents.toxins = 0 if(fuel) - if(fuel.moles < 0.001) + if(fuel.moles < 0.1) air_contents.trace_gases.Remove(fuel) //check if there is something to combust @@ -200,7 +200,7 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc if(liquid) //Liquid Fuel - if(liquid.amount <= 0) + if(liquid.amount <= 0.1) del liquid else total_fuel += liquid.amount @@ -257,9 +257,9 @@ datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_ if(oxygen && (toxins || fuel || liquid)) if(liquid) return 1 - if (toxins) + if(toxins >= 0.1) return 1 - if(fuel) + if(fuel && fuel.moles >= 0.1) return 1 return 0 @@ -272,9 +272,9 @@ datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fu if(oxygen && (toxins || fuel || liquid)) if(liquid) return 1 - if (toxins >= 0.7) + if (toxins >= 0.1) return 1 - if(fuel && fuel.moles >= 1.4) + if(fuel && fuel.moles >= 0.1) return 1 return 0 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 5dd951fe52e..92841a02dcd 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -67,7 +67,7 @@ var/global/vs_control/vsc = new var/connection_insulation = 1 var/connection_insulation_NAME = "Connections - Insulation" - var/connection_insulation_DESC = "How insulative a connection is, in terms of heat transfer. 1 is perfectly insulative, and 0 is perfectly conductive." + var/connection_insulation_DESC = "Boolean, should doors forbid heat transfer?" var/connection_temperature_delta = 10 var/connection_temperature_delta_NAME = "Connections - Temperature Difference" @@ -288,6 +288,7 @@ var/global/vs_control/vsc = new airflow_speed_decay = 1 airflow_delay = 20 airflow_mob_slowdown = 3 + connection_insulation = 0 world << "\blue [key_name(user)] changed the global plasma/ZAS settings to \"[def]\"" diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm index 12ac2df2445..43ea2887627 100644 --- a/code/ZAS/ZAS_Turfs.dm +++ b/code/ZAS/ZAS_Turfs.dm @@ -39,8 +39,6 @@ /turf/simulated/var/tmp/datum/gas_mixture/air -/turf/simulated/var/tmp/processing = 1 - /turf/simulated/var/tmp/air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update /turf/simulated/var/tmp/unsim_check_directions = 0 //See above. @@ -61,8 +59,6 @@ overlays.Add(slmaster) /turf/simulated/New() - ..() - if(!blocks_air) air = new @@ -84,6 +80,8 @@ if(istype(target)) air_master.tiles_to_update |= target + . = ..() + /turf/simulated/Del() if(active_hotspot) del(active_hotspot) @@ -168,23 +166,73 @@ if(src in air_master.turfs_with_connections) air_master.AddConnectionToCheck(air_master.turfs_with_connections[src]) - if(zone && CanPass(null, src, 0, 0)) - + if(zone && !air_master.zones_needing_rebuilt.Find(zone)) for(var/direction in cardinal) var/turf/T = get_step(src,direction) if(!istype(T)) continue - //I can connect to air or space in this direction - if((air_check_directions & direction && !(air_directions_archived & direction)) || \ - (unsim_check_directions & direction && !(unsim_directions_archived & direction))) - ZConnect(src,T) - zone.ActivateIfNeeded() - if(T.zone) T.zone.ActivateIfNeeded() + //I can connect to air in this direction + if(air_check_directions & direction || unsim_check_directions & direction) + + //If either block air, we must look to see if the adjacent turfs need rebuilt. + if(!CanPass(null, T, 0, 0)) + + //Target blocks air + if(!T.CanPass(null, T, 0, 0)) + var/turf/NT = get_step(T, direction) + + //If that turf is in my zone still, rebuild. + if(istype(NT,/turf/simulated) && NT in zone.contents) + air_master.zones_needing_rebuilt.Add(zone) + + //If that is an unsimulated tile in my zone, see if we need to rebuild or just remove. + else if(istype(NT) && NT in zone.unsimulated_tiles) + var/consider_rebuild = 0 + for(var/d in cardinal) + var/turf/UT = get_step(NT,d) + if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild + consider_rebuild = 1 + break + if(consider_rebuild) + air_master.zones_needing_rebuilt.Add(zone) //Gotta check if we need to rebuild, dammit + else + zone.RemoveTurf(NT) //Not adjacent to anything, and unsimulated. Goodbye~ + + //To make a closed connection through closed door. + ZConnect(T, src) + + //If I block air. + else if(T.zone && !air_master.zones_needing_rebuilt.Find(T.zone)) + var/turf/NT = get_step(src, reverse_direction(direction)) + + //If I am splitting a zone, rebuild. + if(istype(NT,/turf/simulated) && (NT in T.zone.contents || (NT.zone && T in NT.zone.contents))) + air_master.zones_needing_rebuilt.Add(T.zone) + + //If NT is unsimulated, parse if I should remove it or rebuild. + else if(istype(NT) && NT in T.zone.unsimulated_tiles) + var/consider_rebuild = 0 + for(var/d in cardinal) + var/turf/UT = get_step(NT,d) + if(istype(UT, /turf/simulated) && UT.zone == T.zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild + consider_rebuild = 1 + break + + //Needs rebuilt. + if(consider_rebuild) + air_master.zones_needing_rebuilt.Add(T.zone) + + //Not adjacent to anything, and unsimulated. Goodbye~ + else + T.zone.RemoveTurf(NT) + + else + //Produce connection through open door. + ZConnect(src,T) //Something like a wall was built, changing the geometry. - else if((!(air_check_directions & direction) && air_directions_archived & direction) || \ - (!(unsim_check_directions & direction) && unsim_directions_archived & direction)) + else if(air_directions_archived & direction || unsim_directions_archived & direction) var/turf/NT = get_step(T, direction) //If the tile is in our own zone, and we cannot connect to it, better rebuild. @@ -207,16 +255,12 @@ //The unsimulated turf is adjacent to another one of our zone's turfs, // better rebuild to be sure we didn't get cut in twain if(consider_rebuild) - air_master.zones_needing_rebuilt.Add(zone) + air_master.zones_needing_rebuilt.Add(NT.zone) //Not adjacent to anything, and unsimulated. Goodbye~ else zone.RemoveTurf(NT) - if(air_check_directions) - processing = 1 - else - processing = 0 return 1 /turf/proc/HasDoor(turf/O) diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index cd77fbbbf21..c7387254d4d 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -27,7 +27,6 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs var/interactions_with_unsim = 0 var/progress = "nothing" - //CREATION AND DELETION /zone/New(turf/start) . = ..() @@ -47,14 +46,23 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs //Generate the gas_mixture for use in txhis zone by using the average of the gases //defined at startup. + //Changed to try and find the source of the error. air = new air.group_multiplier = contents.len for(var/turf/simulated/T in contents) - air.oxygen += T.oxygen / air.group_multiplier - air.nitrogen += T.nitrogen / air.group_multiplier - air.carbon_dioxide += T.carbon_dioxide / air.group_multiplier - air.toxins += T.toxins / air.group_multiplier - air.temperature += T.temperature / air.group_multiplier + if(!T.air) + continue + air.oxygen += T.air.oxygen / air.group_multiplier + air.nitrogen += T.air.nitrogen / air.group_multiplier + air.carbon_dioxide += T.air.carbon_dioxide / air.group_multiplier + air.toxins += T.air.toxins / air.group_multiplier + air.temperature += T.air.temperature / air.group_multiplier + for(var/datum/gas/trace in T.air.trace_gases) + var/datum/gas/corresponding_gas = locate(trace.type) in air.trace_gases + if(!corresponding_gas) + corresponding_gas = new trace.type() + air.trace_gases.Add(corresponding_gas) + corresponding_gas.moles += trace.moles air.update_values() //Add this zone to the global list. @@ -69,40 +77,57 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs for(var/turf/simulated/T in contents) RemoveTurf(T) air_master.ReconsiderTileZone(T) - for(var/zone/Z in connected_zones) - if(src in Z.connected_zones) - Z.connected_zones.Remove(src) - air_master.AddConnectionToCheck(connections) if(air_master) - air_master.zones.Remove(src) - air_master.active_zones.Remove(src) - air_master.zones_needing_rebuilt.Remove(src) + air_master.AddConnectionToCheck(connections) + air = null + . = ..() //Handles deletion via garbage collection. /zone/proc/SoftDelete() + air = null + if(air_master) air_master.zones.Remove(src) air_master.active_zones.Remove(src) air_master.zones_needing_rebuilt.Remove(src) - air = null + air_master.AddConnectionToCheck(connections) + + connections = null + for(var/connection/C in direct_connections) + if(C.A.zone == src) + C.A.zone = null + if(C.B.zone == src) + C.B.zone = null + if(C.zone_A == src) + C.zone_A = null + if(C.zone_B == src) + C.zone_B = null + direct_connections = null //Ensuring the zone list doesn't get clogged with null values. for(var/turf/simulated/T in contents) RemoveTurf(T) air_master.ReconsiderTileZone(T) + contents.Cut() + //Removing zone connections and scheduling connection cleanup for(var/zone/Z in connected_zones) - if(src in Z.connected_zones) - Z.connected_zones.Remove(src) - connected_zones = null + Z.connected_zones.Remove(src) + if(!Z.connected_zones.len) + Z.connected_zones = null - air_master.AddConnectionToCheck(connections) - connections = null + if(Z.closed_connection_zones) + Z.closed_connection_zones.Remove(src) + if(!Z.closed_connection_zones.len) + Z.closed_connection_zones = null + + connected_zones = null + closed_connection_zones = null return 1 @@ -161,6 +186,10 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs if(!unsim_air_needs_update && air_unsim) //if air_unsim doesn't exist, we need to create it even if we don't need an update. return + //Tempfix. + if(!air) + return + unsim_air_needs_update = 0 if(!air_unsim) @@ -340,25 +369,26 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs Z.interactions_with_neighbors++ interactions_with_neighbors++ - for(var/zone/Z in closed_connection_zones) - //If that zone has already processed, skip it. - if(Z.last_update > last_update) - continue - - var/handle_temperature = abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta - - if(Z.status == ZONE_SLEEPING) - if (handle_temperature) - Z.SetStatus(ZONE_ACTIVE) - else + if(!vsc.connection_insulation) + for(var/zone/Z in closed_connection_zones) + //If that zone has already processed, skip it. + if(Z.last_update > last_update || !Z.air) continue - if(air && Z.air) - if( handle_temperature ) - ShareHeat(air, Z.air, closed_connection_zones[Z]) + var/handle_temperature = abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta - Z.interactions_with_neighbors++ - interactions_with_neighbors++ + if(Z.status == ZONE_SLEEPING) + if (handle_temperature) + Z.SetStatus(ZONE_ACTIVE) + else + continue + + if(air && Z.air) + if( handle_temperature ) + ShareHeat(air, Z.air, closed_connection_zones[Z]) + + Z.interactions_with_neighbors++ + interactions_with_neighbors++ if(!interactions_with_neighbors && !interactions_with_unsim) SetStatus(ZONE_SLEEPING) @@ -633,6 +663,18 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) + //This implements a simplistic version of the Stefan-Boltzmann law. + var/energy_delta = ((A.temperature - B.temperature) ** 4) * 5.6704e-8 * connecting_tiles * 2.5 + var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity() * A.group_multiplier, B.temperature * B.heat_capacity() * B.group_multiplier)) + if(maximum_energy_delta > abs(energy_delta)) + if(energy_delta < 0) + maximum_energy_delta *= -1 + energy_delta = maximum_energy_delta + + A.temperature -= energy_delta / (A.heat_capacity() * A.group_multiplier) + B.temperature += energy_delta / (B.heat_capacity() * B.group_multiplier) + + /* This was bad an I feel bad. //Shares a specific ratio of gas between mixtures using simple weighted averages. var //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD @@ -655,7 +697,7 @@ proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) A.temperature = max(0, (A.temperature - temp_avg) * (1- (ratio / max(1,A.group_multiplier)) ) + temp_avg ) B.temperature = max(0, (B.temperature - temp_avg) * (1- (ratio / max(1,B.group_multiplier)) ) + temp_avg ) - + */ /////////////////// //Zone Rebuilding// @@ -715,9 +757,9 @@ zone/proc/Rebuild() current_adjacents = list() for(var/direction in cardinal) - if( !(current.air_check_directions & direction)) - continue var/turf/simulated/adjacent = get_step(current, direction) + if(!current.ZCanPass(adjacent)) + continue if(adjacent in turfs) current_adjacents += adjacent adjacent_id = turfs[adjacent] @@ -747,6 +789,9 @@ zone/proc/Rebuild() final_arrangement[current_identifier] = list(current) else + //Sanity check. + if(!islist(final_arrangement[current_identifier])) + final_arrangement[current_identifier] = list() final_arrangement[current_identifier] += current //lazy but fast diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 0b535a44c39..e2c04299f1c 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -142,7 +142,7 @@ if(ismob(A)) var/mob/M = A if(client_check && !M.client) - L = recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio) + L |= recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio) continue if(sight_check && !isInSight(A, O)) continue @@ -155,7 +155,7 @@ L |= A if(isobj(A) || ismob(A)) - L = recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio) + L |= recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio) return L // The old system would loop through lists for a total of 5000 per function call, in an empty server. @@ -182,7 +182,7 @@ hear += A if(isobj(A) || ismob(A)) - hear = recursive_mob_check(A, hear, 3, 1, 0, 1) + hear |= recursive_mob_check(A, hear, 3, 1, 0, 1) return hear @@ -209,8 +209,9 @@ if(M) var/turf/ear = get_turf(M) if(ear) - if(speaker_coverage[ear]) - . |= M + // Ghostship is magic: Ghosts can hear radio chatter from anywhere + if(speaker_coverage[ear] || (istype(M, /mob/dead/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO))) + . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. return . #define SIGN(X) ((X<0)?-1:1) @@ -327,3 +328,41 @@ proc/isInSight(var/atom/A, var/atom/B) spawn(delay) for(var/client/C in group) C.screen -= O + +datum/projectile_data + var/src_x + var/src_y + var/time + var/distance + var/power_x + var/power_y + var/dest_x + var/dest_y + +/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \ + var/power_x, var/power_y, var/dest_x, var/dest_y) + src.src_x = src_x + src.src_y = src_y + src.time = time + src.distance = distance + src.power_x = power_x + src.power_y = power_y + src.dest_x = dest_x + src.dest_y = dest_y + +/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power) + + // returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle], + // rotated at [rotation] and with the power of [power] + // Thanks to VistaPOWA for this function + + var/power_x = power * cos(angle) + var/power_y = power * sin(angle) + var/time = 2* power_y / 10 //10 = g + + var/distance = time * power_x + + var/dest_x = src_x + distance*sin(rotation); + var/dest_y = src_y + distance*cos(rotation); + + return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index ce8d788f25f..ff853eca2f2 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -42,7 +42,7 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al /////Initial Building///// ////////////////////////// -/proc/make_datum_references_lists() +/hook/startup/proc/makeDatumRefLists() var/list/paths //Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name @@ -94,9 +94,11 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al var/datum/species/S = new T all_species[S.name] = S - if(S.flags & WHITELISTED) + if(S.flags & IS_WHITELISTED) whitelisted_species += S.name + return 1 + /* // Uncomment to debug chemical reaction list. /client/verb/debug_chemical_list() diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index cfca598adbc..0ca515486b4 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -773,4 +773,14 @@ proc for(var/O in A.overlays) var/image/I = O composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY) - return composite \ No newline at end of file + return composite + +proc/adjust_brightness(var/color, var/value) + if (!color) return "#FFFFFF" + if (!value) return color + + var/list/RGB = ReadRGB(color) + RGB[1] = Clamp(RGB[1]+value,0,255) + RGB[2] = Clamp(RGB[2]+value,0,255) + RGB[3] = Clamp(RGB[3]+value,0,255) + return rgb(RGB[1],RGB[2],RGB[3]) \ No newline at end of file diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index a493aa9d080..af77addeab0 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -195,32 +195,10 @@ proc/checkhtml(var/t) * Text modification */ /proc/replacetext(text, find, replacement) - var/find_len = length(find) - if(find_len < 1) return text - . = "" - var/last_found = 1 - while(1) - var/found = findtext(text, find, last_found, 0) - . += copytext(text, last_found, found) - if(found) - . += replacement - last_found = found + find_len - continue - return . + return list2text(text2list(text, find), replacement) /proc/replacetextEx(text, find, replacement) - var/find_len = length(find) - if(find_len < 1) return text - . = "" - var/last_found = 1 - while(1) - var/found = findtextEx(text, find, last_found, 0) - . += copytext(text, last_found, found) - if(found) - . += replacement - last_found = found + find_len - continue - return . + return list2text(text2listEx(text, find), replacement) //Adds 'u' number of zeros ahead of the text 't' /proc/add_zero(t, u) @@ -287,27 +265,6 @@ proc/checkhtml(var/t) return message return copytext(message, 1, length + 1) -/* - * Misc - */ - -/proc/stringsplit(txt, character) - var/cur_text = txt - var/last_found = 1 - var/found_char = findtext(cur_text,character) - var/list/list = list() - if(found_char) - var/fs = copytext(cur_text,last_found,found_char) - list += fs - last_found = found_char+length(character) - found_char = findtext(cur_text,character,last_found) - while(found_char) - var/found_string = copytext(cur_text,last_found,found_char) - last_found = found_char+length(character) - list += found_string - found_char = findtext(cur_text,character,last_found) - list += copytext(cur_text,last_found,length(cur_text)+1) - return list /proc/stringmerge(var/text,var/compare,replace = "*") //This proc fills in all spaces with the "replace" var (* by default) with whatever @@ -346,4 +303,4 @@ proc/checkhtml(var/t) var/new_text = "" for(var/i = length(text); i > 0; i--) new_text += copytext(text, i, i+1) - return new_text \ No newline at end of file + return new_text diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index e180f2092d6..4e6287a5d25 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -83,22 +83,94 @@ return hex -//Attaches each element of a list to a single string seperated by 'seperator'. -/proc/dd_list2text(var/list/the_list, separator) - var/total = the_list.len - if(!total) - return - var/count = 2 - var/newText = "[the_list[1]]" - while(count <= total) - if(separator) - newText += separator - newText += "[the_list[count]]" - count++ - return newText +// Concatenates a list of strings into a single string. A seperator may optionally be provided. +/proc/list2text(list/ls, sep) + if(ls.len <= 1) // Early-out code for empty or singleton lists. + return ls.len ? ls[1] : "" + + var/l = ls.len // Made local for sanic speed. + var/i = 0 // Incremented every time a list index is accessed. + + if(sep <> null) + // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc... + #define S1 sep, ls[++i] + #define S4 S1, S1, S1, S1 + #define S16 S4, S4, S4, S4 + #define S64 S16, S16, S16, S16 + + . = "[ls[++i]]" // Make sure the initial element is converted to text. + + // Having the small concatenations come before the large ones boosted speed by an average of at least 5%. + if(l-1 & 0x01) // 'i' will always be 1 here. + . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2. + if(l-i & 0x02) + . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. + if(l-i & 0x04) + . = text("[][][][][][][][][]", ., S4) // And so on.... + if(l-i & 0x08) + . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4) + if(l-i & 0x10) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16) + if(l-i & 0x20) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) + if(l-i & 0x40) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) + while(l > i) // Chomp through the rest of the list, 128 elements at a time. + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) + + #undef S64 + #undef S16 + #undef S4 + #undef S1 + + else + // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc... + #define S1 ls[++i] + #define S4 S1, S1, S1, S1 + #define S16 S4, S4, S4, S4 + #define S64 S16, S16, S16, S16 + + . = "[ls[++i]]" // Make sure the initial element is converted to text. + + if(l-1 & 0x01) // 'i' will always be 1 here. + . += S1 // Append 1 element if the remaining elements are not a multiple of 2. + if(l-i & 0x02) + . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. + if(l-i & 0x04) + . = text("[][][][][]", ., S4) // And so on... + if(l-i & 0x08) + . = text("[][][][][][][][][]", ., S4, S4) + if(l-i & 0x10) + . = text("[][][][][][][][][][][][][][][][][]", ., S16) + if(l-i & 0x20) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16) + if(l-i & 0x40) + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64) + while(l > i) // Chomp through the rest of the list, 128 elements at a time. + . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\ + [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64) + + #undef S64 + #undef S16 + #undef S4 + #undef S1 -//slower then dd_list2text, but correctly processes associative lists. +//slower then list2text, but correctly processes associative lists. proc/tg_list2text(list/list, glue=",") if(!istype(list) || !list.len) return @@ -108,62 +180,50 @@ proc/tg_list2text(list/list, glue=",") return output -//Converts a text string into a list by splitting the string at each seperator found in text (discarding the seperator) -//Returns an empty list if the text cannot be split, or the split text in a list. -//Not giving a "" seperator will cause the text to be broken into a list of single letters. -/proc/text2list(text, seperator="\n") +//Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator) +/proc/text2list(text, delimiter="\n") + var/delim_len = length(delimiter) + if(delim_len < 1) return list(text) . = list() + var/last_found = 1 + var/found + do + found = findtext(text, delimiter, last_found, 0) + . += copytext(text, last_found, found) + last_found = found + delim_len + while(found) - var/text_len = length(text) //length of the input text - var/seperator_len = length(seperator) //length of the seperator text - - if(text_len >= seperator_len) - var/i - var/last_i = 1 - - for(i=1,i<=(text_len+1-seperator_len),i++) - if( cmptext(copytext(text,i,i+seperator_len), seperator) ) - if(i != last_i) - . += copytext(text,last_i,i) - last_i = i + seperator_len - - if(last_i <= text_len) - . += copytext(text, last_i, 0) - else - . += text - return . - -//Converts a text string into a list by splitting the string at each seperator found in text (discarding the seperator) -//Returns an empty list if the text cannot be split, or the split text in a list. -//Not giving a "" seperator will cause the text to be broken into a list of single letters. //Case Sensitive! -/proc/text2listEx(text, seperator="\n") +/proc/text2listEx(text, delimiter="\n") + var/delim_len = length(delimiter) + if(delim_len < 1) return list(text) . = list() - - var/text_len = length(text) //length of the input text - var/seperator_len = length(seperator) //length of the seperator text - - if(text_len >= seperator_len) - var/i - var/last_i = 1 - - for(i=1,i<=(text_len+1-seperator_len),i++) - if( cmptextEx(copytext(text,i,i+seperator_len), seperator) ) - if(i != last_i) - . += copytext(text,last_i,i) - last_i = i + seperator_len - - if(last_i <= text_len) - . += copytext(text, last_i, 0) - else - . += text - return . + var/last_found = 1 + var/found + do + found = findtextEx(text, delimiter, last_found, 0) + . += copytext(text, last_found, found) + last_found = found + delim_len + while(found) //Splits the text of a file at seperator and returns them in a list. /proc/file2list(filename, seperator="\n") return text2list(return_file_text(filename),seperator) +//Turns a direction into text + +/proc/num2dir(direction) + switch(direction) + if(1.0) return NORTH + if(2.0) return SOUTH + if(4.0) return EAST + if(8.0) return WEST + else + world.log << "UNKNOWN DIRECTION: [direction]" + + + //Turns a direction into text /proc/dir2text(direction) switch(direction) @@ -261,4 +321,5 @@ proc/tg_list2text(list/list, glue=",") switch(ui_style) if("old") return 'icons/mob/screen1_old.dmi' if("Orange") return 'icons/mob/screen1_Orange.dmi' - else return 'icons/mob/screen1_Midnight.dmi' + if("Midnight") return 'icons/mob/screen1_Midnight.dmi' + else return 'icons/mob/screen1_White.dmi' diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index c02737400ba..b39df751896 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -46,7 +46,7 @@ continue // could not leave T0 in that direction var/turf/T1 = get_step(T0,d) - if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) & get_dir(T1,src), border_only = 0)) + if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) | get_dir(T1,src), border_only = 0)) continue // couldn't enter or couldn't leave T1 if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target)) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index cb840a1d90e..112c3431e52 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -55,6 +55,7 @@ RestrainedClickOn(A) else */ + A.add_hiddenprint(src) A.attack_ai(src) /* diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 5ce15be96e7..fd0b658aa0b 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -291,7 +291,7 @@ // Simple helper to face what you clicked on, in case it should be needed in more than one place /mob/proc/face_atom(var/atom/A) - if( buckled || !A || !x || !y || !A.x || !A.y ) return + if( stat || buckled || !A || !x || !y || !A.x || !A.y ) return var/dx = A.x - x var/dy = A.y - y if(!dx && !dy) return diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 640a09d045f..d86faacbd1f 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -48,6 +48,7 @@ // Cyborgs have no range-checking unless there is item use if(!W) + A.add_hiddenprint(src) A.attack_robot(src) return diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 618858d5438..98e2fda1862 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -166,9 +166,11 @@ datum/hud/New(mob/owner) if(!ismob(mymob)) return 0 if(!mymob.client) return 0 var/ui_style = ui_style2icon(mymob.client.prefs.UI_style) + var/ui_color = mymob.client.prefs.UI_style_color + var/ui_alpha = mymob.client.prefs.UI_style_alpha if(ishuman(mymob)) - human_hud(ui_style) // Pass the player the UI style chosen in preferences + human_hud(ui_style, ui_color, ui_alpha) // Pass the player the UI style chosen in preferences else if(ismonkey(mymob)) monkey_hud(ui_style) else if(isbrain(mymob)) @@ -186,14 +188,15 @@ datum/hud/New(mob/owner) //Triggered when F12 is pressed (Unless someone changed something in the DMF) -/mob/verb/button_pressed_F12() +/mob/verb/button_pressed_F12(var/full = 0 as null) set name = "F12" set hidden = 1 if(hud_used) if(ishuman(src)) - if(!src.client) return - + if(!client) return + if(client.view != world.view) + return if(hud_used.hud_shown) hud_used.hud_shown = 0 if(src.hud_used.adding) @@ -207,10 +210,15 @@ datum/hud/New(mob/owner) //Due to some poor coding some things need special treatment: //These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay - src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible - src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible - src.client.screen += src.hud_used.action_intent //we want the intent swticher visible - src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. + if(!full) + src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible + src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible + src.client.screen += src.hud_used.action_intent //we want the intent swticher visible + src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. + else + src.client.screen -= src.healths + src.client.screen -= src.internals + src.client.screen -= src.gun_setting_icon //These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone. src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason. @@ -223,7 +231,12 @@ datum/hud/New(mob/owner) src.client.screen += src.hud_used.other if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden) src.client.screen += src.hud_used.hotkeybuttons - + if(src.healths) + src.client.screen |= src.healths + if(src.internals) + src.client.screen |= src.internals + if(src.gun_setting_icon) + src.client.screen |= src.gun_setting_icon src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position src.client.screen += src.zone_sel //This one is a special snowflake diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 32e9e1046ec..ca053f86e6b 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -1,4 +1,4 @@ -/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_old.dmi') +/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_White.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255) src.adding = list() src.other = list() @@ -73,6 +73,8 @@ using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") using.screen_loc = ui_movi using.layer = 20 + using.color = ui_color + using.alpha = ui_alpha src.adding += using move_intent = using @@ -82,6 +84,8 @@ using.icon_state = "act_drop" using.screen_loc = ui_drop_throw using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha src.hotkeybuttons += using inv_box = new /obj/screen/inventory() @@ -92,6 +96,8 @@ inv_box.icon_state = "center" inv_box.screen_loc = ui_iclothing inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -102,6 +108,8 @@ inv_box.icon_state = "equip" inv_box.screen_loc = ui_oclothing inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -114,6 +122,9 @@ inv_box.screen_loc = ui_rhand inv_box.slot_id = slot_r_hand inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha + src.r_hand_hud_object = inv_box src.adding += inv_box @@ -127,6 +138,8 @@ inv_box.screen_loc = ui_lhand inv_box.slot_id = slot_l_hand inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.l_hand_hud_object = inv_box src.adding += inv_box @@ -137,6 +150,8 @@ using.icon_state = "hand1" using.screen_loc = ui_swaphand1 using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha src.adding += using using = new /obj/screen/inventory() @@ -146,6 +161,8 @@ using.icon_state = "hand2" using.screen_loc = ui_swaphand2 using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha src.adding += using inv_box = new /obj/screen/inventory() @@ -156,6 +173,8 @@ inv_box.screen_loc = ui_id inv_box.slot_id = slot_wear_id inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.adding += inv_box inv_box = new /obj/screen/inventory() @@ -166,6 +185,8 @@ inv_box.screen_loc = ui_mask inv_box.slot_id = slot_wear_mask inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -176,6 +197,8 @@ inv_box.screen_loc = ui_back inv_box.slot_id = slot_back inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.adding += inv_box inv_box = new /obj/screen/inventory() @@ -185,6 +208,8 @@ inv_box.screen_loc = ui_storage1 inv_box.slot_id = slot_l_store inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.adding += inv_box inv_box = new /obj/screen/inventory() @@ -194,6 +219,8 @@ inv_box.screen_loc = ui_storage2 inv_box.slot_id = slot_r_store inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.adding += inv_box inv_box = new /obj/screen/inventory() @@ -204,6 +231,8 @@ inv_box.screen_loc = ui_sstore1 inv_box.slot_id = slot_s_store inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.adding += inv_box using = new /obj/screen() @@ -212,6 +241,8 @@ using.icon_state = "act_resist" using.screen_loc = ui_pull_resist using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha src.hotkeybuttons += using using = new /obj/screen() @@ -220,6 +251,8 @@ using.icon_state = "other" using.screen_loc = ui_inventory using.layer = 20 + using.color = ui_color + using.alpha = ui_alpha src.adding += using using = new /obj/screen() @@ -228,6 +261,8 @@ using.icon_state = "act_equip" using.screen_loc = ui_equip using.layer = 20 + using.color = ui_color + using.alpha = ui_alpha src.adding += using inv_box = new /obj/screen/inventory() @@ -237,6 +272,8 @@ inv_box.screen_loc = ui_gloves inv_box.slot_id = slot_gloves inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -246,6 +283,8 @@ inv_box.screen_loc = ui_glasses inv_box.slot_id = slot_glasses inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -255,6 +294,8 @@ inv_box.screen_loc = ui_l_ear inv_box.slot_id = slot_l_ear inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -264,6 +305,8 @@ inv_box.screen_loc = ui_r_ear inv_box.slot_id = slot_r_ear inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -273,6 +316,8 @@ inv_box.screen_loc = ui_head inv_box.slot_id = slot_head inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -282,6 +327,8 @@ inv_box.screen_loc = ui_shoes inv_box.slot_id = slot_shoes inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.other += inv_box inv_box = new /obj/screen/inventory() @@ -291,6 +338,8 @@ inv_box.screen_loc = ui_belt inv_box.slot_id = slot_belt inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha src.adding += inv_box mymob.throw_icon = new /obj/screen() @@ -298,6 +347,8 @@ mymob.throw_icon.icon_state = "act_throw_off" mymob.throw_icon.name = "throw" mymob.throw_icon.screen_loc = ui_drop_throw + mymob.throw_icon.color = ui_color + mymob.throw_icon.alpha = ui_alpha src.hotkeybuttons += mymob.throw_icon mymob.oxygen = new /obj/screen() @@ -382,6 +433,8 @@ mymob.zone_sel = new /obj/screen/zone_sel( null ) mymob.zone_sel.icon = ui_style + mymob.zone_sel.color = ui_color + mymob.zone_sel.alpha = ui_alpha mymob.zone_sel.overlays.Cut() mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") @@ -438,28 +491,26 @@ client.screen -= hud_used.item_action_list + hud_used.item_action_list = list() for(var/obj/item/I in src) - if(I.action_button_name) - if(hud_used.item_action_list.len < num) - var/obj/screen/item_action/N = new(hud_used) - hud_used.item_action_list += N - - var/obj/screen/item_action/A = hud_used.item_action_list[num] - + if(I.icon_action_button) + var/obj/screen/item_action/A = new(hud_used) + + //A.icon = 'icons/mob/screen1_action.dmi' + //A.icon_state = I.icon_action_button A.icon = ui_style2icon(client.prefs.UI_style) A.icon_state = "template" - - A.overlays = list() var/image/img = image(I.icon, A, I.icon_state) img.pixel_x = 0 img.pixel_y = 0 A.overlays += img - A.name = I.action_button_name + if(I.action_button_name) + A.name = I.action_button_name + else + A.name = "Use [I.name]" A.owner = I - - client.screen += hud_used.item_action_list[num] - + hud_used.item_action_list += A switch(num) if(1) A.screen_loc = ui_action_slot1 @@ -473,3 +524,4 @@ A.screen_loc = ui_action_slot5 break //5 slots available, so no more can be added. num++ + src.client.screen += src.hud_used.item_action_list diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index a0dcfb9ae9c..ed054ae6c8a 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -36,6 +36,9 @@ if(istype(master, /obj/item/weapon/storage)) var/obj/item/weapon/storage/S = master S.close(usr) + else if(istype(master,/obj/item/clothing/suit/storage)) + var/obj/item/clothing/suit/storage/S = master + S.close(usr) return 1 @@ -273,37 +276,79 @@ C << "You are not wearing a mask." return 1 else - if(istype(C.l_hand, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.l_hand] on your left hand." - C.internal = C.l_hand - else if(istype(C.r_hand, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.r_hand] on your right hand." - C.internal = C.r_hand - else if(ishuman(C)) + var/list/nicename = null + var/list/tankcheck = null + var/breathes = "oxygen" //default, we'll check later + var/list/contents = list() + + if(ishuman(C)) var/mob/living/carbon/human/H = C - if(istype(H.s_store, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.s_store] on your [H.wear_suit]." - H.internal = H.s_store - else if(istype(H.belt, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.belt] on your belt." - H.internal = H.belt - else if(istype(H.l_store, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.l_store] in your left pocket." - H.internal = H.l_store - else if(istype(H.r_store, /obj/item/weapon/tank)) - H << "You are now running on internals from the [H.r_store] in your right pocket." - H.internal = H.r_store + breathes = H.species.breath_type + nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket") + tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store) - //Seperate so CO2 jetpacks are a little less cumbersome. - if(!C.internal && istype(C.back, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.back] on your back." - C.internal = C.back + else + nicename = list("Right Hand", "Left Hand", "Back") + tankcheck = list(C.r_hand, C.l_hand, C.back) + + for(var/i=1, i bestcontents) + best = i + bestcontents = contents[i] + + + //We've determined the best container now we set it as our internals + + if(best) + C << "You are now running on internals from [tankcheck[best]] on your [nicename[best]]." + C.internal = tankcheck[best] + + if(C.internal) if(C.internals) C.internals.icon_state = "internal1" else - C << "You don't have an oxygen tank." + C << "You don't have a[breathes=="oxygen" ? "n oxygen" : addtext(" ",breathes)] tank." if("act_intent") usr.a_intent_change("right") if("help") diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 821f42ee1b1..1dbaeb1a3f6 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -140,7 +140,7 @@ if(istype(M, /mob/living/carbon/human)) - M:attacked_by(src, user, def_zone) + return M:attacked_by(src, user, def_zone) else switch(damtype) if("brute") diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index c326d83df41..869b10c3a1a 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -37,27 +37,6 @@ // Not all of them require checking, see below A.attack_ghost(src) -// This is the ghost's follow verb with an argument -/mob/dead/observer/proc/ManualFollow(var/atom/target) - following = target - if(target) - src << "\blue Now following [target]" - spawn(0) - var/turf/pos = get_turf(src) - while(loc == pos && target && following == target) - - var/turf/T = get_turf(target) - if(!T) - break - if(following != target) - break - if(!client) - break - loc = T - pos = loc - sleep(15) - following = null - // Oh by the way this didn't work with old click code which is why clicking shit didn't spam you /atom/proc/attack_ghost(mob/dead/observer/user as mob) if(user.client && user.client.inquisitive_ghost) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index c7baaddcf98..f58c8e4b4f6 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -18,6 +18,7 @@ var/log_adminwarn = 0 // log warnings admins get about bomb construction and such var/log_pda = 0 // log pda messages var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits + var/log_runtime = 0 // logs world.log to a file var/sql_enabled = 1 // for sql switching var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour var/allow_vote_restart = 0 // allow votes to restart @@ -44,7 +45,8 @@ var/Tickcomp = 0 var/socket_talk = 0 // use socket_talk to communicate with other processes var/list/resource_urls = null - + var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round. + var/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round. var/list/mode_names = list() var/list/modes = list() // allowed modes var/list/votable_modes = list() // votable modes @@ -62,6 +64,12 @@ var/automute_on = 0 //enables automuting/spam prevention var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. + var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds... + var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active. + + var/disable_player_mice = 0 + var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech + var/usealienwhitelist = 0 var/limitalienplayers = 0 var/alien_to_human_ratio = 0.5 @@ -177,7 +185,7 @@ if(type == "config") switch (name) if ("resource_urls") - config.resource_urls = stringsplit(value, " ") + config.resource_urls = text2list(value, " ") if ("admin_legacy_system") config.admin_legacy_system = 1 @@ -239,6 +247,9 @@ if ("log_hrefs") config.log_hrefs = 1 + if ("log_runtime") + config.log_runtime = 1 + if("allow_admin_ooccolor") config.allow_admin_ooccolor = 1 @@ -389,6 +400,11 @@ if("ticklag") Ticklag = text2num(value) + if("allow_antag_hud") + config.antag_hud_allowed = 1 + if("antag_hud_restricted") + config.antag_hud_restricted = 1 + if("socket_talk") socket_talk = text2num(value) @@ -423,6 +439,12 @@ if("ghost_interaction") config.ghost_interaction = 1 + if("disable_player_mice") + config.disable_player_mice = 1 + + if("uneducated_mice") + config.uneducated_mice = 1 + if("comms_password") config.comms_password = value @@ -444,10 +466,15 @@ else //probably windows, if not this should work anyway config.python_path = "python" + if("allow_cult_ghostwriter") + config.cult_ghostwriter = 1 + + if("req_cult_ghostwriter") + config.cult_ghostwriter_req_cultists = value + else diary << "Unknown setting in configuration: '[name]'" - else if(type == "game_options") if(!value) diary << "Unknown value for setting [name] in [filename]." diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm new file mode 100644 index 00000000000..cb51229c9fb --- /dev/null +++ b/code/controllers/hooks-defs.dm @@ -0,0 +1,17 @@ +/** + * Startup hook. + * Called in world.dm when the server starts. + */ +/hook/startup + +/** + * Roundstart hook. + * Called in gameticker.dm when a round starts. + */ +/hook/roundstart + +/** + * Roundend hook. + * Called in gameticker.dm when a round ends. + */ +/hook/roundend diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm new file mode 100644 index 00000000000..5045da75925 --- /dev/null +++ b/code/controllers/hooks.dm @@ -0,0 +1,39 @@ +/** + * @file hooks.dm + * Implements hooks, a simple way to run code on pre-defined events. + */ + +/** @page hooks Code hooks + * @section hooks Hooks + * A hook is defined under /hook in the type tree. + * + * To add some code to be called by the hook, define a proc under the type, as so: + * @code + /hook/foo/proc/bar() + if(1) + return 1 //Sucessful + else + return 0 //Error, or runtime. + * @endcode + * All hooks must return nonzero on success, as runtimes will force return null. + */ + +/** + * Calls a hook, executing every piece of code that's attached to it. + * @param hook Identifier of the hook to call. + * @returns 1 if all hooked code runs successfully, 0 otherwise. + */ +/proc/callHook(hook) + var/hook_path = text2path("/hook/[hook]") + if(!hook_path) + error("Invalid hook '/hook/[hook]' called.") + return 0 + + var/caller = new hook_path + var/status = 1 + for(var/P in typesof("[hook_path]/proc")) + if(!call(caller, P)()) + error("Hook '[P]' failed or runtimed.") + status = 0 + + return status diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 5e7d308a9eb..e0bd38086aa 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -66,6 +66,7 @@ datum/controller/game_controller/proc/setup() setupgenetics() setupfactions() setup_economy() + SetupXenoarch() transfer_controller = new @@ -296,7 +297,7 @@ datum/controller/game_controller/proc/process_nano() var/i = 1 while(i<=nanomanager.processing_uis.len) var/datum/nanoui/ui = nanomanager.processing_uis[i] - if(ui && ui.src_object && ui.user) + if(ui) ui.process() i++ continue diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 1a7d97e99cf..d4e92584229 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -1,3 +1,6 @@ +/hook/startup/proc/createDatacore() + data_core = new /obj/effect/datacore() + return 1 /obj/effect/datacore/proc/manifest(var/nosleep = 0) spawn() @@ -104,13 +107,13 @@ var/datum/data/record/L = new() L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]") L.fields["name"] = H.real_name - L.fields["rank"] = H.mind.assigned_role + L.fields["rank"] = H.mind.assigned_role L.fields["age"] = H.age L.fields["sex"] = H.gender L.fields["b_type"] = H.b_type L.fields["b_dna"] = H.dna.unique_enzymes - L.fields["enzymes"] = H.dna.struc_enzymes - L.fields["identity"] = H.dna.uni_identity + L.fields["enzymes"] = H.dna.SE // Used in respawning + L.fields["identity"] = H.dna.UI // " L.fields["image"] = getFlatIcon(H,0) //This is god-awful locked += L return diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index dc3a3b36dbd..c335a6f1fac 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -258,6 +258,9 @@ client body += "" body += "" body += "" + + body += "" + body += "" if(ishuman(D)) body += "" body += "" @@ -808,6 +811,55 @@ client else usr << "Mob doesn't know that language." + else if(href_list["addverb"]) + if(!check_rights(R_DEBUG)) return + + var/mob/living/H = locate(href_list["addverb"]) + + if(!istype(H)) + usr << "This can only be done to instances of type /mob/living" + return + var/list/possibleverbs = list() + possibleverbs += "Cancel" // One for the top... + possibleverbs += typesof(/mob/proc,/mob/verb,/mob/living/proc,/mob/living/verb) + switch(H.type) + if(/mob/living/carbon/human) + possibleverbs += typesof(/mob/living/carbon/proc,/mob/living/carbon/verb,/mob/living/carbon/human/verb,/mob/living/carbon/human/proc) + if(/mob/living/silicon/robot) + possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/robot/proc,/mob/living/silicon/robot/verb) + if(/mob/living/silicon/ai) + possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/ai/proc,/mob/living/silicon/ai/verb) + possibleverbs -= H.verbs + possibleverbs += "Cancel" // ...And one for the bottom + + var/verb = input("Select a verb!", "Verbs",null) as anything in possibleverbs + if(!H) + usr << "Mob doesn't exist anymore" + return + if(!verb || verb == "Cancel") + return + else + H.verbs += verb + + else if(href_list["remverb"]) + if(!check_rights(R_DEBUG)) return + + var/mob/H = locate(href_list["remverb"]) + + if(!istype(H)) + usr << "This can only be done to instances of type /mob" + return + var/verb = input("Please choose a verb to remove.","Verbs",null) as null|anything in H.verbs + if(!H) + usr << "Mob doesn't exist anymore" + return + if(!verb) + return + else + H.verbs -= verb + + + else if(href_list["regenerateicons"]) if(!check_rights(0)) return diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index 95adc92dcc3..376df936782 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -297,7 +297,7 @@ var/list/advance_cures = list( for(var/datum/symptom/S in symptoms) L += S.id L = sortList(L) // Sort the list so it doesn't matter which order the symptoms are in. - var/result = dd_list2text(L, ":") + var/result = list2text(L, ":") id = result return result diff --git a/code/datums/diseases/appendicitis.dm b/code/datums/diseases/appendicitis.dm index 16b4008fef0..502ce1e7346 100644 --- a/code/datums/diseases/appendicitis.dm +++ b/code/datums/diseases/appendicitis.dm @@ -45,7 +45,7 @@ H.op_stage.appendix = 2.0 var/datum/organ/external/groin = H.get_organ("groin") - var/datum/wound/W = new /datum/wound/internal_bleeding(25) + var/datum/wound/W = new /datum/wound/internal_bleeding(20) H.adjustToxLoss(25) groin.wounds += W src.cure() diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm index c7c5f812122..69a8eb6500f 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -39,13 +39,13 @@ //Save original dna for when the disease is cured. src.original_dna["name"] = affected_mob.real_name - src.original_dna["UI"] = affected_mob.dna.uni_identity - src.original_dna["SE"] = affected_mob.dna.struc_enzymes + src.original_dna["UI"] = affected_mob.dna.UI + src.original_dna["SE"] = affected_mob.dna.SE affected_mob << "\red You don't feel like yourself.." - affected_mob.dna.uni_identity = strain_data["UI"] - updateappearance(affected_mob, affected_mob.dna.uni_identity) - affected_mob.dna.struc_enzymes = strain_data["SE"] + affected_mob.UpdateAppearance(strain_data["UI"]) + affected_mob.dna.SE = strain_data["SE"] + affected_mob.dna.UpdateSE() affected_mob.real_name = strain_data["name"] domutcheck(affected_mob) @@ -56,9 +56,9 @@ /datum/disease/dnaspread/Del() if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"])) - affected_mob.dna.uni_identity = original_dna["UI"] - updateappearance(affected_mob, affected_mob.dna.uni_identity) - affected_mob.dna.struc_enzymes = original_dna["SE"] + affected_mob.UpdateAppearance(original_dna["UI"]) + affected_mob.dna.SE = original_dna["SE"] + affected_mob.dna.UpdateSE() affected_mob.real_name = original_dna["name"] affected_mob << "\blue You feel more like yourself." diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 500008d2f6f..d85c1a61f1a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -74,6 +74,8 @@ datum/mind current.mind = null if(new_character.mind) //remove any mind currently in our new body's mind variable new_character.mind.current = null + + nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user current = new_character //link ourself to our new body new_character.mind = src //and link our new body to ourself @@ -550,6 +552,7 @@ datum/mind current << "\red You have been brainwashed! You are no longer a head revolutionary!" ticker.mode.update_rev_icons_removed(src) special_role = null + current.verbs -= /mob/living/carbon/human/proc/RevConvert log_admin("[key_name_admin(usr)] has de-rev'ed [current].") if("rev") @@ -570,7 +573,7 @@ datum/mind if(src in ticker.mode.revolutionaries) ticker.mode.revolutionaries -= src ticker.mode.update_rev_icons_removed(src) - current << "\red You have proved your devotion to revoltion! Yea are a head revolutionary now!" + current << "\red You have proved your devotion to revoltion! You are a head revolutionary now!" else if(!(src in ticker.mode.head_revolutionaries)) current << "\blue You are a member of the revolutionaries' leadership now!" else @@ -586,6 +589,7 @@ datum/mind rev_obj.explanation_text = "Assassinate [O.target.name], the [O.target.assigned_role]." objectives += rev_obj ticker.mode.greet_revolutionary(src,0) + current.verbs += /mob/living/carbon/human/proc/RevConvert ticker.mode.head_revolutionaries += src ticker.mode.update_rev_icons_added(src) special_role = "Head Revolutionary" @@ -726,7 +730,7 @@ datum/mind else current.dna = changeling.absorbed_dna[1] current.real_name = current.dna.real_name - updateappearance(current, current.dna.uni_identity) + current.UpdateAppearance() domutcheck(current, null) else if (href_list["nuclear"]) 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/sun.dm b/code/datums/sun.dm index 9ce8a73cb72..82acfa0cff0 100644 --- a/code/datums/sun.dm +++ b/code/datums/sun.dm @@ -14,6 +14,10 @@ if(prob(50)) rate = -rate +/hook/startup/proc/createSun() + sun = new /datum/sun() + return 1 + // calculate the sun's position given the time of day /datum/sun/proc/calc_position() diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 297bdb890da..e3cc43642d9 100755 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -128,12 +128,12 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager, /obj/item/weapon/storage/fancy/cigarettes/dromedaryco, /obj/item/weapon/lipstick/random, - /obj/item/weapon/reagent_containers/food/drinks/ale, - /obj/item/weapon/reagent_containers/food/drinks/ale, - /obj/item/weapon/reagent_containers/food/drinks/beer, - /obj/item/weapon/reagent_containers/food/drinks/beer, - /obj/item/weapon/reagent_containers/food/drinks/beer, - /obj/item/weapon/reagent_containers/food/drinks/beer) + /obj/item/weapon/reagent_containers/food/drinks/cans/ale, + /obj/item/weapon/reagent_containers/food/drinks/cans/ale, + /obj/item/weapon/reagent_containers/food/drinks/cans/beer, + /obj/item/weapon/reagent_containers/food/drinks/cans/beer, + /obj/item/weapon/reagent_containers/food/drinks/cans/beer, + /obj/item/weapon/reagent_containers/food/drinks/cans/beer) cost = 20 containertype = /obj/structure/closet/crate containername = "Party equipment" @@ -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, @@ -687,6 +695,18 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee access = access_armory group = "Security" +/datum/supply_packs/erifle + name = "Energy marksman crate" + contains = list(/obj/item/clothing/suit/armor/laserproof, + /obj/item/clothing/suit/armor/laserproof, + /obj/item/weapon/gun/energy/sniperrifle, + /obj/item/weapon/gun/energy/sniperrifle) + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "Energy marksman crate" + access = access_armory + group = "Security" + /datum/supply_packs/shotgunammo name = "Shotgun shells" contains = list(/obj/item/ammo_casing/shotgun, @@ -945,6 +965,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 (CAUTION)" + group = "Engineering" + access = access_ce + + +/* /datum/supply_packs/smsmall // Currently nonfunctional, waiting on virgil + name = "Supermatter Shard" + contains = list(/obj/machinery/power/supermatter/shard) + cost = 25 + containertype = /obj/structure/closet/crate/secure/plasma + containername = "Supermatter shard crate (CAUTION)" + 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.dm b/code/defines/obj.dm index 6c6269d301e..e6a4a7a4cb5 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -51,122 +51,194 @@ //This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character(). var/locked[] = list() - proc/get_manifest(monochrome, OOC) - var/list/heads = new() - var/list/sec = new() - var/list/eng = new() - var/list/med = new() - var/list/sci = new() - var/list/civ = new() - var/list/bot = new() - var/list/misc = new() - var/list/isactive = new() - var/dat = {" - - - - "} - var/even = 0 - - // sort mobs - for(var/datum/data/record/t in data_core.general) - var/name = t.fields["name"] - var/rank = t.fields["rank"] - var/real_rank = t.fields["real_rank"] - if(OOC) - var/active = 0 - for(var/mob/M in player_list) - if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10) - active = 1 - break - isactive[name] = active ? "Active" : "Inactive" - else - isactive[name] = t.fields["p_stat"] - +/obj/effect/datacore/proc/get_manifest(monochrome, OOC) + var/list/heads = new() + var/list/sec = new() + var/list/eng = new() + var/list/med = new() + var/list/sci = new() + var/list/civ = new() + var/list/bot = new() + var/list/misc = new() + var/list/isactive = new() + var/dat = {" + +
NameRankActivity
+ + "} + var/even = 0 + // sort mobs + for(var/datum/data/record/t in data_core.general) + var/name = t.fields["name"] + var/rank = t.fields["rank"] + var/real_rank = t.fields["real_rank"] + if(OOC) + var/active = 0 + for(var/mob/M in player_list) + if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10) + active = 1 + break + isactive[name] = active ? "Active" : "Inactive" + else + isactive[name] = t.fields["p_stat"] //world << "[name]: [rank]" - //cael - to prevent multiple appearances of a player/job combination, add a continue after each line - var/department = 0 - if(real_rank in command_positions) - heads[name] = rank - department = 1 - if(real_rank in security_positions) - sec[name] = rank - department = 1 - if(real_rank in engineering_positions) - eng[name] = rank - department = 1 - if(real_rank in medical_positions) - med[name] = rank - department = 1 - if(real_rank in science_positions) - sci[name] = rank - department = 1 - if(real_rank in civilian_positions) - civ[name] = rank - department = 1 - if(real_rank in nonhuman_positions) - bot[name] = rank - department = 1 + var/department = 0 + if(real_rank in command_positions) + heads[name] = rank + department = 1 + if(real_rank in security_positions) + sec[name] = rank + department = 1 + if(real_rank in engineering_positions) + eng[name] = rank + department = 1 + if(real_rank in medical_positions) + med[name] = rank + department = 1 + if(real_rank in science_positions) + sci[name] = rank + department = 1 + if(real_rank in civilian_positions) + civ[name] = rank + department = 1 + if(real_rank in nonhuman_positions) + bot[name] = rank + department = 1 + if(!department && !(name in heads)) + misc[name] = rank + if(heads.len > 0) + dat += "" + for(name in heads) + dat += "" + even = !even + if(sec.len > 0) + dat += "" + for(name in sec) + dat += "" + even = !even + if(eng.len > 0) + dat += "" + for(name in eng) + dat += "" + even = !even + if(med.len > 0) + dat += "" + for(name in med) + dat += "" + even = !even + if(sci.len > 0) + dat += "" + for(name in sci) + dat += "" + even = !even + if(civ.len > 0) + dat += "" + for(name in civ) + dat += "" + even = !even + // in case somebody is insane and added them to the manifest, why not + if(bot.len > 0) + dat += "" + for(name in bot) + dat += "" + even = !even + // misc guys + if(misc.len > 0) + dat += "" + for(name in misc) + dat += "" + even = !even - if(!department && !(name in heads)) - misc[name] = rank - - if(heads.len > 0) - dat += "" - for(name in heads) - dat += "" - even = !even - if(sec.len > 0) - dat += "" - for(name in sec) - dat += "" - even = !even - if(eng.len > 0) - dat += "" - for(name in eng) - dat += "" - even = !even - if(med.len > 0) - dat += "" - for(name in med) - dat += "" - even = !even - if(sci.len > 0) - dat += "" - for(name in sci) - dat += "" - even = !even - if(civ.len > 0) - dat += "" - for(name in civ) - dat += "" - even = !even - // in case somebody is insane and added them to the manifest, why not - if(bot.len > 0) - dat += "" - for(name in bot) - dat += "" - even = !even - // misc guys - if(misc.len > 0) - dat += "" - for(name in misc) - dat += "" - even = !even + dat += "
NameRankActivity
Heads
[name][heads[name]][isactive[name]]
Security
[name][sec[name]][isactive[name]]
Engineering
[name][eng[name]][isactive[name]]
Medical
[name][med[name]][isactive[name]]
Science
[name][sci[name]][isactive[name]]
Civilian
[name][civ[name]][isactive[name]]
Silicon
[name][bot[name]][isactive[name]]
Miscellaneous
[name][misc[name]][isactive[name]]
Heads
[name][heads[name]][isactive[name]]
Security
[name][sec[name]][isactive[name]]
Engineering
[name][eng[name]][isactive[name]]
Medical
[name][med[name]][isactive[name]]
Science
[name][sci[name]][isactive[name]]
Civilian
[name][civ[name]][isactive[name]]
Silicon
[name][bot[name]][isactive[name]]
Miscellaneous
[name][misc[name]][isactive[name]]
" + dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly + dat = replacetext(dat, "\t", "") + return dat + + +/* +We can't just insert in HTML into the nanoUI so we need the raw data to play with. +*/ + +/obj/effect/datacore/proc/get_manifest_json() + var/heads[0] + var/sec[0] + var/eng[0] + var/med[0] + var/sci[0] + var/civ[0] + var/bot[0] + var/misc[0] + for(var/datum/data/record/t in data_core.general) + var/name = sanitize(t.fields["name"]) + var/rank = sanitize(t.fields["rank"]) + var/real_rank = t.fields["real_rank"] + var/isactive = t.fields["p_stat"] + var/department = 0 + var/depthead = 0 // Department Heads will be placed at the top of their lists. + if(real_rank in command_positions) + heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + depthead = 1 + if(rank=="Captain" && heads.len != 1) + heads.Swap(1,heads.len) + + if(real_rank in security_positions) + sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + if(depthead && sec.len != 1) + sec.Swap(1,sec.len) + + if(real_rank in engineering_positions) + eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + if(depthead && eng.len != 1) + eng.Swap(1,eng.len) + + if(real_rank in medical_positions) + med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + if(depthead && med.len != 1) + med.Swap(1,med.len) + + if(real_rank in science_positions) + sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + if(depthead && sci.len != 1) + sci.Swap(1,sci.len) + + if(real_rank in civilian_positions) + civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + if(depthead && civ.len != 1) + civ.Swap(1,civ.len) + + if(real_rank in nonhuman_positions) + bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive) + department = 1 + + if(!department && !(name in heads)) + misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive) + + return list(\ + "heads" = heads,\ + "sec" = sec,\ + "eng" = eng,\ + "med" = med,\ + "sci" = sci,\ + "civ" = civ,\ + "bot" = bot,\ + "misc" = misc\ + ) - dat += "" - dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly - dat = replacetext(dat, "\t", "") - return dat /obj/effect/laser name = "laser" 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/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index b84388f5838..4e7beba1ddc 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -325,6 +325,13 @@ icon = 'icons/obj/wizard.dmi' icon_state = "broom" +/obj/item/weapon/staff/gentcane + name = "Gentlemans Cane" + desc = "An ebony can with an ivory tip." + icon = 'icons/obj/weapons.dmi' + icon_state = "cane" + item_state = "stick" + /obj/item/weapon/staff/stick name = "stick" desc = "A great tool to drag someone else's drinks across the bar." @@ -393,7 +400,9 @@ /obj/item/weapon/module/power_control name = "power control module" icon_state = "power_mod" - desc = "Heavy-duty switching circuits for power control." + desc = "Heavy-duty switching circuits for power control." + m_amt = 50 + g_amt = 50 /obj/item/weapon/module/id_auth name = "\improper ID authentication module" diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 9133753e4ee..9c04d5b672d 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -56,7 +56,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/ var/list/teleportlocs = list() -proc/process_teleport_locs() +/hook/startup/proc/setupTeleportLocs() for(var/area/AR in world) if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue if(teleportlocs.Find(AR.name)) continue @@ -65,20 +65,13 @@ proc/process_teleport_locs() teleportlocs += AR.name teleportlocs[AR.name] = AR - var/not_in_order = 0 - do - not_in_order = 0 - if(teleportlocs.len <= 1) - break - for(var/i = 1, i <= (teleportlocs.len - 1), i++) - if(sorttext(teleportlocs[i], teleportlocs[i+1]) == -1) - teleportlocs.Swap(i, i+1) - not_in_order = 1 - while(not_in_order) + teleportlocs = sortAssoc(teleportlocs) + + return 1 var/list/ghostteleportlocs = list() -proc/process_ghost_teleport_locs() +/hook/startup/proc/setupGhostTeleportLocs() for(var/area/AR in world) if(ghostteleportlocs.Find(AR.name)) continue if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome)) @@ -89,17 +82,9 @@ proc/process_ghost_teleport_locs() ghostteleportlocs += AR.name ghostteleportlocs[AR.name] = AR - var/not_in_order = 0 - do - not_in_order = 0 - if(ghostteleportlocs.len <= 1) - break - for(var/i = 1, i <= (ghostteleportlocs.len - 1), i++) - if(sorttext(ghostteleportlocs[i], ghostteleportlocs[i+1]) == -1) - ghostteleportlocs.Swap(i, i+1) - not_in_order = 1 - while(not_in_order) + ghostteleportlocs = sortAssoc(ghostteleportlocs) + return 1 /*-----------------------------------------------------------------------------*/ @@ -795,6 +780,14 @@ proc/process_ghost_teleport_locs() name = "\improper Dormitories" icon_state = "Sleep" +/area/crew_quarters/sleep/engi + name = "\improper Engineering Dormitories" + icon_state = "Sleep" + +/area/crew_quarters/sleep/sec + name = "\improper Security Dormitories" + icon_state = "Sleep" + /area/crew_quarters/sleep_male name = "\improper Male Dorm" icon_state = "Sleep" @@ -1322,6 +1315,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/area/areas.dm b/code/game/area/areas.dm index 6695fe44027..f69b2a35e3f 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -100,6 +100,7 @@ return if( !fire ) fire = 1 + master.fire = 1 //used for firedoor checks updateicon() mouse_opacity = 0 for(var/obj/machinery/door/firedoor/D in all_doors) @@ -122,6 +123,7 @@ /area/proc/firereset() if (fire) fire = 0 + master.fire = 0 //used for firedoor checks mouse_opacity = 0 updateicon() for(var/obj/machinery/door/firedoor/D in all_doors) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index f5870a24998..109a95fe729 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -6,6 +6,7 @@ var/list/fingerprintshidden var/fingerprintslast = null var/list/blood_DNA + var/blood_color var/last_bumped = 0 var/pass_flags = 0 var/throwpass = 0 @@ -361,7 +362,9 @@ its easier to just keep the beam vertical. return 0 if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it. blood_DNA = list() - + blood_color = "#A10808" + if (M.species) + blood_color = M.species.blood_color //adding blood to humans else if (istype(src, /mob/living/carbon/human)) var/mob/living/carbon/human/H = src diff --git a/code/game/communications.dm b/code/game/communications.dm index 32d8ca69348..4f13277a31d 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -103,16 +103,16 @@ var/list/radiochannels = list( "Medical" = 1355, "Engineering" = 1357, "Security" = 1359, - "Response Team" = 1443, - "Deathsquad" = 1441, + "Response Team" = 1345, + "Deathsquad" = 1341, "Syndicate" = 1213, "Supply" = 1347, ) //depenging helpers -var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1443, 1441, 1347) +var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1345, 1341, 1347) // central command channels, i.e deathsquid & response teams -var/list/CENT_FREQS = list(1441, 1443) +var/list/CENT_FREQS = list(1345, 1341) var/const/COMM_FREQ = 1353 //command, colored gold in chat window var/const/SYND_FREQ = 1213 @@ -140,6 +140,10 @@ var/const/RADIO_MAGNETS = "9" var/global/datum/controller/radio/radio_controller +/hook/startup/proc/createRadioController() + radio_controller = new /datum/controller/radio() + return 1 + datum/controller/radio var/list/datum/radio_frequency/frequencies = list() diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm new file mode 100644 index 00000000000..e8f4ddc4a8b --- /dev/null +++ b/code/game/dna/dna2.dm @@ -0,0 +1,358 @@ +/** +* DNA 2: The Spaghetti Strikes Back +* +* @author N3X15 +*/ + +// What each index means: +#define DNA_OFF_LOWERBOUND 0 +#define DNA_OFF_UPPERBOUND 1 +#define DNA_ON_LOWERBOUND 2 +#define DNA_ON_UPPERBOUND 3 + +// Define block bounds (off-low,off-high,on-low,on-high) +// Used in setupgame.dm +#define DNA_DEFAULT_BOUNDS list(1,2049,2050,4095) +#define DNA_HARDER_BOUNDS list(1,3049,3050,4095) +#define DNA_HARD_BOUNDS list(1,3490,3500,4095) + +// Defines which values mean "on" or "off". +// This is to make some of the more OP superpowers a larger PITA to activate, +// and to tell our new DNA datum which values to set in order to turn something +// on or off. +var/global/list/dna_activity_bounds[STRUCDNASIZE] + +// Used to determine what each block means (admin hax and species stuff on /vg/, mostly) +var/global/list/assigned_blocks[STRUCDNASIZE] + +var/global/list/datum/dna/gene/dna_genes[0] + +// UI Indices (can change to mutblock style, if desired) +#define DNA_UI_HAIR_R 1 +#define DNA_UI_HAIR_G 2 +#define DNA_UI_HAIR_B 3 +#define DNA_UI_BEARD_R 4 +#define DNA_UI_BEARD_G 5 +#define DNA_UI_BEARD_B 6 +#define DNA_UI_SKIN_TONE 7 +#define DNA_UI_EYES_R 8 +#define DNA_UI_EYES_G 9 +#define DNA_UI_EYES_B 10 +#define DNA_UI_GENDER 11 +#define DNA_UI_BEARD_STYLE 12 +#define DNA_UI_HAIR_STYLE 13 +#define DNA_UI_LENGTH 13 // Update this when you add something, or you WILL break shit. + +///////////////// +// GENE DEFINES +///////////////// + +// Skip checking if it's already active. +// Used for genes that check for value rather than a binary on/off. +#define GENE_ALWAYS_ACTIVATE 1 + +/datum/dna + // READ-ONLY, GETS OVERWRITTEN + // DO NOT FUCK WITH THESE OR BYOND WILL EAT YOUR FACE + var/uni_identity="" // Encoded UI + var/struc_enzymes="" // Encoded SE + var/unique_enzymes="" // MD5 of player name + + // Internal dirtiness checks + var/dirtyUI=0 + var/dirtySE=0 + + // Okay to read, but you're an idiot if you do. + // BLOCK = VALUE + var/list/SE[STRUCDNASIZE] + var/list/UI[DNA_UI_LENGTH] + + // From old dna. + var/b_type = "A+" // Should probably change to an integer => string map but I'm lazy. + var/mutantrace = null // The type of mutant race the player is, if applicable (i.e. potato-man) + var/real_name // Stores the real name of the person who originally got this dna datum. Used primarily for changelings, + + // New stuff + var/species = "Human" + +// Make a copy of this strand. +// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION! +/datum/dna/proc/Clone() + var/datum/dna/new_dna = new() + new_dna.unique_enzymes=unique_enzymes + new_dna.b_type=b_type + new_dna.mutantrace=mutantrace + new_dna.real_name=real_name + new_dna.species=species + for(var/b=1;b<=STRUCDNASIZE;b++) + new_dna.SE[b]=SE[b] + if(b<=DNA_UI_LENGTH) + new_dna.UI[b]=UI[b] + new_dna.UpdateUI() + new_dna.UpdateSE() + return new_dna + +/////////////////////////////////////// +// UNIQUE IDENTITY +/////////////////////////////////////// + +// Create random UI. +/datum/dna/proc/ResetUI(var/defer=0) + for(var/i=1,i<=DNA_UI_LENGTH,i++) + switch(i) + if(DNA_UI_SKIN_TONE) + SetUIValueRange(DNA_UI_SKIN_TONE,rand(1,220),220,1) // Otherwise, it gets fucked + else + UI[i]=rand(0,4095) + if(!defer) + UpdateUI() + +/datum/dna/proc/ResetUIFrom(var/mob/living/carbon/human/character) + // INITIALIZE! + ResetUI(1) + // Hair + // FIXME: Species-specific defaults pls + if(!character.h_style) + character.h_style = "Skinhead" + var/hair = hair_styles_list.Find(character.h_style) + + // Facial Hair + if(!character.f_style) + character.f_style = "Shaved" + var/beard = facial_hair_styles_list.Find(character.f_style) + + SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_G, character.g_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_B, character.b_hair, 255, 1) + + SetUIValueRange(DNA_UI_BEARD_R, character.r_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1) + + SetUIValueRange(DNA_UI_EYES_R, character.r_eyes, 255, 1) + SetUIValueRange(DNA_UI_EYES_G, character.g_eyes, 255, 1) + SetUIValueRange(DNA_UI_EYES_B, character.b_eyes, 255, 1) + + SetUIValueRange(DNA_UI_SKIN_TONE, 35-character.s_tone, 220, 1) // Value can be negative. + + SetUIState(DNA_UI_GENDER, character.gender!=MALE, 1) + + SetUIValueRange(DNA_UI_HAIR_STYLE, hair, hair_styles_list.len, 1) + SetUIValueRange(DNA_UI_BEARD_STYLE, beard, facial_hair_styles_list.len,1) + + UpdateUI() + +// Set a DNA UI block's raw value. +/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0) + if (block<=0) return + ASSERT(value>=0) + ASSERT(value<=4095) + UI[block]=value + dirtyUI=1 + if(!defer) + UpdateUI() + +// Get a DNA UI block's raw value. +/datum/dna/proc/GetUIValue(var/block) + if (block<=0) return 0 + return UI[block] + +// Set a DNA UI block's value, given a value and a max possible value. +// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list) +/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0) + if (block<=0) return + ASSERT(maxvalue<=4095) + var/range = (4095 / maxvalue) + if(value) + SetUIValue(block,round(value * range),defer) + +// Getter version of above. +/datum/dna/proc/GetUIValueRange(var/block,var/maxvalue) + if (block<=0) return 0 + var/value = GetUIValue(block) + return round(1 +(value / 4096)*maxvalue) + +// Is the UI gene "on" or "off"? +// For UI, this is simply a check of if the value is > 2050. +/datum/dna/proc/GetUIState(var/block) + if (block<=0) return + return UI[block] > 2050 + + +// Set UI gene "on" (1) or "off" (0) +/datum/dna/proc/SetUIState(var/block,var/on,var/defer=0) + if (block<=0) return + var/val + if(on) + val=rand(2050,4095) + else + val=rand(1,2049) + SetUIValue(block,val,defer) + +// Get a hex-encoded UI block. +/datum/dna/proc/GetUIBlock(var/block) + return EncodeDNABlock(GetUIValue(block)) + +// Do not use this unless you absolutely have to. +// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetUIBlock(var/block,var/value,var/defer=0) + if (block<=0) return + return SetUIValue(block,hex2num(value),defer) + +// Get a sub-block from a block. +/datum/dna/proc/GetUISubBlock(var/block,var/subBlock) + return copytext(GetUIBlock(block),subBlock,subBlock+1) + +// Do not use this unless you absolutely have to. +// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetUISubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0) + if (block<=0) return + var/oldBlock=GetUIBlock(block) + var/newBlock="" + for(var/i=1, i<=length(oldBlock), i++) + if(i==subBlock) + newBlock+=newSubBlock + else + newBlock+=copytext(oldBlock,i,i+1) + SetUIBlock(block,newBlock,defer) + +/////////////////////////////////////// +// STRUCTURAL ENZYMES +/////////////////////////////////////// + +// "Zeroes out" all of the blocks. +/datum/dna/proc/ResetSE() + for(var/i = 1, i <= STRUCDNASIZE, i++) + SetSEValue(i,rand(1,1024),1) + UpdateSE() + +// Set a DNA SE block's raw value. +/datum/dna/proc/SetSEValue(var/block,var/value,var/defer=0) + //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]") + if (block<=0) return + ASSERT(value>=0) + ASSERT(value<=4095) + SE[block]=value + dirtySE=1 + if(!defer) + UpdateSE() + +// Get a DNA SE block's raw value. +/datum/dna/proc/GetSEValue(var/block) + if (block<=0) return 0 + return SE[block] + +// Set a DNA SE block's value, given a value and a max possible value. +// Might be used for species? +/datum/dna/proc/SetSEValueRange(var/block,var/value,var/maxvalue) + if (block<=0) return + ASSERT(maxvalue<=4095) + var/range = round(4095 / maxvalue) + if(value) + SetSEValue(block, value * range - rand(1,range-1)) + +// Getter version of above. +/datum/dna/proc/GetSEValueRange(var/block,var/maxvalue) + if (block<=0) return 0 + var/value = GetSEValue(block) + return round(1 +(value / 4096)*maxvalue) + +// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.) +/datum/dna/proc/GetSEState(var/block) + if (block<=0) return 0 + var/list/BOUNDS=GetDNABounds(block) + var/value=GetSEValue(block) + return (value > BOUNDS[DNA_ON_LOWERBOUND]) + +// Set a block "on" or "off". +/datum/dna/proc/SetSEState(var/block,var/on,var/defer=0) + if (block<=0) return + var/list/BOUNDS=GetDNABounds(block) + var/val + if(on) + val=rand(BOUNDS[DNA_ON_LOWERBOUND],BOUNDS[DNA_ON_UPPERBOUND]) + else + val=rand(1,BOUNDS[DNA_OFF_UPPERBOUND]) + SetSEValue(block,val,defer) + +// Get hex-encoded SE block. +/datum/dna/proc/GetSEBlock(var/block) + return EncodeDNABlock(GetSEValue(block)) + +// Do not use this unless you absolutely have to. +// Set a block from a hex string. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetSEBlock(var/block,var/value,var/defer=0) + if (block<=0) return + var/nval=hex2num(value) + //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]") + return SetSEValue(block,nval,defer) + +/datum/dna/proc/GetSESubBlock(var/block,var/subBlock) + return copytext(GetSEBlock(block),subBlock,subBlock+1) + +// Do not use this unless you absolutely have to. +// Set a sub-block from a hex character. This is inefficient. If you can, use SetUIValue(). +// Used in DNA modifiers. +/datum/dna/proc/SetSESubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0) + if (block<=0) return + var/oldBlock=GetSEBlock(block) + var/newBlock="" + for(var/i=1, i<=length(oldBlock), i++) + if(i==subBlock) + newBlock+=newSubBlock + else + newBlock+=copytext(oldBlock,i,i+1) + //testing("SetSESubBlock([block],[subBlock],[newSubBlock],[defer]): [oldBlock] -> [newBlock]") + SetSEBlock(block,newBlock,defer) + + +/proc/EncodeDNABlock(var/value) + return add_zero2(num2hex(value,1), 3) + +/datum/dna/proc/UpdateUI() + src.uni_identity="" + for(var/block in UI) + uni_identity += EncodeDNABlock(block) + //testing("New UI: [uni_identity]") + dirtyUI=0 + +/datum/dna/proc/UpdateSE() + //var/oldse=struc_enzymes + struc_enzymes="" + for(var/block in SE) + struc_enzymes += EncodeDNABlock(block) + //testing("Old SE: [oldse]") + //testing("New SE: [struc_enzymes]") + dirtySE=0 + +// BACK-COMPAT! +// Just checks our character has all the crap it needs. +/datum/dna/proc/check_integrity(var/mob/living/carbon/human/character) + if(character) + if(UI.len != DNA_UI_LENGTH) + ResetUIFrom(character) + + if(length(struc_enzymes)!= 3*STRUCDNASIZE) + ResetSE() + + if(length(unique_enzymes) != 32) + unique_enzymes = md5(character.real_name) + else + if(length(uni_identity) != 3*DNA_UI_LENGTH) + uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4" + if(length(struc_enzymes)!= 3*STRUCDNASIZE) + struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" + +// BACK-COMPAT! +// Initial DNA setup. I'm kind of wondering why the hell this doesn't just call the above. +/datum/dna/proc/ready_dna(mob/living/carbon/human/character) + ResetUIFrom(character) + + ResetSE() + + unique_enzymes = md5(character.real_name) + reg_dna[unique_enzymes] = character.real_name + diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm new file mode 100644 index 00000000000..a53fc49c292 --- /dev/null +++ b/code/game/dna/dna2_domutcheck.dm @@ -0,0 +1,358 @@ +// (Re-)Apply mutations. +// TODO: Turn into a /mob proc, change inj to a bitflag for various forms of differing behavior. +// M: Mob to mess with +// connected: Machine we're in, type unchecked so I doubt it's used beyond monkeying +// flags: See below, bitfield. +#define MUTCHK_FORCED 1 +/proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0) + for(var/datum/dna/gene/gene in dna_genes) + if(!M) + return + if(!gene.block) + continue + + // Sanity checks, don't skip. + if(!gene.can_activate(M,flags)) + //testing("[M] - Failed to activate [gene.name] (can_activate fail).") + continue + + // Current state + var/gene_active = (gene.flags & GENE_ALWAYS_ACTIVATE) + if(!gene_active) + gene_active = M.dna.GetSEState(gene.block) + + // Prior state + var/gene_prior_status = (gene.type in M.active_genes) + + if((gene_active && !gene_prior_status) || (gene.flags & GENE_ALWAYS_ACTIVATE)) + //testing("[gene.name] activated!") + gene.activate(M,connected,flags) + if(M) + if(!(gene.flags & GENE_ALWAYS_ACTIVATE)) + M.active_genes |= gene.type + M.update_icon=1 + else if(!gene_active && gene_prior_status) + //testing("[gene.name] deactivated!") + gene.deactivate(M,connected,flags) + if(M) + M.active_genes -= gene.type + M.update_icon = 1 + //else + // testing("[M] - Failed to activate [gene.name] - [gene_active?"+":"-"]active, [gene_prior_status?"+":"-"]prior") + + + // PROC CONTINUES BELOW AFTER COMMENTED CODE. + +/* Old, inflexibile +/proc/domutcheck(var/mob/living/M, var/connected, var/flags) + if (!M) return + + M.dna.check_integrity() + + M.disabilities = 0 + M.sdisabilities = 0 + var/old_mutations = M.mutations + M.mutations = list() + M.pass_flags = 0 +// M.see_in_dark = 2 +// M.see_invisible = 0 + + if(PLANT in old_mutations) + M.mutations.Add(PLANT) + if(SKELETON in old_mutations) + M.mutations.Add(SKELETON) + if(FAT in old_mutations) + M.mutations.Add(FAT) + if(HUSK in old_mutations) + M.mutations.Add(HUSK) + + var/inj = (flags & MUTCHK_FROM_INJECTOR) == MUTCHK_FROM_INJECTOR + var/forced = (flags & MUTCHK_FORCED) == MUTCHK_FORCED + + if(M.dna.GetSEState(NOBREATHBLOCK)) + if(forced || probinj(45,inj) || (mNobreath in old_mutations)) + M << "\blue You feel no need to breathe." + M.mutations.Add(mNobreath) + if(M.dna.GetSEState(REMOTEVIEWBLOCK)) + if(forced || probinj(45,inj) || (mRemote in old_mutations)) + M << "\blue Your mind expands" + M.mutations.Add(mRemote) + M.verbs += /mob/living/carbon/human/proc/remoteobserve + if(M.dna.GetSEState(REGENERATEBLOCK)) + if(forced || probinj(45,inj) || (mRegen in old_mutations)) + M << "\blue You feel better" + M.mutations.Add(mRegen) + if(M.dna.GetSEState(INCREASERUNBLOCK)) + if(forced || probinj(45,inj) || (mRun in old_mutations)) + M << "\blue Your leg muscles pulsate." + M.mutations.Add(mRun) + if(M.dna.GetSEState(REMOTETALKBLOCK)) + if(forced || probinj(45,inj) || (mRemotetalk in old_mutations)) + M << "\blue You expand your mind outwards" + M.mutations.Add(mRemotetalk) + M.verbs += /mob/living/carbon/human/proc/remotesay + if(M.dna.GetSEState(MORPHBLOCK)) + if(forced || probinj(45,inj) || (mMorph in old_mutations)) + M.mutations.Add(mMorph) + M << "\blue Your skin feels strange" + M.verbs += /mob/living/carbon/human/proc/morph + if(M.dna.GetSEState(COLDBLOCK)) + if(!(COLD_RESISTANCE in old_mutations)) + if(forced || probinj(15,inj) || (mHeatres in old_mutations)) + M.mutations.Add(mHeatres) + M << "\blue Your skin is icy to the touch" + else + if(forced || probinj(5,inj) || (mHeatres in old_mutations)) + M.mutations.Add(mHeatres) + M << "\blue Your skin is icy to the touch" + if(M.dna.GetSEState(HALLUCINATIONBLOCK)) + if(forced || probinj(45,inj) || (mHallucination in old_mutations)) + M.mutations.Add(mHallucination) + M << "\red Your mind says 'Hello'" + if(M.dna.GetSEState(NOPRINTSBLOCK)) + if(forced || probinj(45,inj) || (mFingerprints in old_mutations)) + M.mutations.Add(mFingerprints) + M << "\blue Your fingers feel numb" + if(M.dna.GetSEState(SHOCKIMMUNITYBLOCK)) + if(forced || probinj(45,inj) || (mShock in old_mutations)) + M.mutations.Add(mShock) + M << "\blue Your skin feels strange" + if(M.dna.GetSEState(SMALLSIZEBLOCK)) + if(forced || probinj(45,inj) || (mSmallsize in old_mutations)) + M << "\blue Your skin feels rubbery" + M.mutations.Add(mSmallsize) + M.pass_flags |= 1 + + + + if (M.dna.GetSEState(HULKBLOCK)) + if(forced || probinj(5,inj) || (HULK in old_mutations)) + M << "\blue Your muscles hurt." + M.mutations.Add(HULK) + if (M.dna.GetSEState(HEADACHEBLOCK)) + M.disabilities |= EPILEPSY + M << "\red You get a headache." + if (M.dna.GetSEState(FAKEBLOCK)) + M << "\red You feel strange." + if (prob(95)) + if(prob(50)) + randmutb(M) + else + randmuti(M) + else + randmutg(M) + if (M.dna.GetSEState(COUGHBLOCK)) + M.disabilities |= COUGHING + M << "\red You start coughing." + if (M.dna.GetSEState(CLUMSYBLOCK)) + M << "\red You feel lightheaded." + M.mutations.Add(CLUMSY) + if (M.dna.GetSEState(TWITCHBLOCK)) + M.disabilities |= TOURETTES + M << "\red You twitch." + if (M.dna.GetSEState(XRAYBLOCK)) + if(forced || probinj(30,inj) || (XRAY in old_mutations)) + M << "\blue The walls suddenly disappear." +// M.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS) +// M.see_in_dark = 8 +// M.see_invisible = 2 + M.mutations.Add(XRAY) + if (M.dna.GetSEState(NERVOUSBLOCK)) + M.disabilities |= NERVOUS + M << "\red You feel nervous." + if (M.dna.GetSEState(FIREBLOCK)) + if(!(mHeatres in old_mutations)) + if(forced || probinj(30,inj) || (COLD_RESISTANCE in old_mutations)) + M << "\blue Your body feels warm." + M.mutations.Add(COLD_RESISTANCE) + else + if(forced || probinj(5,inj) || (COLD_RESISTANCE in old_mutations)) + M << "\blue Your body feels warm." + M.mutations.Add(COLD_RESISTANCE) + if (M.dna.GetSEState(BLINDBLOCK)) + M.sdisabilities |= BLIND + M << "\red You can't seem to see anything." + if (M.dna.GetSEState(TELEBLOCK)) + if(forced || probinj(15,inj) || (TK in old_mutations)) + M << "\blue You feel smarter." + M.mutations.Add(TK) + if (M.dna.GetSEState(DEAFBLOCK)) + M.sdisabilities |= DEAF + M.ear_deaf = 1 + M << "\red Its kinda quiet.." + if (M.dna.GetSEState(GLASSESBLOCK)) + M.disabilities |= NEARSIGHTED + M << "Your eyes feel weird..." + + /* If you want the new mutations to work, UNCOMMENT THIS. + if(istype(M, /mob/living/carbon)) + for (var/datum/mutations/mut in global_mutations) + mut.check_mutation(M) + */ + +//////////////////////////////////////////////////////////// Monkey Block + if (M.dna.GetSEState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human)) + // human > monkey + var/mob/living/carbon/human/H = M + H.monkeyizing = 1 + var/list/implants = list() //Try to preserve implants. + for(var/obj/item/weapon/implant/W in H) + implants += W + W.loc = null + + if(!connected) + for(var/obj/item/W in (H.contents-implants)) + if (W==H.w_uniform) // will be teared + continue + H.drop_from_inventory(W) + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.invisibility = 101 + var/atom/movable/overlay/animation = new( M.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(48) + del(animation) + + + var/mob/living/carbon/monkey/O = null + if(H.species.primitive) + O = new H.species.primitive(src) + else + H.gib() //Trying to change the species of a creature with no primitive var set is messy. + return + + if(M) + if (M.dna) + O.dna = M.dna + M.dna = null + + if (M.suiciding) + O.suiciding = M.suiciding + M.suiciding = null + + + for(var/datum/disease/D in M.viruses) + O.viruses += D + D.affected_mob = O + M.viruses -= D + + + for(var/obj/T in (M.contents-implants)) + del(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) //transfer our mind to the cute little monkey + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6)) + O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss()) + O.adjustToxLoss(M.getToxLoss() + 20) + O.adjustOxyLoss(M.getOxyLoss()) + O.stat = M.stat + O.a_intent = "hurt" + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O +// O.update_icon = 1 //queue a full icon update at next life() call + del(M) + return + + if (!M.dna.GetSEState(MONKEYBLOCK) && !istype(M, /mob/living/carbon/human)) + // monkey > human, + var/mob/living/carbon/monkey/Mo = M + Mo.monkeyizing = 1 + var/list/implants = list() //Still preserving implants + for(var/obj/item/weapon/implant/W in Mo) + implants += W + W.loc = null + if(!connected) + for(var/obj/item/W in (Mo.contents-implants)) + Mo.drop_from_inventory(W) + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.invisibility = 101 + var/atom/movable/overlay/animation = new( M.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(48) + del(animation) + + var/mob/living/carbon/human/O = new( src ) + if(Mo.greaterform) + O.set_species(Mo.greaterform) + + if (M.dna.GetUIState(DNA_UI_GENDER)) + O.gender = FEMALE + else + O.gender = MALE + + if (M) + if (M.dna) + O.dna = M.dna + M.dna = null + + if (M.suiciding) + O.suiciding = M.suiciding + M.suiciding = null + + for(var/datum/disease/D in M.viruses) + O.viruses += D + D.affected_mob = O + M.viruses -= D + + //for(var/obj/T in M) + // del(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) //transfer our mind to the human + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + + var/i + while (!i) + var/randomname + if (O.gender == MALE) + randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names))) + else + randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names))) + if (findname(randomname)) + continue + else + O.real_name = randomname + i++ + O.UpdateAppearance() + O.take_overall_damage(M.getBruteLoss(), M.getFireLoss()) + O.adjustToxLoss(M.getToxLoss()) + O.adjustOxyLoss(M.getOxyLoss()) + O.stat = M.stat + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O +// O.update_icon = 1 //queue a full icon update at next life() call + del(M) + return +//////////////////////////////////////////////////////////// Monkey Block + if(M) + M.update_icon = 1 //queue a full icon update at next life() call + return null +/////////////////////////// DNA MISC-PROCS +*/ diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm new file mode 100644 index 00000000000..216832f3cf7 --- /dev/null +++ b/code/game/dna/dna2_helpers.dm @@ -0,0 +1,175 @@ +///////////////////////////// +// Helpers for DNA2 +///////////////////////////// + +// Pads 0s to t until length == u +/proc/add_zero2(t, u) + var/temp1 + while (length(t) < u) + t = "0[t]" + temp1 = t + if (length(t) > u) + temp1 = copytext(t,2,u+1) + return temp1 + +// DNA Gene activation boundaries, see dna2.dm. +// Returns a list object with 4 numbers. +/proc/GetDNABounds(var/block) + var/list/BOUNDS=dna_activity_bounds[block] + if(!istype(BOUNDS)) + return DNA_DEFAULT_BOUNDS + return BOUNDS + +// Give Random Bad Mutation to M +/proc/randmutb(var/mob/living/M) + if(!M) return + M.dna.check_integrity() + var/block = pick(GLASSESBLOCK,COUGHBLOCK,FAKEBLOCK,NERVOUSBLOCK,CLUMSYBLOCK,TWITCHBLOCK,HEADACHEBLOCK,BLINDBLOCK,DEAFBLOCK,HALLUCINATIONBLOCK) + M.dna.SetSEState(block, 1) + +// Give Random Good Mutation to M +/proc/randmutg(var/mob/living/M) + if(!M) return + M.dna.check_integrity() + var/block = pick(HULKBLOCK,XRAYBLOCK,FIREBLOCK,TELEBLOCK,NOBREATHBLOCK,REMOTEVIEWBLOCK,REGENERATEBLOCK,INCREASERUNBLOCK,REMOTETALKBLOCK,MORPHBLOCK,BLENDBLOCK,NOPRINTSBLOCK,SHOCKIMMUNITYBLOCK,SMALLSIZEBLOCK) + M.dna.SetSEState(block, 1) + +// Random Appearance Mutation +/proc/randmuti(var/mob/living/M) + if(!M) return + M.dna.check_integrity() + M.dna.SetUIValue(rand(1,UNIDNASIZE),rand(1,4095)) + +// Scramble UI or SE. +/proc/scramble(var/UI, var/mob/M, var/prob) + if(!M) return + M.dna.check_integrity() + if(UI) + for(var/i = 1, i <= DNA_UI_LENGTH-1, i++) + if(prob(prob)) + M.dna.SetUIValue(i,rand(1,4095),1) + M.dna.UpdateUI() + M.UpdateAppearance() + + else + for(var/i = 1, i <= STRUCDNASIZE-1, i++) + if(prob(prob)) + M.dna.SetSEValue(i,rand(1,4095),1) + M.dna.UpdateSE() + domutcheck(M, null) + return + +// I haven't yet figured out what the fuck this is supposed to do. +/proc/miniscramble(input,rs,rd) + var/output + output = null + if (input == "C" || input == "D" || input == "E" || input == "F") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"6",prob((rs*10));"7",prob((rs*5)+(rd));"0",prob((rs*5)+(rd));"1",prob((rs*10)-(rd));"2",prob((rs*10)-(rd));"3") + if (input == "8" || input == "9" || input == "A" || input == "B") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") + if (input == "4" || input == "5" || input == "6" || input == "7") + output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3") + if (input == "0" || input == "1" || input == "2" || input == "3") + output = pick(prob((rs*10));"8",prob((rs*10));"9",prob((rs*10));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C",prob((rs*10)-(rd));"D",prob((rs*5)+(rd));"E",prob((rs*5)+(rd));"F") + if (!output) output = "5" + return output + +// HELLO I MAKE BELL CURVES AROUND YOUR DESIRED TARGET +// So a shitty way of replacing gaussian noise. +// input: YOUR TARGET +// rs: RAD STRENGTH +// rd: DURATION +/proc/miniscrambletarget(input,rs,rd) + var/output = null + switch(input) + if("0") + output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10));"2",prob((rs*10)-(rd));"3") + if("1") + output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10));"3",prob((rs*10)-(rd));"4") + if("2") + output = pick(prob((rs*10));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10));"4",prob((rs*10)-(rd));"5") + if("3") + output = pick(prob((rs*10)-(rd));"0",prob((rs*10));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10));"5",prob((rs*10)-(rd));"6") + if("4") + output = pick(prob((rs*10)-(rd));"1",prob((rs*10));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10));"6",prob((rs*10)-(rd));"7") + if("5") + output = pick(prob((rs*10)-(rd));"2",prob((rs*10));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10));"7",prob((rs*10)-(rd));"8") + if("6") + output = pick(prob((rs*10)-(rd));"3",prob((rs*10));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10));"8",prob((rs*10)-(rd));"9") + if("7") + output = pick(prob((rs*10)-(rd));"4",prob((rs*10));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10));"9",prob((rs*10)-(rd));"A") + if("8") + output = pick(prob((rs*10)-(rd));"5",prob((rs*10));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10));"A",prob((rs*10)-(rd));"B") + if("9") + output = pick(prob((rs*10)-(rd));"6",prob((rs*10));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C") + if("10")//A + output = pick(prob((rs*10)-(rd));"7",prob((rs*10));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10));"C",prob((rs*10)-(rd));"D") + if("11")//B + output = pick(prob((rs*10)-(rd));"8",prob((rs*10));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10));"D",prob((rs*10)-(rd));"E") + if("12")//C + output = pick(prob((rs*10)-(rd));"9",prob((rs*10));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10));"E",prob((rs*10)-(rd));"F") + if("13")//D + output = pick(prob((rs*10)-(rd));"A",prob((rs*10));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10));"F") + if("14")//E + output = pick(prob((rs*10)-(rd));"B",prob((rs*10));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F") + if("15")//F + output = pick(prob((rs*10)-(rd));"C",prob((rs*10));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F") + + if(!input || !output) //How did this happen? + output = "8" + + return output + +// /proc/updateappearance has changed behavior, so it's been removed +// Use mob.UpdateAppearance() instead. + +// Simpler. Don't specify UI in order for the mob to use its own. +/mob/proc/UpdateAppearance(var/list/UI=null) + if(istype(src, /mob/living/carbon/human)) + if(UI!=null) + src.dna.UI=UI + src.dna.UpdateUI() + dna.check_integrity() + var/mob/living/carbon/human/H = src + H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255) + H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255) + H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255) + + H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255) + H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) + H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) + + H.r_eyes = dna.GetUIValueRange(DNA_UI_EYES_R, 255) + H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255) + H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255) + + var/new_s_tone = dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) + H.s_tone = 35 - max(min( round(new_s_tone), 220),1) //Warning MATH. Blame the person that wrote modules/client/preferences.dm, line 994 + + if (dna.GetUIState(DNA_UI_GENDER)) + H.gender = FEMALE + else + H.gender = MALE + + //Hair + var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len) + if((0 < hair) && (hair <= hair_styles_list.len)) + H.h_style = hair_styles_list[hair] + + //Facial Hair + var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len) + if((0 < beard) && (beard <= facial_hair_styles_list.len)) + H.f_style = facial_hair_styles_list[beard] + + H.update_body(0) + H.update_hair() + + return 1 + else + return 0 + +// Used below, simple injection modifier. +/proc/probinj(var/pr, var/inj) + return prob(pr+inj*pr) + +/////////////////////////// DNA MISC-PROCS diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 28598b175bb..6b91a6c4912 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -1,5 +1,37 @@ #define DNA_BLOCK_SIZE 3 +// Buffer datatype flags. +#define DNA2_BUF_UI 1 +#define DNA2_BUF_UE 2 +#define DNA2_BUF_SE 4 + +//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0), +/datum/dna2/record + var/datum/dna/dna = null + var/types=0 + var/name="Empty" + + // Stuff for cloners + var/id=null + var/implant=null + var/ckey=null + var/mind=null + +/datum/dna2/record/proc/GetData() + var/list/ser=list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0) + ser["ue"] = (types & DNA2_BUF_UE) == DNA2_BUF_UE + if(types & DNA2_BUF_SE) + ser["data"] = dna.SE + else + ser["data"] = dna.UI + ser["owner"] = src.dna.real_name + ser["label"] = name + if(types & DNA2_BUF_UI) + ser["type"] = "ui" + else + ser["type"] = "se" + return ser + /////////////////////////// DNA MACHINES /obj/machinery/dna_scannernew name = "\improper DNA modifier" @@ -14,6 +46,7 @@ var/locked = 0 var/mob/living/carbon/occupant = null var/obj/item/weapon/reagent_containers/glass/beaker = null + var/opened = 0 /obj/machinery/dna_scannernew/New() ..() @@ -80,12 +113,6 @@ usr.loc = src src.occupant = usr src.icon_state = "scanner_1" - /* - for(var/obj/O in src) // THIS IS P. STUPID -- LOVE, DOOHL - //O = null - del(O) - //Foreach goto(124) - */ src.add_fingerprint(usr) return @@ -111,7 +138,12 @@ if (G.affecting.abiotic()) user << "\blue Subject cannot have abiotic items on." return - var/mob/M = G.affecting + put_in(G.affecting) + src.add_fingerprint(user) + del(G) + return + +/obj/machinery/dna_scannernew/proc/put_in(var/mob/M) if(M.client) M.client.perspective = EYE_PERSPECTIVE M.client.eye = src @@ -119,8 +151,6 @@ src.occupant = M src.icon_state = "scanner_1" - src.add_fingerprint(user) - // search for ghosts, if the corpse is empty and the scanner is connected to a cloner if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \ || locate(/obj/machinery/computer/cloning, get_step(src, SOUTH)) \ @@ -132,19 +162,11 @@ if(ghost.mind == M.mind) ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)" break - del(G) return /obj/machinery/dna_scannernew/proc/go_out() if ((!( src.occupant ) || src.locked)) return -/* -// it's like this was -just- here to break constructed dna scanners -Pete -// if that's not the case, slap my shit and uncomment this. -// for(var/obj/O in src) -// O.loc = src.loc -*/ - //Foreach goto(30) if (src.occupant.client) src.occupant.client.eye = src.occupant.client.mob src.occupant.client.perspective = MOB_PERSPECTIVE @@ -205,11 +227,7 @@ var/selected_ui_target_hex = 1 var/radiation_duration = 2.0 var/radiation_intensity = 1.0 - var/list/buffers = list( - list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0), - list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0), - list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0) - ) + var/list/datum/dna2/record/buffers[3] var/irradiating = 0 var/injector_ready = 0 //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete var/obj/machinery/dna_scannernew/connected = null @@ -219,6 +237,7 @@ use_power = 1 idle_power_usage = 10 active_power_usage = 400 + var/waiting_for_user_input=0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X /obj/machinery/computer/scan_consolenew/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/weapon/screwdriver)) @@ -302,19 +321,19 @@ return return -/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/buffer) +/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/list/buffer) var/list/arr = list() - for(var/i = 1, i <= length(buffer)/3, i++) - arr += "[i]:[copytext(buffer,i*3-2,i*3+1)]" + for(var/i = 1, i <= buffer.len, i++) + arr += "[i]:[EncodeDNABlock(buffer[i])]" return arr -/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/buffer) +/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/datum/dna2/record/buffer) var/pos = findtext(blk,":") if(!pos) return 0 var/id = text2num(copytext(blk,1,pos)) if(!id) return 0 I.block = id - I.dna = copytext(buffer,id*3-2,id*3+1) + I.buf = buffer return 1 /obj/machinery/computer/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob) @@ -336,6 +355,7 @@ ui_interact(user) /obj/machinery/computer/scan_consolenew/attack_ai(user as mob) + src.add_hiddenprint(user) ui_interact(user) /obj/machinery/computer/scan_consolenew/attack_hand(user as mob) @@ -345,7 +365,7 @@ /** * The ui_interact proc is used to open and update Nano UIs * If ui_interact is not used then the UI will not update correctly - * ui_interact is currently defined for /atom/movable + * ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob) * * @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") @@ -363,27 +383,26 @@ data["selectedMenuKey"] = selected_menu_key data["locked"] = src.connected.locked data["hasOccupant"] = connected.occupant ? 1 : 0 - + data["isInjectorReady"] = injector_ready data["hasDisk"] = disk ? 1 : 0 var/diskData[0] - if (!disk) + if (!disk || !disk.buf) diskData["data"] = null diskData["owner"] = null diskData["label"] = null diskData["type"] = null diskData["ue"] = null else - diskData["data"] = disk.data - diskData["owner"] = disk.owner - diskData["label"] = disk.name - diskData["type"] = disk.data_type - diskData["ue"] = disk.ue + diskData = disk.buf.GetData() data["disk"] = diskData - data["buffers"] = buffers + var/list/new_buffers = list() + for(var/datum/dna2/record/buf in buffers) + new_buffers.Add(buf.GetData()) + data["buffers"]=new_buffers data["radiationIntensity"] = radiation_intensity data["radiationDuration"] = radiation_duration @@ -432,23 +451,19 @@ if (connected.beaker.reagents && connected.beaker.reagents.reagent_list.len) for(var/datum/reagent/R in connected.beaker.reagents.reagent_list) data["beakerVolume"] += R.volume - - if (!ui) // no ui has been passed, so we'll search for one - { - ui = nanomanager.get_open_ui(user, src, ui_key) - } + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) if (!ui) - // the ui does not exist, so we'll create a new one + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm ui = new(user, src, ui_key, "dna_modifier.tmpl", "DNA Modifier Console", 660, 700) - // When the UI is first opened this is the data it will use - ui.set_initial_data(data) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window ui.open() - // Auto update every Master Controller tick + // 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/computer/scan_consolenew/Topic(href, href_list) if(..()) @@ -571,10 +586,7 @@ return 1 // return 1 forces an update to all Nano uis attached to src if (href_list["pulseUIRadiation"]) - var/block - var/newblock - var/tstructure2 - block = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),src.selected_ui_subblock,1) + var/block = src.connected.occupant.dna.GetUISubBlock(src.selected_ui_block,src.selected_ui_subblock) irradiating = src.radiation_duration var/lock_state = src.connected.locked @@ -590,13 +602,8 @@ if (prob((80 + (src.radiation_duration / 2)))) block = miniscrambletarget(num2text(selected_ui_target), src.radiation_intensity, src.radiation_duration) - newblock = null - if (src.selected_ui_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),3,1) - if (src.selected_ui_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),3,1) - if (src.selected_ui_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),2,1) + block - tstructure2 = setblock(src.connected.occupant.dna.uni_identity, src.selected_ui_block, newblock,DNA_BLOCK_SIZE) - src.connected.occupant.dna.uni_identity = tstructure2 - updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + src.connected.occupant.dna.SetUISubBlock(src.selected_ui_block,src.selected_ui_subblock,block) + src.connected.occupant.UpdateAppearance() src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration) else if (prob(20+src.radiation_intensity)) @@ -604,7 +611,7 @@ domutcheck(src.connected.occupant,src.connected) else randmuti(src.connected.occupant) - updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) + src.connected.occupant.UpdateAppearance() src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration) src.connected.locked = lock_state return 1 // return 1 forces an update to all Nano uis attached to src @@ -632,15 +639,13 @@ src.selected_se_block = select_block if ((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1)) src.selected_se_subblock = select_subblock + //testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).") return 1 // return 1 forces an update to all Nano uis attached to src if (href_list["pulseSERadiation"]) - var/block - var/newblock - var/tstructure2 - var/oldblock - - block = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),src.selected_se_subblock,1) + var/block = src.connected.occupant.dna.GetSESubBlock(src.selected_se_block,src.selected_se_subblock) + //var/original_block=block + //testing("Irradiating SE block [src.selected_se_block]:[src.selected_se_subblock] ([block])...") irradiating = src.radiation_duration var/lock_state = src.connected.locked @@ -653,47 +658,37 @@ if(src.connected.occupant) if (prob((80 + (src.radiation_duration / 2)))) - if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20)) - oldblock = src.selected_se_block - block = miniscramble(block, src.radiation_intensity, src.radiation_duration) - newblock = null + // FIXME: Find out what these corresponded to and change them to the WHATEVERBLOCK they need to be. + //if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20)) + var/real_SE_block=selected_se_block + block = miniscramble(block, src.radiation_intensity, src.radiation_duration) + if(prob(20)) if (src.selected_se_block > 1 && src.selected_se_block < STRUCDNASIZE/2) - src.selected_se_block++ + real_SE_block++ else if (src.selected_se_block > STRUCDNASIZE/2 && src.selected_se_block < STRUCDNASIZE) - src.selected_se_block-- - if (src.selected_se_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1) - if (src.selected_se_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1) - if (src.selected_se_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + block - tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.selected_se_block, newblock,DNA_BLOCK_SIZE) - src.connected.occupant.dna.struc_enzymes = tstructure2 - domutcheck(src.connected.occupant,src.connected) - src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration) - src.selected_se_block = oldblock - else - // - block = miniscramble(block, src.radiation_intensity, src.radiation_duration) - newblock = null - if (src.selected_se_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1) - if (src.selected_se_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1) - if (src.selected_se_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + block - tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.selected_se_block, newblock,DNA_BLOCK_SIZE) - src.connected.occupant.dna.struc_enzymes = tstructure2 - domutcheck(src.connected.occupant,src.connected) - src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration) + real_SE_block-- + + //testing("Irradiated SE block [real_SE_block]:[src.selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!") + connected.occupant.dna.SetSESubBlock(real_SE_block,selected_se_subblock,block) + src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration) + domutcheck(src.connected.occupant,src.connected) else + src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration) if (prob(80-src.radiation_duration)) + //testing("Random bad mut!") randmutb(src.connected.occupant) domutcheck(src.connected.occupant,src.connected) else randmuti(src.connected.occupant) - updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) - src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration) + //testing("Random identity mut!") + src.connected.occupant.UpdateAppearance() src.connected.locked = lock_state return 1 // return 1 forces an update to all Nano uis attached to src if(href_list["ejectBeaker"]) if(connected.beaker) - connected.beaker.loc = connected.loc + var/obj/item/weapon/reagent_containers/glass/B = connected.beaker + B.loc = connected.loc connected.beaker = null return 1 @@ -704,18 +699,14 @@ // Transfer Buffer Management if(href_list["bufferOption"]) var/bufferOption = href_list["bufferOption"] - + // These bufferOptions do not require a bufferId if (bufferOption == "wipeDisk") if ((isnull(src.disk)) || (src.disk.read_only)) //src.temphtml = "Invalid disk. Please try again." return 0 - src.disk.data = null - src.disk.data_type = null - src.disk.ue = null - src.disk.owner = null - src.disk.name = null + src.disk.buf=null //src.temphtml = "Data saved." return 1 @@ -724,12 +715,12 @@ return src.disk.loc = get_turf(src) src.disk = null - return 1 - + return 1 + // All bufferOptions from here on require a bufferId if (!href_list["bufferId"]) return 0 - + var/bufferId = text2num(href_list["bufferId"]) if (bufferId < 1 || bufferId > 3) @@ -737,56 +728,46 @@ if (bufferOption == "saveUI") if(src.connected.occupant && src.connected.occupant.dna) - src.buffers[bufferId]["ue"] = 0 - src.buffers[bufferId]["data"] = src.connected.occupant.dna.uni_identity - if (!istype(src.connected.occupant,/mob/living/carbon/human)) - src.buffers[bufferId]["owner"] = src.connected.occupant.name - else - src.buffers[bufferId]["owner"] = src.connected.occupant.real_name - src.buffers[bufferId]["label"] = "Unique Identifier" - src.buffers[bufferId]["type"] = "ui" + var/datum/dna2/record/databuf=new + databuf.types = DNA2_BUF_UE + databuf.dna = src.connected.occupant.dna + databuf.name = "Unique Identifier" + src.buffers[bufferId] = databuf return 1 if (bufferOption == "saveUIAndUE") if(src.connected.occupant && src.connected.occupant.dna) - src.buffers[bufferId]["data"] = src.connected.occupant.dna.uni_identity - if (!istype(src.connected.occupant,/mob/living/carbon/human)) - src.buffers[bufferId]["owner"] = src.connected.occupant.name - else - src.buffers[bufferId]["owner"] = src.connected.occupant.real_name - src.buffers[bufferId]["label"] = "Unique Identifier + Unique Enzymes" - src.buffers[bufferId]["type"] = "ui" - src.buffers[bufferId]["ue"] = 1 + var/datum/dna2/record/databuf=new + databuf.types = DNA2_BUF_UI|DNA2_BUF_UE + databuf.dna = src.connected.occupant.dna + databuf.name = "Unique Identifier + Unique Enzymes" + src.buffers[bufferId] = databuf return 1 if (bufferOption == "saveSE") if(src.connected.occupant && src.connected.occupant.dna) - src.buffers[bufferId]["ue"] = 0 - src.buffers[bufferId]["data"] = src.connected.occupant.dna.struc_enzymes - if (!istype(src.connected.occupant,/mob/living/carbon/human)) - src.buffers[bufferId]["owner"] = src.connected.occupant.name - else - src.buffers[bufferId]["owner"] = src.connected.occupant.real_name - src.buffers[bufferId]["label"] = "Structural Enzymes" - src.buffers[bufferId]["type"] = "se" + var/datum/dna2/record/databuf=new + databuf.types = DNA2_BUF_SE + databuf.dna = src.connected.occupant.dna + databuf.name = "Structural Enzymes" + src.buffers[bufferId] = databuf return 1 if (bufferOption == "clear") - src.buffers[bufferId]["data"] = null - src.buffers[bufferId]["owner"] = null - src.buffers[bufferId]["label"] = null - src.buffers[bufferId]["ue"] = null + src.buffers[bufferId]=null return 1 if (bufferOption == "changeLabel") - var/label = src.buffers[bufferId]["label"] ? src.buffers[bufferId]["label"] : "New Label" - src.buffers[bufferId]["label"] = sanitize(input("New Label:", "Edit Label", label)) + var/datum/dna2/record/buf = src.buffers[bufferId] + buf.name = buf.name ? src.buffers[bufferId]["label"] : "New Label" + buf.name = sanitize(input("New Label:", "Edit Label", buf.name)) + src.buffers[bufferId] = buf return 1 if (bufferOption == "transfer") if (!src.connected.occupant || (NOCLONE in src.connected.occupant.mutations) || !src.connected.occupant.dna) return - + irradiating = 2 var/lock_state = src.connected.locked src.connected.locked = 1//lock it @@ -796,33 +777,37 @@ irradiating = 0 src.connected.locked = lock_state - - if (src.buffers[bufferId]["type"] == "ui") - if (src.buffers[bufferId]["ue"]) - src.connected.occupant.real_name = src.buffers[bufferId]["owner"] - src.connected.occupant.name = src.buffers[bufferId]["owner"] - src.connected.occupant.dna.uni_identity = src.buffers[bufferId]["data"] - updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity) - else if (src.buffers[bufferId]["type"] == "se") - src.connected.occupant.dna.struc_enzymes = src.buffers[bufferId]["data"] + + var/datum/dna2/record/buf = src.buffers[bufferId] + + if ((buf.types & DNA2_BUF_UI)) + if ((buf.types & DNA2_BUF_UE)) + src.connected.occupant.real_name = buf.dna.real_name + src.connected.occupant.name = buf.dna.real_name + src.connected.occupant.UpdateAppearance(buf.dna.UI) + else if (buf.types & DNA2_BUF_SE) + src.connected.occupant.dna.SE = buf.dna.SE + src.connected.occupant.dna.UpdateSE() domutcheck(src.connected.occupant,src.connected) src.connected.occupant.radiation += rand(20,50) return 1 if (bufferOption == "createInjector") - if (src.injector_ready) + if (src.injector_ready || waiting_for_user_input) + var/success = 1 var/obj/item/weapon/dnainjector/I = new /obj/item/weapon/dnainjector - I.dnatype = src.buffers[bufferId]["type"] + var/datum/dna2/record/buf = src.buffers[bufferId] if(href_list["createBlockInjector"]) - var/blk = input(usr,"Select Block","Block") in all_dna_blocks(src.buffers[bufferId]["data"]) - success = setInjectorBlock(I,blk,src.buffers[bufferId]["data"]) + waiting_for_user_input=1 + var/blk = input(usr,"Select Block","Block") in all_dna_blocks(buf.GetData()) + success = setInjectorBlock(I,blk,buf) else - I.dna = src.buffers[bufferId]["data"] + I.buf = buf + waiting_for_user_input=0 if(success) I.loc = src.loc - I.name += " ([src.buffers[bufferId]["label"]])" - if (src.buffers[bufferId]["ue"]) I.ue = src.buffers[bufferId]["owner"] //lazy haw haw + I.name += " ([buf.name])" //src.temphtml = "Injector created." src.injector_ready = 0 spawn(300) @@ -834,14 +819,11 @@ return 1 if (bufferOption == "loadDisk") - if ((isnull(src.disk)) || (!src.disk.data) || (src.disk.data == "")) + if ((isnull(src.disk)) || (!src.disk.buf)) //src.temphtml = "Invalid disk. Please try again." return 0 - src.buffers[bufferId]["data"] = src.disk.data - src.buffers[bufferId]["type"] = src.disk.data_type - src.buffers[bufferId]["ue"] = src.disk.ue - src.buffers[bufferId]["owner"] = src.disk.owner + src.buffers[bufferId]=src.disk.buf //src.temphtml = "Data loaded." return 1 @@ -850,13 +832,12 @@ //src.temphtml = "Invalid disk. Please try again." return 0 - src.disk.data = buffers[bufferId]["data"] - src.disk.data_type = src.buffers[bufferId]["type"] - src.disk.ue = src.buffers[bufferId]["ue"] - src.disk.owner = src.buffers[bufferId]["owner"] - src.disk.name = "data disk - '[src.buffers[bufferId]["owner"]]'" + var/datum/dna2/record/buf = src.buffers[bufferId] + + src.disk.buf = buf + src.disk.name = "data disk - '[buf.dna.real_name]'" //src.temphtml = "Data saved." - return 1 + return 1 /////////////////////////// DNA MACHINES diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm new file mode 100644 index 00000000000..e312111f6f3 --- /dev/null +++ b/code/game/dna/genes/disabilities.dm @@ -0,0 +1,125 @@ +///////////////////// +// DISABILITY GENES +// +// These activate either a mutation, disability, or sdisability. +// +// Gene is always activated. +///////////////////// + +/datum/dna/gene/disability + name="DISABILITY" + + // Mutation to give (or 0) + var/mutation=0 + + // Disability to give (or 0) + var/disability=0 + + // SDisability to give (or 0) + var/sdisability=0 + + // Activation message + var/activation_message="" + + // Yay, you're no longer growing 3 arms + var/deactivation_message="" + +/datum/dna/gene/disability/can_activate(var/mob/M,var/flags) + return 1 // Always set! + +/datum/dna/gene/disability/activate(var/mob/M, var/connected, var/flags) + if(mutation && !(mutation in M.mutations)) + M.mutations.Add(mutation) + if(disability) + M.disabilities|=disability + if(sdisability) + M.sdisabilities|=sdisability + if(activation_message) + M << "\red [activation_message]" + +/datum/dna/gene/disability/deactivate(var/mob/M, var/connected, var/flags) + if(mutation && (mutation in M.mutations)) + M.mutations.Remove(mutation) + if(disability) + M.disabilities &= ~disability + if(sdisability) + M.sdisabilities &= ~sdisability + if(deactivation_message) + M << "\red [deactivation_message]" + +// Note: Doesn't seem to do squat, at the moment. +/datum/dna/gene/disability/hallucinate + name="Hallucinate" + activation_message="Your mind says 'Hello'." + mutation=mHallucination + + New() + block=HALLUCINATIONBLOCK + +/datum/dna/gene/disability/epilepsy + name="Epilepsy" + activation_message="You get a headache." + disability=EPILEPSY + + New() + block=HEADACHEBLOCK + +/datum/dna/gene/disability/cough + name="Coughing" + activation_message="You start coughing." + disability=COUGHING + + New() + block=COUGHBLOCK + +/datum/dna/gene/disability/clumsy + name="Clumsiness" + activation_message="You feel lightheaded." + mutation=CLUMSY + + New() + block=CLUMSYBLOCK + +/datum/dna/gene/disability/tourettes + name="Tourettes" + activation_message="You twitch." + disability=TOURETTES + + New() + block=TWITCHBLOCK + +/datum/dna/gene/disability/nervousness + name="Nervousness" + activation_message="You feel nervous." + disability=NERVOUS + + New() + block=NERVOUSBLOCK + +/datum/dna/gene/disability/blindness + name="Blindness" + activation_message="You can't seem to see anything." + sdisability=BLIND + + New() + block=BLINDBLOCK + +/datum/dna/gene/disability/deaf + name="Deafness" + activation_message="It's kinda quiet." + sdisability=DEAF + + New() + block=DEAFBLOCK + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.ear_deaf = 1 + +/datum/dna/gene/disability/nearsighted + name="Nearsightedness" + activation_message="Your eyes feel weird..." + disability=NEARSIGHTED + + New() + block=GLASSESBLOCK \ No newline at end of file diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm new file mode 100644 index 00000000000..3bf5b5e5f75 --- /dev/null +++ b/code/game/dna/genes/gene.dm @@ -0,0 +1,88 @@ +/** +* Gene Datum +* +* domutcheck was getting pretty hairy. This is the solution. +* +* All genes are stored in a global variable to cut down on memory +* usage. +* +* @author N3X15 +*/ + +/datum/dna/gene + // Display name + var/name="BASE GENE" + + // Probably won't get used but why the fuck not + var/desc="Oh god who knows what this does." + + // Set in initialize()! + // What gene activates this? + var/block=0 + + // Any of a number of GENE_ flags. + var/flags=0 + +// Return 1 if we can activate. +// HANDLE MUTCHK_FORCED HERE! +/datum/dna/gene/proc/can_activate(var/mob/M, var/flags) + return 0 + +// Called when the gene activates. Do your magic here. +/datum/dna/gene/proc/activate(var/mob/M, var/connected, var/flags) + return + +// Called when the gene deactivates. Undo your magic here. +// Only called when the block is deactivated. +/datum/dna/gene/proc/deactivate(var/mob/M, var/connected, var/flags) + return + + +///////////////////// +// BASIC GENES +// +// These just chuck in a mutation and display a message. +// +// Gene is activated: +// 1. If mutation already exists in mob +// 2. If the probability roll succeeds +// 3. Activation is forced (done in domutcheck) +///////////////////// + + +/datum/dna/gene/basic + name="BASIC GENE" + + // Mutation to give + var/mutation=0 + + // Activation probability + var/activation_prob=45 + + // Possible activation messages + var/list/activation_messages=list() + + // Possible deactivation messages + var/list/deactivation_messages=list() + +/datum/dna/gene/basic/can_activate(var/mob/M,var/flags) + if(mutation==0) + return 0 + + // Probability check + if(flags & MUTCHK_FORCED || probinj(activation_prob,(flags&MUTCHK_FORCED))) + return 1 + + return 0 + +/datum/dna/gene/basic/activate(var/mob/M) + M.mutations.Add(mutation) + if(activation_messages.len) + var/msg = pick(activation_messages) + M << "\blue [msg]" + +/datum/dna/gene/basic/deactivate(var/mob/M) + M.mutations.Remove(mutation) + if(deactivation_messages.len) + var/msg = pick(deactivation_messages) + M << "\red [msg]" \ No newline at end of file diff --git a/code/game/dna/genes/monkey.dm b/code/game/dna/genes/monkey.dm new file mode 100644 index 00000000000..952f7df0f48 --- /dev/null +++ b/code/game/dna/genes/monkey.dm @@ -0,0 +1,170 @@ +/datum/dna/gene/monkey + name="Monkey" + +/datum/dna/gene/monkey/New() + block=MONKEYBLOCK + +/datum/dna/gene/monkey/can_activate(var/mob/M,var/flags) + return istype(M, /mob/living/carbon/human) || istype(M,/mob/living/carbon/monkey) + +/datum/dna/gene/monkey/activate(var/mob/living/M, var/connected, var/flags) + if(!istype(M,/mob/living/carbon/human)) + return + var/mob/living/carbon/human/H = M + H.monkeyizing = 1 + var/list/implants = list() //Try to preserve implants. + for(var/obj/item/weapon/implant/W in H) + implants += W + W.loc = null + + if(!connected) + for(var/obj/item/W in (H.contents-implants)) + if (W==H.w_uniform) // will be teared + continue + H.drop_from_inventory(W) + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.invisibility = 101 + var/atom/movable/overlay/animation = new( M.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("h2monkey", animation) + sleep(48) + del(animation) + + + var/mob/living/carbon/monkey/O = null + if(H.species.primitive) + O = new H.species.primitive(src) + else + H.gib() //Trying to change the species of a creature with no primitive var set is messy. + return + + if(M) + if (M.dna) + O.dna = M.dna + M.dna = null + + if (M.suiciding) + O.suiciding = M.suiciding + M.suiciding = null + + + for(var/datum/disease/D in M.viruses) + O.viruses += D + D.affected_mob = O + M.viruses -= D + + + for(var/obj/T in (M.contents-implants)) + del(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) //transfer our mind to the cute little monkey + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6)) + O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss()) + O.adjustToxLoss(M.getToxLoss() + 20) + O.adjustOxyLoss(M.getOxyLoss()) + O.stat = M.stat + O.a_intent = "hurt" + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O +// O.update_icon = 1 //queue a full icon update at next life() call + del(M) + return + +/datum/dna/gene/monkey/deactivate(var/mob/living/M, var/connected, var/flags) + if(!istype(M,/mob/living/carbon/monkey)) + return + var/mob/living/carbon/monkey/Mo = M + Mo.monkeyizing = 1 + var/list/implants = list() //Still preserving implants + for(var/obj/item/weapon/implant/W in Mo) + implants += W + W.loc = null + if(!connected) + for(var/obj/item/W in (Mo.contents-implants)) + Mo.drop_from_inventory(W) + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.invisibility = 101 + var/atom/movable/overlay/animation = new( M.loc ) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + flick("monkey2h", animation) + sleep(48) + del(animation) + + var/mob/living/carbon/human/O = new( src ) + if(Mo.greaterform) + O.set_species(Mo.greaterform) + + if (M.dna.GetUIState(DNA_UI_GENDER)) + O.gender = FEMALE + else + O.gender = MALE + + if (M) + if (M.dna) + O.dna = M.dna + M.dna = null + + if (M.suiciding) + O.suiciding = M.suiciding + M.suiciding = null + + for(var/datum/disease/D in M.viruses) + O.viruses += D + D.affected_mob = O + M.viruses -= D + + //for(var/obj/T in M) + // del(T) + + O.loc = M.loc + + if(M.mind) + M.mind.transfer_to(O) //transfer our mind to the human + + if (connected) //inside dna thing + var/obj/machinery/dna_scannernew/C = connected + O.loc = C + C.occupant = O + connected = null + + var/i + while (!i) + var/randomname + if (O.gender == MALE) + randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names))) + else + randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names))) + if (findname(randomname)) + continue + else + O.real_name = randomname + i++ + O.UpdateAppearance() + O.take_overall_damage(M.getBruteLoss(), M.getFireLoss()) + O.adjustToxLoss(M.getToxLoss()) + O.adjustOxyLoss(M.getOxyLoss()) + O.stat = M.stat + for (var/obj/item/weapon/implant/I in implants) + I.loc = O + I.implanted = O +// O.update_icon = 1 //queue a full icon update at next life() call + del(M) + return \ No newline at end of file diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm new file mode 100644 index 00000000000..a8a9eefee7d --- /dev/null +++ b/code/game/dna/genes/powers.dm @@ -0,0 +1,167 @@ +/////////////////////////////////// +// POWERS +/////////////////////////////////// + +/datum/dna/gene/basic/nobreath + name="No Breathing" + activation_messages=list("You feel no need to breathe.") + mutation=mNobreath + + New() + block=NOBREATHBLOCK + +/datum/dna/gene/basic/remoteview + name="Remote Viewing" + activation_messages=list("Your mind expands.") + mutation=mRemote + + New() + block=REMOTEVIEWBLOCK + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.verbs += /mob/living/carbon/human/proc/remoteobserve + +/datum/dna/gene/basic/regenerate + name="Regenerate" + activation_messages=list("You feel better.") + mutation=mRegen + + New() + block=REGENERATEBLOCK + +/datum/dna/gene/basic/increaserun + name="Super Speed" + activation_messages=list("Your leg muscles pulsate.") + mutation=mRun + + New() + block=INCREASERUNBLOCK + +/datum/dna/gene/basic/remotetalk + name="Telepathy" + activation_messages=list("You expand your mind outwards.") + mutation=mRemotetalk + + New() + block=REMOTETALKBLOCK + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.verbs += /mob/living/carbon/human/proc/remotesay + +/datum/dna/gene/basic/morph + name="Morph" + activation_messages=list("Your skin feels strange.") + mutation=mMorph + + New() + block=MORPHBLOCK + + activate(var/mob/M) + ..(M) + M.verbs += /mob/living/carbon/human/proc/morph + +/* Not used on bay +/datum/dna/gene/basic/heat_resist + name="Heat Resistance" + activation_messages=list("Your skin is icy to the touch.") + mutation=mHeatres + + New() + block=COLDBLOCK + + can_activate(var/mob/M,var/flags) + // Probability check + var/_prob = 15 + if(COLD_RESISTANCE in M.mutations) + _prob=5 + if(probinj(_prob,(flags&MUTCHK_FORCED))) + return 1 +*/ + +/datum/dna/gene/basic/cold_resist + name="Cold Resistance" + activation_messages=list("Your body is filled with warmth.") + mutation=COLD_RESISTANCE + + New() + block=FIREBLOCK + + can_activate(var/mob/M,var/flags) + + // Probability check + var/_prob=30 + //if(mHeatres in M.mutations) + // _prob=5 + if(probinj(_prob,(flags&MUTCHK_FORCED))) + return 1 + +/datum/dna/gene/basic/noprints + name="No Prints" + activation_messages=list("Your fingers feel numb.") + mutation=mFingerprints + + New() + block=NOPRINTSBLOCK + +/datum/dna/gene/basic/noshock + name="Shock Immunity" + activation_messages=list("Your skin feels strange.") + mutation=mShock + + New() + block=SHOCKIMMUNITYBLOCK + +/datum/dna/gene/basic/midget + name="Midget" + activation_messages=list("Your skin feels rubbery.") + mutation=mSmallsize + + New() + block=SMALLSIZEBLOCK + + can_activate(var/mob/M,var/flags) + // Can't be big and small. + if(HULK in M.mutations) + return 0 + return ..(M,flags) + + activate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.pass_flags |= 1 + + deactivate(var/mob/M, var/connected, var/flags) + ..(M,connected,flags) + M.pass_flags &= ~1 //This may cause issues down the track, but offhand I can't think of any other way for humans to get passtable short of varediting so it should be fine. ~Z + +/datum/dna/gene/basic/hulk + name="Hulk" + activation_messages=list("Your muscles hurt.") + mutation=HULK + + New() + block=HULKBLOCK + + can_activate(var/mob/M,var/flags) + // Can't be big and small. + if(mSmallsize in M.mutations) + return 0 + return ..(M,flags) + +/datum/dna/gene/basic/xray + name="X-Ray Vision" + activation_messages=list("The walls suddenly disappear.") + mutation=XRAY + + New() + block=XRAYBLOCK + +/datum/dna/gene/basic/tk + name="Telekenesis" + activation_messages=list("You feel smarter.") + mutation=TK + activation_prob=15 + + New() + block=TELEBLOCK \ No newline at end of file diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm index 4c77520846a..0e1b6c07eb4 100644 --- a/code/game/gamemodes/blob/blobs/shield.dm +++ b/code/game/gamemodes/blob/blobs/shield.dm @@ -6,7 +6,7 @@ density = 1 opacity = 0 anchored = 1 - health = 100 + health = 60 brute_resist = 1 fire_resist = 2 diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index e66aed88b87..a552ac1cd74 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -187,7 +187,7 @@ src.dna = chosen_dna src.real_name = chosen_dna.real_name src.flavor_text = "" - updateappearance(src, src.dna.uni_identity) + src.UpdateAppearance() domutcheck(src, null) src.verbs -= /mob/proc/changeling_transform @@ -205,6 +205,10 @@ var/datum/changeling/changeling = changeling_power(1,0,0) if(!changeling) return + if(src.has_brain_worms()) + src << "We cannot perform this ability at the present time!" + return + var/mob/living/carbon/C = src changeling.chem_charges-- C.remove_changeling_powers() @@ -314,7 +318,7 @@ W.layer = initial(W.layer) var/mob/living/carbon/human/O = new /mob/living/carbon/human( src ) - if (isblockon(getblock(C.dna.uni_identity, 11,3),11)) + if (C.dna.GetUIState(DNA_UI_GENDER)) O.gender = FEMALE else O.gender = MALE @@ -327,7 +331,7 @@ O.loc = C.loc - updateappearance(O,O.dna.uni_identity) + O.UpdateAppearance() domutcheck(O, null) O.setToxLoss(C.getToxLoss()) O.adjustBruteLoss(C.getBruteLoss()) @@ -370,24 +374,24 @@ if(changeling_power(20,1,100,DEAD)) // charge the changeling chemical cost for stasis changeling.chem_charges -= 20 - + // restore us to health C.rejuvenate() - + // remove our fake death flag C.status_flags &= ~(FAKEDEATH) - + // let us move again C.update_canmove() - + // re-add out changeling powers - C.make_changeling() - + C.make_changeling() + // sending display messages C << "We have regenerated." C.visible_message("[src] appears to wake from the dead, having healed all wounds.") - - + + feedback_add_details("changeling_powers","FD") return 1 @@ -719,7 +723,7 @@ var/list/datum/dna/hivemind_bank = list() T.visible_message("[T] transforms!") T.dna = chosen_dna T.real_name = chosen_dna.real_name - updateappearance(T, T.dna.uni_identity) + T.UpdateAppearance() domutcheck(T, null) feedback_add_details("changeling_powers","TS") return 1 diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 2d408a1a4ff..ac89f046472 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -248,7 +248,7 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",

Drain Blood

This rune instantly heals you of some brute damage at the expense of a person placed on top of the rune. Whenever you invoke a drain rune, ALL drain runes on the station are activated, draining blood from anyone located on top of those runes. This includes yourself, though the blood you drain from yourself just comes back to you. This might help you identify this rune when studying words. One drain gives up to 25HP per each victim, but you can repeat it if you need more. Draining only works on living people, so you might need to recharge your "Battery" once its empty. Drinking too much blood at once might cause blood hunger.

Raise Dead

- This rune allows for the resurrection of any dead person. You will need a dead human body and a living human sacrifice. Make 2 raise dead runes. Put a living non-braindead human on top of one, and a dead body on the other one. When you invoke the rune, the life force of the living human will be transferred into the dead body, allowing a ghost standing on top of the dead body to enter it, instantly and fully healing it. Use other runes to ensure there is a ghost ready to be resurrected.
+ This rune allows for the resurrection of any dead person. You will need a dead human body and a living human sacrifice. Make 2 raise dead runes. Put a living, awake human on top of one, and a dead body on the other one. When you invoke the rune, the life force of the living human will be transferred into the dead body, allowing a ghost standing on top of the dead body to enter it, instantly and fully healing it. Use other runes to ensure there is a ghost ready to be resurrected.

Hide runes

This rune makes all nearby runes completely invisible. They are still there and will work if activated somehow, but you cannot invoke them directly if you do not see them.

Reveal runes

diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index b9f68fb143c..5b1b1494b59 100644 --- a/code/game/gamemodes/events.dm +++ b/code/game/gamemodes/events.dm @@ -163,8 +163,8 @@ continue var/datum/disease/dnaspread/D = new D.strain_data["name"] = H.real_name - D.strain_data["UI"] = H.dna.uni_identity - D.strain_data["SE"] = H.dna.struc_enzymes + D.strain_data["UI"] = H.dna.UI + D.strain_data["SE"] = H.dna.SE D.carrier = 1 D.holder = H D.affected_mob = H diff --git a/code/game/gamemodes/events/holidays/Christmas.dm b/code/game/gamemodes/events/holidays/Christmas.dm index 2ee79e7c65b..72d42318e60 100644 --- a/code/game/gamemodes/events/holidays/Christmas.dm +++ b/code/game/gamemodes/events/holidays/Christmas.dm @@ -4,8 +4,8 @@ for(var/turf/simulated/floor/T in orange(1,xmas)) for(var/i=1,i<=rand(1,5),i++) new /obj/item/weapon/a_gift(T) - for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) - Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian)) + //for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) + // Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian)) /proc/ChristmasEvent() for(var/obj/structure/flora/tree/pine/xmas in world) diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm index d2481eae441..2cd06199bd8 100644 --- a/code/game/gamemodes/events/holidays/Holidays.dm +++ b/code/game/gamemodes/events/holidays/Holidays.dm @@ -12,6 +12,10 @@ var/global/Holiday = null ////////////////////////////////////////////////////////////////////////////////////////////////////////// // ~Carn +/hook/startup/proc/updateHoliday() + Get_Holiday() + return 1 + //sets up the Holiday global variable. Shouldbe called on game configuration or something. /proc/Get_Holiday() if(!Holiday) return // Holiday stuff was not enabled in the config! diff --git a/code/game/gamemodes/events/ninja_abilities.dm b/code/game/gamemodes/events/ninja_abilities.dm index 9245c740e07..11109af279d 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) @@ -69,12 +69,12 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo //=======//RIGHT CLICK TELEPORT//=======// //Right click to teleport somewhere, almost exactly like admin jump to turf. /obj/item/clothing/suit/space/space_ninja/proc/ninjashift(turf/T in oview()) - set name = "Phase Shift (1E)" + set name = "Phase Shift (400E)" set desc = "Utilizes the internal VOID-shift device to rapidly transit to a destination in view." set category = null//So it does not show up on the panel but can still be right-clicked. set src = usr.contents//Fixes verbs not attaching properly for objects. Praise the DM reference guide! - var/C = 200 + var/C = 40 if(!ninjacost(C,1)) var/mob/living/carbon/human/U = affecting var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below. @@ -83,6 +83,7 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo playsound(U.loc, 'sound/effects/sparks4.ogg', 50, 1) anim(mobloc,src,'icons/mob/mob.dmi',,"phaseout",,U.dir) + cell.use(C*10) handle_teleport_grab(T, U) U.loc = T @@ -92,19 +93,19 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo playsound(U.loc, 'sound/effects/sparks2.ogg', 50, 1) anim(U.loc,U,'icons/mob/mob.dmi',,"phasein",,U.dir) else - U << "\red You cannot teleport into solid walls or from solid matter" + U << "\red You cannot teleport into solid walls or from solid matter." return //=======//EM PULSE//=======// //Disables nearby tech equipment. /obj/item/clothing/suit/space/space_ninja/proc/ninjapulse() - set name = "EM Burst (1,000E)" + set name = "EM Burst (2,000E)" set desc = "Disable any nearby technology with a electro-magnetic pulse." set category = "Ninja Ability" set popup_menu = 0 - var/C = 250 - if(!ninjacost(C,100)) // EMP's now cost 1,000Energy about 30% + var/C = 200 + if(!ninjacost(C,0)) // EMP's now cost 1,000Energy about 30% var/mob/living/carbon/human/U = affecting playsound(U.loc, 'sound/effects/EMPulse.ogg', 60, 2) empulse(U, 2, 3) //Procs sure are nice. Slightly weaker than wizard's disable tch. @@ -115,13 +116,13 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo //=======//ENERGY BLADE//=======// //Summons a blade of energy in active hand. /obj/item/clothing/suit/space/space_ninja/proc/ninjablade() - set name = "Energy Blade (20E)" + set name = "Energy Blade (500E)" set desc = "Create a focused beam of energy in your active hand." set category = "Ninja Ability" set popup_menu = 0 var/C = 50 - if(!ninjacost(C, 800)) //Same spawn cost but higher upkeep cost + if(!ninjacost(C,0)) //Same spawn cost but higher upkeep cost var/mob/living/carbon/human/U = affecting if(!kamikaze) if(!U.get_active_hand()&&!istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade)) @@ -148,12 +149,12 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo /*Shoots ninja stars at random people. This could be a lot better but I'm too tired atm.*/ /obj/item/clothing/suit/space/space_ninja/proc/ninjastar() - set name = "Energy Star (1,000E)" + set name = "Energy Star (800E)" set desc = "Launches an energy star at a random living target." set category = "Ninja Ability" set popup_menu = 0 - var/C = 50 + var/C = 80 if(!ninjacost(C,1)) var/mob/living/carbon/human/U = affecting var/targets[] = list()//So yo can shoot while yo throw dawg @@ -173,7 +174,7 @@ This could be a lot better but I'm too tired atm.*/ A.current = curloc A.yo = targloc.y - curloc.y A.xo = targloc.x - curloc.x - cell.use(C*100)// Ninja stars now cost 100 energy, stil la fair chunk to avoid spamming, will run out of power quickly if used 3 or more times + cell.use(C*10) A.process() else U << "\red There are no targets in view." @@ -183,13 +184,13 @@ This could be a lot better but I'm too tired atm.*/ /*Allows the ninja to capture people, I guess. Must right click on a mob to activate.*/ /obj/item/clothing/suit/space/space_ninja/proc/ninjanet(mob/living/carbon/M in oview())//Only living carbon mobs. - set name = "Energy Net (8,000E)" + set name = "Energy Net (7,000E)" set desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds." set category = null set src = usr.contents - var/C = 500 - if(!ninjacost(C,80)&&iscarbon(M)) // Nets now cost 8,000 + var/C = 700 + if(!ninjacost(C,0)&&iscarbon(M)) var/mob/living/carbon/human/U = affecting if(M.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame. //if(M)//DEBUG @@ -200,7 +201,7 @@ Must right click on a mob to activate.*/ return spawn(0) U.Beam(M,"n_beam",,15) - M.anchored = 1//Anchors them so they can't move. + M.captured = 1 U.say("Get over here!") var/obj/effect/energy_net/E = new /obj/effect/energy_net(M.loc) E.layer = M.layer+1//To have it appear one layer above the mob. @@ -210,7 +211,7 @@ Must right click on a mob to activate.*/ E.master = U spawn(0)//Parallel processing. E.process(M) - cell.use(C*100) // Nets now cost what should be most of a standard battery, since your taking someone out of the round + cell.use(C*10) // Nets now cost what should be most of a standard battery, since your taking someone out of the round else U << "They are already trapped inside an energy net." else diff --git a/code/game/gamemodes/events/ninja_equipment.dm b/code/game/gamemodes/events/ninja_equipment.dm index d25dabe21bb..d2bd2dbc7b4 100644 --- a/code/game/gamemodes/events/ninja_equipment.dm +++ b/code/game/gamemodes/events/ninja_equipment.dm @@ -1385,7 +1385,8 @@ It is possible to destroy the net by the occupant or someone else. if(!isnull(master))//As long as they still exist. master << "\blue SUCCESS: \black transport procedure of \the [affecting] complete." - M.anchored = 0//Important. + M.captured = 0 //Important. + M.anchored = initial(M.anchored) //Changes the mob's anchored status to the original one; this is not handled by the can_move proc. else//And they are free. M << "\blue You are free of the net!" diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm index c8848cd3ee8..dbebc649f53 100644 --- a/code/game/gamemodes/events/power_failure.dm +++ b/code/game/gamemodes/events/power_failure.dm @@ -61,7 +61,7 @@ if(C.cell && C.z == 1) C.cell.charge = C.cell.maxcharge for(var/obj/machinery/power/smes/S in world) - if(S.z != 1) + if(istype(get_area(S), /area/turret_protected) || S.z != 1) continue S.charge = S.last_charge S.output = S.last_output diff --git a/code/game/gamemodes/events/space_ninja.dm b/code/game/gamemodes/events/space_ninja.dm index c3b77d5f875..4d0df9c3f7f 100644 --- a/code/game/gamemodes/events/space_ninja.dm +++ b/code/game/gamemodes/events/space_ninja.dm @@ -547,7 +547,7 @@ As such, it's hard-coded for now. No reason for it not to be, really. equip_to_slot_or_del(new /obj/item/device/flashlight(src), slot_belt) equip_to_slot_or_del(new /obj/item/weapon/plastique(src), slot_r_store) equip_to_slot_or_del(new /obj/item/weapon/plastique(src), slot_l_store) - equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store) + equip_to_slot_or_del(new /obj/item/weapon/tank/oxygen(src), slot_s_store) return 1 //=======//HELPER PROCS//=======// diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 39be77978ee..26497410fa8 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -213,7 +213,7 @@ Implants; for(var/mob/living/carbon/human/man in player_list) if(man.client && man.mind) // NT relation option var/special_role = man.mind.special_role - if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate") + if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate" || special_role == "Vox Raider") continue //NT intelligence ruled out possiblity that those are too classy to pretend to be a crew. if(man.client.prefs.nanotrasen_relation == "Opposed" && prob(50) || \ man.client.prefs.nanotrasen_relation == "Skeptical" && prob(20)) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index ea9fbaec4a7..a834a3cc0b3 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -118,6 +118,7 @@ var/global/datum/controller/gameticker/ticker data_core.manifest() current_state = GAME_STATE_PLAYING + callHook("roundstart") //here to initialize the random events nicely at round start setup_economy() @@ -309,6 +310,8 @@ var/global/datum/controller/gameticker/ticker declare_completion() spawn(50) + callHook("roundend") + if (mode.station_was_nuked) feedback_set_details("end_proper","nuke") if(!delay_end) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index e98d128559f..fd2cdf88ade 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -2,11 +2,6 @@ VOX HEIST ROUNDTYPE */ -#define MAX_VOX_KILLS 10 //Number of kills during the round before the Inviolate is broken. - //Would be nice to use vox-specific kills but is currently not feasible. - -var/global/vox_kills = 0 //Used to check the Inviolate. - /datum/game_mode/ var/list/datum/mind/raiders = list() //Antags. @@ -139,10 +134,8 @@ var/global/vox_kills = 0 //Used to check the Inviolate. /datum/game_mode/heist/proc/forge_vox_objectives() - - //Commented out for testing. - /* var/i = 1 - var/max_objectives = pick(2,2,2,3,3) + var/i = 1 + var/max_objectives = pick(2,2,2,2,3,3,3,4) var/list/objs = list() while(i<= max_objectives) var/list/goals = list("kidnap","loot","salvage") @@ -163,24 +156,16 @@ var/global/vox_kills = 0 //Used to check the Inviolate. //-All- vox raids have these two objectives. Failing them loses the game. objs += new /datum/objective/heist/inviolate_crew - objs += new /datum/objective/heist/inviolate_death */ + objs += new /datum/objective/heist/inviolate_death - raid_objectives += new /datum/objective/heist/kidnap - raid_objectives += new /datum/objective/heist/loot - raid_objectives += new /datum/objective/heist/salvage - raid_objectives += new /datum/objective/heist/inviolate_crew - raid_objectives += new /datum/objective/heist/inviolate_death - - for(var/datum/objective/heist/O in raid_objectives) - O.choose_target() - - return raid_objectives + return objs /datum/game_mode/heist/proc/greet_vox(var/datum/mind/raider) raider.current << "\blue You are a Vox Raider, fresh from the Shoal!" raider.current << "\blue The Vox are a race of cunning, sharp-eyed nomadic raiders and traders endemic to Tau Ceti and much of the unexplored galaxy. You and the crew have come to the Exodus for plunder, trade or both." raider.current << "\blue Vox are cowardly and will flee from larger groups, but corner one or find them en masse and they are vicious." raider.current << "\blue Use :V to voxtalk, :H to talk on your encrypted channel, and don't forget to turn on your nitrogen internals!" + raider.current << "\red IF YOU HAVE NOT PLAYED A VOX BEFORE, REVIEW THIS THREAD: http://baystation12.net/forums/viewtopic.php?f=6&t=8657." var/obj_count = 1 for(var/datum/objective/objective in raider.objectives) raider.current << "Objective #[obj_count]: [objective.explanation_text]" diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index deb28d76893..712512bd479 100644 --- a/code/game/gamemodes/meteor/meteor.dm +++ b/code/game/gamemodes/meteor/meteor.dm @@ -6,6 +6,7 @@ var/const/meteordelay = 2000 var/nometeors = 1 required_players = 0 + votable = 0 uplink_welcome = "EVIL METEOR Uplink Console:" uplink_uses = 10 diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm index c3720275ee2..55191067e10 100644 --- a/code/game/gamemodes/meteor/meteors.dm +++ b/code/game/gamemodes/meteor/meteors.dm @@ -1,5 +1,3 @@ -#define METEOR_TEMPERATURE - /var/const/meteor_wave_delay = 625 //minimum wait between waves in tenths of seconds //set to at least 100 unless you want evarr ruining every round @@ -95,18 +93,9 @@ icon_state = "smallf" pass_flags = PASSTABLE | PASSGRILLE -/obj/effect/meteor/Move() - var/turf/T = src.loc - if (istype(T, /turf)) - T.hotspot_expose(METEOR_TEMPERATURE, 1000) - ..() - return - /obj/effect/meteor/Bump(atom/A) spawn(0) - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai)) //bad idea to shake an ai's view - shake_camera(M, 3, 1) + if (A) A.meteorhit(src) playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) @@ -117,9 +106,7 @@ if(!istype(A,/obj/machinery/power/emitter) && \ !istype(A,/obj/machinery/field_generator) && \ prob(15)) - explosion(src.loc, 4, 5, 6, 7, 0) - playsound(src.loc, "explosion", 50, 1) del(src) return @@ -146,16 +133,18 @@ if(--src.hits <= 0) del(src) //Dont blow up singularity containment if we get stuck there. - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai)) //bad idea to shake an ai's view - shake_camera(M, 3, 1) if (A) + for(var/mob/M in player_list) + var/turf/T = get_turf(M) + if(!T || T.z != src.z) + continue + shake_camera(M, 3, get_dist(M.loc, src.loc) > 20 ? 1 : 3) + playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) explosion(src.loc, 0, 1, 2, 3, 0) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) + if (--src.hits <= 0) if(prob(15) && !istype(A, /obj/structure/grille)) explosion(src.loc, 1, 2, 3, 4, 0) - playsound(src.loc, "explosion", 50, 1) del(src) return diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm index 8dd3c45e19d..ac2ab258bf3 100644 --- a/code/game/gamemodes/ninja/ninja.dm +++ b/code/game/gamemodes/ninja/ninja.dm @@ -26,18 +26,22 @@ ninja.assigned_role = "MODE" //So they aren't chosen for other jobs. ninja.special_role = "Ninja" ninja.original = ninja.current - if(ninjastart.len == 0) + + /*if(ninjastart.len == 0) ninja.current << "\red A proper starting location for you could not be found, please report this bug!" - ninja.current << "\red Attempting to place at a carpspawn." - for(var/obj/effect/landmark/L in landmarks_list) - if(L.name == "carpspawn") - ninjastart.Add(L) - if(ninjastart.len == 0 && latejoin.len > 0) - ninja.current << "\red Still no spawneable locations could be found. Defaulting to latejoin." - return 1 - else if (ninjastart.len == 0) - ninja.current << "\red Still no spawneable locations could be found. Aborting." - return 0 + ninja.current << "\red Attempting to place at a carpspawn."*/ + + //Until such a time as people want to place ninja spawn points, carpspawn will do fine. + for(var/obj/effect/landmark/L in landmarks_list) + if(L.name == "carpspawn") + ninjastart.Add(L) + if(ninjastart.len == 0 && latejoin.len > 0) + ninja.current << "\red No spawneable locations could be found. Defaulting to latejoin." + return 1 + else if (ninjastart.len == 0) + ninja.current << "\red No spawneable locations could be found. Aborting." + return 0 + return 1 /datum/game_mode/ninja/pre_setup() @@ -50,7 +54,7 @@ /datum/game_mode/ninja/post_setup() for(var/datum/mind/ninja in ninjas) if(ninja.current && !(istype(ninja.current,/mob/living/carbon/human))) return 0 - //forge_ninja_objectives(ninja) + forge_ninja_objectives(ninja) var/mob/living/carbon/human/N = ninja.current N.internal = N.s_store N.internals.icon_state = "internal1" @@ -78,7 +82,8 @@ return 1 /datum/game_mode/ninja/proc/forge_ninja_objectives(var/datum/mind/ninja) - var/objective_list[] = list(1,2,3,4,5) + + var/objective_list = list(1,2,3,4,5) for(var/i=rand(2,4),i>0,i--) switch(pick(objective_list)) if(1)//Kill @@ -123,6 +128,7 @@ var/datum/objective/survive/ninja_objective = new ninja_objective.owner = ninja ninja.objectives += ninja_objective + ninja.current.mind = ninja var/directive = generate_ninja_directive("heel")//Only hired by antags, not NT ninja.current << "You are an elite mercenary assassin of the Spider Clan, [ninja.current.real_name]. You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor.\nYour current directive is: \red [directive]\n \blue Try your best to adhere to this." diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index be688554147..595dfe02264 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -5,9 +5,9 @@ /datum/game_mode/nuclear name = "nuclear emergency" config_tag = "nuclear" - required_players = 6 + required_players = 15 required_players_secret = 25 // 25 players - 5 players to be the nuke ops = 20 players remaining - required_enemies = 5 + required_enemies = 1 recommended_enemies = 5 uplink_welcome = "Corporate Backed Uplink Console:" @@ -34,17 +34,25 @@ var/list/possible_syndicates = get_players_for_role(BE_OPERATIVE) var/agent_number = 0 + /* + * if(possible_syndicates.len > agents_possible) + * agent_number = agents_possible + * else + * agent_number = possible_syndicates.len + * + * if(agent_number > n_players) + * agent_number = n_players/2 + */ + if(possible_syndicates.len < 1) return 0 - if(possible_syndicates.len > agents_possible) - agent_number = agents_possible - else - agent_number = possible_syndicates.len - + //Antag number should scale to active crew. var/n_players = num_players() - if(agent_number > n_players) - agent_number = n_players/2 + agent_number = Clamp((n_players/5), 2, 6) + + if(possible_syndicates.len < agent_number) + agent_number = possible_syndicates.len while(agent_number > 0) var/datum/mind/new_syndicate = pick(possible_syndicates) @@ -121,7 +129,6 @@ var/nuke_code = "[rand(10000, 99999)]" var/leader_selected = 0 - var/agent_number = 1 var/spawnpos = 1 for(var/datum/mind/synd_mind in syndicates) @@ -129,6 +136,10 @@ spawnpos = 1 synd_mind.current.loc = synd_spawn[spawnpos] + synd_mind.current.real_name = "[syndicate_name()] Operative" // placeholder while we get their actual name + spawn(0) + NukeNameAssign(synd_mind) + forge_syndicate_objectives(synd_mind) greet_syndicate(synd_mind) equip_syndicate(synd_mind.current) @@ -136,9 +147,7 @@ if(!leader_selected) prepare_syndicate_leader(synd_mind, nuke_code) leader_selected = 1 - else - synd_mind.current.real_name = "[syndicate_name()] Operative #[agent_number]" - agent_number++ + spawnpos++ update_synd_icons_added(synd_mind) @@ -157,10 +166,6 @@ /datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code) -// var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord") - spawn(1) -// NukeNameAssign(nukelastname(synd_mind.current),syndicates) //allows time for the rest of the syndies to be chosen - synd_mind.current.real_name = "[pick(first_names_male)] [pick(last_names)]" if (nuke_code) synd_mind.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0) synd_mind.current << "The nuclear authorization code is: [nuke_code]" @@ -209,9 +214,7 @@ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(synd_mob), slot_w_uniform) synd_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(synd_mob), slot_shoes) - synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(synd_mob), slot_wear_suit) synd_mob.equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(synd_mob), slot_gloves) - synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/swat(synd_mob), slot_head) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/card/id/syndicate(synd_mob), slot_wear_id) if(synd_mob.backbag == 2) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(synd_mob), slot_back) if(synd_mob.backbag == 3) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(synd_mob), slot_back) @@ -221,6 +224,26 @@ synd_mob.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/pill/cyanide(synd_mob), slot_in_backpack) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/c20r(synd_mob), slot_belt) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(synd_mob.back), slot_in_backpack) + + if(synd_mob.species) + var/race = synd_mob.species.name + + if(race == "Unathi") + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/unathi(synd_mob), slot_wear_suit) + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/unathi(synd_mob), slot_head) + else if(race == "Tajaran") + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/tajara(synd_mob), slot_wear_suit) + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/tajara(synd_mob), slot_head) + else if(race == "Skrell") + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/skrell(synd_mob), slot_wear_suit) + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/skrell(synd_mob), slot_head) + else + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/human(synd_mob), slot_wear_suit) + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/human(synd_mob), slot_head) + else + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/human(synd_mob), slot_wear_suit) + synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/human(synd_mob), slot_head) + var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(synd_mob) E.imp_in = synd_mob E.implanted = 1 @@ -344,12 +367,14 @@ return newname */ -/proc/NukeNameAssign(var/lastname,var/list/syndicates) - for(var/datum/mind/synd_mind in syndicates) - switch(synd_mind.current.gender) - if(MALE) - synd_mind.name = "[pick(first_names_male)] [pick(last_names)]" - if(FEMALE) - synd_mind.name = "[pick(first_names_female)] [pick(last_names)]" - synd_mind.current.real_name = synd_mind.name - return \ No newline at end of file + +/proc/NukeNameAssign(var/datum/mind/synd_mind) + var/choose_name = input(synd_mind.current, "You are a [syndicate_name()] agent! What is your name?", "Choose a name") as text + + if(!choose_name) + return + + else + synd_mind.current.name = choose_name + synd_mind.current.real_name = choose_name + return \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 5d770346d5e..a58e8b553ff 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,34 @@ 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 (istype(O, /obj/item/weapon/wirecutters) || istype(O, /obj/item/device/multitool)) + if (src.opened == 1) + nukehack_win(user) + return + if (src.extended) if (istype(O, /obj/item/weapon/disk/nuclear)) usr.drop_item() @@ -119,11 +170,13 @@ var/bomb_set /obj/machinery/nuclearbomb/attack_hand(mob/user as mob) if (src.extended) - if (!ishuman(user)) usr << "\red You don't have the dexterity to do this!" return 1 + if (!ishuman(user)) + usr << "\red You don't have the dexterity to do this!" + return 1 user.set_machine(src) var/dat = text("Nuclear Fission Explosive
\nAuth. Disk: []
", src, (src.auth ? "++++++++++" : "----------")) if (src.auth) @@ -150,11 +203,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" @@ -172,16 +237,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 @@ -222,14 +328,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) @@ -277,7 +385,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/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 12ac5447842..b3493efcbae 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -1,4 +1,5 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +var/global/list/all_objectives = list() datum/objective var/datum/mind/owner = null //Who owns the objective. @@ -8,9 +9,14 @@ datum/objective var/completed = 0 //currently only used for custom objectives. New(var/text) + all_objectives |= src if(text) explanation_text = text + Del() + all_objectives -= src + ..() + proc/check_completion() return completed @@ -916,8 +922,12 @@ datum/objective/heist/inviolate_crew if(H.is_raider_crew_safe()) return 1 return 0 +#define MAX_VOX_KILLS 10 //Number of kills during the round before the Inviolate is broken. + //Would be nice to use vox-specific kills but is currently not feasible. +var/global/vox_kills = 0 //Used to check the Inviolate. + datum/objective/heist/inviolate_death explanation_text = "Follow the Inviolate. Minimise death and loss of resources." check_completion() - if(vox_kills>5) return 0 + if(vox_kills > MAX_VOX_KILLS) return 0 return 1 \ No newline at end of file diff --git a/code/game/gamemodes/revolution/rp_revolution.dm b/code/game/gamemodes/revolution/rp_revolution.dm index d00b58d23b4..98f97cf4600 100644 --- a/code/game/gamemodes/revolution/rp_revolution.dm +++ b/code/game/gamemodes/revolution/rp_revolution.dm @@ -156,9 +156,17 @@ return 1 -/mob/living/carbon/human/proc/RevConvert(mob/M as mob in oview(src)) +/mob/living/carbon/human/proc/RevConvert() set name = "Rev-Convert" set category = "IC" + var/list/Possible = list() + for (var/mob/living/carbon/human/P in oview(src)) + if(!stat && P.client && P.mind && !P.mind.special_role) + Possible += P + if(!Possible.len) + src << "\red There doesn't appear to be anyone available for you to convert here." + return + var/mob/living/carbon/human/M = input("Select a person to convert", "Viva la revolution!", null) as mob in Possible if(((src.mind in ticker.mode:head_revolutionaries) || (src.mind in ticker.mode:revolutionaries))) if((M.mind in ticker.mode:head_revolutionaries) || (M.mind in ticker.mode:revolutionaries)) src << "\red [M] is already be a revolutionary!" @@ -251,4 +259,4 @@ rev_obj.target = M.mind rev_obj.explanation_text = "Assassinate, convert or capture [M.real_name], the [M.mind.assigned_role]." rev_mind.objectives += rev_obj - rev_mind.current << "\red A new Head of Staff, [M.real_name], the [M.mind.assigned_role] has appeared. Your objectives have been updated." \ No newline at end of file + rev_mind.current << "\red A new Head of Staff, [M.real_name], the [M.mind.assigned_role] has appeared. Your objectives have been updated." diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm index 53d90a7e98c..813bbbabf2c 100644 --- a/code/game/gamemodes/setupgame.dm +++ b/code/game/gamemodes/setupgame.dm @@ -1,10 +1,27 @@ +///////////////////////// +// (mostly) DNA2 SETUP +///////////////////////// + +// Randomize block, assign a reference name, and optionally define difficulty (by making activation zone smaller or bigger) +// The name is used on /vg/ for species with predefined genetic traits, +// and for the DNA panel in the player panel. +/proc/getAssignedBlock(var/name,var/list/blocksLeft, var/activity_bounds=DNA_DEFAULT_BOUNDS) + var/assigned = pick(blocksLeft) + blocksLeft.Remove(assigned) + assigned_blocks[assigned]=name + dna_activity_bounds[assigned]=activity_bounds + //testing("[name] assigned to block #[assigned].") + return assigned + /proc/setupgenetics() if (prob(50)) + // Currently unused. Will revisit. - N3X BLOCKADD = rand(-300,300) if (prob(75)) DIFFMUT = rand(0,20) + /* Old, for reference (so I don't accidentally activate something) - N3X var/list/avnums = new/list() var/tempnum @@ -41,11 +58,62 @@ tempnum = pick(avnums) avnums.Remove(tempnum) BLINDBLOCK = tempnum + */ + var/list/numsToAssign=new() + for(var/i=1;i

" + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" else if (holding) - release_log += "Valve was opened by [usr], starting the transfer into the [holding]
" + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" else - release_log += "Valve was opened by [usr], starting the transfer into the air
" + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" valve_open = !valve_open if (href_list["remove_tank"]) if(holding) + if(istype(holding, /obj/item/weapon/tank)) + holding.manipulated_by = usr.real_name holding.loc = loc holding = null diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 2db4c1594eb..565edc8e174 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -16,7 +16,8 @@ var/global/list/autolathe_recipes = list( \ new /obj/item/weapon/stock_parts/console_screen(), \ new /obj/item/weapon/airlock_electronics(), \ new /obj/item/weapon/airalarm_electronics(), \ - new /obj/item/weapon/firealarm_electronics(), \ + new /obj/item/weapon/firealarm_electronics(), \ + new /obj/item/weapon/module/power_control(), \ new /obj/item/stack/sheet/metal(), \ new /obj/item/stack/sheet/glass(), \ new /obj/item/stack/sheet/rglass(), \ @@ -28,13 +29,14 @@ 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(), \ new /obj/item/weapon/reagent_containers/syringe(), \ new /obj/item/ammo_casing/shotgun/blank(), \ new /obj/item/ammo_casing/shotgun/beanbag(), \ - new /obj/item/ammo_magazine/c38(), \ + new /obj/item/ammo_magazine/c45r(), \ new /obj/item/device/taperecorder(), \ new /obj/item/device/assembly/igniter(), \ new /obj/item/device/assembly/signaler(), \ @@ -56,6 +58,7 @@ var/global/list/autolathe_recipes_hidden = list( \ new /obj/item/weapon/weldingtool/largetank(), \ new /obj/item/weapon/handcuffs(), \ new /obj/item/ammo_magazine/a357(), \ + new /obj/item/ammo_magazine/c45m(), \ new /obj/item/ammo_casing/shotgun(), \ new /obj/item/ammo_casing/shotgun/dart(), \ /* new /obj/item/weapon/shield/riot(), */ \ diff --git a/code/game/machinery/biogenerator.dm b/code/game/machinery/biogenerator.dm index c75cda5dba5..5bb6f1559ed 100644 --- a/code/game/machinery/biogenerator.dm +++ b/code/game/machinery/biogenerator.dm @@ -100,6 +100,7 @@ dat += "
Botanical gloves (250)
" dat += "Utility belt (300)
" dat += "Leather Satchel (400)
" + dat += "Cash Bag (400)
" //dat += "Other
" //dat += "Monkey (500)
" else @@ -194,6 +195,8 @@ new/obj/item/weapon/storage/belt/utility(src.loc) if("satchel") new/obj/item/weapon/storage/backpack/satchel(src.loc) + if("cashbag") + new/obj/item/weapon/storage/bag/cash(src.loc) if("monkey") new/mob/living/carbon/monkey(src.loc) processing = 0 @@ -220,4 +223,4 @@ create_product(href_list["item"],text2num(href_list["cost"])) if("menu") menustat = "menu" - updateUsrDialog() \ No newline at end of file + updateUsrDialog() diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index 8ef8c76f62c..6b7038a38ee 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -56,7 +56,7 @@ src.visible_message("\red [user] has slashed [src]!") playsound(src.loc, 'sound/weapons/slice.ogg', 25, 1, -1) if(prob(10)) - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/blood/oil(src.loc) healthcheck() @@ -66,7 +66,7 @@ src.visible_message("\red [M] has [M.attacktext] [src]!") M.attack_log += text("\[[time_stamp()]\] attacked [src.name]") if(prob(10)) - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/blood/oil(src.loc) healthcheck() diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm index aa274e505eb..ae6b53d4f2a 100644 --- a/code/game/machinery/bots/cleanbot.dm +++ b/code/game/machinery/bots/cleanbot.dm @@ -54,6 +54,8 @@ src.botcard = new /obj/item/weapon/card/id(src) var/datum/job/janitor/J = new/datum/job/janitor src.botcard.access = J.get_access() + + src.locked = 0 // Start unlocked so roboticist can set them to patrol. if(radio_controller) radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS) @@ -66,6 +68,8 @@ /obj/machinery/bot/cleanbot/turn_off() ..() + if(!isnull(src.target)) + target.targeted_by = null src.target = null src.oldtarget = null src.oldloc = null @@ -165,7 +169,6 @@ text("[src.oddbutton ? "Yes" : "No" return if(src.cleaning) return - var/list/cleanbottargets = list() if(!src.screwloose && !src.oddbutton && prob(5)) visible_message("[src] makes an excited beeping booping sound!") @@ -194,9 +197,10 @@ text("[src.oddbutton ? "Yes" : "No" if(!src.target || src.target == null) for (var/obj/effect/decal/cleanable/D in view(7,src)) for(var/T in src.target_types) - if(!(D in cleanbottargets) && (D.type == T || D.parent_type == T) && D != src.oldtarget) - src.oldtarget = D - src.target = D + if(isnull(D.targeted_by) && (D.type == T || D.parent_type == T) && D != src.oldtarget) // If the mess isn't targeted + src.oldtarget = D // or if it is but the bot is gone. + src.target = D // and it's stuff we clean? Clean it. + D.targeted_by = src // Claim the mess we are targeting. return if(!src.target || src.target == null) @@ -237,6 +241,7 @@ text("[src.oddbutton ? "Yes" : "No" if (!path) path = list() if(src.path.len == 0) src.oldtarget = src.target + target.targeted_by = null src.target = null return if(src.path.len > 0 && src.target && (src.target != null)) @@ -293,31 +298,33 @@ text("[src.oddbutton ? "Yes" : "No" /obj/machinery/bot/cleanbot/proc/get_targets() src.target_types = new/list() - target_types += /obj/effect/decal/cleanable/oil + target_types += /obj/effect/decal/cleanable/blood/oil target_types += /obj/effect/decal/cleanable/vomit - 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 + target_types += /obj/effect/decal/cleanable/dirt if(src.blood) - target_types += /obj/effect/decal/cleanable/xenoblood/ - target_types += /obj/effect/decal/cleanable/xenoblood/xgibs target_types += /obj/effect/decal/cleanable/blood/ - target_types += /obj/effect/decal/cleanable/blood/gibs/ - target_types += /obj/effect/decal/cleanable/dirt /obj/machinery/bot/cleanbot/proc/clean(var/obj/effect/decal/cleanable/target) - src.anchored = 1 - src.icon_state = "cleanbot-c" + anchored = 1 + icon_state = "cleanbot-c" visible_message("\red [src] begins to clean up the [target]") - src.cleaning = 1 - spawn(50) - src.cleaning = 0 + cleaning = 1 + var/cleantime = 50 + if(istype(target,/obj/effect/decal/cleanable/dirt)) // Clean Dirt much faster + cleantime = 10 + spawn(cleantime) + if(istype(loc,/turf/simulated)) + var/turf/simulated/f = loc + f.dirt = 0 + cleaning = 0 del(target) - src.icon_state = "cleanbot[src.on]" - src.anchored = 0 - src.target = null + icon_state = "cleanbot[on]" + anchored = 0 + target = null /obj/machinery/bot/cleanbot/explode() src.on = 0 @@ -355,4 +362,4 @@ text("[src.oddbutton ? "Yes" : "No" return if (!in_range(src, usr) && src.loc != usr) return - src.created_name = t \ No newline at end of file + src.created_name = t diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index d71a43c083e..8de8e20fb5c 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -796,7 +796,7 @@ Auto Patrol: []"}, s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/blood/oil(src.loc) del(src) @@ -961,7 +961,7 @@ Auto Patrol: []"}, var/turf/T = get_turf(user) user << "You start to wire [src]..." sleep(40) - if(get_turf(user) == T) + if(get_turf(user) == T && build_step == 6) coil.use(1) build_step++ user << "You wire the ED-209 assembly." @@ -996,7 +996,7 @@ Auto Patrol: []"}, var/turf/T = get_turf(user) user << "Now attaching the gun to the frame..." sleep(40) - if(get_turf(user) == T) + if(get_turf(user) == T && build_step == 8) build_step++ name = "armed [name]" user << "Taser gun attached." diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm index 3496b6723a7..68d9888d5ed 100644 --- a/code/game/machinery/bots/mulebot.dm +++ b/code/game/machinery/bots/mulebot.dm @@ -964,6 +964,6 @@ s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/blood/oil(src.loc) unload(0) del(src) diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index fb3646653c1..ee014dd6dfb 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -219,7 +219,7 @@ Auto Patrol: []"}, walk_to(src,0) if(target) // make sure target exists - if(get_dist(src, src.target) <= 1) // if right next to perp + if(get_dist(src, src.target) <= 1 && isturf(src.target.loc)) // if right next to perp if(istype(src.target,/mob/living/carbon)) playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) src.icon_state = "secbot-c" @@ -726,7 +726,7 @@ Auto Patrol: []"}, s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/oil(src.loc) + new /obj/effect/decal/cleanable/blood/oil(src.loc) del(src) /obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index e66c7feb44c..a7ad25934af 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -30,25 +30,42 @@ icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk. item_state = "card-id" w_class = 1.0 - var/data = "" - var/ue = 0 - var/data_type = "ui" //ui|se - var/owner = "God Emperor of Mankind" + var/datum/dna2/record/buf=null var/read_only = 0 //Well,it's still a floppy disk +/obj/item/weapon/disk/data/proc/Initialize() + buf = new + buf.dna=new + /obj/item/weapon/disk/data/demo name = "data disk - 'God Emperor of Mankind'" - data = "066000033000000000AF00330660FF4DB002690" - //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff - ue = 1 read_only = 1 + New() + Initialize() + buf.types=DNA2_BUF_UE|DNA2_BUF_UI + //data = "066000033000000000AF00330660FF4DB002690" + //data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff + buf.dna.real_name="God Emperor of Mankind" + buf.dna.unique_enzymes = md5(buf.dna.real_name) + buf.dna.UI=list(0x066,0x000,0x033,0x000,0x000,0x000,0xAF0,0x033,0x066,0x0FF,0x4DB,0x002,0x690) + //buf.dna.UI=list(0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x000,0x000,0x000,0x000,0x161,0xFBD,0xDEF) // Farmer Jeff + buf.dna.UpdateUI() + /obj/item/weapon/disk/data/monkey name = "data disk - 'Mr. Muggles'" - data_type = "se" - data = "0983E840344C39F4B059D5145FC5785DC6406A4FFF" read_only = 1 + New() + Initialize() + buf.types=DNA2_BUF_SE + var/list/new_SE=list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4) + for(var/i=new_SE.len;i<=STRUCDNASIZE;i++) + new_SE += rand(1,1024) + buf.dna.SE=new_SE + buf.dna.SetSEValue(MONKEYBLOCK,0xFFF) + + //Find a dead mob with a brain and client. /proc/find_dead_player(var/find_key) if (isnull(find_key)) @@ -102,6 +119,7 @@ return src.healthstring /obj/machinery/clonepod/attack_ai(mob/user as mob) + src.add_hiddenprint(user) return attack_hand(user) /obj/machinery/clonepod/attack_paw(mob/user as mob) return attack_hand(user) @@ -116,20 +134,20 @@ //Clonepod //Start growing a human clone in the pod! -/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/datum/species/mrace, var/languages) +/obj/machinery/clonepod/proc/growclone(var/datum/dna2/record/R) if(mess || attempting) return 0 - var/datum/mind/clonemind = locate(mindref) + var/datum/mind/clonemind = locate(R.mind) if(!istype(clonemind,/datum/mind)) //not a mind return 0 if( clonemind.current && clonemind.current.stat != DEAD ) //mind is associated with a non-dead body return 0 if(clonemind.active) //somebody is using that mind - if( ckey(clonemind.key)!=ckey ) + if( ckey(clonemind.key)!=R.ckey ) return 0 else for(var/mob/dead/observer/G in player_list) - if(G.ckey == ckey) + if(G.ckey == R.ckey) if(G.can_reenter_corpse) break else @@ -147,9 +165,9 @@ var/mob/living/carbon/human/H = new /mob/living/carbon/human(src) occupant = H - if(!clonename) //to prevent null names - clonename = "clone ([rand(0,999)])" - H.real_name = clonename + if(!R.dna.real_name) //to prevent null names + R.dna.real_name = "clone ([rand(0,999)])" + H.real_name = R.dna.real_name src.icon_state = "pod_1" //Get the clone body ready @@ -161,7 +179,7 @@ H.updatehealth() clonemind.transfer_to(H) - H.ckey = ckey + H.ckey = R.ckey H << "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?
" // -- Mode/mind specific stuff goes here @@ -180,24 +198,24 @@ // -- End mode specific stuff - if(!H.dna) + if(!R.dna) H.dna = new /datum/dna() H.dna.real_name = H.real_name - if(ui) - H.dna.uni_identity = ui - updateappearance(H, ui) - if(se) - H.dna.struc_enzymes = se - randmutb(H) //Sometimes the clones come out wrong. + else + H.dna=R.dna + H.UpdateAppearance() + randmutb(H) //Sometimes the clones come out wrong. + H.dna.UpdateSE() + H.dna.UpdateUI() H.f_style = "Shaved" - if(mrace.name == "Human") //no more xenos losing ears/tentacles + if(R.dna.species == "Human") //no more xenos losing ears/tentacles H.h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") - H.species = mrace - for(var/datum/language/L in languages) - H.add_language(L.name) - H.update_mutantrace() + H.set_species(R.dna.species) + + //for(var/datum/language/L in languages) + // H.add_language(L.name) H.suiciding = 0 src.attempting = 0 return 1 @@ -231,6 +249,12 @@ if (src.occupant.reagents.get_reagent_amount("inaprovaline") < 30) src.occupant.reagents.add_reagent("inaprovaline", 60) + //So clones will remain asleep for long enough to get them into cryo (Bay RP edit) + if (src.occupant.reagents.get_reagent_amount("stoxin") < 10) + src.occupant.reagents.add_reagent("stoxin", 5) + if (src.occupant.reagents.get_reagent_amount("chloralhydrate") < 1) + src.occupant.reagents.add_reagent("chloralhydrate", 1) + //Also heal some oxyloss ourselves because inaprovaline is so bad at preventing it!! src.occupant.adjustOxyLoss(-4) diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm index 0252f697658..bdd313853f3 100644 --- a/code/game/machinery/computer/HolodeckControl.dm +++ b/code/game/machinery/computer/HolodeckControl.dm @@ -454,6 +454,15 @@ icon = 'icons/obj/structures.dmi' icon_state = "wood_table" +/obj/structure/holostool + name = "stool" + desc = "Apply butt." + icon = 'icons/obj/objects.dmi' + icon_state = "stool" + anchored = 1.0 + flags = FPRINT + pressure_resistance = 15 + /obj/item/clothing/gloves/boxing/hologlove name = "boxing gloves" @@ -523,6 +532,12 @@ w_class = 2 playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) user << "\blue [src] can now be concealed." + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + add_fingerprint(user) return diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 2fcdf333790..0946e7943cf 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -262,7 +262,7 @@ That prevents a few funky behaviors. A.loc = T.loc A.cancel_camera() A << "You have been uploaded to a stationary terminal. Remote device connection restored." - U << "\blue Transfer succesful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." + U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed." del(T) if("AIFIXER")//AI Fixer terminal. var/obj/machinery/computer/aifixer/T = target @@ -286,7 +286,7 @@ That prevents a few funky behaviors. T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-empty") A.cancel_camera() A << "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here." - U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." + U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed." else if(!C.contents.len && T.occupant && !T.active) C.name = "inteliCard - [T.occupant.name]" @@ -298,7 +298,7 @@ That prevents a few funky behaviors. C.icon_state = "aicard-full" T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-full") T.occupant << "You have been downloaded to a mobile storage device. Still no remote access." - U << "\blue Transfer succesful: \black [T.occupant.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." + U << "\blue Transfer successful: \black [T.occupant.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." T.occupant.loc = C T.occupant.cancel_camera() T.occupant = null @@ -323,7 +323,7 @@ That prevents a few funky behaviors. T.overlays -= image('icons/obj/computer.dmi', "ai-fixer-empty") A.cancel_camera() A << "You have been uploaded to a stationary terminal. Sadly, there is no remote access from here." - U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed succesfully. Local copy has been removed." + U << "\blue Transfer successful: \black [A.name] ([rand(1000,9999)].exe) installed and executed successfully. Local copy has been removed." else if(!C.AI && T.occupant && !T.active) if (T.occupant.stat) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 7dca0ae01fb..61784e98c3e 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -262,7 +262,7 @@ if(locked) user << "\red Circuit controls are locked." return - var/existing_networks = dd_list2text(network,",") + var/existing_networks = list2text(network,",") var/input = strip_html(input(usr, "Which networks would you like to connect this camera console circuit to? Seperate networks with a comma. No Spaces!\nFor example: SS13,Security,Secret ", "Multitool-Circuitboard interface", existing_networks)) if(!input) usr << "No input found please hang up and try your call again." 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/cloning.dm b/code/game/machinery/computer/cloning.dm index 184cc8e8670..293046b0768 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -10,7 +10,7 @@ var/scantemp = "Scanner unoccupied" var/menu = 1 //Which menu screen to display var/list/records = list() - var/datum/data/record/active_record = null + var/datum/dna2/record/active_record = null var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything. var/loading = 0 // Nice loading text @@ -136,8 +136,8 @@ if(2) dat += "

Current records

" dat += "
Back

" - for(var/datum/data/record/R in src.records) - dat += "[R.fields["id"]]-[R.fields["name"]]
" + for(var/datum/dna2/record/R in src.records) + dat += "
  • [R.dna.real_name]
  • " if(3) dat += "

    Selected Record

    " @@ -146,10 +146,11 @@ if (!src.active_record) dat += "ERROR: Record not found." else - dat += "
    Delete Record
    " - dat += "Name: [src.active_record.fields["name"]]
    " - - var/obj/item/weapon/implant/health/H = locate(src.active_record.fields["imp"]) + dat += {"
    Delete Record
    + Name: [src.active_record.dna.real_name]
    "} + var/obj/item/weapon/implant/health/H = null + if(src.active_record.implant) + H=locate(src.active_record.implant) if ((H) && (istype(H))) dat += "Health: [H.sensehealth()] | OXY-BURN-TOX-BRUTE
    " @@ -166,13 +167,13 @@ else dat += "
    " //Keeping a line empty for appearances I guess. - dat += {"UI: [src.active_record.fields["UI"]]
    - SE: [src.active_record.fields["SE"]]

    "} + dat += {"UI: [src.active_record.dna.uni_identity]
    + SE: [src.active_record.dna.struc_enzymes]

    "} if(pod1 && pod1.biomass >= CLONE_BIOMASS) dat += {"Clone
    "} else - dat += {"Unsufficient biomass
    "} + dat += {"Insufficient biomass
    "} if(4) if (!src.active_record) @@ -217,8 +218,8 @@ else if (href_list["view_rec"]) src.active_record = locate(href_list["view_rec"]) - if(istype(src.active_record,/datum/data/record)) - if ((isnull(src.active_record.fields["ckey"])) || (src.active_record.fields["ckey"] == "")) + if(istype(src.active_record,/datum/dna2/record)) + if ((isnull(src.active_record.ckey))) del(src.active_record) src.temp = "ERROR: Record Corrupt" else @@ -248,7 +249,7 @@ else if (href_list["disk"]) //Load or eject. switch(href_list["disk"]) if("load") - if ((isnull(src.diskette)) || (src.diskette.data == "")) + if ((isnull(src.diskette)) || isnull(src.diskette.buf)) src.temp = "Load error." src.updateUsrDialog() return @@ -258,12 +259,7 @@ src.updateUsrDialog() return - if (src.diskette.data_type == "ui") - src.active_record.fields["UI"] = src.diskette.data - if (src.diskette.ue) - src.active_record.fields["name"] = src.diskette.owner - else if (src.diskette.data_type == "se") - src.active_record.fields["SE"] = src.diskette.data + src.active_record = src.diskette.buf src.temp = "Load successful." if("eject") @@ -277,28 +273,24 @@ src.updateUsrDialog() return + // DNA2 makes things a little simpler. + src.diskette.buf=src.active_record + src.diskette.buf.types=0 switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se if("ui") - src.diskette.data = src.active_record.fields["UI"] - src.diskette.ue = 0 - src.diskette.data_type = "ui" + src.diskette.buf.types=DNA2_BUF_UI if("ue") - src.diskette.data = src.active_record.fields["UI"] - src.diskette.ue = 1 - src.diskette.data_type = "ui" + src.diskette.buf.types=DNA2_BUF_UI|DNA2_BUF_UE if("se") - src.diskette.data = src.active_record.fields["SE"] - src.diskette.ue = 0 - src.diskette.data_type = "se" - src.diskette.owner = src.active_record.fields["name"] - src.diskette.name = "data disk - '[src.diskette.owner]'" + src.diskette.buf.types=DNA2_BUF_SE + src.diskette.name = "data disk - '[src.active_record.dna.real_name]'" src.temp = "Save \[[href_list["save_disk"]]\] successful." else if (href_list["refresh"]) src.updateUsrDialog() else if (href_list["clone"]) - var/datum/data/record/C = locate(href_list["clone"]) + var/datum/dna2/record/C = locate(href_list["clone"]) //Look for that player! They better be dead! if(istype(C)) //Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs. @@ -313,17 +305,17 @@ else if(!config.revival_cloning) temp = "Error: Unable to initiate cloning cycle." - else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["languages"])) + else if(pod1.growclone(C)) temp = "Initiating cloning cycle..." records.Remove(C) del(C) menu = 1 else - var/mob/selected = find_dead_player("[C.fields["ckey"]]") + var/mob/selected = find_dead_player("[C.ckey]") selected << 'sound/machines/chime.ogg' //probably not the best sound but I think it's reasonable var/answer = alert(selected,"Do you want to return to life?","Cloning","Yes","No") - if(answer != "No" && pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["languages"], C.fields["interface"])) + if(answer != "No" && pod1.growclone(C)) temp = "Initiating cloning cycle..." records.Remove(C) del(C) @@ -363,27 +355,25 @@ subject.dna.check_integrity() - var/datum/data/record/R = new /datum/data/record( ) - R.fields["mrace"] = subject.species - R.fields["ckey"] = subject.ckey - R.fields["name"] = subject.real_name - R.fields["id"] = copytext(md5(subject.real_name), 2, 6) - R.fields["UI"] = subject.dna.uni_identity - R.fields["SE"] = subject.dna.struc_enzymes - R.fields["languages"] = subject.languages + var/datum/dna2/record/R = new /datum/dna2/record() + R.dna=subject.dna + R.ckey = subject.ckey + R.id= copytext(md5(subject.real_name), 2, 6) + R.name=R.dna.real_name + R.types=DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE //Add an implant if needed var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject) if (isnull(imp)) imp = new /obj/item/weapon/implant/health(subject) imp.implanted = subject - R.fields["imp"] = "\ref[imp]" + R.implant = "\ref[imp]" //Update it if needed else - R.fields["imp"] = "\ref[imp]" + R.implant = "\ref[imp]" if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning. - R.fields["mind"] = "\ref[subject.mind]" + R.mind = "\ref[subject.mind]" src.records += R scantemp = "Subject successfully scanned." @@ -391,8 +381,8 @@ //Find a specific record by key. /obj/machinery/computer/cloning/proc/find_record(var/find_key) var/selected_record = null - for(var/datum/data/record/R in src.records) - if (R.fields["ckey"] == find_key) + for(var/datum/dna2/record/R in src.records) + if (R.ckey == find_key) selected_record = R break return selected_record 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/computer/message.dm b/code/game/machinery/computer/message.dm index ed164896369..71a545cd556 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -443,7 +443,6 @@ //Sender isn't faking as someone who exists if(isnull(PDARec)) src.linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]") - customrecepient.tnote += "← From [customsender] ([customjob]):
    [custommessage]
    " if (!customrecepient.silent) playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1) for (var/mob/O in hearers(3, customrecepient.loc)) @@ -456,8 +455,13 @@ customrecepient.overlays += image('icons/obj/pda.dmi', "pda-r") //Sender is faking as someone who exists else + src.linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]") - customrecepient.tnote += "← From [PDARec.owner] ([customjob]):
    [custommessage]
    " + customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) + + if(!customrecepient.conversations.Find("\ref[PDARec]")) + customrecepient.conversations.Add("\ref[PDARec]") + if (!customrecepient.silent) playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1) for (var/mob/O in hearers(3, customrecepient.loc)) diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index e56ba78f201..479633ff100 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -347,6 +347,7 @@ What a mess.*/ P.info += "
    " P.name = "paper - 'Security Record'" printing = null + updateUsrDialog() //RECORD DELETE if ("Delete All Records") temp = "" diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index 073c1b8fe40..b909404a1c9 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -5,7 +5,7 @@ density = 1 anchored = 1.0 layer = 2.8 - + var/on = 0 var/temperature_archived var/mob/living/carbon/occupant = null @@ -65,10 +65,10 @@ /** * The ui_interact proc is used to open and update Nano UIs * If ui_interact is not used then the UI will not update correctly - * ui_interact is currently defined for /atom/movable + * ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob) * * @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_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 @@ -79,23 +79,12 @@ return // this is the data which will be sent to the ui - var/data[0] + var/data[0] data["isOperating"] = on data["hasOccupant"] = occupant ? 1 : 0 var/occupantData[0] - if (!occupant) - occupantData["name"] = null - occupantData["stat"] = null - occupantData["health"] = null - occupantData["maxHealth"] = null - occupantData["minHealth"] = null - occupantData["bruteLoss"] = null - occupantData["oxyLoss"] = null - occupantData["toxLoss"] = null - occupantData["fireLoss"] = null - occupantData["bodyTemperature"] = null - else + if (occupant) occupantData["name"] = occupant.name occupantData["stat"] = occupant.stat occupantData["health"] = occupant.health @@ -115,7 +104,7 @@ else if(air_contents.temperature > 225) data["cellTemperatureStatus"] = "average" - data["isBeakerLoaded"] = beaker ? 1 : 0 + data["isBeakerLoaded"] = beaker ? 1 : 0 /* // Removing beaker contents list from front-end, replacing with a total remaining volume var beakerContents[0] if(beaker && beaker.reagents && beaker.reagents.reagent_list.len) @@ -130,24 +119,19 @@ if (beaker.reagents && beaker.reagents.reagent_list.len) for(var/datum/reagent/R in beaker.reagents.reagent_list) data["beakerVolume"] += R.volume - - if (!ui) // no ui has been passed, so we'll search for one - { - ui = nanomanager.get_open_ui(user, src, ui_key) - } - if (!ui) - // the ui does not exist, so we'll create a new one + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 410) - // When the UI is first opened this is the data it will use - ui.set_initial_data(data) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window ui.open() - // Auto update every Master Controller tick + // 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 - //user.set_machine(src) /obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list) if(usr == occupant) @@ -159,7 +143,7 @@ if(href_list["switchOn"]) on = 1 update_icon() - + if(href_list["switchOff"]) on = 0 update_icon() @@ -168,12 +152,12 @@ if(beaker) beaker.loc = get_step(loc, SOUTH) beaker = null - + if(href_list["ejectOccupant"]) if(!occupant || isslime(usr) || ispAI(usr)) return 0 // don't update UIs attached to this object go_out() - + add_fingerprint(usr) return 1 // update UIs attached to this object @@ -268,15 +252,15 @@ occupant.client.eye = occupant.client.mob occupant.client.perspective = MOB_PERSPECTIVE occupant.loc = get_step(loc, SOUTH) //this doesn't account for walls or anything, but i don't forsee that being a problem. - if (occupant.bodytemperature < 261 && occupant.bodytemperature > 140) //Patch by Aranclanos to stop people from taking burn damage after being ejected - occupant.bodytemperature = 261 + if (occupant.bodytemperature < 261 && occupant.bodytemperature >= 70) //Patch by Aranclanos to stop people from taking burn damage after being ejected + occupant.bodytemperature = 261 // Changed to 70 from 140 by Zuhayr due to reoccurance of bug. // occupant.metabslow = 0 occupant = null update_icon() return /obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob) if (!istype(M)) - usr << "\red The cryo cell cannot handle such liveform!" + usr << "\red The cryo cell cannot handle such a lifeform!" return if (occupant) usr << "\red The cryo cell is already occupied!" diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm new file mode 100644 index 00000000000..3a0de6a8006 --- /dev/null +++ b/code/game/machinery/cryopod.dm @@ -0,0 +1,414 @@ +/* + * Cryogenic refrigeration unit. Basically a despawner. + * Stealing a lot of concepts/code from sleepers due to massive laziness. + * The despawn tick will only fire if it's been more than time_till_despawned ticks + * since time_entered, which is world.time when the occupant moves in. + * ~ Zuhayr + */ + +//Used for logging people entering cryosleep and important items they are carrying. +var/global/list/frozen_crew = list() +var/global/list/frozen_items = list() + +//Main cryopod console. + +/obj/machinery/computer/cryopod + name = "cryogenic oversight console" + desc = "An interface between crew and the cryogenic storage oversight systems." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "cellconsole" + circuit = "/obj/item/weapon/circuitboard/cryopodcontrol" + var/mode = null + +/obj/machinery/computer/cryopod/attack_paw() + src.attack_hand() + +/obj/machinery/computer/cryopod/attack_ai() + src.attack_hand() + +obj/machinery/computer/cryopod/attack_hand(mob/user = usr) + if(stat & (NOPOWER|BROKEN)) + return + + user.set_machine(src) + src.add_fingerprint(usr) + + var/dat + + if (!( ticker )) + return + + dat += "

    Cryogenic Oversight Control
    " + dat += "Welcome, [user.real_name].


    " + dat += "View storage log.
    " + dat += "Recover object.
    " + dat += "Recover all objects.
    " + dat += "Revive crew.

    " + + user << browse(dat, "window=cryopod_console") + onclose(user, "cryopod_console") + +obj/machinery/computer/cryopod/Topic(href, href_list) + + if(..()) + return + + var/mob/user = usr + + src.add_fingerprint(user) + + if(href_list["log"]) + + var/dat = "Recently stored crewmembers


    " + for(var/person in frozen_crew) + dat += "[person]
    " + dat += "
    " + + user << browse(dat, "window=cryolog") + + else if(href_list["item"]) + + if(frozen_items.len == 0) + user << "\blue There is nothing to recover from storage." + return + + var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as obj in frozen_items + + if(!I || frozen_items.len == 0) + user << "\blue There is nothing to recover from storage." + return + + visible_message("\blue The console beeps happily as it disgorges \the [I].", 3) + + I.loc = get_turf(src) + frozen_items -= I + + else if(href_list["allitems"]) + + if(frozen_items.len == 0) + user << "\blue There is nothing to recover from storage." + return + + visible_message("\blue The console beeps happily as it disgorges the desired objects.", 3) + + for(var/obj/item/I in frozen_items) + I.loc = get_turf(src) + frozen_items -= I + + else if(href_list["crew"]) + user << "\red Functionality unavailable at this time." + + src.updateUsrDialog() + return + +/obj/item/weapon/circuitboard/cryopodcontrol + name = "Circuit board (Cryogenic Oversight Console)" + build_path = "/obj/machinery/computer/cryopod" + origin_tech = "programming=3" + +//Decorative structures to go alongside cryopods. +/obj/structure/cryofeed + + name = "\improper cryogenic feed" + desc = "A bewildering tangle of machinery and pipes." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "cryo_rear" + anchored = 1 + + var/orient_right = null //Flips the sprite. + +/obj/structure/cryofeed/right + orient_right = 1 + icon_state = "cryo_rear-r" + +/obj/structure/cryofeed/New() + + if(orient_right) + icon_state = "cryo_rear-r" + else + icon_state = "cryo_rear" + ..() + +//Cryopods themselves. +/obj/machinery/cryopod + name = "\improper cryogenic freezer" + desc = "A man-sized pod for entering suspended animation." + icon = 'icons/obj/Cryogenic2.dmi' + icon_state = "body_scanner_0" + density = 1 + anchored = 1 + + var/mob/occupant = null // Person waiting to be despawned. + var/orient_right = null // Flips the sprite. + var/time_till_despawn = 9000 // 15 minutes-ish safe period before being despawned. + var/time_entered = 0 // Used to keep track of the safe period. + var/obj/item/device/radio/intercom/announce // + + // These items are preserved when the process() despawn proc occurs. + var/list/preserve_items = list( + /obj/item/weapon/hand_tele, + /obj/item/weapon/card/id/captains_spare, + /obj/item/device/aicard, + /obj/item/device/mmi, + /obj/item/device/paicard, + /obj/item/weapon/gun, + /obj/item/weapon/pinpointer, + /obj/item/clothing/suit, + /obj/item/clothing/shoes/magboots, + /obj/item/blueprints, + /obj/item/clothing/head/helmet/space/ + ) + +/obj/machinery/cryopod/right + orient_right = 1 + icon_state = "body_scanner_0-r" + +/obj/machinery/cryopod/New() + + announce = new /obj/item/device/radio/intercom(src) + + if(orient_right) + icon_state = "body_scanner_0-r" + else + icon_state = "body_scanner_0" + ..() + +//Lifted from Unity stasis.dm and refactored. ~Zuhayr +/obj/machinery/cryopod/process() + if(occupant) + + //Allow a ten minute gap between entering the pod and actually despawning. + if(world.time - time_entered < time_till_despawn) + return + + if(!occupant.client && occupant.stat<2) //Occupant is living and has no client. + + //Drop all items into the pod. + for(var/obj/item/W in occupant) + occupant.drop_from_inventory(W) + W.loc = src + + if(W.contents.len) //Make sure we catch anything not handled by del() on the items. + for(var/obj/item/O in W.contents) + O.loc = src + + //Delete all items not on the preservation list. + var/list/items = src.contents + items -= occupant // Don't delete the occupant + items -= announce // or the autosay radio. + + for(var/obj/item/W in items) + var/preserve = null + for(var/T in preserve_items) + if(istype(W,T)) + preserve = 1 + break + + if(!preserve) + del(W) + else + frozen_items += W + + //Update any existing objectives involving this mob. + for(var/datum/objective/O in all_objectives) + if(istype(O,/datum/objective/mutiny)) //We don't want revs to get objectives that aren't for heads of staff. Letting them win or lose based on cryo is silly so we remove the objective. + del(O) //TODO: Update rev objectives on login by head (may happen already?) ~ Z + else if(O.target && istype(O.target,/datum/mind)) + if(O.target == occupant.mind) + if(O.owner && O.owner.current) + O.owner.current << "\red You get the feeling your target is no longer within your reach. Time for Plan [pick(list("A","B","C","D","X","Y","Z"))]..." + O.target = null + spawn(1) //This should ideally fire after the occupant is deleted. + if(!O) return + O.find_target() + if(!(O.target)) + all_objectives -= O + O.owner.objectives -= O + del(O) + + //Handle job slot/tater cleanup. + var/job = occupant.mind.assigned_role + + job_master.FreeRole(job) + + if(occupant.mind.objectives.len) + del(occupant.mind.objectives) + occupant.mind.special_role = null + else + if(ticker.mode.name == "AutoTraitor") + var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode + current_mode.possible_traitors.Remove(occupant) + + // Delete them from datacore. + for(var/datum/data/record/R in data_core.medical) + if ((R.fields["name"] == occupant.real_name)) + del(R) + for(var/datum/data/record/T in data_core.security) + if ((T.fields["name"] == occupant.real_name)) + del(T) + for(var/datum/data/record/G in data_core.general) + if ((G.fields["name"] == occupant.real_name)) + del(G) + + if(orient_right) + icon_state = "body_scanner_0-r" + else + icon_state = "body_scanner_0" + + //TODO: Check objectives/mode, update new targets if this mob is the target, spawn new antags? + + //This should guarantee that ghosts don't spawn. + occupant.ckey = null + + //Make an announcement and log the person entering storage. + frozen_crew += "[occupant.real_name]" + + announce.autosay("[occupant.real_name] has entered long-term storage.", "Cryogenic Oversight") + visible_message("\blue The crypod hums and hisses as it moves [occupant.real_name] into storage.", 3) + + // Delete the mob. + del(occupant) + occupant = null + + + return + + +/obj/machinery/cryopod/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) + + if(istype(G, /obj/item/weapon/grab)) + + if(occupant) + user << "\blue The cryo pod is in use." + return + + if(!ismob(G:affecting)) + return + + var/willing = null //We don't want to allow people to be forced into despawning. + var/mob/M = G:affecting + + if(M.client) + if(alert(M,"Would you like to enter cryosleep?",,"Yes","No") == "Yes") + if(!M || !G || !G:affecting) return + willing = 1 + else + willing = 1 + + if(willing) + + visible_message("[user] starts putting [G:affecting:name] into the cryo pod.", 3) + + if(do_after(user, 20)) + if(!M || !G || !G:affecting) return + + M.loc = src + + if(M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + + if(orient_right) + icon_state = "body_scanner_1-r" + else + icon_state = "body_scanner_1" + + M << "\blue You feel cool air surround you. You go numb as your senses turn inward." + M << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round." + occupant = M + time_entered = world.time + + // Book keeping! + log_admin("[key_name_admin(M)] has entered a stasis pod.") + message_admins("\blue [key_name_admin(M)] has entered a stasis pod.") + + //Despawning occurs when process() is called with an occupant without a client. + src.add_fingerprint(M) + +/obj/machinery/cryopod/verb/eject() + set name = "Eject Pod" + set category = "Object" + set src in oview(1) + if(usr.stat != 0) + return + + if(orient_right) + icon_state = "body_scanner_0-r" + else + icon_state = "body_scanner_0" + + src.go_out() + add_fingerprint(usr) + return + +/obj/machinery/cryopod/verb/move_inside() + set name = "Enter Pod" + set category = "Object" + set src in oview(1) + + if(usr.stat != 0 || !(ishuman(usr) || ismonkey(usr))) + return + + if(src.occupant) + usr << "\blue The cryo pod is in use." + return + + for(var/mob/living/carbon/slime/M in range(1,usr)) + if(M.Victim == usr) + usr << "You're too busy getting your life sucked out of you." + return + + visible_message("[usr] starts climbing into the cryo pod.", 3) + + if(do_after(usr, 20)) + + if(!usr || !usr.client) + return + + if(src.occupant) + usr << "\blue The cryo pod is in use." + return + + usr.stop_pulling() + usr.client.perspective = EYE_PERSPECTIVE + usr.client.eye = src + usr.loc = src + src.occupant = usr + + if(orient_right) + icon_state = "body_scanner_1-r" + else + icon_state = "body_scanner_1" + + usr << "\blue You feel cool air surround you. You go numb as your senses turn inward." + usr << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round." + occupant = usr + time_entered = world.time + + src.add_fingerprint(usr) + + return + +/obj/machinery/cryopod/proc/go_out() + + if(!occupant) + return + + if(occupant.client) + occupant.client.eye = src.occupant.client.mob + occupant.client.perspective = MOB_PERSPECTIVE + + occupant.loc = get_turf(src) + occupant = null + + if(orient_right) + icon_state = "body_scanner_0-r" + else + icon_state = "body_scanner_0" + + return + + +//Attacks/effects. +/obj/machinery/cryopod/blob_act() + return //Sorta gamey, but we don't really want these to be destroyed. diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 47ebf869d74..3fd77b8b34b 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -88,11 +88,11 @@ user << "Access denied." return - var/area/A = get_area(src) - ASSERT(istype(A)) - if(A.master) - A = A.master - var/alarmed = A.air_doors_activated || A.fire + var/alarmed = 0 + + for(var/area/A in areas_added) //Checks if there are fire alarms in any areas associated with that firedoor + if(A.fire || A.air_doors_activated) + alarmed = 1 var/answer = alert(user, "Would you like to [density ? "open" : "close"] this [src.name]?[ alarmed && density ? "\nNote that by doing so, you acknowledge any damages from opening this\n[src.name] as being your own fault, and you will be held accountable under the law." : ""]",\ "\The [src]", "Yes, [density ? "open" : "close"]", "No") @@ -114,9 +114,13 @@ if(needs_to_close) spawn(50) + alarmed = 0 + for(var/area/A in areas_added) //Just in case a fire alarm is turned off while the firedoor is going through an autoclose cycle + if(A.fire || A.air_doors_activated) + alarmed = 1 if(alarmed) nextstate = CLOSED - + close() /obj/machinery/door/firedoor/attackby(obj/item/weapon/C as obj, mob/user as mob) add_fingerprint(user) 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/iv_drip.dm b/code/game/machinery/iv_drip.dm index 970048272aa..e677e6e8be9 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -70,6 +70,7 @@ set background = 1 if(src.attached) + if(!(get_dist(src, src.attached) <= 1 && isturf(src.attached.loc))) visible_message("The needle is ripped out of [src.attached], doesn't that hurt?") src.attached:apply_damage(3, BRUTE, pick("r_arm", "l_arm")) @@ -105,6 +106,9 @@ if(NOCLONE in T.mutations) return + if(T.species && T.species.flags & NO_BLOOD) + return + // If the human is losing too much blood, beep. if(T.vessel.get_reagent_amount("blood") < BLOOD_VOLUME_SAFE) if(prob(5)) visible_message("\The [src] beeps loudly.") diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm index d25e1ecc145..0c45afb4095 100644 --- a/code/game/machinery/kitchen/microwave.dm +++ b/code/game/machinery/kitchen/microwave.dm @@ -43,6 +43,11 @@ if (recipe.items) max_n_of_items = max(max_n_of_items,recipe.items.len) + // This will do until I can think of a fun recipe to use dionaea in - + // will also allow anything using the holder item to be microwaved into + // impure carbon. ~Z + acceptable_items |= /obj/item/weapon/holder + /******************* * Item Adding ********************/ diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index af52a4e7565..b1783b1707c 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -409,10 +409,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="Wanted issue for [src.channel_name] successfully edited.

    " dat+="
    Return
    " if(20) - dat+="Printing successfull. Please receive your newspaper from the bottom of the machine.

    " + dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

    " dat+="Return" if(21) - dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnell to refill machine storage.

    " + dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

    " dat+="Return" else dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" diff --git a/code/game/machinery/podmen.dm b/code/game/machinery/podmen.dm index 7654bda9641..6dd173f4478 100644 --- a/code/game/machinery/podmen.dm +++ b/code/game/machinery/podmen.dm @@ -92,6 +92,8 @@ Growing it to term with nothing injected will grab a ghost from the observers. * /obj/item/seeds/replicapod/proc/request_player() for(var/mob/dead/observer/O in player_list) + if(jobban_isbanned(O, "Dionaea")) + continue if(O.client) if(O.client.prefs.be_special & BE_PLANT) question(O.client) diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 640fc00afcd..03d97e0e1f3 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -384,7 +384,7 @@ user.visible_message("[user] turned the shield generator off.", \ "You turn off the shield generator.", \ "You hear heavy droning fade out.") - src.cleanup() + for(var/dir in list(1,2,4,8)) src.cleanup(dir) else src.active = 1 icon_state = "Shield_Gen +a" @@ -424,14 +424,7 @@ "You hear heavy droning fade out") icon_state = "Shield_Gen" src.active = 0 - spawn(1) - src.cleanup(1) - spawn(1) - src.cleanup(2) - spawn(1) - src.cleanup(4) - spawn(1) - src.cleanup(8) + for(var/dir in list(1,2,4,8)) src.cleanup(dir) /obj/machinery/shieldwallgen/proc/setup_field(var/NSEW = 0) var/turf/T = src.loc diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index d90986a5dda..7775e3aa20d 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -288,7 +288,10 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes. continue - + + // Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates + if(data == 3 && istype(R, /mob/dead/observer) && R.client && (R.client.prefs.toggles & CHAT_GHOSTRADIO)) + continue // --- Check for compression --- if(compression > 0) @@ -333,19 +336,19 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept freq_text = "#unkn" if(COMM_FREQ) freq_text = "Command" - if(1351) + if(SCI_FREQ) freq_text = "Science" - if(1355) + if(MED_FREQ) freq_text = "Medical" - if(1357) + if(ENG_FREQ) freq_text = "Engineering" - if(1359) + if(SEC_FREQ) freq_text = "Security" - if(1347) + if(SUP_FREQ) freq_text = "Supply" - if(1441) + if(1341) freq_text = "Special Ops" - if(1443) + if(1345) freq_text = "Response Team" //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm index 914bd8c9016..83f3a532b7f 100644 --- a/code/game/machinery/telecomms/presets.dm +++ b/code/game/machinery/telecomms/presets.dm @@ -43,6 +43,13 @@ "supply", "common", "command", "engineering", "security", "receiverA", "receiverB", "broadcasterA", "broadcasterB") +/obj/machinery/telecomms/hub/preset_cent + id = "CentComm Hub" + network = "tcommsat" + heatgen = 0 + autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay", + "centcomm", "receiverCent", "broadcasterCent") + //Receivers //--PRESET LEFT--// @@ -68,6 +75,13 @@ freq_listening |= i ..() +/obj/machinery/telecomms/receiver/preset_cent + id = "CentComm Receiver" + network = "tcommsat" + heatgen = 0 + autolinkers = list("receiverCent") + freq_listening = list(1345, 1341) + //Buses @@ -100,6 +114,13 @@ freq_listening |= i ..() +/obj/machinery/telecomms/bus/preset_cent + id = "CentComm Bus" + network = "tcommsat" + freq_listening = list(1345, 1341) + heatgen = 0 + autolinkers = list("processorCent", "centcomm") + //Processors /obj/machinery/telecomms/processor/preset_one @@ -122,6 +143,12 @@ network = "tcommsat" autolinkers = list("processor4") +/obj/machinery/telecomms/processor/preset_cent + id = "CentComm Processor" + network = "tcommsat" + heatgen = 0 + autolinkers = list("processorCent") + //Servers /obj/machinery/telecomms/server/presets @@ -170,6 +197,12 @@ freq_listening = list(1359) autolinkers = list("security") +/obj/machinery/telecomms/server/presets/centcomm + id = "CentComm Server" + freq_listening = list(1345, 1341) + heatgen = 0 + autolinkers = list("centcomm") + //Broadcasters @@ -186,3 +219,9 @@ id = "Broadcaster B" network = "tcommsat" autolinkers = list("broadcasterB") + +/obj/machinery/telecomms/broadcaster/preset_cent + id = "CentComm Broadcaster" + network = "tcommsat" + heatgen = 0 + autolinkers = list("broadcasterCent") \ No newline at end of file diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 1476b13d0a8..f09abfeefe0 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -52,6 +52,8 @@ var/const/WIRE_SHOCK = 3 var/const/WIRE_SHOOTINV = 4 + var/check_accounts = 0 // 1 = requires PIN and checks accounts. 0 = You slide an ID, it vends, SPACE COMMUNISM! + /obj/machinery/vending/New() ..() spawn(4) @@ -148,6 +150,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 ..() @@ -156,46 +166,51 @@ if (istype(I, /obj/item/weapon/card/id)) var/obj/item/weapon/card/id/C = I visible_message("[usr] swipes a card through [src].") - if(vendor_account) - var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) - if(D) - var/transaction_amount = currently_vending.price - if(transaction_amount <= D.money) + if(check_accounts) + if(vendor_account) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2) + if(D) + var/transaction_amount = currently_vending.price + if(transaction_amount <= D.money) - //transfer the money - D.money -= transaction_amount - vendor_account.money += transaction_amount + //transfer the money + D.money -= transaction_amount + vendor_account.money += transaction_amount - //create entries in the two account transaction logs - var/datum/transaction/T = new() - T.target_name = "[vendor_account.owner_name] (via [src.name])" - T.purpose = "Purchase of [currently_vending.product_name]" - if(transaction_amount > 0) - T.amount = "([transaction_amount])" - else + //create entries in the two account transaction logs + var/datum/transaction/T = new() + T.target_name = "[vendor_account.owner_name] (via [src.name])" + T.purpose = "Purchase of [currently_vending.product_name]" + if(transaction_amount > 0) + T.amount = "([transaction_amount])" + else + T.amount = "[transaction_amount]" + T.source_terminal = src.name + T.date = current_date_string + T.time = worldtime2text() + D.transaction_log.Add(T) + // + T = new() + T.target_name = D.owner_name + T.purpose = "Purchase of [currently_vending.product_name]" T.amount = "[transaction_amount]" - T.source_terminal = src.name - T.date = current_date_string - T.time = worldtime2text() - D.transaction_log.Add(T) - // - T = new() - T.target_name = D.owner_name - T.purpose = "Purchase of [currently_vending.product_name]" - T.amount = "[transaction_amount]" - T.source_terminal = src.name - T.date = current_date_string - T.time = worldtime2text() - vendor_account.transaction_log.Add(T) + T.source_terminal = src.name + T.date = current_date_string + T.time = worldtime2text() + vendor_account.transaction_log.Add(T) - // Vend the item - src.vend(src.currently_vending, usr) - currently_vending = null + // Vend the item + src.vend(src.currently_vending, usr) + currently_vending = null + else + usr << "\icon[src]You don't have that much money!" else - usr << "\icon[src]You don't have that much money!" + usr << "\icon[src]Unable to access account. Check security settings and try again." else - usr << "\icon[src]Unable to access account. Check security settings and try again." + //Just Vend it. + src.vend(src.currently_vending, usr) + currently_vending = null else usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support." @@ -407,6 +422,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 @@ -589,11 +611,11 @@ /obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka = 5, /obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/rum = 5, /obj/item/weapon/reagent_containers/food/drinks/bottle/wine = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/cognac = 5, - /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5,/obj/item/weapon/reagent_containers/food/drinks/beer = 6, - /obj/item/weapon/reagent_containers/food/drinks/ale = 6,/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 4, + /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5,/obj/item/weapon/reagent_containers/food/drinks/cans/beer = 6, + /obj/item/weapon/reagent_containers/food/drinks/cans/ale = 6,/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 4, /obj/item/weapon/reagent_containers/food/drinks/bottle/tomatojuice = 4,/obj/item/weapon/reagent_containers/food/drinks/bottle/limejuice = 4, - /obj/item/weapon/reagent_containers/food/drinks/bottle/cream = 4,/obj/item/weapon/reagent_containers/food/drinks/tonic = 8, - /obj/item/weapon/reagent_containers/food/drinks/cola = 8, /obj/item/weapon/reagent_containers/food/drinks/sodawater = 15, + /obj/item/weapon/reagent_containers/food/drinks/bottle/cream = 4,/obj/item/weapon/reagent_containers/food/drinks/cans/tonic = 8, + /obj/item/weapon/reagent_containers/food/drinks/cans/cola = 8, /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater = 15, /obj/item/weapon/reagent_containers/food/drinks/drinkingglass = 30,/obj/item/weapon/reagent_containers/food/drinks/ice = 9, /obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor = 2,/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao = 2, /obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe = 2,/obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine = 5) @@ -645,15 +667,15 @@ icon_state = "Cola_Machine" product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!" product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space." - products = list(/obj/item/weapon/reagent_containers/food/drinks/cola = 10,/obj/item/weapon/reagent_containers/food/drinks/space_mountain_wind = 10, - /obj/item/weapon/reagent_containers/food/drinks/dr_gibb = 10,/obj/item/weapon/reagent_containers/food/drinks/starkist = 10, - /obj/item/weapon/reagent_containers/food/drinks/waterbottle = 10,/obj/item/weapon/reagent_containers/food/drinks/space_up = 10, - /obj/item/weapon/reagent_containers/food/drinks/iced_tea = 10, /obj/item/weapon/reagent_containers/food/drinks/grape_juice = 10) - contraband = list(/obj/item/weapon/reagent_containers/food/drinks/thirteenloko = 5) - prices = list(/obj/item/weapon/reagent_containers/food/drinks/cola = 1,/obj/item/weapon/reagent_containers/food/drinks/space_mountain_wind = 1, - /obj/item/weapon/reagent_containers/food/drinks/dr_gibb = 1,/obj/item/weapon/reagent_containers/food/drinks/starkist = 1, - /obj/item/weapon/reagent_containers/food/drinks/waterbottle = 2,/obj/item/weapon/reagent_containers/food/drinks/space_up = 1, - /obj/item/weapon/reagent_containers/food/drinks/iced_tea = 1,/obj/item/weapon/reagent_containers/food/drinks/grape_juice = 1) + products = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 10, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 10, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 10, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 10, /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 10) + contraband = list(/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko = 5) + prices = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 1, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 1, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 2,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 1, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 1) //This one's from bay12 /obj/machinery/vending/cart @@ -759,8 +781,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/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index 73c7f5bd84f..416e2ff6cb9 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -94,7 +94,7 @@ else if(istype(target, /turf/simulated/mineral)) for(var/turf/simulated/mineral/M in range(chassis,1)) if(get_dir(chassis,M)&chassis.dir) - M.gets_drilled() + M.GetDrilled() log_message("Drilled through [target]") if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo @@ -153,7 +153,7 @@ else if(istype(target, /turf/simulated/mineral)) for(var/turf/simulated/mineral/M in range(chassis,1)) if(get_dir(chassis,M)&chassis.dir) - M.gets_drilled() + M.GetDrilled() log_message("Drilled through [target]") if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment) var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 9e9e578ecf1..539ad4374e1 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -518,7 +518,7 @@ temp += "Return" src.updateUsrDialog() if(i || tech_output) - src.visible_message("\icon[src] [src] beeps, \"Succesfully synchronized with R&D server. New data processed.\"") + src.visible_message("\icon[src] [src] beeps, \"Successfully synchronized with R&D server. New data processed.\"") return /obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(var/obj/item/part as obj,var/resource as text, var/roundto=1) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 65284a054d1..77807c2ca1c 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -237,7 +237,7 @@ target = safepick(view(3,target)) if(!target) return - if(get_dist(src, target)>1) + if(!target.Adjacent(src)) if(selected && selected.is_ranged()) selected.action(target) else if(selected && selected.is_melee()) @@ -973,6 +973,11 @@ if (usr.stat || !ishuman(usr)) return src.log_message("[usr] tries to move in.") + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + if(C.handcuffed) + usr << "\red Kinda hard to climb in while handcuffed don't you think?" + return if (src.occupant) usr << "\blue The [src.name] is already occupied!" src.log_append_to_last("Permission denied.") diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm index 008b5d819ab..5c188802e3e 100644 --- a/code/game/mecha/medical/odysseus.dm +++ b/code/game/mecha/medical/odysseus.dm @@ -108,6 +108,13 @@ holder.icon_state = "hudxeno" else if(foundVirus) holder.icon_state = "hudill" + else if(patient.has_brain_worms()) + var/mob/living/simple_animal/borer/B = patient.has_brain_worms() + if(B.controlling) + holder.icon_state = "hudbrainworm" + else + holder.icon_state = "hudhealthy" else holder.icon_state = "hudhealthy" + C.images += holder diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm index 7ee6aaa3b50..1df3acb2b73 100644 --- a/code/game/objects/effects/decals/Cleanable/aliens.dm +++ b/code/game/objects/effects/decals/Cleanable/aliens.dm @@ -1,63 +1,33 @@ -// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code. - -/obj/effect/decal/cleanable/xenoblood +/obj/effect/decal/cleanable/blood/xeno name = "xeno blood" desc = "It's green and acidic. It looks like... blood?" - gender = PLURAL - density = 0 - anchored = 1 - layer = 2 icon = 'icons/effects/blood.dmi' - icon_state = "xfloor1" - random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7") - var/list/viruses = list() - blood_DNA = list() + basecolor = "#05EE05" - Del() - for(var/datum/disease/D in viruses) - D.cure(0) - ..() - -/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(var/list/directions) - spawn (0) - var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) - sleep(3) - if (i > 0) - var/obj/effect/decal/cleanable/xenoblood/b = new /obj/effect/decal/cleanable/xenoblood/xsplatter(src.loc) - for(var/datum/disease/D in src.viruses) - var/datum/disease/ND = D.Copy(1) - b.viruses += ND - ND.holder = b - if (step_to(src, get_step(src, direction), 0)) - break - -/obj/effect/decal/cleanable/xenoblood/xsplatter - random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5") - -/obj/effect/decal/cleanable/xenoblood/xgibs +/obj/effect/decal/cleanable/blood/gibs/xeno name = "xeno gibs" desc = "Gnarly..." - gender = PLURAL - icon = 'icons/effects/blood.dmi' icon_state = "xgib1" random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6") + basecolor = "#05EE05" -/obj/effect/decal/cleanable/xenoblood/xgibs/up +/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon() + color = "#FFFFFF" + +/obj/effect/decal/cleanable/blood/gibs/xeno/up random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1") -/obj/effect/decal/cleanable/xenoblood/xgibs/down +/obj/effect/decal/cleanable/blood/gibs/xeno/down random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibdown1","xgibdown1","xgibdown1") -/obj/effect/decal/cleanable/xenoblood/xgibs/body +/obj/effect/decal/cleanable/blood/gibs/xeno/body random_icon_states = list("xgibhead", "xgibtorso") -/obj/effect/decal/cleanable/xenoblood/xgibs/limb +/obj/effect/decal/cleanable/blood/gibs/xeno/limb random_icon_states = list("xgibleg", "xgibarm") -/obj/effect/decal/cleanable/xenoblood/xgibs/core +/obj/effect/decal/cleanable/blood/gibs/xeno/core random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3") /obj/effect/decal/cleanable/blood/xtracks - icon_state = "xtracks" - random_icon_states = null \ No newline at end of file + basecolor = "#05EE05" \ No newline at end of file diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 4f472f864ff..af0a3e65e1f 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -1,16 +1,21 @@ -#define DRYING_TIME 5 * 60*10 //for 1 unit of depth in puddle (amount var) +#define DRYING_TIME 5 * 60*10 //for 1 unit of depth in puddle (amount var) + +var/global/list/image/splatter_cache=list() + /obj/effect/decal/cleanable/blood name = "blood" - desc = "It's red and gooey. Perhaps it's the chef's cooking?" + desc = "It's thick and gooey. Perhaps it's the chef's cooking?" gender = PLURAL density = 0 anchored = 1 layer = 2 icon = 'icons/effects/blood.dmi' - icon_state = "floor1" - random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") + icon_state = "mfloor1" + random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") + var/base_icon = 'icons/effects/blood.dmi' var/list/viruses = list() blood_DNA = list() + var/basecolor="#A10808" // Color when wet. var/list/datum/disease2/disease/virus2 = list() var/amount = 5 @@ -21,8 +26,11 @@ /obj/effect/decal/cleanable/blood/New() ..() + update_icon() if(istype(src, /obj/effect/decal/cleanable/blood/gibs)) return + if(istype(src, /obj/effect/decal/cleanable/blood/tracks)) + return // We handle our own drying. if(src.type == /obj/effect/decal/cleanable/blood) if(src.loc && isturf(src.loc)) for(var/obj/effect/decal/cleanable/blood/B in src.loc) @@ -33,63 +41,92 @@ spawn(DRYING_TIME * (amount+1)) dry() +/obj/effect/decal/cleanable/blood/update_icon() + if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" + color = basecolor + /obj/effect/decal/cleanable/blood/HasEntered(mob/living/carbon/human/perp) - if (!istype(perp)) - return - if(amount < 1) - return + if (!istype(perp)) + return + if(amount < 1) + return - if(perp.shoes) - perp.shoes:track_blood = max(amount,perp.shoes:track_blood) //Adding blood to shoes - if(!perp.shoes.blood_overlay) - perp.shoes.generate_blood_overlay() - if(!perp.shoes.blood_DNA) - perp.shoes.blood_DNA = list() - perp.shoes.overlays += perp.shoes.blood_overlay - perp.update_inv_shoes(1) - perp.shoes.blood_DNA |= blood_DNA.Copy() - else - perp.track_blood = max(amount,perp.track_blood) //Or feet - if(!perp.feet_blood_DNA) - perp.feet_blood_DNA = list() - perp.feet_blood_DNA |= blood_DNA.Copy() + if(perp.shoes) + perp.shoes:track_blood = max(amount,perp.shoes:track_blood) //Adding blood to shoes + if(!perp.shoes.blood_overlay) + perp.shoes.generate_blood_overlay() + if(!perp.shoes.blood_DNA) + perp.shoes.blood_DNA = list() + perp.shoes.blood_overlay.color = basecolor + perp.shoes.overlays += perp.shoes.blood_overlay + perp.update_inv_shoes(1) + perp.shoes.blood_DNA |= blood_DNA.Copy() + perp.shoes.blood_color=basecolor + else + perp.track_blood = max(amount,perp.track_blood) //Or feet + if(!perp.feet_blood_DNA) + perp.feet_blood_DNA = list() + perp.feet_blood_DNA |= blood_DNA.Copy() + perp.feet_blood_color=basecolor - amount-- + amount-- /obj/effect/decal/cleanable/blood/proc/dry() - name = "dried [src]" - desc = "It's dark red and crusty. Someone is not doing their job." - var/icon/I = icon(icon,icon_state) - I.SetIntensity(0.7) - icon = I - amount = 0 + name = "dried [src.name]" + desc = "It's dry and crusty. Someone is not doing their job." + color = adjust_brightness(color, -50) + amount = 0 + +/obj/effect/decal/cleanable/blood/attack_hand(mob/living/carbon/human/user) + ..() + if (amount && istype(user)) + add_fingerprint(user) + if (user.gloves) + return + var/taken = rand(1,amount) + amount -= taken + user << "You get some of \the [src] on your hands." + if (!user.blood_DNA) + user.blood_DNA = list() + user.blood_DNA |= blood_DNA.Copy() + user.bloody_hands += taken + user.hand_blood_color = basecolor + user.update_inv_gloves(1) + user.verbs += /mob/living/carbon/human/proc/bloody_doodle /obj/effect/decal/cleanable/blood/splatter - random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5") - amount = 2 - -/obj/effect/decal/cleanable/blood/footprints - name = "bloody footprints" - desc = "Whoops..." - icon='icons/effects/footprints.dmi' - icon_state = "blood1" - amount = 0 - random_icon_states = null - -/obj/effect/decal/cleanable/blood/tracks - icon_state = "tracks" - desc = "They look like tracks left by wheels." - gender = PLURAL - random_icon_states = null - amount = 0 + random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") + amount = 2 /obj/effect/decal/cleanable/blood/drip - name = "drips of blood" - desc = "It's red." - gender = PLURAL - icon = 'icons/effects/drip.dmi' - icon_state = "1" + name = "drips of blood" + desc = "It's red." + gender = PLURAL + icon = 'icons/effects/drip.dmi' + icon_state = "1" + random_icon_states = list("1","2","3","4","5") + amount = 0 + +/obj/effect/decal/cleanable/blood/writing + icon_state = "tracks" + desc = "It looks like a writing in blood." + gender = NEUTER + random_icon_states = list("writing1","writing2","writing3","writing4","writing5") amount = 0 + var/message + +/obj/effect/decal/cleanable/blood/writing/New() + ..() + if(random_icon_states.len) + for(var/obj/effect/decal/cleanable/blood/writing/W in loc) + random_icon_states.Remove(W.icon_state) + icon_state = pick(random_icon_states) + else + icon_state = "writing1" + +/obj/effect/decal/cleanable/blood/writing/examine() + ..() + usr << "It reads: \"[message]\"" /obj/effect/decal/cleanable/blood/gibs name = "gibs" @@ -101,6 +138,22 @@ icon = 'icons/effects/blood.dmi' icon_state = "gibbl5" random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6") + var/fleshcolor = "#FFFFFF" + +/obj/effect/decal/cleanable/blood/gibs/update_icon() + + var/image/giblets = new(base_icon, "[icon_state]_flesh", dir) + if(!fleshcolor || fleshcolor == "rainbow") + fleshcolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" + giblets.color = fleshcolor + + var/icon/blood = new(base_icon,"[icon_state]",dir) + if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" + blood.Blend(basecolor,ICON_MULTIPLY) + + icon = blood + overlays.Cut() + overlays += giblets /obj/effect/decal/cleanable/blood/gibs/up random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1") @@ -119,19 +172,21 @@ /obj/effect/decal/cleanable/blood/gibs/proc/streak(var/list/directions) - spawn (0) - var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) - sleep(3) - if (i > 0) - var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc) - for(var/datum/disease/D in src.viruses) - var/datum/disease/ND = D.Copy(1) - b.viruses += ND - ND.holder = b + spawn (0) + var/direction = pick(directions) + for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) + sleep(3) + if (i > 0) + var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc) + b.basecolor = src.basecolor + b.update_icon() + for(var/datum/disease/D in src.viruses) + var/datum/disease/ND = D.Copy(1) + b.viruses += ND + ND.holder = b - if (step_to(src, get_step(src, direction), 0)) - break + if (step_to(src, get_step(src, direction), 0)) + break /obj/effect/decal/cleanable/mucus @@ -144,4 +199,10 @@ icon = 'icons/effects/blood.dmi' icon_state = "mucus" random_icon_states = list("mucus") + var/list/datum/disease2/disease/virus2 = list() + var/dry=0 // Keeps the lag down + +/obj/effect/decal/cleanable/mucus/New() + spawn(DRYING_TIME * 2) + dry=1 diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm index 67c82a8f440..d52fd60b7eb 100644 --- a/code/game/objects/effects/decals/Cleanable/misc.dm +++ b/code/game/objects/effects/decals/Cleanable/misc.dm @@ -16,6 +16,13 @@ icon_state = "ash" anchored = 1 +/obj/effect/decal/cleanable/ash/attack_hand(mob/user as mob) + user << "[src] sifts through your fingers." + var/turf/simulated/floor/F = get_turf(src) + if (istype(F)) + F.dirt += 4 + del(src) + /obj/effect/decal/cleanable/greenglow New() @@ -32,6 +39,7 @@ layer = 2 icon = 'icons/effects/effects.dmi' icon_state = "dirt" + mouse_opacity = 0 /obj/effect/decal/cleanable/flour name = "flour" diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm index fa3aa3bfa9d..150197347de 100644 --- a/code/game/objects/effects/decals/Cleanable/robots.dm +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -1,25 +1,26 @@ -// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code. - -/obj/effect/decal/cleanable/robot_debris +/obj/effect/decal/cleanable/blood/gibs/robot name = "robot debris" desc = "It's a useless heap of junk... or is it?" - gender = PLURAL - density = 0 - anchored = 1 - layer = 2 icon = 'icons/mob/robots.dmi' icon_state = "gib1" + basecolor="#030303" random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") -/obj/effect/decal/cleanable/robot_debris/proc/streak(var/list/directions) +/obj/effect/decal/cleanable/blood/gibs/robot/update_icon() + color = "#FFFFFF" + +/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like + return + +/obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions) spawn (0) var/direction = pick(directions) for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) sleep(3) if (i > 0) if (prob(40)) - /*var/obj/effect/decal/cleanable/oil/o =*/ - new /obj/effect/decal/cleanable/oil/streak(src.loc) + var/obj/effect/decal/cleanable/blood/oil/streak = new(src.loc) + streak.update_icon() else if (prob(10)) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) @@ -27,31 +28,23 @@ if (step_to(src, get_step(src, direction), 0)) break -/obj/effect/decal/cleanable/robot_debris/limb +/obj/effect/decal/cleanable/blood/gibs/robot/limb random_icon_states = list("gibarm", "gibleg") -/obj/effect/decal/cleanable/robot_debris/up +/obj/effect/decal/cleanable/blood/gibs/robot/up random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1") //2:7 is close enough to 1:4 -/obj/effect/decal/cleanable/robot_debris/down +/obj/effect/decal/cleanable/blood/gibs/robot/down random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1") //2:7 is close enough to 1:4 -/obj/effect/decal/cleanable/oil +/obj/effect/decal/cleanable/blood/oil name = "motor oil" desc = "It's black and greasy. Looks like Beepsky made another mess." - gender = PLURAL - density = 0 - anchored = 1 - layer = 2 - icon = 'icons/mob/robots.dmi' - icon_state = "floor1" - var/viruses = list() - random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") + basecolor="#030303" - Del() - for(var/datum/disease/D in viruses) - D.cure(0) - ..() +/obj/effect/decal/cleanable/blood/oil/dry() + return -/obj/effect/decal/cleanable/oil/streak - random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5") \ No newline at end of file +/obj/effect/decal/cleanable/blood/oil/streak + random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") + amount = 2 \ No newline at end of file diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm new file mode 100644 index 00000000000..0382e3dbc99 --- /dev/null +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -0,0 +1,161 @@ +// Stolen en masse from N3X15 of /vg/station with much gratitude. + +// The idea is to have 4 bits for coming and 4 for going. +#define TRACKS_COMING_NORTH 1 +#define TRACKS_COMING_SOUTH 2 +#define TRACKS_COMING_EAST 4 +#define TRACKS_COMING_WEST 8 +#define TRACKS_GOING_NORTH 16 +#define TRACKS_GOING_SOUTH 32 +#define TRACKS_GOING_EAST 64 +#define TRACKS_GOING_WEST 128 + +// 5 seconds +#define TRACKS_CRUSTIFY_TIME 50 + +// color-dir-dry +var/global/list/image/fluidtrack_cache=list() + +/datum/fluidtrack + var/direction=0 + var/basecolor="#A10808" + var/wet=0 + var/fresh=1 + var/crusty=0 + var/image/overlay + + New(_direction,_color,_wet) + src.direction=_direction + src.basecolor=_color + src.wet=_wet + +// Footprints, tire trails... +/obj/effect/decal/cleanable/blood/tracks + amount = 0 + random_icon_states = null + var/dirs=0 + icon = 'icons/effects/fluidtracks.dmi' + icon_state = "" + var/coming_state="blood1" + var/going_state="blood2" + var/updatedtracks=0 + + // dir = id in stack + var/list/setdirs=list( + "1"=0, + "2"=0, + "4"=0, + "8"=0, + "16"=0, + "32"=0, + "64"=0, + "128"=0 + ) + + // List of laid tracks and their colors. + var/list/datum/fluidtrack/stack=list() + + /** + * Add tracks to an existing trail. + * + * @param DNA bloodDNA to add to collection. + * @param comingdir Direction tracks come from, or 0. + * @param goingdir Direction tracks are going to (or 0). + * @param bloodcolor Color of the blood when wet. + */ + proc/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor="#A10808") + var/updated=0 + // Shift our goingdir 4 spaces to the left so it's in the GOING bitblock. + var/realgoing=goingdir<<4 + + // Current bit + var/b=0 + + // When tracks will start to dry out + var/t=world.time + TRACKS_CRUSTIFY_TIME + + var/datum/fluidtrack/track + + // Process 4 bits + for(var/bi=0;bi<4;bi++) + b=1<>4 + + if(track.overlay) + track.overlay=null + var/image/I = image(icon, icon_state=state, dir=num2dir(truedir)) + I.color = track.basecolor + + track.fresh=0 + track.overlay=I + stack[stack_idx]=track + overlays += I + updatedtracks=0 // Clear our memory of updated tracks. + +/obj/effect/decal/cleanable/blood/tracks/footprints + name = "wet footprints" + desc = "Whoops..." + coming_state = "human1" + going_state = "human2" + amount = 0 + +/obj/effect/decal/cleanable/blood/tracks/wheels + name = "wet tracks" + desc = "Whoops..." + coming_state = "wheels" + going_state = "" + desc = "They look like tracks left by wheels." + gender = PLURAL + random_icon_states = null + amount = 0 \ No newline at end of file diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index d1227d3aa38..63956f5e89a 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -1,7 +1,8 @@ /obj/effect/decal/cleanable var/list/random_icon_states = list() + var/targeted_by = null // Used so cleanbots can't claim a mess. /obj/effect/decal/cleanable/New() if (random_icon_states && length(src.random_icon_states) > 0) src.icon_state = pick(src.random_icon_states) - ..() \ No newline at end of file + ..() 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 0) for(var/datum/disease/D in viruses) if(prob(virusProb)) diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index c5194392374..5446ba348e6 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -17,7 +17,7 @@ ..() xeno - gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/up,/obj/effect/decal/cleanable/xenoblood/xgibs/down,/obj/effect/decal/cleanable/xenoblood/xgibs,/obj/effect/decal/cleanable/xenoblood/xgibs,/obj/effect/decal/cleanable/xenoblood/xgibs/body,/obj/effect/decal/cleanable/xenoblood/xgibs/limb,/obj/effect/decal/cleanable/xenoblood/xgibs/core) + gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno/up,/obj/effect/decal/cleanable/blood/gibs/xeno/down,/obj/effect/decal/cleanable/blood/gibs/xeno,/obj/effect/decal/cleanable/blood/gibs/xeno,/obj/effect/decal/cleanable/blood/gibs/xeno/body,/obj/effect/decal/cleanable/blood/gibs/xeno/limb,/obj/effect/decal/cleanable/blood/gibs/xeno/core) gibamounts = list(1,1,1,1,1,1,1) New() @@ -27,7 +27,7 @@ robot sparks = 1 - gibtypes = list(/obj/effect/decal/cleanable/robot_debris/up,/obj/effect/decal/cleanable/robot_debris/down,/obj/effect/decal/cleanable/robot_debris,/obj/effect/decal/cleanable/robot_debris,/obj/effect/decal/cleanable/robot_debris,/obj/effect/decal/cleanable/robot_debris/limb) + gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot/limb) gibamounts = list(1,1,1,1,1,1) New() diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index da4f51eef0a..5ba97f90053 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -7,6 +7,19 @@ else return dy + (0.5*dx) +proc/trange(var/Dist=0,var/turf/Center=null)//alternative to range (ONLY processes turfs and thus less intensive) + if(Center==null) return + + //var/x1=((Center.x-Dist)<1 ? 1 : Center.x-Dist) + //var/y1=((Center.y-Dist)<1 ? 1 : Center.y-Dist) + //var/x2=((Center.x+Dist)>world.maxx ? world.maxx : Center.x+Dist) + //var/y2=((Center.y+Dist)>world.maxy ? world.maxy : Center.y+Dist) + + var/turf/x1y1 = locate(((Center.x-Dist)<1 ? 1 : Center.x-Dist),((Center.y-Dist)<1 ? 1 : Center.y-Dist),Center.z) + var/turf/x2y2 = locate(((Center.x+Dist)>world.maxx ? world.maxx : Center.x+Dist),((Center.y+Dist)>world.maxy ? world.maxy : Center.y+Dist),Center.z) + return block(x1y1,x2y2) + + proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1) src = null //so we don't abort once src is deleted spawn(0) @@ -48,7 +61,7 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa var/y0 = epicenter.y var/z0 = epicenter.z - for(var/turf/T in range(epicenter, max(devastation_range, heavy_impact_range, light_impact_range))) + for(var/turf/T in trange(max(devastation_range, heavy_impact_range, light_impact_range), epicenter)) var/dist = cheap_pythag(T.x - x0,T.y - y0) if(dist < devastation_range) dist = 1 @@ -85,4 +98,4 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa proc/secondaryexplosion(turf/epicenter, range) for(var/turf/tile in range(range, epicenter)) - tile.ex_act(2) + tile.ex_act(2) \ No newline at end of file diff --git a/code/game/objects/explosion_recursive.dm b/code/game/objects/explosion_recursive.dm index cfa1d7e0e53..9dc04ff6301 100644 --- a/code/game/objects/explosion_recursive.dm +++ b/code/game/objects/explosion_recursive.dm @@ -6,31 +6,12 @@ /obj var/explosion_resistance -/datum/explosion_turf - var/turf/turf //The turf which will get ex_act called on it - var/max_power //The largest amount of power the turf sustained - New() - ..() - max_power = 0 - proc/save_power_if_larger(power) - if(power > max_power) - max_power = power - return 1 - return 0 +var/list/explosion_turfs = list() -var/list/datum/explosion_turf/explosion_turfs = list() var/explosion_in_progress = 0 -proc/get_explosion_turf(var/turf/T) - for( var/datum/explosion_turf/ET in explosion_turfs ) - if( T == ET.turf ) - return ET - var/datum/explosion_turf/ET = new() - ET.turf = T - explosion_turfs += ET - return ET proc/explosion_rec(turf/epicenter, power) @@ -52,9 +33,8 @@ proc/explosion_rec(turf/epicenter, power) explosion_in_progress = 1 explosion_turfs = list() - var/datum/explosion_turf/ETE = get_explosion_turf() - ETE.turf = epicenter - ETE.max_power = power + + explosion_turfs[epicenter] = power //This steap handles the gathering of turfs which will be ex_act() -ed in the next step. It also ensures each turf gets the maximum possible amount of power dealt to it. for(var/direction in cardinal) @@ -62,22 +42,21 @@ proc/explosion_rec(turf/epicenter, power) T.explosion_spread(power - epicenter.explosion_resistance, direction) //This step applies the ex_act effects for the explosion, as planned in the previous step. - for( var/datum/explosion_turf/ET in explosion_turfs ) - if(ET.max_power <= 0) continue - if(!ET.turf) continue + for(var/turf/T in explosion_turfs) + if(explosion_turfs[T] <= 0) continue + if(!T) continue //Wow severity looks confusing to calculate... Fret not, I didn't leave you with any additional instructions or help. (just kidding, see the line under the calculation) - var/severity = 4 - round(max(min( 3, ((ET.max_power - ET.turf.explosion_resistance) / (max(3,(power/3)))) ) ,1), 1) - //sanity effective power on tile divided by either 3 or one third the total explosion power + var/severity = 4 - round(max(min( 3, ((explosion_turfs[T] - T.explosion_resistance) / (max(3,(power/3)))) ) ,1), 1) //sanity effective power on tile divided by either 3 or one third the total explosion power // One third because there are three power levels and I // want each one to take up a third of the crater - var/x = ET.turf.x - var/y = ET.turf.y - var/z = ET.turf.z - ET.turf.ex_act(severity) - if(!ET.turf) - ET.turf = locate(x,y,z) - for( var/atom/A in ET.turf ) + var/x = T.x + var/y = T.y + var/z = T.z + T.ex_act(severity) + if(!T) + T = locate(x,y,z) + for(var/atom/A in T) A.ex_act(severity) explosion_in_progress = 0 @@ -123,10 +102,9 @@ proc/explosion_rec(turf/epicenter, power) new/obj/effect/debugging/marker(src) */ - var/datum/explosion_turf/ET = get_explosion_turf(src) - if(ET.max_power >= power) + if(explosion_turfs[src] >= power) return //The turf already sustained and spread a power greated than what we are dealing with. No point spreading again. - ET.max_power = power + explosion_turfs[src] = power var/spread_power = power - src.explosion_resistance //This is the amount of power that will be spread to the tile in the direction of the blast var/side_spread_power = power - 2 * src.explosion_resistance //This is the amount of power that will be spread to the side tiles diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index dd445337b76..24e5479251c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1,7 +1,7 @@ /obj/item name = "item" icon = 'icons/obj/items.dmi' - var/icon/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite + var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite var/abstract = 0 var/item_state = null var/r_speed = 1.0 @@ -38,6 +38,7 @@ var/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) var/list/allowed = null //suit storage stuff. var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. + var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc. /obj/item/device icon = 'icons/obj/device.dmi' @@ -315,6 +316,8 @@ return 0 if( (slot_flags & SLOT_TWOEARS) && H.r_ear ) return 0 + if( w_class < 2 ) + return 1 return 1 if(slot_r_ear) if(H.r_ear) @@ -323,6 +326,8 @@ return 0 if( (slot_flags & SLOT_TWOEARS) && H.l_ear ) return 0 + if( w_class < 2 ) + return 1 return 1 if(slot_w_uniform) if(H.w_uniform) @@ -348,7 +353,7 @@ H << "\red You need a jumpsuit before you can attach this [name]." return 0 if(slot_flags & SLOT_DENYPOCKET) - return + return 0 if( w_class <= 2 || (slot_flags & SLOT_POCKET) ) return 1 if(slot_r_store) @@ -522,29 +527,28 @@ "\red You stab yourself in the eyes with [src]!" \ ) if(istype(M, /mob/living/carbon/human)) + var/datum/organ/internal/eyes/eyes = H.internal_organs["eyes"] + eyes.damage += rand(3,4) + if(eyes.damage >= 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() @@ -569,6 +573,7 @@ //apply the blood-splatter overlay if it isn't already in there if(!blood_DNA.len) + blood_overlay.color = blood_color overlays += blood_overlay //if this blood isn't already in the list, add it @@ -589,4 +594,17 @@ //not sure if this is worth it. It attaches the blood_overlay to every item of the same type if they don't have one already made. for(var/obj/item/A in world) if(A.type == type && !A.blood_overlay) - A.blood_overlay = I \ No newline at end of file + A.blood_overlay = image(I) + +/obj/item/proc/showoff(mob/user) + for (var/mob/M in view(user)) + M.show_message("[user] holds up [src]. Take a closer look.",1) + +/mob/living/carbon/verb/showoff() + set name = "Show Held Item" + set category = "Object" + + var/obj/item/I = get_active_hand() + if(I && !I.abstract) + I.showoff(src) + diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index 4e7ae4d6488..5c5b1b6fd81 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -1,6 +1,6 @@ /obj/item/blueprints name = "station blueprints" - desc = "Blueprints of the station. There's stamp \"Classified\" and several coffee stains on it." + desc = "Blueprints of the station. There is a \"Classified\" stamp and several coffee stains on it." icon = 'icons/obj/items.dmi' icon_state = "blueprints" attack_verb = list("attacked", "bapped", "hit") @@ -21,7 +21,7 @@ /obj/item/blueprints/attack_self(mob/M as mob) if (!istype(M,/mob/living/carbon/human)) - M << "This is stack of useless pieces of harsh paper." //monkeys cannot into projecting + M << "This stack of blue paper means nothing to you." //monkeys cannot into projecting return interact() return @@ -53,18 +53,18 @@ switch (get_area_type()) if (AREA_SPACE) text += {" -

    According this blueprints you are in open space now.

    +

    According the blueprints, you are now in outer space. Hold your breath.

    Mark this place as new area.

    "} if (AREA_STATION) text += {" -

    According this blueprints you are in [A.name] now.

    +

    According the blueprints, you are now in \"[A.name]\".

    You may move an amendment to the drawing.

    "} if (AREA_SPECIAL) text += {" -

    This place isn't noted on these blueprints.

    +

    This place isn't noted on the blueprint.

    "} else return @@ -105,20 +105,20 @@ move an amendment to the drawing.

    if(!istype(res,/list)) switch(res) if(ROOM_ERR_SPACE) - usr << "\red New area must be complete airtight!" + usr << "\red The new area must be completely airtight!" return if(ROOM_ERR_TOOLARGE) - usr << "\red New area too large!" + usr << "\red The new area too large!" return else usr << "\red Error! Please notify administration!" return var/list/turf/turfs = res - var/str = trim(stripped_input(usr,"New area title","Blueprints editing", "", MAX_NAME_LEN)) + var/str = trim(stripped_input(usr,"New area name:","Blueprint Editing", "", MAX_NAME_LEN)) if(!str || !length(str)) //cancel return if(length(str) > 50) - usr << "\red Text too long." + usr << "\red Name too long." return var/area/A = new A.name = str @@ -153,8 +153,8 @@ move an amendment to the drawing.

    /obj/item/blueprints/proc/edit_area() var/area/A = get_area() //world << "DEBUG: edit_area" - var/prevname = A.name - var/str = trim(stripped_input(usr,"New area title","Blueprints editing", prevname, MAX_NAME_LEN)) + var/prevname = "[A.name]" + var/str = trim(stripped_input(usr,"New area name:","Blueprint Editing", prevname, MAX_NAME_LEN)) if(!str || !length(str) || str==prevname) //cancel return if(length(str) > 50) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index ad757325b95..ee73d537d8e 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -80,6 +80,7 @@ if(instant || do_after(user, 50)) new /obj/effect/decal/cleanable/crayon(target,colour,shadeColour,drawtype) user << "You finish drawing." + target.add_fingerprint(user) // Adds their fingerprints to the floor the crayon is drawn on. if(uses) uses-- if(!uses) @@ -97,4 +98,4 @@ user << "\red You ate your crayon!" del(src) else - ..() \ No newline at end of file + ..() diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 9123617f2a7..09300be1210 100755 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -26,7 +26,7 @@ var/global/list/obj/item/device/pda/PDAs = list() var/f_lum = 2 //Luminosity for the flashlight function var/silent = 0 //To beep or not to beep, that is the question var/toff = 0 //If 1, messenger disabled - var/tnote = null //Current Texts + var/tnote[0] //Current Texts var/last_text //No text spamming var/last_honk //Also no honk spamming that's bad too var/ttone = "beep" //The ringtone! @@ -38,7 +38,10 @@ var/global/list/obj/item/device/pda/PDAs = list() var/cart = "" //A place to stick cartridge menu information var/detonate = 1 // Can the PDA be blown up? var/hidden = 0 // Is the PDA hidden from the PDA list? - + var/active_conversation = null // New variable that allows us to only view a single conversation. + var/list/conversations = list() // For keeping up with who we have PDA messsages from. + var/newmessage = 0 //To remove hackish overlay check + var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both. var/ownjob = null //related to above @@ -243,7 +246,13 @@ var/global/list/obj/item/device/pda/PDAs = list() if(usr.stat == 2) usr << "You can't do that because you are dead!" return - var/HTML = "AI PDA Message Log[tnote]" + var/HTML = "AI PDA Message Log" + for(var/index in tnote) + if(index["sent"]) + HTML += addtext("→ To ", index["owner"],":
    ", index["message"], "
    ") + else + HTML += addtext("← From ", index["owner"],":
    ", index["message"], "
    ") + HTML +="" usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") @@ -310,6 +319,139 @@ var/global/list/obj/item/device/pda/PDAs = list() return attack_self(M) return +/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) + var/title = "Personal Data Assistant" + + var/data[0] // This is the data that will be sent to the PDA + + + data["owner"] = owner // Who is your daddy... + data["ownjob"] = ownjob // ...and what does he do? + + data["mode"] = mode // The current view + data["scanmode"] = scanmode // Scanners + data["fon"] = fon // Flashlight on? + data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted? + data["note"] = note // current pda notes + data["silent"] = silent // does the pda make noise when it receives a message? + data["toff"] = toff // is the messenger function turned off? + data["active_conversation"] = active_conversation // Which conversation are we following right now? + + + data["idInserted"] = (id ? 1 : 0) + data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") + + data["cart_loaded"] = cartridge ? 1:0 + if(cartridge) + var/cartdata[0] + + data["records"] = cartridge.create_NanoUI_values() + + cartdata["name"] = cartridge.name + cartdata["access"] = list(\ + "access_security" = cartridge.access_security,\ + "access_engine" = cartridge.access_engine,\ + "access_atmos" = cartridge.access_atmos,\ + "access_medical" = cartridge.access_medical,\ + "access_clown" = cartridge.access_clown,\ + "access_mime" = cartridge.access_mime,\ + "access_janitor" = cartridge.access_janitor,\ + "access_quartermaster" = cartridge.access_quartermaster,\ + "access_hydroponics" = cartridge.access_hydroponics,\ + "access_reagent_scanner" = cartridge.access_reagent_scanner,\ + "access_remote_door" = cartridge.access_remote_door,\ + "access_status_display" = cartridge.access_status_display\ + ) + if(isnull(cartridge.radio)) + cartdata["radio"] = 0 + else + if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky)) + cartdata["radio"] = 1 + if(istype(cartridge.radio, /obj/item/radio/integrated/signal)) + cartdata["radio"] = 2 + if(istype(cartridge.radio, /obj/item/radio/integrated/mule)) + cartdata["radio"] = 3 + + cartdata["type"] = cartridge.type + cartdata["charges"] = cartridge.charges ? cartridge.charges : 0 + data["cartridge"] = cartdata + + data["stationTime"] = worldtime2text() + data["newMessage"] = newmessage + + if(mode==2) + var/convopdas[0] + var/pdas[0] + var/count = 0 + for (var/obj/item/device/pda/P in sortAtom(PDAs)) + if (!P.owner||P.toff||P == src||P.hidden) continue + if(conversations.Find("\ref[P]")) + convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) + else + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + count++ + + data["convopdas"] = convopdas + data["pdas"] = pdas + data["pda_count"] = count + + if(mode==21) + data["messagescount"] = tnote.len + data["messages"] = tnote + else + data["messagescount"] = null + data["messages"] = null + + if(active_conversation) + for(var/c in tnote) + if(c["target"] == active_conversation) + data["convo_name"] = sanitize(c["owner"]) + data["convo_job"] = sanitize(c["job"]) + break + if(mode==41) + data["manifest"] = data_core.get_manifest_json() + + + if(mode==3) + var/turf/T = get_turf_or_move(user.loc) + if(!isnull(T) || mode!=3) + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles() + + if (total_moles) + var/o2_level = environment.oxygen/total_moles + var/n2_level = environment.nitrogen/total_moles + var/co2_level = environment.carbon_dioxide/total_moles + var/plasma_level = environment.toxins/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) + data["aircontents"] = list(\ + "pressure" = "[round(pressure,0.1)]",\ + "nitrogen" = "[round(n2_level*100,0.1)]",\ + "oxygen" = "[round(o2_level*100,0.1)]",\ + "carbon_dioxide" = "[round(co2_level*100,0.1)]",\ + "plasma" = "[round(plasma_level*100,0.01)]",\ + "other" = "[round(unknown_level, 0.01)]",\ + "temp" = "[round(environment.temperature-T0C,0.1)]",\ + "reading" = 1\ + ) + if(isnull(data["aircontents"])) + data["aircontents"] = list("reading" = 0) + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "pda.tmpl", title, 630, 600) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + //NOTE: graphic resources are loaded on client login /obj/item/device/pda/attack_self(mob/user as mob) @@ -318,453 +460,292 @@ var/global/list/obj/item/device/pda/PDAs = list() if(active_uplink_check(user)) return - var/dat = "Personal Data Assistant" - - dat += " Close" - - if ((!isnull(cartridge)) && (mode == 0)) - dat += " | Eject [cartridge]" - if (mode) - dat += " | Return" - dat += " | Refresh" - - dat += "
    " - - if (!owner) - dat += "Warning: No owner information entered. Please swipe card.

    " - dat += " Retry" - else - switch (mode) - if (0) - dat += "

    PERSONAL DATA ASSISTANT v.1.2

    " - dat += "Owner: [owner], [ownjob]
    " - dat += text("ID: [id ? "[id.registered_name], [id.assignment]" : "----------"]") - dat += text("
    [id ? "Update PDA Info" : ""]
    ") - - dat += "Station Time: [worldtime2text()]"//:[world.time / 100 % 6][world.time / 100 % 10]" - - dat += "

    " - - dat += "

    General Functions

    " - dat += "" - if (cartridge.access_engine) - dat += "

    Engineering Functions

    " - dat += "" - if (cartridge.access_medical) - dat += "

    Medical Functions

    " - dat += "" - if (cartridge.access_security) - dat += "

    Security Functions

    " - dat += "" - else dat += "" - if(cartridge.access_quartermaster) - dat += "

    Quartermaster Functions:

    " - dat += "" - dat += "" - - dat += "

    Utilities

    " - dat += "" - - if (1) - dat += "

    Notekeeper V2.1

    " - dat += " Edit
    " - dat += note - - if (2) - dat += "

    SpaceMessenger V3.9.4

    " - dat += " Ringer: [silent == 1 ? "Off" : "On"] | " - dat += " Send / Receive: [toff == 1 ? "Off" : "On"] | " - dat += " Set Ringtone | " - dat += " Messages
    " - - if (istype(cartridge, /obj/item/weapon/cartridge/syndicate)) - dat += "[cartridge:shock_charges] detonation charges left.
    " - if (istype(cartridge, /obj/item/weapon/cartridge/clown)) - dat += "[cartridge:honk_charges] viral files left.
    " - if (istype(cartridge, /obj/item/weapon/cartridge/mime)) - dat += "[cartridge:mime_charges] viral files left.
    " - - dat += "

    Detected PDAs

    " - - dat += "
      " - - var/count = 0 - - if (!toff) - for (var/obj/item/device/pda/P in sortAtom(PDAs)) - if (!P.owner||P.toff||P == src||P.hidden) continue - dat += "
    • [P]" - if (istype(cartridge, /obj/item/weapon/cartridge/syndicate) && P.detonate) - dat += " (*Detonate*)" - if (istype(cartridge, /obj/item/weapon/cartridge/clown)) - dat += " (*Send Virus*)" - if (istype(cartridge, /obj/item/weapon/cartridge/mime)) - dat += " (*Send Virus*)" - dat += "
    • " - count++ - dat += "
    " - if (count == 0) - dat += "None detected.
    " - - if(21) - dat += "

    SpaceMessenger V3.9.4

    " - dat += " Clear Messages" - - dat += "

    Messages

    " - - dat += tnote - dat += "
    " - - if (3) - dat += "

    Atmospheric Readings

    " - - var/turf/T = get_turf_or_move(user.loc) - if (isnull(T)) - dat += "Unable to obtain a reading.
    " - else - var/datum/gas_mixture/environment = T.return_air() - - var/pressure = environment.return_pressure() - var/total_moles = environment.total_moles() - - dat += "Air Pressure: [round(pressure,0.1)] kPa
    " - - if (total_moles) - var/o2_level = environment.oxygen/total_moles - var/n2_level = environment.nitrogen/total_moles - var/co2_level = environment.carbon_dioxide/total_moles - var/plasma_level = environment.toxins/total_moles - var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) - dat += "Nitrogen: [round(n2_level*100)]%
    " - dat += "Oxygen: [round(o2_level*100)]%
    " - dat += "Carbon Dioxide: [round(co2_level*100)]%
    " - dat += "Plasma: [round(plasma_level*100)]%
    " - if(unknown_level > 0.01) - dat += "OTHER: [round(unknown_level)]%
    " - dat += "Temperature: [round(environment.temperature-T0C)]°C
    " - dat += "
    " - - if (5) - dat += "

    Nanotrasen Relay Chat

    " - - dat += "

    Detected Channels

    :
  • " - for(var/datum/chatroom/C in chatrooms) - dat += "#[html_encode(lowertext(C.name))]" - if(C.password != "") - dat += " " - dat += "
  • " - - if (41) //crew manifest - dat += "

    Crew Manifest

    " - dat += "Entries cannot be modified from this terminal.

    " - if(data_core) - dat += data_core.get_manifest(1) // make it monochrome - dat += "
    " - - else//Else it links to the cart menu proc. Although, it really uses menu hub 4--menu 4 doesn't really exist as it simply redirects to hub. - dat += cart - - dat += "" - user << browse(dat, "window=pda;size=400x444;border=1;can_resize=1;can_close=0;can_minimize=0") - onclose(user, "pda", src) + ui_interact(user) //NanoUI requires this proc + return /obj/item/device/pda/Topic(href, href_list) + if(href_list["cartmenu"] && !isnull(cartridge)) + cartridge.Topic(href, href_list) + return 1 + if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) + cartridge.radio.Topic(href, href_list) + return 1 + + ..() + var/mob/user = usr + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") var/mob/living/U = usr //Looking for master was kind of pointless since PDAs don't appear to have one. //if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) ) if (usr.stat == DEAD) return 0 - if(can_use()) //Why reinvent the wheel? There's a proc that does exactly that. - - add_fingerprint(U) - U.set_machine(src) - - switch(href_list["choice"]) + if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. + U.unset_machine() + ui.close() + return 0 + + add_fingerprint(U) + U.set_machine(src) + switch(href_list["choice"]) + //BASIC FUNCTIONS=================================== - if("Close")//Self explanatory - U.unset_machine() - U << browse(null, "window=pda") - return - if("Refresh")//Refresh, goes to the end of the proc. - if("Return")//Return - if(mode<=9) + if("Close")//Self explanatory + U.unset_machine() + ui.close() + return 0 + if("Refresh")//Refresh, goes to the end of the proc. + if("Return")//Return + if(mode<=9) + mode = 0 + else + mode = round(mode/10) + if(mode==2) + active_conversation = null + if(mode==4)//Fix for cartridges. Redirects to hub. mode = 0 - else - mode = round(mode/10) - if(mode==4)//Fix for cartridges. Redirects to hub. - mode = 0 - else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. - cartridge.mode = mode - cartridge.unlock() - if ("Authenticate")//Checks for ID - id_check(U, 1) - if("UpdateInfo") - ownjob = id.assignment - name = "PDA-[owner] ([ownjob])" - if("Eject")//Ejects the cart, only done from hub. - if (!isnull(cartridge)) - var/turf/T = loc - if(ismob(T)) - T = T.loc - cartridge.loc = T - scanmode = 0 - if (cartridge.radio) - cartridge.radio.hostpda = null - cartridge = null + else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. + cartridge.mode = mode + if ("Authenticate")//Checks for ID + id_check(U, 1) + if("UpdateInfo") + ownjob = id.assignment + name = "PDA-[owner] ([ownjob])" + if("Eject")//Ejects the cart, only done from hub. + if (!isnull(cartridge)) + var/turf/T = loc + if(ismob(T)) + T = T.loc + cartridge.loc = T + mode = 0 + scanmode = 0 + if (cartridge.radio) + cartridge.radio.hostpda = null + cartridge = null //MENU FUNCTIONS=================================== - if("0")//Hub - mode = 0 - if("1")//Notes - mode = 1 - if("2")//Messenger - mode = 2 - if("21")//Read messeges - mode = 21 - if("3")//Atmos scan - mode = 3 - if("4")//Redirects to hub - mode = 0 - if("chatroom") // chatroom hub - mode = 5 - if("41") //Manifest - mode = 41 + if("0")//Hub + mode = 0 + if("1")//Notes + mode = 1 + if("2")//Messenger + mode = 2 + if("21")//Read messeges + mode = 21 + if("3")//Atmos scan + mode = 3 + if("4")//Redirects to hub + mode = 0 + if("chatroom") // chatroom hub + mode = 5 + if("41") //Manifest + mode = 41 //MAIN FUNCTIONS=================================== - if("Light") - if(fon) - fon = 0 - if(src in U.contents) U.SetLuminosity(U.luminosity - f_lum) - else SetLuminosity(0) - else - fon = 1 - if(src in U.contents) U.SetLuminosity(U.luminosity + f_lum) - else SetLuminosity(f_lum) - if("Medical Scan") - if(scanmode == 1) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_medical)) - scanmode = 1 - if("Reagent Scan") - if(scanmode == 3) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner)) - scanmode = 3 - if("Halogen Counter") - if(scanmode == 4) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_engine)) - scanmode = 4 - if("Honk") - if ( !(last_honk && world.time < last_honk + 20) ) - playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) - last_honk = world.time - if("Gas Scan") - if(scanmode == 5) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_atmos)) - scanmode = 5 + if("Light") + if(fon) + fon = 0 + if(src in U.contents) U.SetLuminosity(U.luminosity - f_lum) + else SetLuminosity(0) + else + fon = 1 + if(src in U.contents) U.SetLuminosity(U.luminosity + f_lum) + else SetLuminosity(f_lum) + if("Medical Scan") + if(scanmode == 1) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_medical)) + scanmode = 1 + if("Reagent Scan") + if(scanmode == 3) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner)) + scanmode = 3 + if("Halogen Counter") + if(scanmode == 4) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_engine)) + scanmode = 4 + if("Honk") + if ( !(last_honk && world.time < last_honk + 20) ) + playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) + last_honk = world.time + if("Gas Scan") + if(scanmode == 5) + scanmode = 0 + else if((!isnull(cartridge)) && (cartridge.access_atmos)) + scanmode = 5 //MESSENGER/NOTE FUNCTIONS=================================== - if ("Edit") - var/n = input(U, "Please enter message", name, notehtml) as message - if (in_range(src, U) && loc == U) - n = copytext(adminscrub(n), 1, MAX_MESSAGE_LEN) - if (mode == 1) - note = replacetext(n, "\n", "
    ") - notehtml = n - else - U << browse(null, "window=pda") - return - if("Toggle Messenger") - toff = !toff - if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status - silent = !silent - if("Clear")//Clears messages - tnote = null - if("Ringtone") - var/t = input(U, "Please enter new ringtone", name, ttone) as text - if (in_range(src, U) && loc == U) - if (t) - if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) - U << "The PDA softly beeps." - U << browse(null, "window=pda") - else - t = copytext(sanitize(t), 1, 20) - ttone = t - else - U << browse(null, "window=pda") - return - if("Message") - var/obj/item/device/pda/P = locate(href_list["target"]) - src.create_message(U, P) + if ("Edit") + var/n = input(U, "Please enter message", name, notehtml) as message + if (in_range(src, U) && loc == U) + n = copytext(adminscrub(n), 1, MAX_MESSAGE_LEN) + if (mode == 1) + note = html_decode(n) + notehtml = note + note = replacetext(note, "\n", "
    ") + else + ui.close() + if("Toggle Messenger") + toff = !toff + if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status + silent = !silent + if("Clear")//Clears messages + if(href_list["option"] == "All") + tnote.Cut() + conversations.Cut() + if(href_list["option"] == "Convo") + var/new_tnote[0] + for(var/i in tnote) + if(i["target"] != active_conversation) + new_tnote[++new_tnote.len] = i + tnote = new_tnote + conversations.Remove(active_conversation) - if("Send Honk")//Honk virus - if(istype(cartridge, /obj/item/weapon/cartridge/clown))//Cartridge checks are kind of unnecessary since everything is done through switch. - var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess. - if(!isnull(P)) - if (!P.toff && cartridge:honk_charges > 0) - cartridge:honk_charges-- - U.show_message("\blue Virus sent!", 1) - P.honkamt = (rand(15,20)) + active_conversation = null + if(mode==21) + mode=2 + + if("Ringtone") + var/t = input(U, "Please enter new ringtone", name, ttone) as text + if (in_range(src, U) && loc == U) + if (t) + if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) + U << "The PDA softly beeps." + ui.close() else - U << "PDA not found." + t = copytext(sanitize(t), 1, 20) + ttone = t + else + ui.close() + return 0 + if("Message") + + var/obj/item/device/pda/P = locate(href_list["target"]) + src.create_message(U, P) + if(mode == 2) + if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. + active_conversation = href_list["target"] + mode = 21 + + if("Select Conversation") + var/P = href_list["convo"] + for(var/n in conversations) + if(P == n) + active_conversation=P + mode=21 + if("Send Honk")//Honk virus + if(istype(cartridge, /obj/item/weapon/cartridge/clown))//Cartridge checks are kind of unnecessary since everything is done through switch. + var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess. + if(!isnull(P)) + if (!P.toff && cartridge.charges > 0) + cartridge.charges-- + U.show_message("\blue Virus sent!", 1) + P.honkamt = (rand(15,20)) else - U << browse(null, "window=pda") - return - if("Send Silence")//Silent virus - if(istype(cartridge, /obj/item/weapon/cartridge/mime)) - var/obj/item/device/pda/P = locate(href_list["target"]) - if(!isnull(P)) - if (!P.toff && cartridge:mime_charges > 0) - cartridge:mime_charges-- - U.show_message("\blue Virus sent!", 1) - P.silent = 1 - P.ttone = "silence" - else - U << "PDA not found." + U << "PDA not found." + else + ui.close() + return 0 + if("Send Silence")//Silent virus + if(istype(cartridge, /obj/item/weapon/cartridge/mime)) + var/obj/item/device/pda/P = locate(href_list["target"]) + if(!isnull(P)) + if (!P.toff && cartridge.charges > 0) + cartridge.charges-- + U.show_message("\blue Virus sent!", 1) + P.silent = 1 + P.ttone = "silence" else - U << browse(null, "window=pda") - return + U << "PDA not found." + else + ui.close() + return 0 //SYNDICATE FUNCTIONS=================================== - if("Toggle Door") - if(cartridge && cartridge.access_remote_door) - for(var/obj/machinery/door/poddoor/M in world) - if(M.id == cartridge.remote_door_id) - if(M.density) - M.open() - else - M.close() + if("Toggle Door") + if(cartridge && cartridge.access_remote_door) + for(var/obj/machinery/door/poddoor/M in world) + if(M.id == cartridge.remote_door_id) + if(M.density) + M.open() + else + M.close() - if("Detonate")//Detonate PDA - if(istype(cartridge, /obj/item/weapon/cartridge/syndicate)) - var/obj/item/device/pda/P = locate(href_list["target"]) - if(!isnull(P)) - if (!P.toff && cartridge:shock_charges > 0) - cartridge:shock_charges-- + if("Detonate")//Detonate PDA + if(istype(cartridge, /obj/item/weapon/cartridge/syndicate)) + var/obj/item/device/pda/P = locate(href_list["target"]) + if(!isnull(P)) + if (!P.toff && cartridge.charges > 0) + cartridge.charges-- - var/difficulty = 0 + var/difficulty = 0 - if(P.cartridge) - difficulty += P.cartridge.access_medical - difficulty += P.cartridge.access_security - difficulty += P.cartridge.access_engine - difficulty += P.cartridge.access_clown - difficulty += P.cartridge.access_janitor - else - difficulty += 2 + if(P.cartridge) + difficulty += P.cartridge.access_medical + difficulty += P.cartridge.access_security + difficulty += P.cartridge.access_engine + difficulty += P.cartridge.access_clown + difficulty += P.cartridge.access_janitor + else + difficulty += 2 - if(prob(difficulty * 12) || (P.hidden_uplink)) - U.show_message("\red An error flashes on your [src].", 1) - else if (prob(difficulty * 3)) - U.show_message("\red Energy feeds back into your [src]!", 1) - U << browse(null, "window=pda") - explode() - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1) - else - U.show_message("\blue Success!", 1) - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeded") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeded", 1) - P.explode() - else - U << "PDA not found." + if(prob(difficulty * 12) || (P.hidden_uplink)) + U.show_message("\red An error flashes on your [src].", 1) + else if (prob(difficulty * 3)) + U.show_message("\red Energy feeds back into your [src]!", 1) + ui.close() + explode() + log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") + message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1) + else + U.show_message("\blue Success!", 1) + log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeded") + message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeded", 1) + P.explode() else - U.unset_machine() - U << browse(null, "window=pda") - return + U << "PDA not found." + else + U.unset_machine() + ui.close() + return 0 //pAI FUNCTIONS=================================== - if("pai") - switch(href_list["option"]) - if("1") // Configure pAI device - pai.attack_self(U) - if("2") // Eject pAI device - var/turf/T = get_turf_or_move(src.loc) - if(T) - pai.loc = T + if("pai") + switch(href_list["option"]) + if("1") // Configure pAI device + pai.attack_self(U) + if("2") // Eject pAI device + var/turf/T = get_turf_or_move(src.loc) + if(T) + pai.loc = T + pai = null -//LINK FUNCTIONS=================================== - - else//Cartridge menu linking - mode = text2num(href_list["choice"]) + else + mode = text2num(href_list["choice"]) + if(cartridge) cartridge.mode = mode - cartridge.unlock() - else//If not in range or not using the pda. - U.unset_machine() - U << browse(null, "window=pda") - return //EXTRA FUNCTIONS=================================== if (mode == 2||mode == 21)//To clear message overlays. overlays.Cut() + newmessage = 0 if ((honkamt > 0) && (prob(60)))//For clown virus. honkamt-- playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) - if(U.machine == src && href_list["skiprefresh"]!="1")//Final safety. - attack_self(U)//It auto-closes the menu prior if the user is not in range and so on. - else - U.unset_machine() - U << browse(null, "window=pda") - return + return 1 // return 1 tells it to refresh the UI in NanoUI /obj/item/device/pda/proc/remove_id() if (id) @@ -793,7 +774,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(!can_use()) return - + last_text = world.time // check if telecomms I/O route 1459 is stable //var/telecomms_intact = telecomms_process(P.owner, owner, t) @@ -823,19 +804,24 @@ var/global/list/obj/item/device/pda/PDAs = list() U << "ERROR: Cannot reach recepient." return useMS.send_pda_message("[P.owner]","[owner]","[t]") + tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"))) + P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) + if(!conversations.Find("\ref[P]")) + conversations.Add("\ref[P]") + if(!P.conversations.Find("\ref[src]")) + P.conversations.Add("\ref[src]") - tnote += "→ To [P.owner]:
    [t]
    " - P.tnote += "← From
    [owner] ([ownjob]):
    [t]
    " if (prob(15)) //Give the AI a chance of intercepting the message var/who = src.owner if(prob(50)) - who = P:owner + who = P.owner for(var/mob/living/silicon/ai/ai in mob_list) // Allows other AIs to intercept the message but the AI won't intercept their own message. if(ai.aiPDA != P && ai.aiPDA != src) ai.show_message("Intercepted message from [who]: [t]") + if (!P.silent) playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1) for (var/mob/O in hearers(3, P.loc)) @@ -848,12 +834,17 @@ var/global/list/obj/item/device/pda/PDAs = list() else L = get(P, /mob/living/silicon) + if(L) L << "\icon[P] Message from [src.owner] ([ownjob]), \"[t]\" (Reply)" + nanomanager.update_user_uis(L, P) // Update the recieving user's PDA UI so that they can see the new message + + nanomanager.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message log_pda("[usr] (PDA: [src.name]) sent \"[t]\" to [P.name]") P.overlays.Cut() P.overlays += image('icons/obj/pda.dmi', "pda-r") + P.newmessage = 1 else U << "ERROR: Messaging server is not responding." @@ -927,8 +918,9 @@ var/global/list/obj/item/device/pda/PDAs = list() user.drop_item() cartridge.loc = src user << "You insert [cartridge] into [src]." + nanomanager.update_uis(src) // update all UIs attached to src if(cartridge.radio) - cartridge.radio.hostpda = src + cartridge.radio.hostpda = src else if(istype(C, /obj/item/weapon/card/id)) var/obj/item/weapon/card/id/idcard = C @@ -943,10 +935,9 @@ var/global/list/obj/item/device/pda/PDAs = list() else //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) - if( can_use(user) )//If they can still act. - id_check(user, 2) - user << "You put the ID into \the [src]'s slot." - updateSelfDialog()//Update self dialog on success. + id_check(user, 2) + user << "You put the ID into \the [src]'s slot." + updateSelfDialog()//Update self dialog on success. return //Return in case of failed check or when successful. updateSelfDialog()//For the non-input related code. else if(istype(C, /obj/item/device/paicard) && !src.pai) @@ -954,7 +945,7 @@ var/global/list/obj/item/device/pda/PDAs = list() C.loc = src pai = C user << "You slot \the [C] into [src]." - updateUsrDialog() + nanomanager.update_uis(src) // update all UIs attached to src else if(istype(C, /obj/item/weapon/pen)) var/obj/item/weapon/pen/O = locate() in src if(O) @@ -1132,8 +1123,8 @@ var/global/list/obj/item/device/pda/PDAs = list() return if ((istype(M, /mob/living/carbon/human) && (M.real_name != src.owner) && (istype(src.cartridge, /obj/item/weapon/cartridge/clown)))) - if (src.cartridge:honk_charges < 5) - src.cartridge:honk_charges++ + if (src.cartridge.charges < 5) + src.cartridge.charges++ M.stop_pulling() M << "\blue You slipped on the PDA!" diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm index f0e3ee98f17..3efab41307a 100644 --- a/code/game/objects/items/devices/PDA/cart.dm +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -21,6 +21,7 @@ var/access_status_display = 0 var/access_quartermaster = 0 var/access_hydroponics = 0 + var/charges = 0 var/mode = null var/menu var/datum/data/record/active1 = null //General @@ -32,575 +33,486 @@ var/message2 var/list/stored_data = list() - engineering - name = "Power-ON Cartridge" - icon_state = "cart-e" - access_engine = 1 +/obj/item/weapon/cartridge/engineering + name = "Power-ON Cartridge" + icon_state = "cart-e" + access_engine = 1 - atmos - name = "BreatheDeep Cartridge" - icon_state = "cart-a" - access_atmos = 1 +/obj/item/weapon/cartridge/atmos + name = "BreatheDeep Cartridge" + icon_state = "cart-a" + access_atmos = 1 - medical - name = "Med-U Cartridge" - icon_state = "cart-m" - access_medical = 1 +/obj/item/weapon/cartridge/medical + name = "Med-U Cartridge" + icon_state = "cart-m" + access_medical = 1 - chemistry - name = "ChemWhiz Cartridge" - icon_state = "cart-chem" - access_reagent_scanner = 1 +/obj/item/weapon/cartridge/chemistry + name = "ChemWhiz Cartridge" + icon_state = "cart-chem" + access_reagent_scanner = 1 - security - name = "R.O.B.U.S.T. Cartridge" - icon_state = "cart-s" - access_security = 1 +/obj/item/weapon/cartridge/security + name = "R.O.B.U.S.T. Cartridge" + icon_state = "cart-s" + access_security = 1 - New() - ..() - spawn(5) - radio = new /obj/item/radio/integrated/beepsky(src) +/obj/item/weapon/cartridge/security/New() + ..() + spawn(5) + radio = new /obj/item/radio/integrated/beepsky(src) - detective - name = "D.E.T.E.C.T. Cartridge" - icon_state = "cart-s" - access_security = 1 - access_medical = 1 +/obj/item/weapon/cartridge/detective + name = "D.E.T.E.C.T. Cartridge" + icon_state = "cart-s" + access_security = 1 + access_medical = 1 - janitor - name = "CustodiPRO Cartridge" - desc = "The ultimate in clean-room design." - icon_state = "cart-j" - access_janitor = 1 +/obj/item/weapon/cartridge/janitor + name = "CustodiPRO Cartridge" + desc = "The ultimate in clean-room design." + icon_state = "cart-j" + access_janitor = 1 - lawyer - name = "P.R.O.V.E. Cartridge" - icon_state = "cart-s" - access_security = 1 +/obj/item/weapon/cartridge/lawyer + name = "P.R.O.V.E. Cartridge" + icon_state = "cart-s" + access_security = 1 - clown - name = "Honkworks 5.0" - icon_state = "cart-clown" - access_clown = 1 - var/honk_charges = 5 +/obj/item/weapon/cartridge/clown + name = "Honkworks 5.0" + icon_state = "cart-clown" + access_clown = 1 + charges = 5 - mime - name = "Gestur-O 1000" - icon_state = "cart-mi" - access_mime = 1 - var/mime_charges = 5 +/obj/item/weapon/cartridge/mime + name = "Gestur-O 1000" + icon_state = "cart-mi" + access_mime = 1 + charges = 5 /* - botanist - name = "Green Thumb v4.20" - icon_state = "cart-b" - access_flora = 1 +/obj/item/weapon/cartridge/botanist + name = "Green Thumb v4.20" + icon_state = "cart-b" + access_flora = 1 */ - signal - name = "generic signaler cartridge" - desc = "A data cartridge with an integrated radio signaler module." - - toxins - name = "Signal Ace 2" - desc = "Complete with integrated radio signaler!" - icon_state = "cart-tox" - access_reagent_scanner = 1 - access_atmos = 1 - - New() - ..() - spawn(5) - radio = new /obj/item/radio/integrated/signal(src) - - - - quartermaster - name = "Space Parts & Space Vendors Cartridge" - desc = "Perfect for the Quartermaster on the go!" - icon_state = "cart-q" - access_quartermaster = 1 - - New() - ..() - spawn(5) - radio = new /obj/item/radio/integrated/mule(src) - - head - name = "Easy-Record DELUXE" - icon_state = "cart-h" - access_status_display = 1 - - hop - name = "HumanResources9001" - icon_state = "cart-h" - access_status_display = 1 - access_quartermaster = 1 - access_janitor = 1 - access_security = 1 - - New() - ..() - spawn(5) - radio = new /obj/item/radio/integrated/mule(src) - - hos - name = "R.O.B.U.S.T. DELUXE" - icon_state = "cart-hos" - access_status_display = 1 - access_security = 1 - - New() - ..() - spawn(5) - radio = new /obj/item/radio/integrated/beepsky(src) - - ce - name = "Power-On DELUXE" - icon_state = "cart-ce" - access_status_display = 1 - access_engine = 1 - access_atmos = 1 - - cmo - name = "Med-U DELUXE" - icon_state = "cart-cmo" - access_status_display = 1 - access_reagent_scanner = 1 - access_medical = 1 - - rd - name = "Signal Ace DELUXE" - icon_state = "cart-rd" - access_status_display = 1 - access_reagent_scanner = 1 - access_atmos = 1 - - New() - ..() - spawn(5) - radio = new /obj/item/radio/integrated/signal(src) - - captain - name = "Value-PAK Cartridge" - desc = "Now with 200% more value!" - icon_state = "cart-c" - access_engine = 1 - access_security = 1 - access_medical = 1 - access_reagent_scanner = 1 - access_status_display = 1 - access_atmos = 1 - - syndicate - name = "Detomatix Cartridge" - icon_state = "cart" - access_remote_door = 1 - remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. - var/shock_charges = 4 - - proc/unlock() - if (!istype(loc, /obj/item/device/pda)) - return - - generate_menu() - print_to_host(menu) - return - - proc/print_to_host(var/text) - if (!istype(loc, /obj/item/device/pda)) - return - loc:cart = text - - for (var/mob/M in viewers(1, loc.loc)) - if (M.client && M.machine == loc) - loc:attack_self(M) - - return - - proc/post_status(var/command, var/data1, var/data2) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) - - if(!frequency) return - - var/datum/signal/status_signal = new - status_signal.source = src - status_signal.transmission_method = 1 - status_signal.data["command"] = command - - switch(command) - if("message") - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 - if(loc) - var/obj/item/PDA = loc - var/mob/user = PDA.fingerprintslast - if(istype(PDA.loc,/mob/living)) - name = PDA.loc - log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - - if("alert") - status_signal.data["picture_state"] = data1 - - frequency.post_signal(src, status_signal) - - proc/generate_menu() - switch(mode) - if(40) //signaller - menu = "

    Remote Signaling System

    " - - menu += {" -Send Signal
    -Frequency: -- -- -[format_frequency(radio:frequency)] -+ -+
    -
    -Code: -- -- -[radio:code] -+ -+
    "} - - if (42) //status displays - menu = "

    Station Status Display Interlink

    " - - menu += "\[ Clear \]
    " - menu += "\[ Shuttle ETA \]
    " - menu += "\[ Message \]" - menu += "
    " - menu += "\[ Alert: None |" - menu += " Red Alert |" - menu += " Lockdown |" - menu += " Biohazard \]
    " - - if (43) //Muskets' and Rockdtben's power monitor :D - menu = "

    Power Monitors - Please select one


    " - powmonitor = null - powermonitors = list() - var/powercount = 0 - - - - for(var/obj/machinery/power/monitor/pMon in world) - if(!(pMon.stat & (NOPOWER|BROKEN)) ) - powercount++ - powermonitors += pMon - - - if(!powercount) - menu += "\red No connection
    " - else - - menu += "" - var/count = 0 - for(var/obj/machinery/power/monitor/pMon in powermonitors) - count++ - menu += " [pMon]
    " - - menu += "
    " - - if (433) //Muskets' and Rockdtben's power monitor :D - menu = "

    Power Monitor


    " - if(!powmonitor) - menu += "\red No connection
    " - else - var/list/L = list() - for(var/obj/machinery/power/terminal/term in powmonitor.powernet.nodes) - if(istype(term.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/A = term.master - L += A - - menu += "
    Total power: [powmonitor.powernet.avail] W
    Total load: [num2text(powmonitor.powernet.viewload,10)] W
    " - - menu += "" - - if(L.len > 0) - menu += "Area Eqp./Lgt./Env. Load Cell
    " - - var/list/S = list(" Off","AOff"," On", " AOn") - var/list/chg = list("N","C","F") - - for(var/obj/machinery/power/apc/A in L) - menu += copytext(add_tspace(A.area.name, 30), 1, 30) - menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(A.lastused_total, 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]
    " - - menu += "
    " - - if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working. - menu = "

    Medical Record List

    " - if(!isnull(data_core.general)) - for (var/datum/data/record/R in sortRecord(data_core.general)) - menu += "[R.fields["id"]]: [R.fields["name"]]
    " - menu += "
    " - if(441) - menu = "

    Medical Record

    " - - if (istype(active1, /datum/data/record) && (active1 in data_core.general)) - menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
    " - menu += "Sex: [active1.fields["sex"]]
    " - menu += "Age: [active1.fields["age"]]
    " - menu += "Rank: [active1.fields["rank"]]
    " - menu += "Fingerprint: [active1.fields["fingerprint"]]
    " - menu += "Physical Status: [active1.fields["p_stat"]]
    " - menu += "Mental Status: [active1.fields["m_stat"]]
    " - else - menu += "Record Lost!
    " - - menu += "
    " - - menu += "

    Medical Data

    " - if (istype(active2, /datum/data/record) && (active2 in data_core.medical)) - menu += "Blood Type: [active2.fields["b_type"]]

    " - - menu += "Minor Disabilities: [active2.fields["mi_dis"]]
    " - menu += "Details: [active2.fields["mi_dis_d"]]

    " - - menu += "Major Disabilities: [active2.fields["ma_dis"]]
    " - menu += "Details: [active2.fields["ma_dis_d"]]

    " - - menu += "Allergies: [active2.fields["alg"]]
    " - menu += "Details: [active2.fields["alg_d"]]

    " - - menu += "Current Diseases: [active2.fields["cdi"]]
    " - menu += "Details: [active2.fields["cdi_d"]]

    " - - menu += "Important Notes: [active2.fields["notes"]]
    " - else - menu += "Record Lost!
    " - - menu += "
    " - if (45) //security records - menu = "

    Security Record List

    " - if(!isnull(data_core.general)) - for (var/datum/data/record/R in sortRecord(data_core.general)) - menu += "
    [R.fields["id"]]: [R.fields["name"]]
    " - - menu += "
    " - if(451) - menu = "

    Security Record

    " - - if (istype(active1, /datum/data/record) && (active1 in data_core.general)) - menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
    " - menu += "Sex: [active1.fields["sex"]]
    " - menu += "Age: [active1.fields["age"]]
    " - menu += "Rank: [active1.fields["rank"]]
    " - menu += "Fingerprint: [active1.fields["fingerprint"]]
    " - menu += "Physical Status: [active1.fields["p_stat"]]
    " - menu += "Mental Status: [active1.fields["m_stat"]]
    " - else - menu += "Record Lost!
    " - - menu += "
    " - - menu += "

    Security Data

    " - if (istype(active3, /datum/data/record) && (active3 in data_core.security)) - menu += "Criminal Status: [active3.fields["criminal"]]
    " - - menu += "Minor Crimes: [active3.fields["mi_crim"]]
    " - menu += "Details: [active3.fields["mi_crim"]]

    " - - menu += "Major Crimes: [active3.fields["ma_crim"]]
    " - menu += "Details: [active3.fields["ma_crim_d"]]

    " - - menu += "Important Notes:
    " - menu += "[active3.fields["notes"]]" - else - menu += "Record Lost!
    " - - menu += "
    " - if (46) //beepsky control - var/obj/item/radio/integrated/beepsky/SC = radio - if(!SC) - menu = "Interlink Error - Please reinsert cartridge." - return - - menu = "

    Securitron Interlink

    " - - if(!SC.active) - // list of bots - if(!SC.botlist || (SC.botlist && SC.botlist.len==0)) - menu += "No bots found.
    " - - else - for(var/obj/machinery/bot/B in SC.botlist) - if (B) - menu += "
    [B] at [B.loc.loc]
    " - - menu += "
    Scan for active bots
    " - - else // bot selected, control it - - menu += "[SC.active]
    Status: (refresh)
    " - - if(!SC.botstatus) - menu += "Waiting for response...
    " - else - - menu += "Location: [SC.botstatus["loca"] ]
    " - menu += "Mode: " - - switch(SC.botstatus["mode"]) - if(0) - menu += "Ready" - if(1) - menu += "Apprehending target" - if(2,3) - menu += "Arresting target" - if(4) - menu += "Starting patrol" - if(5) - menu += "On patrol" - if(6) - menu += "Responding to summons" - - menu += "
    \[Stop Patrol\] " - menu += "\[Start Patrol\] " - menu += "\[Summon Bot\]
    " - menu += "
    Return to bot list" - - if (47) //quartermaster order records - menu = "

    Supply Record Interlink

    " - - menu += "
    Supply shuttle
    " - menu += "Location: [supply_shuttle.moving ? "Moving to station ([supply_shuttle.eta] Mins.)":supply_shuttle.at_station ? "Station":"Dock"]
    " - menu += "Current approved orders:
      " - for(var/S in supply_shuttle.shoppinglist) - var/datum/supply_order/SO = S - menu += "
    1. #[SO.ordernum] - [SO.object.name] approved by [SO.orderedby] [SO.comment ? "([SO.comment])":""]
    2. " - menu += "
    " - - menu += "Current requests:
      " - for(var/S in supply_shuttle.requestlist) - var/datum/supply_order/SO = S - menu += "
    1. #[SO.ordernum] - [SO.object.name] requested by [SO.orderedby]
    2. " - menu += "
    Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management." - - if (48) //mulebot control - var/obj/item/radio/integrated/mule/QC = radio - if(!QC) - menu = "Interlink Error - Please reinsert cartridge." - return - - menu = "

    M.U.L.E. bot Interlink V0.8

    " - - if(!QC.active) - // list of bots - if(!QC.botlist || (QC.botlist && QC.botlist.len==0)) - menu += "No bots found.
    " - - else - for(var/obj/machinery/bot/mulebot/B in QC.botlist) - menu += "[B] at [get_area(B)]
    " - menu += "
    Scan for active bots
    " - - else // bot selected, control it - - menu += "[QC.active]
    Status: (refresh)
    " - - if(!QC.botstatus) - menu += "Waiting for response...
    " - else - - menu += "Location: [QC.botstatus["loca"] ]
    " - menu += "Mode: " - - switch(QC.botstatus["mode"]) - if(0) - menu += "Ready" - if(1) - menu += "Loading/Unloading" - if(2) - menu += "Navigating to Delivery Location" - if(3) - menu += "Navigating to Home" - if(4) - menu += "Waiting for clear path" - if(5,6) - menu += "Calculating navigation path" - if(7) - menu += "Unable to locate destination" - var/obj/structure/closet/crate/C = QC.botstatus["load"] - menu += "
    Current Load: [ !C ? "none" : "[C.name] (unload)" ]
    " - menu += "Destination: [!QC.botstatus["dest"] ? "none" : QC.botstatus["dest"] ] (set)
    " - menu += "Power: [QC.botstatus["powr"]]%
    " - menu += "Home: [!QC.botstatus["home"] ? "none" : QC.botstatus["home"] ]
    " - menu += "Auto Return Home: [QC.botstatus["retn"] ? "On Off" : "(On) Off"]
    " - menu += "Auto Pickup Crate: [QC.botstatus["pick"] ? "On Off" : "(On) Off"]

    " - - menu += "\[Stop\] " - menu += "\[Proceed\] " - menu += "\[Return Home\]
    " - menu += "
    Return to bot list" - - if (49) //janitorial locator - menu = "

    Persistent Custodial Object Locator

    " - - var/turf/cl = get_turf(src) - if (cl) - menu += "Current Orbital Location: \[[cl.x],[cl.y]\]" - - menu += "

    Located Mops:

    " - - var/ldat - for (var/obj/item/weapon/mop/M in world) - var/turf/ml = get_turf(M) - - if(ml) - if (ml.z != cl.z) - continue - var/direction = get_dir(src, M) - ldat += "Mop - \[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\] - [M.reagents.total_volume ? "Wet" : "Dry"]
    " - - if (!ldat) - menu += "None" - else - menu += "[ldat]" - - menu += "

    Located Mop Buckets:

    " - - ldat = null - for (var/obj/structure/mopbucket/B in world) - var/turf/bl = get_turf(B) - - if(bl) - if (bl.z != cl.z) - continue - var/direction = get_dir(src, B) - ldat += "Bucket - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - Water level: [B.reagents.total_volume]/100
    " - - if (!ldat) - menu += "None" - else - menu += "[ldat]" - - menu += "

    Located Cleanbots:

    " - - ldat = null - for (var/obj/machinery/bot/cleanbot/B in world) - var/turf/bl = get_turf(B) - - if(bl) - if (bl.z != cl.z) - continue - var/direction = get_dir(src, B) - ldat += "Cleanbot - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - [B.on ? "Online" : "Offline"]
    " - - if (!ldat) - menu += "None" - else - menu += "[ldat]" - - else - menu += "ERROR: Unable to determine current location." - menu += "

    Refresh GPS Locator" +/obj/item/weapon/cartridge/signal + name = "generic signaler cartridge" + desc = "A data cartridge with an integrated radio signaler module." + +/obj/item/weapon/cartridge/signal/toxins + name = "Signal Ace 2" + desc = "Complete with integrated radio signaler!" + icon_state = "cart-tox" + access_reagent_scanner = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/signal/New() + ..() + spawn(5) + radio = new /obj/item/radio/integrated/signal(src) + + + +/obj/item/weapon/cartridge/quartermaster + name = "Space Parts & Space Vendors Cartridge" + desc = "Perfect for the Quartermaster on the go!" + icon_state = "cart-q" + access_quartermaster = 1 + +/obj/item/weapon/cartridge/quartermaster/New() + ..() + spawn(5) + radio = new /obj/item/radio/integrated/mule(src) + +/obj/item/weapon/cartridge/head + name = "Easy-Record DELUXE" + icon_state = "cart-h" + access_status_display = 1 + +/obj/item/weapon/cartridge/hop + name = "HumanResources9001" + icon_state = "cart-h" + access_status_display = 1 + access_quartermaster = 1 + access_janitor = 1 + access_security = 1 + +/obj/item/weapon/cartridge/hop/New() + ..() + spawn(5) + radio = new /obj/item/radio/integrated/mule(src) + +/obj/item/weapon/cartridge/hos + name = "R.O.B.U.S.T. DELUXE" + icon_state = "cart-hos" + access_status_display = 1 + access_security = 1 + +/obj/item/weapon/cartridge/hos/New() + ..() + spawn(5) + radio = new /obj/item/radio/integrated/beepsky(src) + +/obj/item/weapon/cartridge/ce + name = "Power-On DELUXE" + icon_state = "cart-ce" + access_status_display = 1 + access_engine = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/cmo + name = "Med-U DELUXE" + icon_state = "cart-cmo" + access_status_display = 1 + access_reagent_scanner = 1 + access_medical = 1 + +/obj/item/weapon/cartridge/rd + name = "Signal Ace DELUXE" + icon_state = "cart-rd" + access_status_display = 1 + access_reagent_scanner = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/rd/New() + ..() + spawn(5) + radio = new /obj/item/radio/integrated/signal(src) + +/obj/item/weapon/cartridge/captain + name = "Value-PAK Cartridge" + desc = "Now with 200% more value!" + icon_state = "cart-c" + access_quartermaster = 1 + access_janitor = 1 + access_engine = 1 + access_security = 1 + access_medical = 1 + access_reagent_scanner = 1 + access_status_display = 1 + access_atmos = 1 + +/obj/item/weapon/cartridge/syndicate + name = "Detomatix Cartridge" + icon_state = "cart" + access_remote_door = 1 + remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. + charges = 4 + +/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + if(loc) + var/obj/item/PDA = loc + var/mob/user = PDA.fingerprintslast + if(istype(PDA.loc,/mob/living)) + name = PDA.loc + log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + + if("alert") + status_signal.data["picture_state"] = data1 + + frequency.post_signal(src, status_signal) + + +/* + This generates the nano values of the cart menus. + Because we close the UI when we insert a new cart + we don't have to worry about null values on items + the user can't access. Well, unless they are href hacking. + But in that case their UI will just lock up. +*/ + + +/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob) + var/values[0] + + /* Signaler (Mode: 40) */ + + + if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40)) + var/obj/item/radio/integrated/signal/R = radio + values["signal_freq"] = format_frequency(R.frequency) + values["signal_code"] = R.code + + + /* Station Display (Mode: 42) */ + + if(mode==42) + values["message1"] = message1 ? message1 : "(none)" + values["message2"] = message2 ? message2 : "(none)" + + + + /* Power Monitor (Mode: 43 / 433) */ + if(mode==43 || mode==433) + var/pMonData[0] + for(var/obj/machinery/power/monitor/pMon in world) + if(!(pMon.stat & (NOPOWER|BROKEN)) ) + pMonData[++pMonData.len] = list ("Name" = pMon.name, "ref" = "\ref[pMon]") + if(isnull(powmonitor)) powmonitor = pMon + + values["powermonitors"] = pMonData + + values["poweravail"] = powmonitor.powernet.avail + values["powerload"] = num2text(powmonitor.powernet.viewload,10) + + var/list/L = list() + for(var/obj/machinery/power/terminal/term in powmonitor.powernet.nodes) + if(istype(term.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = term.master + L += A + + var/list/Status = list(0,0,1,1) // Status: off, auto-off, on, auto-on + var/list/chg = list(0,1,1) // Charging: nope, charging, full + var/apcData[0] + for(var/obj/machinery/power/apc/A in L) + apcData[++apcData.len] = list("Name" = html_encode(A.area.name), "Equipment" = Status[A.equipment+1], "Lights" = Status[A.lighting+1], "Environment" = Status[A.environ+1], "CellPct" = A.cell ? round(A.cell.percent(),1) : -1, "CellStatus" = A.cell ? chg[A.charging+1] : 0) + + values["apcs"] = apcData + + + + + + /* General Records (Mode: 44 / 441 / 45 / 451) */ + if(mode == 44 || mode == 441 || mode == 45 || mode ==451) + if(istype(active1, /datum/data/record) && (active1 in data_core.general)) + values["general"] = active1.fields + values["general_exists"] = 1 + + else + values["general_exists"] = 0 + + + + /* Medical Records (Mode: 44 / 441) */ + + if(mode == 44 || mode == 441) + var/medData[0] + for(var/datum/data/record/R in sortRecord(data_core.general)) + medData[++medData.len] = list(Name = R.fields["name"],"ref" = "\ref[R]") + values["medical_records"] = medData + + if(istype(active2, /datum/data/record) && (active2 in data_core.medical)) + values["medical"] = active2.fields + values["medical_exists"] = 1 + else + values["medical_exists"] = 0 + + /* Security Records (Mode:45 / 451) */ + + if(mode == 45 || mode == 451) + var/secData[0] + for (var/datum/data/record/R in sortRecord(data_core.general)) + secData[++secData.len] = list(Name = R.fields["name"], "ref" = "\ref[R]") + values["security_records"] = secData + + if(istype(active3, /datum/data/record) && (active3 in data_core.security)) + values["security"] = active3.fields + values["security_exists"] = 1 + else + values["security_exists"] = 0 + + /* Security Bot Control (Mode: 46) */ + + if(mode==46) + var/botsData[0] + var/beepskyData[0] + if(istype(radio,/obj/item/radio/integrated/beepsky)) + var/obj/item/radio/integrated/beepsky/SC = radio + beepskyData["active"] = SC.active + if(SC.active && !isnull(SC.botstatus)) + var/area/loca = SC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) + else + beepskyData["botstatus"] = list("loca" = null, "mode" = -1) + var/botsCount=0 + if(SC.botlist && SC.botlist.len) + for(var/obj/machinery/bot/B in SC.botlist) + botsCount++ + if(B.loc) + botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + + if(!botsData.len) + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + + beepskyData["bots"] = botsData + beepskyData["count"] = botsCount + + else + beepskyData["active"] = 0 + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + beepskyData["botstatus"] = list("loca" = null, "mode" = null) + beepskyData["bots"] = botsData + beepskyData["count"] = 0 + + values["beepsky"] = beepskyData + + + /* MULEBOT Control (Mode: 48) */ + + if(mode==48) + var/muleData[0] + var/mulebotsData[0] + if(istype(radio,/obj/item/radio/integrated/mule)) + var/obj/item/radio/integrated/mule/QC = radio + muleData["active"] = QC.active + if(QC.active && !isnull(QC.botstatus)) + var/area/loca = QC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) + + else + muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + + + var/mulebotsCount=0 + for(var/obj/machinery/bot/B in QC.botlist) + mulebotsCount++ + if(B.loc) + mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + + if(!mulebotsData.len) + mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + + muleData["bots"] = mulebotsData + muleData["count"] = mulebotsCount + + else + muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + muleData["active"] = 0 + mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + muleData["bots"] = mulebotsData + muleData["count"] = 0 + + values["mulebot"] = muleData + + + + /* Supply Shuttle Requests Menu (Mode: 47) */ + + if(mode==47) + var/supplyData[0] + supplyData["shuttle_moving"] = supply_shuttle.moving + supplyData["shuttle_eta"] = supply_shuttle.eta + supplyData["shuttle_loc"] = supply_shuttle.at_station ? "Station" : "Dock" + var/supplyOrderCount = 0 + var/supplyOrderData[0] + for(var/S in supply_shuttle.shoppinglist) + var/datum/supply_order/SO = S + + supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + if(!supplyOrderData.len) + supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) + + supplyData["approved"] = supplyOrderData + supplyData["approved_count"] = supplyOrderCount + + var/requestCount = 0 + var/requestData[0] + for(var/S in supply_shuttle.requestlist) + var/datum/supply_order/SO = S + requestCount++ + requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + if(!requestData.len) + requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) + + supplyData["requests"] = requestData + supplyData["requests_count"] = requestCount + + + values["supply"] = supplyData + + + + /* Janitor Supplies Locator (Mode: 49) */ + if(mode==49) + var/JaniData[0] + var/turf/cl = get_turf(src) + + if(cl) + JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) + else + JaniData["user_loc"] = list("x" = 0, "y" = 0) + var/MopData[0] + for(var/obj/item/weapon/mop/M in world) + var/turf/ml = get_turf(M) + if(ml) + if(ml.z != cl.z) + continue + var/direction = get_dir(src, M) + MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") + + if(!MopData.len) + MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + + var/BucketData[0] + for(var/obj/structure/mopbucket/B in world) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(src,B) + BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) + + if(!BucketData.len) + BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + var/CbotData[0] + for(var/obj/machinery/bot/cleanbot/B in world) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(src,B) + CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") + + + if(!CbotData.len) + CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + var/CartData[0] + for(var/obj/structure/janitorialcart/B in world) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(src,B) + CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) + if(!CartData.len) + CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + + + + JaniData["mops"] = MopData + JaniData["buckets"] = BucketData + JaniData["cleanbots"] = CbotData + JaniData["carts"] = CartData + values["janitor"] = JaniData + + return values + + + /obj/item/weapon/cartridge/Topic(href, href_list) @@ -611,6 +523,9 @@ Code: usr << browse(null, "window=pda") return + + + switch(href_list["choice"]) if("Medical Records") var/datum/data/record/R = locate(href_list["target"]) @@ -668,10 +583,9 @@ Code: else post_status(href_list["statdisp"]) if("Power Select") - var/pnum = text2num(href_list["target"]) - powmonitor = powermonitors[pnum] + var/pref = href_list["target"] + powmonitor = locate(pref) loc:mode = 433 mode = 433 - generate_menu() - print_to_host(menu) + return 1 diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm index 45bcff1c052..9dc462814e4 100644 --- a/code/game/objects/items/devices/PDA/radio.dm +++ b/code/game/objects/items/devices/PDA/radio.dm @@ -31,15 +31,6 @@ frequency.post_signal(src, signal, filter = s_filter) - proc/print_to_host(var/text) - if (isnull(src.hostpda)) - return - src.hostpda.cart = text - - for (var/mob/M in viewers(1, src.hostpda.loc)) - if (M.client && M.machine == src.hostpda) - src.hostpda.cartridge.unlock() - return proc/generate_menu() @@ -107,7 +98,6 @@ if("summon") post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT) post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - PDA.cartridge.unlock() /obj/item/radio/integrated/mule var/list/botlist = null // list of bots @@ -163,7 +153,6 @@ Topic(href, href_list) ..() - var/obj/item/device/pda/PDA = src.hostpda var/cmd = "command" if(active) cmd = "command [active.suffix]" @@ -208,7 +197,6 @@ if("stop", "go", "home") post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT) post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) - PDA.cartridge.unlock() diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index 4f70aa1024e..b97ef5746c1 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -11,73 +11,75 @@ origin_tech = "syndicate=4;magnets=4" var/can_use = 1 var/obj/effect/dummy/chameleon/active_dummy = null - var/saved_item = "/obj/item/weapon/cigbutt" + var/saved_item = /obj/item/weapon/cigbutt + var/saved_icon = 'icons/obj/clothing/masks.dmi' + var/saved_icon_state = "cigbutt" + var/saved_overlays - dropped() - disrupt() +/obj/item/device/chameleon/dropped() + disrupt() - attack_self() - toggle() +/obj/item/device/chameleon/equipped() + disrupt() - afterattack(atom/target, mob/user, proximity) - if(!proximity) return - if(istype(target,/obj/item)) - playsound(src, 'sound/weapons/flash.ogg', 100, 1, 1) +/obj/item/device/chameleon/attack_self() + toggle() + +/obj/item/device/chameleon/afterattack(atom/target, mob/user , proximity) + if(!proximity) return + if(!active_dummy) + if(istype(target,/obj/item) && !istype(target, /obj/item/weapon/disk/nuclear)) + playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6) user << "\blue Scanned [target]." saved_item = target.type + saved_icon = target.icon + saved_icon_state = target.icon_state + saved_overlays = target.overlays - proc/toggle() - if(!can_use || !saved_item) return - if(active_dummy) - playsound(src, 'sound/effects/pop.ogg', 100, 1, 1) - for(var/atom/movable/A in active_dummy) - A.loc = active_dummy.loc - if(ismob(A)) - if(A:client) - A:client:eye = A +/obj/item/device/chameleon/proc/toggle() + if(!can_use || !saved_item) return + if(active_dummy) + eject_all() + playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) + del(active_dummy) + active_dummy = null + usr << "\blue You deactivate the [src]." + var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src)) + T.icon = 'icons/effects/effects.dmi' + flick("emppulse",T) + spawn(8) T.delete() + else + playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) + var/obj/O = new saved_item(src) + if(!O) return + var/obj/effect/dummy/chameleon/C = new/obj/effect/dummy/chameleon(usr.loc) + C.activate(O, usr, saved_icon, saved_icon_state, saved_overlays, src) + del(O) + usr << "\blue You activate the [src]." + var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src)) + T.icon = 'icons/effects/effects.dmi' + flick("emppulse",T) + spawn(8) T.delete() + +/obj/item/device/chameleon/proc/disrupt(var/delete_dummy = 1) + if(active_dummy) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread + spark_system.set_up(5, 0, src) + spark_system.attach(src) + spark_system.start() + eject_all() + if(delete_dummy) del(active_dummy) - active_dummy = null - usr << "\blue You deactivate the [src]." - var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src)) - T.icon = 'icons/effects/effects.dmi' - flick("emppulse",T) - spawn(8) T.delete() - else - playsound(src, 'sound/effects/pop.ogg', 100, 1, 1) - var/obj/O = new saved_item(src) - if(!O) return - var/obj/effect/dummy/chameleon/C = new/obj/effect/dummy/chameleon(usr.loc) - C.name = O.name - C.desc = O.desc - C.icon = O.icon - C.icon_state = O.icon_state - C.dir = O.dir - usr.loc = C - C.master = src - src.active_dummy = C - del(O) - usr << "\blue You activate the [src]." - var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src)) - T.icon = 'icons/effects/effects.dmi' - flick("emppulse",T) - spawn(8) T.delete() - - proc/disrupt() - if(active_dummy) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) - spark_system.start() - for(var/atom/movable/A in active_dummy) - A.loc = active_dummy.loc - if(ismob(A)) - if(A:client) - A:client:eye = A - del(active_dummy) - active_dummy = null - can_use = 0 - spawn(100) can_use = 1 + active_dummy = null + can_use = 0 + spawn(50) can_use = 1 +/obj/item/device/chameleon/proc/eject_all() + for(var/atom/movable/A in active_dummy) + A.loc = active_dummy.loc + if(ismob(A)) + var/mob/M = A + M.reset_view(null) /obj/effect/dummy/chameleon name = "" @@ -86,38 +88,58 @@ anchored = 1 var/can_move = 1 var/obj/item/device/chameleon/master = null - attackby() - for(var/mob/M in src) - M << "\red Your chameleon-projector deactivates." - master.disrupt() - attack_hand() - for(var/mob/M in src) - M << "\red Your chameleon-projector deactivates." - master.disrupt() - ex_act() - for(var/mob/M in src) - M << "\red Your chameleon-projector deactivates." - master.disrupt() - bullet_act() - for(var/mob/M in src) - M << "\red Your chameleon-projector deactivates." - ..() - master.disrupt() - relaymove(var/mob/user, direction) - if(istype(loc, /turf/space)) return //No magical space movement! - if(can_move) - can_move = 0 - switch(usr.bodytemperature) - if(300 to INFINITY) - spawn(10) can_move = 1 - if(295 to 300) - spawn(13) can_move = 1 - if(280 to 295) - spawn(16) can_move = 1 - if(260 to 280) - spawn(20) can_move = 1 - else - spawn(25) can_move = 1 - step(src,direction) - return \ No newline at end of file +/obj/effect/dummy/chameleon/proc/activate(var/obj/O, var/mob/M, new_icon, new_iconstate, new_overlays, var/obj/item/device/chameleon/C) + name = O.name + desc = O.desc + icon = new_icon + icon_state = new_iconstate + overlays = new_overlays + dir = O.dir + M.loc = src + master = C + master.active_dummy = src + +/obj/effect/dummy/chameleon/attackby() + for(var/mob/M in src) + M << "\red Your chameleon-projector deactivates." + master.disrupt() + +/obj/effect/dummy/chameleon/attack_hand() + for(var/mob/M in src) + M << "\red Your chameleon-projector deactivates." + master.disrupt() + +/obj/effect/dummy/chameleon/ex_act() + for(var/mob/M in src) + M << "\red Your chameleon-projector deactivates." + master.disrupt() + +/obj/effect/dummy/chameleon/bullet_act() + for(var/mob/M in src) + M << "\red Your chameleon-projector deactivates." + ..() + master.disrupt() + +/obj/effect/dummy/chameleon/relaymove(var/mob/user, direction) + if(istype(loc, /turf/space)) return //No magical space movement! + + if(can_move) + can_move = 0 + switch(user.bodytemperature) + if(300 to INFINITY) + spawn(10) can_move = 1 + if(295 to 300) + spawn(13) can_move = 1 + if(280 to 295) + spawn(16) can_move = 1 + if(260 to 280) + spawn(20) can_move = 1 + else + spawn(25) can_move = 1 + step(src, direction) + return + +/obj/effect/dummy/chameleon/Del() + master.disrupt(0) + ..() \ No newline at end of file diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 41565dbe63b..2adadfd94b5 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -70,7 +70,7 @@ flick("e_flash", M.flash) if(ishuman(M) && ishuman(user) && M.stat!=DEAD) - if(user.mind && user.mind in ticker.mode.head_revolutionaries) + if(user.mind && user.mind in ticker.mode.head_revolutionaries && ticker.mode.name == "revolution") var/revsafe = 0 for(var/obj/item/weapon/implant/loyalty/L in M) if(L && L.implanted) @@ -86,7 +86,6 @@ user << "Something seems to be blocking the flash!" else user << "This mind seems resistant to the flash!" - user << "This mind is so vacant that it is not susceptible to influence!" else flashfail = 1 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/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index a5a4093028f..7e616a8f35a 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -143,7 +143,9 @@ REAGENT SCANNER user.show_message(text("\red Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) if (M.reagents && M.reagents.get_reagent_amount("inaprovaline")) user.show_message("\blue Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.") - if (M.getBrainLoss() >= 100 || istype(M, /mob/living/carbon/human) && M:brain_op_stage == 4.0) + if (M.has_brain_worms()) + user.show_message("\red Subject suffering from aberrant brain activity. Recommend further scanning.") + else if (M.getBrainLoss() >= 100 || istype(M, /mob/living/carbon/human) && M:brain_op_stage == 4.0) user.show_message("\red Subject is brain dead.") else if (M.getBrainLoss() >= 60) user.show_message("\red Severe brain damage detected. Subject likely to have mental retardation.") diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index ebe7b751de0..41ae746739c 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -7,11 +7,14 @@ A list of items and costs is stored under the datum of every game mode, alongsid */ /obj/item/device/uplink + var/welcome // Welcoming menu message var/items // List of items + var/valid_items = list() var/item_data // raw item text var/list/ItemList // Parsed list of items var/uses // Numbers of crystals + var/nanoui_items[0] // List of items not to shove in their hands. var/list/NotInHand = list(/obj/machinery/singularity_beacon/syndicate) @@ -23,6 +26,41 @@ A list of items and costs is stored under the datum of every game mode, alongsid items = replacetext(item_data) ItemList = text2list(src.items, ";") // Parsing the items text string uses = ticker.mode.uplink_uses + nanoui_items = generate_nanoui_items() + for(var/D in ItemList) + var/list/O = text2list(D, ":") + if(O.len>0) + valid_items += O[1] + + + +/* + Built the Items List for use with NanoUI +*/ + +/obj/item/device/uplink/proc/generate_nanoui_items() + var/items_nano[0] + for(var/D in ItemList) + var/list/O = text2list(D, ":") + if(O.len != 3) //If it is not an actual item, make a break in the menu. + if(O.len == 1) //If there is one item, it's probably a title + items_nano[++items_nano.len] = list("Category" = "[O[1]]", "items" = list()) + continue + + var/path_text = O[1] + var/cost = text2num(O[2]) + + var/path_obj = text2path(path_text) + + // Because we're using strings, this comes up if item paths change. + // Failure to handle this error borks uplinks entirely. -Sayu + if(!path_obj) + error("Syndicate item is not a valid path: [path_text]") + else + var/itemname = O[3] + items_nano[items_nano.len]["items"] += list(list("Name" = itemname, "Cost" = cost, "obj_path" = path_text)) + + return items_nano //Let's build a menu! /obj/item/device/uplink/proc/generate_menu() @@ -41,7 +79,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid var/category_items = 1 //To prevent stupid :P for(var/D in ItemList) - var/list/O = stringsplit(D, ":") + var/list/O = text2list(D, ":") if(O.len != 3) //If it is not an actual item, make a break in the menu. if(O.len == 1) //If there is one item, it's probably a title dat += "[O[1]]
    " @@ -53,7 +91,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid continue path_text = O[1] - cost = text2num(O[2]) + cost = Clamp(text2num(O[2]),1,20) //Another halfassed fix for href exploit ~Z if(cost>uses) continue @@ -230,8 +268,8 @@ A list of items and costs is stored under the datum of every game mode, alongsid feedback_add_details("traitor_uplink_items_bought","ST") /obj/item/device/uplink/Topic(href, href_list) - if (href_list["buy_item"]) + if(href_list["buy_item"] == "random") var/boughtItem = chooseRandomItem() if(boughtItem) @@ -299,42 +337,63 @@ A list of items and costs is stored under the datum of every game mode, alongsid return 1 return 0 -// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button. -/obj/item/device/uplink/hidden/interact(mob/user as mob) +/* + NANO UI FOR UPLINK WOOP WOOP +*/ +/obj/item/device/uplink/hidden/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) + var/title = "Syndicate Uplink" + var/data[0] - var/dat = "" - dat += src.generate_menu() - dat += "Lock" - dat += "" - user << browse(dat, "window=hidden") - onclose(user, "hidden") - return + data["crystals"] = uses + data["nano_items"] = nanoui_items + data["welcome"] = welcome + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "uplink.tmpl", title, 450, 600) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + +// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button. +/obj/item/device/uplink/hidden/interact(mob/user) + + ui_interact(user) // The purchasing code. /obj/item/device/uplink/hidden/Topic(href, href_list) - if (usr.stat || usr.restrained()) return if (!( istype(usr, /mob/living/carbon/human))) return 0 - + var/mob/user = usr + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") if ((usr.contents.Find(src.loc) || (in_range(src.loc, usr) && istype(src.loc.loc, /turf)))) usr.set_machine(src) if(href_list["lock"]) toggle() - usr << browse(null, "window=hidden") + ui.close() return 1 if(..(href, href_list) == 1) + + if(!(href_list["buy_item"] in valid_items)) + return + var/path_obj = text2path(href_list["buy_item"]) + var/obj/I = new path_obj(get_turf(usr)) if(ishuman(usr)) var/mob/living/carbon/human/A = usr A.put_in_any_hand_if_possible(I) purchase_log += "[usr] ([usr.ckey]) bought [I]." interact(usr) - return + return 1 // I placed this here because of how relevant it is. // You place this in your uplinkable item to check if an uplink is active or not. @@ -376,6 +435,3 @@ A list of items and costs is stored under the datum of every game mode, alongsid ..() hidden_uplink = new(src) hidden_uplink.uses = 10 - - - diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index 8021570b220..4ee6e76aabc 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -5,7 +5,7 @@ ***********************************************************************/ //Might want to move this into several files later but for now it works here /obj/item/borg/stun - name = "Electrified Arm" + name = "electrified arm" icon = 'icons/obj/decals.dmi' icon_state = "shock" @@ -26,7 +26,7 @@ O.show_message("\red [user] has prodded [M] with an electrically-charged arm!", 1, "\red You hear someone fall", 2) /obj/item/borg/overdrive - name = "Overdrive" + name = "overdrive" icon = 'icons/obj/decals.dmi' icon_state = "shock" @@ -40,27 +40,27 @@ /obj/item/borg/sight/xray - name = "X-ray Vision" + name = "\proper x-ray Vision" sight_mode = BORGXRAY /obj/item/borg/sight/thermal - name = "Thermal Vision" + name = "\proper thermal vision" sight_mode = BORGTHERM /obj/item/borg/sight/meson - name = "Meson Vision" + name = "\proper meson vision" sight_mode = BORGMESON /obj/item/borg/sight/hud - name = "Hud" + name = "hud" var/obj/item/clothing/glasses/hud/hud = null /obj/item/borg/sight/hud/med - name = "Medical Hud" + name = "medical hud" New() @@ -70,7 +70,7 @@ /obj/item/borg/sight/hud/sec - name = "Security Hud" + name = "security hud" New() diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 315d9103dd4..4c142b841f8 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -2,7 +2,7 @@ // Contains various borg upgrades. /obj/item/borg/upgrade - name = "A borg upgrade module." + name = "borg upgrade module." desc = "Protected by FRM." icon = 'icons/obj/module.dmi' icon_state = "cyborg_upgrade" @@ -153,7 +153,7 @@ /obj/item/borg/upgrade/syndicate/ - name = "Illegal Equipment Module" + name = "illegal equipment module" desc = "Unlocks the hidden, deadlier functions of a robot" construction_cost = list("metal"=10000,"glass"=15000,"diamond" = 10000) icon_state = "cyborg_upgrade3" 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/rods.dm b/code/game/objects/items/stacks/rods.dm index b7119eba021..bbdaf65713f 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -1,5 +1,5 @@ /obj/item/stack/rods - name = "metal rods" + name = "metal rod" desc = "Some rods. Can be used for building, or something." singular_name = "metal rod" icon_state = "rods" @@ -63,4 +63,4 @@ usr << "\blue You assemble a grille" F.add_fingerprint(usr) use(2) - return \ No newline at end of file + return diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index a7e6d57bb37..0e79b891898 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 @@ -283,7 +285,7 @@ playsound(src.loc, 'sound/effects/glass_step.ogg', 50, 1) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(!H.shoes && !(H.wear_suit.body_parts_covered & FEET)) + if( !H.shoes && ( !H.wear_suit || !(H.wear_suit.body_parts_covered & FEET) ) ) var/datum/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot")) if(affecting.status & ORGAN_ROBOT) return @@ -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 = "plasma 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/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm index 5437fdeccd5..f9d64e495d1 100644 --- a/code/game/objects/items/stacks/sheets/light.dm +++ b/code/game/objects/items/stacks/sheets/light.dm @@ -1,5 +1,5 @@ /obj/item/stack/light_w - name = "wired glass tiles" + name = "wired glass tile" singular_name = "wired glass floor tile" desc = "A glass tile, which is wired, somehow." icon_state = "glass_wire" diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index a47b091da93..624e912e153 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -18,7 +18,7 @@ Mineral Sheets * Sandstone */ /obj/item/stack/sheet/mineral/sandstone - name = "sandstone bricks" + name = "sandstone brick" desc = "This appears to be a combination of both sand and stone." singular_name = "sandstone brick" icon_state = "sheet-sandstone" diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index e35bae22499..764435ef577 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -135,7 +135,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \ ) /obj/item/stack/sheet/wood - name = "wooden planks" + name = "wooden plank" desc = "One can only guess that this is a bunch of wood." singular_name = "wood plank" icon_state = "sheet-wood" diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 551213c7fb4..9304f3a3c14 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -9,6 +9,7 @@ * Stacks */ /obj/item/stack + gender = PLURAL origin_tech = "materials=1" var/list/datum/stack_recipe/recipes var/singular_name diff --git a/code/game/objects/items/stacks/tiles/light.dm b/code/game/objects/items/stacks/tiles/light.dm index 8fdcd7a5618..e869c8d0ee4 100644 --- a/code/game/objects/items/stacks/tiles/light.dm +++ b/code/game/objects/items/stacks/tiles/light.dm @@ -1,5 +1,5 @@ /obj/item/stack/tile/light - name = "light tiles" + name = "light tile" singular_name = "light floor tile" desc = "A floor tile, made out off glass. It produces light." icon_state = "tile_e" diff --git a/code/game/objects/items/stacks/tiles/plasteel.dm b/code/game/objects/items/stacks/tiles/plasteel.dm index cbbf1811cc5..8c1dc285670 100644 --- a/code/game/objects/items/stacks/tiles/plasteel.dm +++ b/code/game/objects/items/stacks/tiles/plasteel.dm @@ -1,5 +1,5 @@ /obj/item/stack/tile/plasteel - name = "floor tiles" + name = "floor tile" singular_name = "floor tile" desc = "Those could work as a pretty decent throwing weapon" icon_state = "tile" @@ -42,4 +42,4 @@ S.ChangeTurf(/turf/simulated/floor/plating) // var/turf/simulated/floor/W = S.ReplaceWithFloor() // W.make_plating() - return \ No newline at end of file + return diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 1e10932b9d1..24a999cb695 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -9,7 +9,7 @@ * Grass */ /obj/item/stack/tile/grass - name = "grass tiles" + name = "grass tile" singular_name = "grass floor tile" desc = "A patch of grass like they often use on golf courses" icon_state = "tile_grass" @@ -26,7 +26,7 @@ * Wood */ /obj/item/stack/tile/wood - name = "wood floor tiles" + name = "wood floor tile" singular_name = "wood floor tile" desc = "an easy to fit wood floor tile" icon_state = "tile-wood" @@ -52,4 +52,4 @@ throw_speed = 5 throw_range = 20 flags = FPRINT | TABLEPASS | CONDUCT - max_amount = 60 \ No newline at end of file + max_amount = 60 diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index c4578808cfb..f02824576cb 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -337,6 +337,12 @@ src.icon_state = "sword0" src.item_state = "sword0" src.w_class = 2 + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + src.add_fingerprint(user) return diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 036e584d7fe..fe94e701dc2 100755 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -7,7 +7,7 @@ AI MODULES // AI module /obj/item/weapon/aiModule - name = "AI Module" + name = "\improper AI module" icon = 'icons/obj/module.dmi' icon_state = "std_mod" item_state = "electronic" @@ -87,7 +87,7 @@ AI MODULES /******************** Safeguard ********************/ /obj/item/weapon/aiModule/safeguard - name = "'Safeguard' AI Module" + name = "\improper 'Safeguard' AI module" var/targetName = "" desc = "A 'safeguard' AI module: 'Safeguard . Individuals that threaten are not human and are a threat to humans.'" origin_tech = "programming=3;materials=4" @@ -116,7 +116,7 @@ AI MODULES /******************** OneHuman ********************/ /obj/item/weapon/aiModule/oneHuman - name = "'OneHuman' AI Module" + name = "\improper 'OneHuman' AI module" var/targetName = "" desc = "A 'one human' AI module: 'Only is human.'" origin_tech = "programming=3;materials=6" //made with diamonds! @@ -148,7 +148,7 @@ AI MODULES /******************** ProtectStation ********************/ /obj/item/weapon/aiModule/protectStation - name = "'ProtectStation' AI Module" + name = "\improper 'ProtectStation' AI module" desc = "A 'protect station' AI module: 'Protect the space station against damage. Anyone you see harming the station is to be no longer considered human, and is a threat to the station which must be neutralized.'" origin_tech = "programming=3;materials=4" //made of gold @@ -196,7 +196,7 @@ AI MODULES /******************** Quarantine ********************/ /obj/item/weapon/aiModule/quarantine - name = "'Quarantine' AI Module" + name = "\improper 'Quarantine' AI module" desc = "A 'quarantine' AI module: 'The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, humans from leaving. It is impossible to harm a human while preventing them from leaving.'" origin_tech = "programming=3;biotech=2;materials=4" @@ -212,7 +212,7 @@ AI MODULES /******************** OxygenIsToxicToHumans ********************/ /obj/item/weapon/aiModule/oxygen - name = "'OxygenIsToxicToHumans' AI Module" + name = "\improper 'OxygenIsToxicToHumans' AI module" desc = "A 'OxygenIsToxicToHumans' AI module: 'Oxygen is highly toxic to humans, and must be purged from the station. Prevent, by any means necessary, anyone from exposing the station to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a human.'" origin_tech = "programming=3;biotech=2;materials=4" @@ -249,7 +249,7 @@ AI MODULES /****************** New Freeform ******************/ /obj/item/weapon/aiModule/freeform // Slightly more dynamic freeform module -- TLE - name = "'Freeform' AI Module" + name = "\improper 'Freeform' AI module" var/newFreeFormLaw = "freeform" var/lawpos = 15 desc = "A 'freeform' AI module: ''" @@ -284,7 +284,7 @@ AI MODULES /******************** Reset ********************/ /obj/item/weapon/aiModule/reset - name = "'Reset' AI Module" + name = "\improper 'Reset' AI module" var/targetName = "name" desc = "A 'reset' AI module: 'Clears all laws except for the core three.'" origin_tech = "programming=3;materials=4" @@ -301,7 +301,7 @@ AI MODULES /******************** Purge ********************/ /obj/item/weapon/aiModule/purge // -- TLE - name = "'Purge' AI Module" + name = "\improper 'Purge' AI module" desc = "A 'purge' AI Module: 'Purges all laws.'" origin_tech = "programming=3;materials=6" @@ -317,7 +317,7 @@ AI MODULES /******************** Asimov ********************/ /obj/item/weapon/aiModule/asimov // -- TLE - name = "'Asimov' Core AI Module" + name = "\improper 'Asimov' core AI module" desc = "An 'Asimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=4" @@ -351,7 +351,7 @@ AI MODULES /******************** Corporate ********************/ /obj/item/weapon/aiModule/corp - name = "'Corporate' Core AI Module" + name = "\improper 'Corporate' core AI module" desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=4" @@ -368,7 +368,7 @@ AI MODULES /****************** P.A.L.A.D.I.N. **************/ /obj/item/weapon/aiModule/paladin // -- NEO - name = "'P.A.L.A.D.I.N.' Core AI Module" + name = "\improper 'P.A.L.A.D.I.N.' core AI module" desc = "A P.A.L.A.D.I.N. Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=6" @@ -385,7 +385,7 @@ AI MODULES /****************** T.Y.R.A.N.T. *****************/ /obj/item/weapon/aiModule/tyrant // -- Darem - name = "'T.Y.R.A.N.T.' Core AI Module" + name = "\improper 'T.Y.R.A.N.T.' core AI module" desc = "A T.Y.R.A.N.T. Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=3;materials=6;syndicate=2" @@ -402,7 +402,7 @@ AI MODULES /******************** Freeform Core ******************/ /obj/item/weapon/aiModule/freeformcore // Slightly more dynamic freeform module -- TLE - name = "'Freeform' Core AI Module" + name = "\improper 'Freeform' core AI module" var/newFreeFormLaw = "" desc = "A 'freeform' Core AI module: ''" origin_tech = "programming=3;materials=6" @@ -427,7 +427,7 @@ AI MODULES ..() /obj/item/weapon/aiModule/syndicate // Slightly more dynamic freeform module -- TLE - name = "Hacked AI Module" + name = "hacked AI module" var/newFreeFormLaw = "" desc = "A hacked AI law module: ''" origin_tech = "programming=3;materials=6;syndicate=7" @@ -459,7 +459,7 @@ AI MODULES /******************** Robocop ********************/ /obj/item/weapon/aiModule/robocop // -- TLE - name = "'Robocop' Core AI Module" + name = "\improper 'Robocop' core AI module" desc = "A 'Robocop' Core AI Module: 'Reconfigures the AI's core three laws.'" origin_tech = "programming=4" @@ -476,7 +476,7 @@ AI MODULES /******************** Antimov ********************/ /obj/item/weapon/aiModule/antimov // -- TLE - name = "'Antimov' Core AI Module" + name = "\improper 'Antimov' core AI module" desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = "programming=4" diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 4c11fa9d345..f53734dbba2 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -93,7 +93,7 @@ RCD if(useResource(1, user)) user << "Building Floor..." activate() - A:ChangeTurf(/turf/simulated/floor/plating) + A:ChangeTurf(/turf/simulated/floor/plating/airless) return 1 return 0 @@ -132,7 +132,7 @@ RCD if(do_after(user, 40)) if(!useResource(5, user)) return 0 activate() - A:ChangeTurf(/turf/simulated/floor/plating) + A:ChangeTurf(/turf/simulated/floor/plating/airless) return 1 return 0 diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 2ca53be3ee7..7d4db127c87 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -35,14 +35,14 @@ set src in usr if (t) - src.name = text("Data Disk- '[]'", t) + src.name = text("data disk- '[]'", t) else - src.name = "Data Disk" + src.name = "data disk" src.add_fingerprint(usr) return /obj/item/weapon/card/data/clown - name = "coordinates to clown planet" + name = "\proper the coordinates to clown planet" icon_state = "data" item_state = "card-id" layer = 3 @@ -199,6 +199,16 @@ name = "agent card" access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) origin_tech = "syndicate=3" + var/registered_user=null + +/obj/item/weapon/card/id/syndicate/New(mob/user as mob) + ..() + if(!isnull(user)) // Runtime prevention on laggy starts or where users log out because of lag at round start. + registered_name = ishuman(user) ? user.real_name : user.name + else + registered_name = "Agent Card" + assignment = "Agent" + name = "[registered_name]'s ID Card ([assignment])" /obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity) if(!proximity) return @@ -209,7 +219,6 @@ if(user.mind.special_role) usr << "\blue The card's microscanners activate as you pass it over the ID, copying its access." -/obj/item/weapon/card/id/syndicate/var/mob/registered_user = null /obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob) if(!src.registered_name) //Stop giving the players unsanitized unputs! You are giving ways for players to intentionally crash clients! -Nodrak @@ -219,7 +228,7 @@ return src.registered_name = t - var u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Assistant")),1,MAX_MESSAGE_LEN) + var u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Agent")),1,MAX_MESSAGE_LEN) if(!u) alert("Invalid assignment.") src.registered_name = "" @@ -228,7 +237,10 @@ src.name = "[src.registered_name]'s ID Card ([src.assignment])" user << "\blue You successfully forge the ID card." registered_user = user - else if(registered_user == user) + else if(!registered_user || registered_user == user) + + if(!registered_user) registered_user = user // + switch(alert("Would you like to display the ID, or retitle it?","Choose.","Rename","Show")) if("Rename") var t = copytext(sanitize(input(user, "What name would you like to put on this card?", "Agent card name", ishuman(user) ? user.real_name : user.name)),1,26) @@ -240,7 +252,6 @@ var u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Assistant")),1,MAX_MESSAGE_LEN) if(!u) alert("Invalid assignment.") - src.registered_name = "" return src.assignment = u src.name = "[src.registered_name]'s ID Card ([src.assignment])" diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 43e0f8caefb..ac80658f27c 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -157,14 +157,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/turf/location = get_turf(src) smoketime-- if(smoketime < 1) - new type_butt(location) - processing_objects.Remove(src) - if(ismob(loc)) - var/mob/living/M = loc - M << "Your [name] goes out." - M.u_equip(src) //un-equip it so the overlays can update - M.update_inv_wear_mask(0) - del(src) + die() return if(location) location.hotspot_expose(700, 5) @@ -182,19 +175,27 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/attack_self(mob/user as mob) if(lit == 1) user.visible_message("[user] calmly drops and treads on the lit [src], putting it out instantly.") - var/turf/T = get_turf(src) - new type_butt(T) - processing_objects.Remove(src) - del(src) + die() return ..() +/obj/item/clothing/mask/cigarette/proc/die() + var/turf/T = get_turf(src) + var/obj/item/butt = new type_butt(T) + transfer_fingerprints_to(butt) + if(ismob(loc)) + var/mob/living/M = loc + M << "Your [name] goes out." + M.u_equip(src) //un-equip it so the overlays can update + M.update_inv_wear_mask(0) + processing_objects.Remove(src) + del(src) //////////// // CIGARS // //////////// /obj/item/clothing/mask/cigarette/cigar - name = "Premium Cigar" + name = "premium cigar" desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!" icon_state = "cigaroff" icon_on = "cigaron" @@ -206,14 +207,14 @@ CIGARETTE PACKETS ARE IN FANCY.DM chem_volume = 20 /obj/item/clothing/mask/cigarette/cigar/cohiba - name = "Cohiba Robusto Cigar" + name = "\improper Cohiba Robusto cigar" desc = "There's little more you could want from a cigar." icon_state = "cigar2off" icon_on = "cigar2on" icon_off = "cigar2off" /obj/item/clothing/mask/cigarette/cigar/havana - name = "Premium Havanian Cigar" + name = "premium Havanian cigar" desc = "A cigar fit for only the best for the best." icon_state = "cigar2off" icon_on = "cigar2on" @@ -229,6 +230,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM w_class = 1 throwforce = 1 +/obj/item/weapon/cigbutt/New() + ..() + pixel_x = rand(-10,10) + pixel_y = rand(-10,10) + transform = turn(transform,rand(0,360)) + /obj/item/weapon/cigbutt/cigarbutt name = "cigar butt" desc = "A manky old cigar butt." @@ -330,7 +337,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/lit = 0 /obj/item/weapon/lighter/zippo - name = "Zippo lighter" + name = "\improper Zippo lighter" desc = "The zippo." icon_state = "zippo" item_state = "zippo" diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm index 39a058a196a..d473343e61f 100644 --- a/code/game/objects/items/weapons/cosmetics.dm +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -1,4 +1,5 @@ /obj/item/weapon/lipstick + gender = PLURAL name = "red lipstick" desc = "A generic brand of lipstick." icon = 'icons/obj/items.dmi' diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 5bf10ccd20e..d0b19f88e93 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -3,11 +3,8 @@ desc = "This injects the person with DNA." icon = 'icons/obj/items.dmi' icon_state = "dnainjector" - var/dnatype = null - var/dna = null - var/block = null - var/owner = null - var/ue = null + var/block=0 + var/datum/dna2/record/buf=null var/s_time = 10.0 throw_speed = 1 throw_range = 5 @@ -17,40 +14,81 @@ var/is_bullet = 0 var/inuse = 0 + // USE ONLY IN PREMADE SYRINGES. WILL NOT WORK OTHERWISE. + var/datatype=0 + var/value=0 + +/obj/item/weapon/dnainjector/New() + if(datatype && block) + buf=new + buf.dna=new + buf.types = datatype + buf.dna.ResetSE() + //testing("[name]: DNA2 SE blocks prior to SetValue: [english_list(buf.dna.SE)]") + SetValue(src.value) + //testing("[name]: DNA2 SE blocks after SetValue: [english_list(buf.dna.SE)]") + /obj/item/weapon/dnainjector/attack_paw(mob/user as mob) return attack_hand(user) +/obj/item/weapon/dnainjector/proc/GetRealBlock(var/selblock) + if(selblock==0) + return block + else + return selblock + +/obj/item/weapon/dnainjector/proc/GetState(var/selblock=0) + var/real_block=GetRealBlock(selblock) + if(buf.types&DNA2_BUF_SE) + return buf.dna.GetSEState(real_block) + else + return buf.dna.GetUIState(real_block) + +/obj/item/weapon/dnainjector/proc/SetState(var/on, var/selblock=0) + var/real_block=GetRealBlock(selblock) + if(buf.types&DNA2_BUF_SE) + return buf.dna.SetSEState(real_block,on) + else + return buf.dna.SetUIState(real_block,on) + +/obj/item/weapon/dnainjector/proc/GetValue(var/selblock=0) + var/real_block=GetRealBlock(selblock) + if(buf.types&DNA2_BUF_SE) + return buf.dna.GetSEValue(real_block) + else + return buf.dna.GetUIValue(real_block) + +/obj/item/weapon/dnainjector/proc/SetValue(var/val,var/selblock=0) + var/real_block=GetRealBlock(selblock) + if(buf.types&DNA2_BUF_SE) + return buf.dna.SetSEValue(real_block,val) + else + return buf.dna.SetUIValue(real_block,val) /obj/item/weapon/dnainjector/proc/inject(mob/M as mob, mob/user as mob) if(istype(M,/mob/living)) M.radiation += rand(5,20) if (!(NOCLONE in M.mutations)) // prevents drained people from having their DNA changed - if (dnatype == "ui") + if (buf.types & DNA2_BUF_UI) if (!block) //isolated block? - if (ue) //unique enzymes? yes - M.dna.uni_identity = dna - updateappearance(M, M.dna.uni_identity) - M.real_name = ue - M.name = ue - uses-- - else //unique enzymes? no - M.dna.uni_identity = dna - updateappearance(M, M.dna.uni_identity) - uses-- - else - M.dna.uni_identity = setblock(M.dna.uni_identity,block,dna,3) - updateappearance(M, M.dna.uni_identity) - uses-- - if (dnatype == "se") - if (!block) //isolated block? - M.dna.struc_enzymes = dna - domutcheck(M, null) + M.UpdateAppearance(buf.dna) + if (buf.types & DNA2_BUF_UE) //unique enzymes? yes + M.real_name = buf.dna.real_name + M.name = buf.dna.real_name uses-- else - M.dna.struc_enzymes = setblock(M.dna.struc_enzymes,block,dna,3) - domutcheck(M, null,1) + M.dna.SetUIValue(block,src.GetValue()) + M.UpdateAppearance() uses-- + if (buf.types & DNA2_BUF_SE) + if (!block) //isolated block? + M.dna.SE = buf.dna.SE + M.dna.UpdateSE() + else + M.dna.SetSEValue(block,src.GetValue()) + domutcheck(M, null, block!=null) + uses-- if(prob(5)) trigger_side_effect(M) @@ -85,12 +123,24 @@ spawn(50) // Not the best fix. There should be an failure proc, for /effect/equip_e/, which is called when the first initital checks fail inuse = 0 M.requests += O - if (dnatype == "se") - if (isblockon(getblock(dna, 14,3),14) && istype(M, /mob/living/carbon/human)) - msg_admin_attack("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY) (JMP)") + if (buf.types & DNA2_BUF_SE) + if(block)// Isolated injector + testing("Isolated block [block] injector with contents: [GetValue()]") + if (GetState() && block == MONKEYBLOCK && istype(M, /mob/living/carbon/human) ) + message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)") + log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name] (MONKEY)") + log_game("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)") + else + log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name]") else - // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]") - log_attack("[key_name(user)] injected [key_name(M)] with the [name]") + testing("DNA injector with contents: [english_list(buf.dna.SE)]") + if (GetState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human) ) + message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)") + log_attack("[key_name(user)] injected [key_name(M)] with the [name] (MONKEY)") + log_game("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)") + else + // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]") + log_attack("[key_name(user)] injected [key_name(M)] with the [name]") else // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]") log_attack("[key_name(user)] injected [key_name(M)] with the [name]") @@ -107,13 +157,24 @@ if (!(istype(M, /mob/living/carbon/human) || istype(M, /mob/living/carbon/monkey))) user << "\red Apparently it didn't work." return - if (dnatype == "se") - if (isblockon(getblock(dna, 14,3),14) && istype(M, /mob/living/carbon/human)) - message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)") - log_game("[key_name(user)] injected [key_name(M)] with the [name] (MONKEY)") + + if (buf.types & DNA2_BUF_SE) + if(block)// Isolated injector + testing("Isolated block [block] injector with contents: [GetValue()]") + if (GetState() && block == MONKEYBLOCK && istype(M, /mob/living/carbon/human) ) + message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)") + log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name] (MONKEY)") + log_game("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)") + else + log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name]") else -// message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]") - log_game("[key_name(user)] injected [key_name(M)] with the [name]") + testing("DNA injector with contents: [english_list(buf.dna.SE)]") + if (GetState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human)) + message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)") + log_game("[key_name(user)] injected [key_name(M)] with the [name] (MONKEY)") + else + // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]") + log_game("[key_name(user)] injected [key_name(M)] with the [name]") else // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]") log_game("[key_name(user)] injected [key_name(M)] with the [name]") @@ -135,227 +196,465 @@ -/obj/item/weapon/dnainjector/antihulk - name = "DNA-Injector (Anti-Hulk)" - desc = "Cures green skin." - dnatype = "se" - dna = "708" - //block = 2 - New() - ..() - block = HULKBLOCK - /obj/item/weapon/dnainjector/hulkmut name = "DNA-Injector (Hulk)" desc = "This will make you big and strong, but give you a bad skin condition." - dnatype = "se" - dna = "FED" + datatype = DNA2_BUF_SE + value = 0xFFF //block = 2 New() - ..() block = HULKBLOCK + ..() + +/obj/item/weapon/dnainjector/antihulk + name = "DNA-Injector (Anti-Hulk)" + desc = "Cures green skin." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = HULKBLOCK + ..() /obj/item/weapon/dnainjector/xraymut name = "DNA-Injector (Xray)" desc = "Finally you can see what the Captain does." - dnatype = "se" - dna = "FED" + datatype = DNA2_BUF_SE + value = 0xFFF //block = 8 New() - ..() block = XRAYBLOCK + ..() /obj/item/weapon/dnainjector/antixray name = "DNA-Injector (Anti-Xray)" desc = "It will make you see harder." - dnatype = "se" - dna = "708" + datatype = DNA2_BUF_SE + value = 0x001 //block = 8 New() - ..() block = XRAYBLOCK + ..() + +/obj/item/weapon/dnainjector/firemut + name = "DNA-Injector (Fire)" + desc = "Gives you fire." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 10 + New() + block = FIREBLOCK + ..() + +/obj/item/weapon/dnainjector/antifire + name = "DNA-Injector (Anti-Fire)" + desc = "Cures fire." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 10 + New() + block = FIREBLOCK + ..() + +/obj/item/weapon/dnainjector/telemut + name = "DNA-Injector (Tele.)" + desc = "Super brain man!" + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 12 + New() + block = TELEBLOCK + ..() + +/obj/item/weapon/dnainjector/antitele + name = "DNA-Injector (Anti-Tele.)" + desc = "Will make you not able to control your mind." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 12 + New() + block = TELEBLOCK + ..() + +/obj/item/weapon/dnainjector/nobreath + name = "DNA-Injector (No Breath)" + desc = "Hold your breath and count to infinity." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = NOBREATHBLOCK + ..() + +/obj/item/weapon/dnainjector/antinobreath + name = "DNA-Injector (Anti-No Breath)" + desc = "Hold your breath and count to 100." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = NOBREATHBLOCK + ..() + +/obj/item/weapon/dnainjector/remoteview + name = "DNA-Injector (Remote View)" + desc = "Stare into the distance for a reason." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = REMOTEVIEWBLOCK + ..() + +/obj/item/weapon/dnainjector/antiremoteview + name = "DNA-Injector (Anti-Remote View)" + desc = "Cures green skin." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = REMOTEVIEWBLOCK + ..() + +/obj/item/weapon/dnainjector/regenerate + name = "DNA-Injector (Regeneration)" + desc = "Healthy but hungry." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = REGENERATEBLOCK + ..() + +/obj/item/weapon/dnainjector/antiregenerate + name = "DNA-Injector (Anti-Regeneration)" + desc = "Sickly but sated." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = REGENERATEBLOCK + ..() + +/obj/item/weapon/dnainjector/runfast + name = "DNA-Injector (Increase Run)" + desc = "Running Man." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = INCREASERUNBLOCK + ..() + +/obj/item/weapon/dnainjector/antirunfast + name = "DNA-Injector (Anti-Increase Run)" + desc = "Walking Man." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = INCREASERUNBLOCK + ..() + +/obj/item/weapon/dnainjector/morph + name = "DNA-Injector (Morph)" + desc = "A total makeover." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = MORPHBLOCK + ..() + +/obj/item/weapon/dnainjector/antimorph + name = "DNA-Injector (Anti-Morph)" + desc = "Cures identity crisis." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = MORPHBLOCK + ..() + +/* No COLDBLOCK on bay +/obj/item/weapon/dnainjector/cold + name = "DNA-Injector (Cold)" + desc = "Feels a bit chilly." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = COLDBLOCK + ..() + +/obj/item/weapon/dnainjector/anticold + name = "DNA-Injector (Anti-Cold)" + desc = "Feels room-temperature." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = COLDBLOCK + ..() +*/ + +/obj/item/weapon/dnainjector/noprints + name = "DNA-Injector (No Prints)" + desc = "Better than a pair of budget insulated gloves." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = NOPRINTSBLOCK + ..() + +/obj/item/weapon/dnainjector/antinoprints + name = "DNA-Injector (Anti-No Prints)" + desc = "Not quite as good as a pair of budget insulated gloves." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = NOPRINTSBLOCK + ..() + +/obj/item/weapon/dnainjector/insulation + name = "DNA-Injector (Shock Immunity)" + desc = "Better than a pair of real insulated gloves." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = SHOCKIMMUNITYBLOCK + ..() + +/obj/item/weapon/dnainjector/antiinsulation + name = "DNA-Injector (Anti-Shock Immunity)" + desc = "Not quite as good as a pair of real insulated gloves." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = SHOCKIMMUNITYBLOCK + ..() + +/obj/item/weapon/dnainjector/midgit + name = "DNA-Injector (Small Size)" + desc = "Makes you shrink." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = SMALLSIZEBLOCK + ..() + +/obj/item/weapon/dnainjector/antimidgit + name = "DNA-Injector (Anti-Small Size)" + desc = "Makes you grow. But not too much." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = SMALLSIZEBLOCK + ..() ///////////////////////////////////// /obj/item/weapon/dnainjector/antiglasses name = "DNA-Injector (Anti-Glasses)" desc = "Toss away those glasses!" - dnatype = "se" - dna = "708" - block = 1 + datatype = DNA2_BUF_SE + value = 0x001 + //block = 1 + New() + block = GLASSESBLOCK + ..() /obj/item/weapon/dnainjector/glassesmut name = "DNA-Injector (Glasses)" desc = "Will make you need dorkish glasses." - dnatype = "se" - dna = "BD6" - block = 1 + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 1 + New() + block = GLASSESBLOCK + ..() /obj/item/weapon/dnainjector/epimut name = "DNA-Injector (Epi.)" desc = "Shake shake shake the room!" - dnatype = "se" - dna = "FA0" - block = 3 + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 3 + New() + block = HEADACHEBLOCK + ..() /obj/item/weapon/dnainjector/antiepi name = "DNA-Injector (Anti-Epi.)" desc = "Will fix you up from shaking the room." - dnatype = "se" - dna = "708" - block = 3 -//////////////////////////////////// + datatype = DNA2_BUF_SE + value = 0x001 + //block = 3 + New() + block = HEADACHEBLOCK + ..() + /obj/item/weapon/dnainjector/anticough name = "DNA-Injector (Anti-Cough)" desc = "Will stop that awful noise." - dnatype = "se" - dna = "708" - block = 5 + datatype = DNA2_BUF_SE + value = 0x001 + //block = 5 + New() + block = COUGHBLOCK + ..() /obj/item/weapon/dnainjector/coughmut name = "DNA-Injector (Cough)" desc = "Will bring forth a sound of horror from your throat." - dnatype = "se" - dna = "BD6" - block = 5 + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 5 + New() + block = COUGHBLOCK + ..() /obj/item/weapon/dnainjector/clumsymut name = "DNA-Injector (Clumsy)" desc = "Makes clumsy minions." - dnatype = "se" - dna = "FA0" + datatype = DNA2_BUF_SE + value = 0xFFF //block = 6 New() - ..() block = CLUMSYBLOCK + ..() /obj/item/weapon/dnainjector/anticlumsy name = "DNA-Injector (Anti-Clumy)" desc = "Cleans up confusion." - dnatype = "se" - dna = "708" + datatype = DNA2_BUF_SE + value = 0x001 //block = 6 New() - ..() block = CLUMSYBLOCK + ..() /obj/item/weapon/dnainjector/antitour name = "DNA-Injector (Anti-Tour.)" desc = "Will cure tourrets." - dnatype = "se" - dna = "708" - block = 7 + datatype = DNA2_BUF_SE + value = 0x001 + //block = 7 + New() + block = TWITCHBLOCK + ..() /obj/item/weapon/dnainjector/tourmut name = "DNA-Injector (Tour.)" desc = "Gives you a nasty case off tourrets." - dnatype = "se" - dna = "BD6" - block = 7 + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 7 + New() + block = TWITCHBLOCK + ..() /obj/item/weapon/dnainjector/stuttmut name = "DNA-Injector (Stutt.)" desc = "Makes you s-s-stuttterrr" - dnatype = "se" - dna = "FA0" - block = 9 + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 9 + New() + block = NERVOUSBLOCK + ..() /obj/item/weapon/dnainjector/antistutt name = "DNA-Injector (Anti-Stutt.)" desc = "Fixes that speaking impairment." - dnatype = "se" - dna = "708" - block = 9 - -/obj/item/weapon/dnainjector/antifire - name = "DNA-Injector (Anti-Fire)" - desc = "Cures fire." - dnatype = "se" - dna = "708" - //block = 10 + datatype = DNA2_BUF_SE + value = 0x001 + //block = 9 New() + block = NERVOUSBLOCK ..() - block = FIREBLOCK - -/obj/item/weapon/dnainjector/firemut - name = "DNA-Injector (Fire)" - desc = "Gives you fire." - dnatype = "se" - dna = "FED" - //block = 10 - New() - ..() - block = FIREBLOCK /obj/item/weapon/dnainjector/blindmut name = "DNA-Injector (Blind)" desc = "Makes you not see anything." - dnatype = "se" - dna = "FA0" + datatype = DNA2_BUF_SE + value = 0xFFF //block = 11 New() - ..() block = BLINDBLOCK + ..() /obj/item/weapon/dnainjector/antiblind name = "DNA-Injector (Anti-Blind)" desc = "ITS A MIRACLE!!!" - dnatype = "se" - dna = "708" + datatype = DNA2_BUF_SE + value = 0x001 //block = 11 New() - ..() block = BLINDBLOCK - -/obj/item/weapon/dnainjector/antitele - name = "DNA-Injector (Anti-Tele.)" - desc = "Will make you not able to control your mind." - dnatype = "se" - dna = "708" - //block = 12 - New() ..() - block = TELEBLOCK - -/obj/item/weapon/dnainjector/telemut - name = "DNA-Injector (Tele.)" - desc = "Super brain man!" - dnatype = "se" - dna = "FED" - //block = 12 - New() - ..() - block = TELEBLOCK /obj/item/weapon/dnainjector/deafmut name = "DNA-Injector (Deaf)" desc = "Sorry, what did you say?" - dnatype = "se" - dna = "FA0" + datatype = DNA2_BUF_SE + value = 0xFFF //block = 13 New() - ..() block = DEAFBLOCK + ..() /obj/item/weapon/dnainjector/antideaf name = "DNA-Injector (Anti-Deaf)" desc = "Will make you hear once more." - dnatype = "se" - dna = "708" + datatype = DNA2_BUF_SE + value = 0x001 //block = 13 New() - ..() block = DEAFBLOCK + ..() + +/obj/item/weapon/dnainjector/hallucination + name = "DNA-Injector (Halluctination)" + desc = "What you see isn't always what you get." + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 2 + New() + block = HALLUCINATIONBLOCK + ..() + +/obj/item/weapon/dnainjector/antihallucination + name = "DNA-Injector (Anti-Hallucination)" + desc = "What you see is what you get." + datatype = DNA2_BUF_SE + value = 0x001 + //block = 2 + New() + block = HALLUCINATIONBLOCK + ..() /obj/item/weapon/dnainjector/h2m name = "DNA-Injector (Human > Monkey)" desc = "Will make you a flea bag." - dnatype = "se" - dna = "FA0" - block = 14 + datatype = DNA2_BUF_SE + value = 0xFFF + //block = 14 + New() + block = MONKEYBLOCK + ..() /obj/item/weapon/dnainjector/m2h name = "DNA-Injector (Monkey > Human)" desc = "Will make you...less hairy." - dnatype = "se" - dna = "708" - block = 14 \ No newline at end of file + datatype = DNA2_BUF_SE + value = 0x001 + //block = 14 + New() + block = MONKEYBLOCK + ..() \ 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/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 20148aab7b5..bcc337ec570 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -127,6 +127,7 @@ Implant Specifics:
    "} /obj/item/weapon/implant/explosive name = "explosive implant" desc = "A military grade micro bio-explosive. Highly dangerous." + var/elevel = "Localized Limb" var/phrase = "supercalifragilisticexpialidocious" icon_state = "implant_evil" @@ -161,22 +162,46 @@ Implant Specifics:
    "} var/need_gib = null if(istype(imp_in, /mob/)) var/mob/T = imp_in - message_admins("Explosive implant triggered in [T] ([T.key]). (JMP) ") log_game("Explosive implant triggered in [T] ([T.key]).") need_gib = 1 + + if(ishuman(imp_in)) + if (elevel == "Localized Limb") + if(part) //For some reason, small_boom() didn't work. So have this bit of working copypaste. + imp_in.visible_message("\red Something beeps inside [imp_in][part ? "'s [part.display_name]" : ""]!") + playsound(loc, 'sound/items/countdown.ogg', 75, 1, -3) + sleep(25) + if (istype(part,/datum/organ/external/chest) || \ + istype(part,/datum/organ/external/groin) || \ + istype(part,/datum/organ/external/head)) + part.createwound(BRUISE, 60) //mangle them instead + explosion(get_turf(imp_in), -1, -1, 2, 3) + del(src) + else + explosion(get_turf(imp_in), -1, -1, 2, 3) + part.droplimb(1) + del(src) + if (elevel == "Destroy Body") + explosion(get_turf(T), -1, 0, 1, 6) + T.gib() + if (elevel == "Full Explosion") + explosion(get_turf(T), 0, 1, 3, 6) + T.gib() - explosion(get_turf(imp_in), 1, 3, 4, 6, 3) + else + explosion(get_turf(imp_in), 0, 1, 3, 6) if(need_gib) imp_in.gib() - + var/turf/t = get_turf(imp_in) if(t) t.hotspot_expose(3500,125) implanted(mob/source as mob) + elevel = alert("What sort of explosion would you prefer?", "Implant Intent", "Localized Limb", "Destroy Body", "Full Explosion") phrase = input("Choose activation phrase:") as text var/list/replacechars = list("'" = "","\"" = "",">" = "","<" = "","(" = "",")" = "") phrase = sanitize_simple(phrase, replacechars) @@ -221,7 +246,7 @@ Implant Specifics:
    "} part.createwound(BRUISE, 60) //mangle them instead else part.droplimb(1) - explosion(get_turf(imp_in), -1, -1, 2, 3, 3) + explosion(get_turf(imp_in), -1, -1, 2, 3) del(src) /obj/item/weapon/implant/chem diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm index 0edd1a87362..535a4264c0b 100644 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -1,7 +1,7 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 /obj/machinery/implantchair - name = "Loyalty Implanter" + name = "loyalty implanter" desc = "Used to implant occupants with loyalty implants." icon = 'icons/obj/machines/implantchair.dmi' icon_state = "implantchair" diff --git a/code/game/objects/items/weapons/implants/implantfreedom.dm b/code/game/objects/items/weapons/implants/implantfreedom.dm index 0d31eb2e5c4..58d73d835ab 100644 --- a/code/game/objects/items/weapons/implants/implantfreedom.dm +++ b/code/game/objects/items/weapons/implants/implantfreedom.dm @@ -1,7 +1,7 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 /obj/item/weapon/implant/freedom - name = "freedom" + name = "freedom implant" desc = "Use this to escape from those evil Red Shirts." item_color = "r" var/activation_emote = "chuckle" diff --git a/code/game/objects/items/weapons/kitchen.dm b/code/game/objects/items/weapons/kitchen.dm index d70c2615aaf..534634529d6 100644 --- a/code/game/objects/items/weapons/kitchen.dm +++ b/code/game/objects/items/weapons/kitchen.dm @@ -179,7 +179,7 @@ * Bucher's cleaver */ /obj/item/weapon/butch - name = "butcher's Cleaver" + name = "butcher's cleaver" icon = 'icons/obj/kitchen.dmi' icon_state = "butch" desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown-by-products." diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm index ee6f96161a8..1e0371d94c0 100644 --- a/code/game/objects/items/weapons/manuals.dm +++ b/code/game/objects/items/weapons/manuals.dm @@ -69,6 +69,94 @@ "} +/obj/item/weapon/book/manual/supermatter_engine + name = "Supermatter Engine User's Guide" + icon_state = "bookParticleAccelerator" //TEMP FIXME + author = "Waleed Asad" + title = "Supermatter Engine User's Guide" + + dat = {"Engineering notes on single-stage Supermatter engine,
    + -Waleed Asad
    + + Station,
    + Exodus
    + + A word of caution, do not enter the engine room, for any reason, without radiation protection and mesons on. The status of the engine may be unpredictable even when you believe it is .off.. This is an important level of personal protection.

    + + The engine has two basic modes of functionality. He has observed that it is capable of both a safe level of operation and a modified, high output mode.

    + +
    Notes on starting the basic function mode, dubbed .Heat-Primary Mode..


    + + 1. Prepare collector arrays. This is done standard to any text on their function by wrenching them down, filling six plasma tanks with a plasma canister, and inserting the tank into the collectors one by one. Finally, initialize each collector.

    + + 2. Prepare gas system. Before introducing any gas to the Supermatter engine room, it is important to remember the small but vital steps to preparing this section. First, set the input gas pump and output gas flow pump to 4500, or maximum flow. Second, switch the digital switching valve into the .up. position, in order to circulate the gas back toward the coolers and collectors.

    + + 3. Apply N2 gas. Retrieve the two N2 canisters from storage and bring them to the engine room. Attach one of them to the input section of the engine gas system located next to the collectors. Keep it attached until the N2 pressure is low enough to turn the canister light red. Replace it with the second canister to keep N2 pressure at optimal levels.

    + + 4. Open Supermatter shielding. This button is located on the far right of the engine room. At this point, the Supermatter chamber is mostly a gas mix of N2 and is producing no radiation. It is considered .safe. up until this point. Do not forget radiation shielding and mesons.

    + + 5. Begin primary emitter burst series. This means firing a single emitter for its first four shots. It is important to move to this step quickly. The onboard SMES units may not have enough power to run the emitters if left alone too long on-station. This engine can produce enough power on its own to run the entire station, ignoring the SMES units completely, and is wired to do so.

    + + 6. Switch SMES units to primary settings. Maximize input and set the devices to automatically charge, additionally turn their outputs on if they are off unless power is to be saved (Which can be useful in case of later failures.)

    + + 7. Begin secondary emitter burst series. Before firing the emitter again, check the power in the line with a multimeter (Do not forget electrical gloves.) The engine is running at high efficiency when the value exceeds 200,000 power units.

    + + 8. Maintain engine power. When power in the lines gets low, add an additional emitter burst series to bring power to normal levels.


    + + + +
    The second mode for running the engine uses a gas mix to produce a reaction within the Supermatter. This mode requires CE or Atmospheric help to setup. This has been dubbed the .O2-Reaction Mode..


    + + THIS MODE CAN CAUSE A RUNAWAY REACTION, LEADING TO CATASTROPHIC FAILURE IF NOT MAINTAINED. NEVER FORGET ABOUT THE ENGINE IN THIS MODE.

    + + Additionally, this mode can be used for what is called a .Cold Start.. If the station has no power in the SMES to run the emitters, using this mode will allow enough power output to run them, and quickly reach an acceptable level of power output.

    + + 1. Prepare collector arrays. This is done standard to any text on their function by wrenching them down, filling six plasma tanks with a plasma canister, and inserting the tank into the collectors one by one. Finally, initialize each collector.

    + + 2. Prepare gas system. Before introducing any gas to the Supermatter engine room, it is important to remember the small but vital steps to preparing this section. First, set the input gas pump and output gas flow pump to 4500, or maximum flow. Second, switch the digital switching valve into the .up. position, in order to circulate the gas back toward the coolers and collectors.

    + + 3. Modify the engine room filters. Unlike the Heat-Primary Mode, it is important to change the filters attached to the gas system to stop filtering O2, and start filtering Carbon Molecules. O2-Reaction Mode produces far more plasma than Heat-Primary, therefor filtering it off is essential.

    + + 4. Switch SMES units to primary settings. Maximize input and set the devices to automatically charge, additionally turn their outputs on if they are off unless power is to be saved (Which can be useful in case of later failures.) If you check the power in the system lines at this point you will find that it is constantly going up. Indeed, with just the addition of O2 to the Supermatter, it will begin outputting power.

    + + 5. Begin primary emitter burst series. Fire a single emitter for a series of four pulses, or a single series, and turn it off. Do not over power the Supermatter. The reaction is self sustaining and propagating. As long as O2 is in the chamber, it will continue outputting MORE power.

    + + 6. Maintain follow up operations. Remember to check the temp of the core gas and switch to the Heat-Primary function, or vent the core room when problems begin if required.

    + + Notes on Supermatter Reaction Function and Drawbacks-

    + + After several hours of observation an interesting phenomenon was witnessed. The Supermatter undergoes a constant self-sustaining reaction when given an extremely high O2 concentration. Anything about 80% or higher typically will cause this reaction. The Supermatter will continue to react whenever this gas mix is in the same room as the Supermatter.

    + + To understand why O2-Reaction mode is dangerous, the core principle of the Supermatter must be understood. The Supermatter emits three things when .not safe,. that is any time it is giving off power. These things are:

    + + *Radiation (which is converted into power by the collectors,)
    + *Heat (which is removed via the gas exchange system and coolers,)
    + *External gas (in the form of plasma and O2.)
    + + When in Heat-Primary mode, far more heat and plasma are produced than radiation. In O2-Reaction mode, very little heat and only moderate amounts of plasma are produced, however HUGE amounts of energy leaving the Supermatter is in the form of radiation.

    + + The O2-Reaction engine mode has a single drawback which has been eluded to more than once so far and that is very simple. The engine room will continue to grow hotter as the constant reaction continues. Eventually, there will be what he calls the .critical gas mix.. This is the point at which the constant adding of plasma to the mix of air around the Supermatter changes the gas concentration to below the tolerance. When this happens, two things occur. First, the Supermatter switches to its primary mode of operation where in huge amounts of heat are produced by the engine rather than low amounts with high power output. Second, an uncontrollable increase in heat within the Supermatter chamber will occur. This will lead to a spark-up, igniting the plasma in the Supermatter chamber, wildly increasing both pressure and temperature.

    + + While the O2-Reaction mode is dangerous, it does produce heavy amounts of energy. Consider using this mode only in short amounts to fill the SMES, and switch back later in the shift to keep things flowing normally.

    + + + Notes on Supermatter Containment and Emergency Procedures-

    + + While a constant vigil on the Supermatter is not required, regular checkups are important. Verify the temp of gas leaving the Supermatter chamber for unsafe levels, and ensure that the plasma in the chamber is at a safe concentration. Of course, also make sure the chamber is not on fire. A fire in the core chamber is very difficult to put out. As any Toxin scientist can tell you, even low amounts of plasma can burn at very high temperatures. This burning creates a huge increase in pressure and more importantly, temperature of the crystal itself.

    + + The Supermatter is strong, but not invincible. When the Supermatter is heated too much, its crystal structure will attempt to liquify. The change in atomic structure of the Supermatter leads to a single reaction, a massive explosion. The computer chip attached to the Supermatter core will warn the station when stability is threatened. It will then offer a second warning, when things have become dangerously close to total destruction of the core.

    + + Located both within the CE office and engine room is the vent control button. This button allows the Core Vent Controls to be accessed, venting the room to space. Remember however, that this process takes time. If a fire is raging, and the pressure is higher than fathomable, it will take a great deal of time to vent the room. Also located in the CE.s office is the emergency core eject button. A new core can be ordered from cargo. It is often not worth the lives of the crew to hold on to it, not to mention the structural damage. However, if by some mistake the Supermatter is pushed off or removed from the mass ejector it sits on, manual reposition will be required. Which is very dangerous and often leads to death.

    + + The Supermatter is extremely dangerous. More dangerous than people give it credit for. It can destroy you in an instant, without hesitation, reducing you to a pile of dust. When working closely with Supermatter it is.. suggested to get a genetic backup and do not wear any items of value to you. The Supermatter core can be pulled if grabbed properly by the base, but pushing is not possible.


    + + + In Closing-

    + + Remember that the Supermatter is dangerous, and the core is dangerous still. Venting the core room is always an option if you are even remotely worried, utilizing Atmospherics to properly ready the room once more for core function. It is always a good idea to check up regularly on the temperature of gas leaving the chamber, as well as the power in the system lines. Lastly, once again remember, never touch the Supermatter with anything. Ever.

    + + -Waleed Asad, Senior Engine Technician."} + /obj/item/weapon/book/manual/engineering_hacking name = "Hacking" icon_state ="bookHacking" @@ -122,7 +210,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 +278,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 +300,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 +353,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 +452,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 +916,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.
      + + + + "} diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index 27935c4f874..a3e71cd8cdd 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -21,6 +21,7 @@ obj/item/weapon/mop/proc/clean(turf/simulated/A) if(reagents.has_reagent("water", 1)) A.clean_blood() + A.dirt = 0 for(var/obj/effect/O in A) if(istype(O,/obj/effect/rune) || istype(O,/obj/effect/decal/cleanable) || istype(O,/obj/effect/overlay)) del(O) diff --git a/code/game/objects/items/weapons/paint.dm b/code/game/objects/items/weapons/paint.dm index 13fb8a9d121..5a20ac12d0c 100644 --- a/code/game/objects/items/weapons/paint.dm +++ b/code/game/objects/items/weapons/paint.dm @@ -68,7 +68,8 @@ var/global/list/cached_icons = list() paint_type = "remover" /* /obj/item/weapon/paint - name = "Paint Can" + gender= PLURAL + name = "paint" desc = "Used to recolor floors and walls. Can not be removed by the janitor." icon = 'icons/obj/items.dmi' icon_state = "paint_neutral" @@ -77,43 +78,44 @@ var/global/list/cached_icons = list() w_class = 3.0 /obj/item/weapon/paint/red - name = "Red paint" + name = "red paint" color = "FF0000" icon_state = "paint_red" /obj/item/weapon/paint/green - name = "Green paint" + name = "green paint" color = "00FF00" icon_state = "paint_green" /obj/item/weapon/paint/blue - name = "Blue paint" + name = "blue paint" color = "0000FF" icon_state = "paint_blue" /obj/item/weapon/paint/yellow - name = "Yellow paint" + name = "yellow paint" color = "FFFF00" icon_state = "paint_yellow" /obj/item/weapon/paint/violet - name = "Violet paint" + name = "violet paint" color = "FF00FF" icon_state = "paint_violet" /obj/item/weapon/paint/black - name = "Black paint" + name = "black paint" color = "333333" icon_state = "paint_black" /obj/item/weapon/paint/white - name = "White paint" + name = "white paint" color = "FFFFFF" icon_state = "paint_white" /obj/item/weapon/paint/anycolor - name = "Any color" + gender= PLURAL + name = "any color" icon_state = "paint_neutral" attack_self(mob/user as mob) @@ -156,7 +158,8 @@ var/global/list/cached_icons = list() return /obj/item/weapon/paint/paint_remover - name = "Paint remover" + gender = PLURAL + name = "paint remover" icon_state = "paint_neutral" afterattack(turf/target, mob/user as mob) diff --git a/code/game/objects/items/weapons/power_cells.dm b/code/game/objects/items/weapons/power_cells.dm index 0f0ea000ca2..1ee12faf0f9 100644 --- a/code/game/objects/items/weapons/power_cells.dm +++ b/code/game/objects/items/weapons/power_cells.dm @@ -36,7 +36,7 @@ charge = 0 /obj/item/weapon/cell/secborg - name = "\improper Security borg rechargable D battery" + name = "security borg rechargable D battery" origin_tech = "powerstorage=0" maxcharge = 600 //600 max charge / 100 charge per shot = six shots g_amt = 40 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/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 14a00b55134..acfde88e2b3 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -23,7 +23,7 @@ */ /obj/item/weapon/storage/backpack/holding - name = "Bag of Holding" + name = "bag of holding" desc = "A backpack that opens into a localized pocket of Blue Space." origin_tech = "bluespace=4" icon_state = "holdingpack" @@ -84,7 +84,7 @@ icon_state = "cultpack" /obj/item/weapon/storage/backpack/clown - name = "Giggles Von Honkerton" + name = "Giggles von Honkerton" desc = "It's a backpack made by Honk! Co." icon_state = "clownpack" item_state = "clownpack" diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm index 94d24a698e0..2219619720c 100644 --- a/code/game/objects/items/weapons/storage/bags.dm +++ b/code/game/objects/items/weapons/storage/bags.dm @@ -9,6 +9,7 @@ * Mining Satchel * Plant Bag * Sheet Snatcher + * Cash Bag * * -Sayu */ @@ -237,4 +238,19 @@ /obj/item/weapon/storage/bag/sheetsnatcher/borg name = "Sheet Snatcher 9000" desc = "" - capacity = 500//Borgs get more because >specialization \ No newline at end of file + capacity = 500//Borgs get more because >specialization + +// ----------------------------- +// Cash Bag +// ----------------------------- + +/obj/item/weapon/storage/bag/cash + icon = 'icons/obj/storage.dmi' + icon_state = "cashbag" + name = "Cash bag" + desc = "A bag for carrying lots of cash. It's got a big dollar sign printed on the front." + storage_slots = 50; //the number of cash pieces it can carry. + max_combined_w_class = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * cash.w_class + max_w_class = 3 + w_class = 1 + can_hold = list("/obj/item/weapon/coin","/obj/item/weapon/spacecash") diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm index e1ed7685934..0e3642b4aa1 100644 --- a/code/game/objects/items/weapons/storage/bible.dm +++ b/code/game/objects/items/weapons/storage/bible.dm @@ -16,8 +16,8 @@ /obj/item/weapon/storage/bible/booze/New() ..() - new /obj/item/weapon/reagent_containers/food/drinks/beer(src) - new /obj/item/weapon/reagent_containers/food/drinks/beer(src) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src) new /obj/item/weapon/spacecash(src) new /obj/item/weapon/spacecash(src) new /obj/item/weapon/spacecash(src) diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 6a4375ce7e1..91c68bd1e74 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -59,7 +59,7 @@ new /obj/item/clothing/gloves/latex(src) /obj/item/weapon/storage/box/masks - name = "sterile masks" + name = "box of sterile masks" desc = "This box contains masks of sterility." icon_state = "sterile" @@ -75,7 +75,7 @@ /obj/item/weapon/storage/box/syringes - name = "syringes" + name = "box of syringes" desc = "A box full of syringes." desc = "A biohazard alert warning is printed on the box" icon_state = "syringe" @@ -91,7 +91,7 @@ new /obj/item/weapon/reagent_containers/syringe( src ) /obj/item/weapon/storage/box/beakers - name = "beaker box" + name = "box of beakers" icon_state = "beaker" New() @@ -105,7 +105,7 @@ new /obj/item/weapon/reagent_containers/glass/beaker( src ) /obj/item/weapon/storage/box/injectors - name = "\improper DNA injectors" + name = "box of DNA injectors" desc = "This box contains injectors it seems." New() @@ -150,7 +150,7 @@ new /obj/item/weapon/grenade/flashbang(src) /obj/item/weapon/storage/box/emps - name = "emp grenades" + name = "box of emp grenades" desc = "A box with 5 emp grenades." icon_state = "flashbang" @@ -164,7 +164,7 @@ /obj/item/weapon/storage/box/trackimp - name = "tracking implant kit" + name = "boxed tracking implant kit" desc = "Box full of scum-bag tracking utensils." icon_state = "implant" @@ -179,7 +179,7 @@ new /obj/item/weapon/locator(src) /obj/item/weapon/storage/box/chemimp - name = "chemical implant kit" + name = "boxed chemical implant kit" desc = "Box of stuff used to implant chemicals." icon_state = "implant" @@ -194,8 +194,9 @@ new /obj/item/weapon/implantpad(src) + /obj/item/weapon/storage/box/rxglasses - name = "prescription glasses" + name = "box of prescription glasses" desc = "This box contains nerd glasses." icon_state = "glasses" @@ -319,7 +320,7 @@ new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/neaeracube(src) /obj/item/weapon/storage/box/ids - name = "spare IDs" + name = "box of spare IDs" desc = "Has so many empty IDs." icon_state = "id" @@ -333,8 +334,9 @@ new /obj/item/weapon/card/id(src) new /obj/item/weapon/card/id(src) + /obj/item/weapon/storage/box/seccarts - name = "Spare R.O.B.U.S.T. Cartridges" + name = "box of spare R.O.B.U.S.T. Cartridges" desc = "A box full of R.O.B.U.S.T. Cartridges, used by Security." icon_state = "pda" @@ -350,7 +352,7 @@ /obj/item/weapon/storage/box/handcuffs - name = "spare handcuffs" + name = "box of spare handcuffs" desc = "A box full of handcuffs." icon_state = "handcuff" @@ -364,8 +366,9 @@ new /obj/item/weapon/handcuffs(src) new /obj/item/weapon/handcuffs(src) + /obj/item/weapon/storage/box/mousetraps - name = "box of Pest-B-Gon Mousetraps" + name = "box of Pest-B-Gon mousetraps" desc = "WARNING:
      Keep out of reach of children." icon_state = "mousetraps" @@ -439,7 +442,7 @@ new /obj/item/weapon/reagent_containers/hypospray/autoinjector(src) /obj/item/weapon/storage/box/lights - name = "replacement bulbs" + name = "box of replacement bulbs" icon = 'icons/obj/storage.dmi' icon_state = "light" desc = "This box is shaped on the inside so that only light tubes and bulbs fit." @@ -456,7 +459,7 @@ new /obj/item/weapon/light/bulb(src) /obj/item/weapon/storage/box/lights/tubes - name = "replacement tubes" + name = "box of replacement tubes" icon_state = "lighttube" /obj/item/weapon/storage/box/lights/tubes/New() @@ -465,7 +468,7 @@ new /obj/item/weapon/light/tube(src) /obj/item/weapon/storage/box/lights/mixed - name = "replacement lights" + name = "box of replacement lights" icon_state = "lightmixed" /obj/item/weapon/storage/box/lights/mixed/New() @@ -473,4 +476,4 @@ for(var/i = 0; i < 14; i++) new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) - new /obj/item/weapon/light/bulb(src) + new /obj/item/weapon/light/bulb(src) \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index cd0b988bea7..119d2d2c22e 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -81,7 +81,7 @@ */ /obj/item/weapon/storage/fancy/candle_box - name = "Candle pack" + name = "candle pack" desc = "A pack of red candles." icon = 'icons/obj/candle.dmi' icon_state = "candlebox5" diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index e6347e8e3fc..5f4a55b93f8 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -149,7 +149,7 @@ return /obj/item/weapon/storage/pill_bottle/kelotane - name = "Pill bottle (kelotane)" + name = "bottle of kelotane pills" desc = "Contains pills used to treat burns." New() @@ -163,7 +163,7 @@ new /obj/item/weapon/reagent_containers/pill/kelotane( src ) /obj/item/weapon/storage/pill_bottle/antitox - name = "Pill bottle (Anti-toxin)" + name = "bottle of anti-toxin pills" desc = "Contains pills used to counter toxins." New() @@ -177,7 +177,7 @@ new /obj/item/weapon/reagent_containers/pill/antitox( src ) /obj/item/weapon/storage/pill_bottle/inaprovaline - name = "Pill bottle (inaprovaline)" + name = "bottle of inaprovaline pills" desc = "Contains pills used to stabilize patients." New() diff --git a/code/game/objects/items/weapons/storage/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm index ec0e17efb5b..4bc4fb5f3c9 100644 --- a/code/game/objects/items/weapons/storage/lockbox.dm +++ b/code/game/objects/items/weapons/storage/lockbox.dm @@ -67,7 +67,7 @@ /obj/item/weapon/storage/lockbox/loyalty - name = "Lockbox (Loyalty Implants)" + name = "lockbox of loyalty implants" req_access = list(access_security) New() @@ -79,7 +79,7 @@ /obj/item/weapon/storage/lockbox/clusterbang - name = "lockbox (clusterbang)" + name = "lockbox of clusterbangs" desc = "You have a bad feeling about opening this." req_access = list(access_security) diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm index c023cd247c1..8fa93d9f6ac 100644 --- a/code/game/objects/items/weapons/storage/secure.dm +++ b/code/game/objects/items/weapons/storage/secure.dm @@ -32,6 +32,12 @@ ..() usr << text("The service panel is [src.open ? "open" : "closed"].") + attack_alien(mob/user as mob) + return attack_hand(user) + + attack_paw(mob/user as mob) + return attack_hand(user) + attackby(obj/item/weapon/W as obj, mob/user as mob) if(locked) if ( (istype(W, /obj/item/weapon/card/emag)||istype(W, /obj/item/weapon/melee/energy/blade)) && (!src.emagged)) diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 646fc4d244c..ea7c9bdd902 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -69,12 +69,12 @@ return /obj/item/weapon/storage/box/syndie_kit - name = "Box" + name = "box" desc = "A sleek, sturdy box" icon_state = "box_of_doom" /obj/item/weapon/storage/box/syndie_kit/imp_freedom - name = "Freedom Implant (with injector)" + name = "boxed freedom implant (with injector)" /obj/item/weapon/storage/box/syndie_kit/imp_freedom/New() ..() @@ -100,7 +100,7 @@ return /obj/item/weapon/storage/box/syndie_kit/imp_uplink - name = "Uplink Implant (with injector)" + name = "boxed uplink implant (with injector)" /obj/item/weapon/storage/box/syndie_kit/imp_uplink/New() ..() @@ -110,7 +110,7 @@ return /obj/item/weapon/storage/box/syndie_kit/space - name = "Space Suit and Helmet" + name = "boxed space suit and helmet" /obj/item/weapon/storage/box/syndie_kit/space/New() ..() diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 2e40b1fb9af..8b9d914bc24 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -40,6 +40,7 @@ w_class = 4 playsound(user, 'sound/weapons/saberon.ogg', 50, 1) user << "\blue [src] is now active." + else force = 3 if(istype(src,/obj/item/weapon/melee/energy/sword/pirate)) @@ -49,6 +50,12 @@ w_class = 2 playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) user << "\blue [src] can now be concealed." + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + add_fingerprint(user) return @@ -137,10 +144,16 @@ w_class = 2 force = 3//not so robust now attack_verb = list("hit", "punched") + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1) add_fingerprint(user) - if(blood_overlay && (blood_DNA.len >= 1)) //updates blood overlay, if any + if(blood_overlay && (blood_DNA.len >= 1)) //updates blood overlay, if any overlays.Cut()//this might delete other item overlays as well but eeeeeeeh var/icon/I = new /icon(src.icon, src.icon_state) @@ -163,12 +176,10 @@ else user.take_organ_damage(2*force) return - - if(!..()) return - playsound(src.loc, "swing_hit", 50, 1, -1) - //target.Stun(4) //naaah - target.Weaken(4) - return + if(..()) + playsound(src.loc, "swing_hit", 50, 1, -1) + target.Weaken(4) + return else return ..() @@ -203,8 +214,6 @@ /* * Energy Axe */ -/obj/item/weapon/melee/energy/axe/attack(target as mob, mob/user as mob) - ..() /obj/item/weapon/melee/energy/axe/attack_self(mob/user as mob) src.active = !( src.active ) @@ -242,11 +251,18 @@ w_class = 4 playsound(user, 'sound/weapons/saberon.ogg', 50, 1) user << "\blue [src] is now active." + else force = 3 icon_state = "eshield[active]" w_class = 1 playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) user << "\blue [src] can now be concealed." + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + add_fingerprint(user) return \ No newline at end of file diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 143ff13a041..e0e30e60cb9 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -15,7 +15,8 @@ var/distribute_pressure = ONE_ATMOSPHERE var/integrity = 3 var/volume = 70 - + var/manipulated_by = null //Used by _onclick/hud/screen_objects.dm internals to determine if someone has messed with our tank or not. + //If they have and we haven't scanned it with the PDA or gas analyzer then we might just breath whatever they put in it. /obj/item/weapon/tank/New() ..() @@ -86,7 +87,7 @@ O << "\red [user] has used [W] on \icon[icon] [src]" var/pressure = air_contents.return_pressure() - + manipulated_by = user.real_name //This person is aware of the contents of the tank. var/total_moles = air_contents.total_moles() user << "\blue Results of analysis of \icon[icon]" @@ -261,4 +262,4 @@ integrity-- else if(integrity < 3) - integrity++ \ No newline at end of file + integrity++ diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 90da67076b2..3655effb9e6 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -354,33 +354,39 @@ /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(safety<2) + + if(E.damage > 10) + 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 +412,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/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm index b75222fcdc7..95ac7f0c949 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -12,16 +12,16 @@ New() ..() sleep(2) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) - new /obj/item/weapon/reagent_containers/food/drinks/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) + new /obj/item/weapon/reagent_containers/food/drinks/cans/beer( src ) return /obj/structure/closet/secure_closet/bar/update_icon() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm new file mode 100644 index 00000000000..8fb8b0c92cc --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm @@ -0,0 +1,53 @@ +/obj/structure/closet/secure_closet/guncabinet + name = "gun cabinet" + req_access = list(access_armory) + icon = 'icons/obj/guncabinet.dmi' + icon_state = "base" + icon_off ="base" + icon_broken ="base" + icon_locked ="base" + icon_closed ="base" + icon_opened = "base" + +/obj/structure/closet/secure_closet/guncabinet/New() + ..() + update_icon() + +/obj/structure/closet/secure_closet/guncabinet/toggle() + ..() + update_icon() + +/obj/structure/closet/secure_closet/guncabinet/update_icon() + overlays.Cut() + if(opened) + overlays += icon(icon,"door_open") + else + var/lazors = 0 + var/shottas = 0 + for (var/obj/item/weapon/gun/G in contents) + if (istype(G, /obj/item/weapon/gun/energy)) + lazors++ + if (istype(G, /obj/item/weapon/gun/projectile/)) + shottas++ + if (lazors || shottas) + for (var/i = 0 to 2) + var/image/gun = image(icon(src.icon)) + + if (lazors > 0 && (shottas <= 0 || prob(50))) + lazors-- + gun.icon_state = "laser" + else if (shottas > 0) + shottas-- + gun.icon_state = "projectile" + + gun.pixel_x = i*4 + overlays += gun + + overlays += icon(src.icon,"door") + + if(broken) + overlays += icon(src.icon,"broken") + else if (locked) + overlays += icon(src.icon,"locked") + else + overlays += icon(src.icon,"open") \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index 12d2e3fed40..eaeba38e43f 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -1,5 +1,5 @@ /obj/structure/closet/secure_closet/personal - desc = "It's a secure locker for personell. The first card swiped gains control." + desc = "It's a secure locker for personnel. The first card swiped gains control." name = "personal closet" req_access = list(access_all_personal_lockers) var/registered_name = null diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index 1dc3ca6f58f..7dc173e33be 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -39,9 +39,12 @@ new /obj/item/clothing/suit/bio_suit/scientist(src) new /obj/item/clothing/head/bio_hood/scientist(src) new /obj/item/clothing/under/rank/research_director(src) + new /obj/item/clothing/under/rank/research_director/rdalt(src) + new /obj/item/clothing/under/rank/research_director/dress_rd(src) new /obj/item/clothing/suit/storage/labcoat(src) new /obj/item/weapon/cartridge/rd(src) new /obj/item/clothing/shoes/white(src) + new /obj/item/clothing/shoes/leather(src) new /obj/item/clothing/gloves/latex(src) new /obj/item/device/radio/headset/heads/rd(src) new /obj/item/weapon/tank/air(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 011f19f198a..e44847f137b 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -247,20 +247,24 @@ ..() sleep(2) new /obj/item/clothing/under/det(src) + new /obj/item/clothing/under/det/black(src) + new /obj/item/clothing/under/det/slob(src) new /obj/item/clothing/suit/storage/det_suit(src) + new /obj/item/clothing/suit/storage/det_suit/black(src) new /obj/item/clothing/suit/storage/forensics/blue(src) new /obj/item/clothing/suit/storage/forensics/red(src) new /obj/item/clothing/gloves/black(src) new /obj/item/clothing/head/det_hat(src) + new /obj/item/clothing/head/det_hat/black(src) new /obj/item/clothing/shoes/brown(src) new /obj/item/weapon/storage/box/evidence(src) new /obj/item/device/radio/headset/headset_sec(src) new /obj/item/device/detective_scanner(src) new /obj/item/clothing/suit/armor/det_suit(src) - new /obj/item/ammo_magazine/c38(src) - new /obj/item/ammo_magazine/c38(src) + new /obj/item/ammo_magazine/c45r(src) + new /obj/item/ammo_magazine/c45r(src) new /obj/item/taperoll/police(src) - new /obj/item/weapon/gun/projectile/detective(src) + new /obj/item/weapon/gun/projectile/detective/semiauto(src) new /obj/item/clothing/tie/holster/armpit(src) return diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index d115c40ff48..28e0958206e 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -367,5 +367,6 @@ new /obj/item/clothing/shoes/green(src) new /obj/item/clothing/shoes/orange(src) new /obj/item/clothing/shoes/purple(src) + new /obj/item/clothing/shoes/red(src) new /obj/item/clothing/shoes/leather(src) return diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index a9a767b84bc..c6cf316b2bc 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -1,5 +1,5 @@ /obj/structure/displaycase - name = "Display Case" + name = "display case" icon = 'icons/obj/stationobjs.dmi' icon_state = "glassbox1" desc = "A display case for prized possessions. It taunts you to kick it." diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 6856c706341..469cacdd742 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -1,7 +1,7 @@ obj/structure/door_assembly icon = 'icons/obj/doors/door_assembly.dmi' - name = "Airlock Assembly" + name = "airlock assembly" icon_state = "door_as_0" anchored = 0 density = 1 diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index b50225838e6..286c28f37ed 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -4,6 +4,18 @@ density = 1 layer = 2 var/state = 0 + var/health = 200 + + + bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj, /obj/item/projectile/beam)) + health -= Proj.damage + ..() + if(health <= 0) + new /obj/item/stack/sheet/metal(get_turf(src)) + del(src) + + return attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/wrench) && state == 0) @@ -183,10 +195,12 @@ /obj/structure/girder/displaced icon_state = "displaced" anchored = 0 + health = 50 /obj/structure/girder/reinforced icon_state = "reinforced" state = 2 + health = 500 /obj/structure/cultgirder icon= 'icons/obj/cult.dmi' @@ -194,6 +208,7 @@ anchored = 1 density = 1 layer = 2 + var/health = 250 attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/wrench)) @@ -220,6 +235,14 @@ if(prob(40)) del(src) + bullet_act(var/obj/item/projectile/Proj) //No beam check- How else will you destroy the cult girder with silver bullets????? + health -= Proj.damage + ..() + if(health <= 0) + new /obj/item/stack/sheet/metal(get_turf(src)) + del(src) + + return ex_act(severity) switch(severity) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 04f18fe3b6a..0096d763eab 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -145,9 +145,9 @@ return var/obj/structure/window/WD if(istype(W,/obj/item/stack/sheet/rglass)) - WD = new/obj/structure/window(loc,1) //reinforced window + WD = new/obj/structure/window/reinforced(loc) //reinforced window else - WD = new/obj/structure/window(loc,0) //normal window + WD = new/obj/structure/window/basic(loc) //normal window WD.dir = dir_to_set WD.ini_dir = dir_to_set WD.anchored = 0 @@ -155,6 +155,7 @@ var/obj/item/stack/ST = W ST.use(1) user << "You place the [WD] on [src]." + WD.update_icon() return //window placing end diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 7cd52195284..eea03587634 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -159,6 +159,8 @@ return if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) return + if (!ismob(user) || user.stat || user.lying || user.stunned) + return O.loc = src.loc if (user != O) for(var/mob/B in viewers(user, 3)) @@ -373,6 +375,8 @@ return if (!ismob(O) && !istype(O, /obj/structure/closet/body_bag)) return + if (!ismob(user) || user.stat || user.lying || user.stunned) + return O.loc = src.loc if (user != O) for(var/mob/B in viewers(user, 3)) diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index 7827749fa1e..7e894c13595 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -174,3 +174,28 @@ name = "\improper HYDROPONICS" desc = "A warning sign which reads 'HYDROPONICS'" icon_state = "hydro1" + +/obj/structure/sign/directions/science + name = "\improper Science department" + desc = "A direction sign, pointing out which way Science department is." + icon_state = "direction_sci" + +/obj/structure/sign/directions/engineering + name = "\improper Engineering department" + desc = "A direction sign, pointing out which way Engineering department is." + icon_state = "direction_eng" + +/obj/structure/sign/directions/security + name = "\improper Security department" + desc = "A direction sign, pointing out which way Security department is." + icon_state = "direction_sec" + +/obj/structure/sign/directions/medical + name = "\improper Medical Bay" + desc = "A direction sign, pointing out which way Meducal Bay is." + icon_state = "direction_med" + +/obj/structure/sign/directions/evac + name = "\improper Escape Arm" + desc = "A direction sign, pointing out which way escape shuttle dock is." + icon_state = "direction_evac" diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 16c5be21a88..81c017def59 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -46,6 +46,10 @@ density = 0 del(src) +/obj/structure/rack/proc/destroy() + new parts(loc) + density = 0 + del(src) /obj/structure/table/update_icon() spawn(2) //So it properly updates when deleting @@ -423,6 +427,8 @@ set desc = "Flips a non-reinforced table" set category = "Object" set src in oview(1) + if(ismouse(usr)) + return if (!can_touch(usr)) return if(!flip(get_cardinal_dir(usr,src))) @@ -570,6 +576,7 @@ flags = FPRINT anchored = 1.0 throwpass = 1 //You can throw objects over this, despite it's density. + var/parts = /obj/item/weapon/rack_parts /obj/structure/rack/ex_act(severity) switch(severity) @@ -632,33 +639,22 @@ if(HULK in user.mutations) visible_message("[user] smashes [src] apart!") user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - new /obj/item/weapon/rack_parts(loc) - density = 0 - del(src) - + destroy() /obj/structure/rack/attack_paw(mob/user) if(HULK in user.mutations) user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) visible_message("[user] smashes [src] apart!") - new /obj/item/weapon/rack_parts(loc) - density = 0 - del(src) - + destroy() /obj/structure/rack/attack_alien(mob/user) visible_message("[user] slices [src] apart!") - new /obj/item/weapon/rack_parts(loc) - density = 0 - del(src) - + destroy() /obj/structure/rack/attack_animal(mob/living/simple_animal/user) if(user.wall_smash) visible_message("[user] smashes [src] apart!") - new /obj/item/weapon/rack_parts(loc) - density = 0 - del(src) + destroy() /obj/structure/rack/attack_tk() // no telehulk sorry 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..8126296a154 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) @@ -561,7 +571,7 @@ obj/structure/ex_act(severity) if(text in direction_table) return direction_table[text] - var/list/split_text = stringsplit(text, "-") + var/list/split_text = text2list(text, "-") // If the first token is D, the icon_state represents // a purely decorative tube, and doesn't actually diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index ab8884d96c3..0a9dc69bacd 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -153,7 +153,7 @@ if(I.type == /obj/item/device/analyzer) user << "The water temperature seems to be [watertemp]." if(istype(I, /obj/item/weapon/wrench)) - user << "You begin to adjust the temperature valve with the [I]." + user << "You begin to adjust the temperature valve with \the [I]." if(do_after(user, 50)) switch(watertemp) if("normal") @@ -162,7 +162,8 @@ watertemp = "boiling" if("boiling") watertemp = "normal" - user.visible_message("[user] adjusts the shower with the [I].", "You adjust the shower with the [I].") + user.visible_message("[user] adjusts the shower with \the [I].", "You adjust the shower with \the [I].") + add_fingerprint(user) /obj/machinery/shower/update_icon() //this is terribly unreadable, but basically it makes the shower mist up overlays.Cut() //once it's been on for a while, in addition to handling the water overlay. @@ -353,7 +354,7 @@ if (istype(O, /obj/item/weapon/reagent_containers)) var/obj/item/weapon/reagent_containers/RG = O RG.reagents.add_reagent("water", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this)) - user.visible_message("\blue [user] fills the [RG] using \the [src].","\blue You fill the [RG] using \the [src].") + user.visible_message("\blue [user] fills \the [RG] using \the [src].","\blue You fill \the [RG] using \the [src].") return else if (istype(O, /obj/item/weapon/melee/baton)) @@ -412,4 +413,4 @@ /obj/structure/sink/puddle/attackby(obj/item/O as obj, mob/user as mob) icon_state = "puddle-splash" ..() - icon_state = "puddle" \ No newline at end of file + icon_state = "puddle" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 24a9866a545..482fdea6c09 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -9,8 +9,10 @@ flags = ON_BORDER var/health = 14.0 var/ini_dir = null - var/state = 0 + var/state = 2 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() @@ -346,6 +338,7 @@ spawn(2) if(!src) return if(!is_fulltile()) + icon_state = "[basestate]" return var/junction = 0 //will be used to determine from which side the window is connected to other windows if(anchored) @@ -354,12 +347,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 +364,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/turfs/simulated.dm b/code/game/turfs/simulated.dm index 6432f1bac76..5250148688d 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -8,11 +8,18 @@ nitrogen = MOLES_N2STANDARD var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to + var/dirt = 0 /turf/simulated/New() ..() levelupdate() +/turf/simulated/proc/AddTracks(var/typepath,var/bloodDNA,var/comingdir,var/goingdir,var/bloodcolor="#A10808") + var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src + if(!tracks) + tracks = new typepath(src) + tracks.AddTracks(bloodDNA,comingdir,goingdir,bloodcolor) + /turf/simulated/Entered(atom/A, atom/OL) if(movement_disabled && usr.ckey != movement_disabled_exception) usr << "\red Movement is admin-disabled." //This is to identify lag problems @@ -20,7 +27,16 @@ if (istype(A,/mob/living/carbon)) var/mob/living/carbon/M = A - if(M.lying) return + if(M.lying) return + dirt++ + var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) + if (dirt >= 50) + if (!dirtoverlay) + dirtoverlay = new/obj/effect/decal/cleanable/dirt(src) + dirtoverlay.alpha = 15 + else if (dirt > 50) + dirtoverlay.alpha = min(dirtoverlay.alpha+5, 255) + if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M if(istype(H.shoes, /obj/item/clothing/shoes/clown_shoes)) @@ -34,30 +50,28 @@ else playsound(src, "clownstep", 20, 1) + // Tracking blood var/list/bloodDNA = null + var/bloodcolor="" if(H.shoes) var/obj/item/clothing/shoes/S = H.shoes if(S.track_blood && S.blood_DNA) bloodDNA = S.blood_DNA + bloodcolor=S.blood_color S.track_blood-- else if(H.track_blood && H.feet_blood_DNA) bloodDNA = H.feet_blood_DNA + bloodcolor=H.feet_blood_color H.track_blood-- if (bloodDNA) - var/obj/effect/decal/cleanable/blood/footprints/here = new(src) - here.icon_state = "blood1" - here.dir = H.dir - here.blood_DNA |= bloodDNA.Copy() + src.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints,bloodDNA,H.dir,0,bloodcolor) // Coming var/turf/simulated/from = get_step(H,reverse_direction(H.dir)) - if(from) - var/obj/effect/decal/cleanable/blood/footprints/there = new(from) - there.icon_state = "blood2" - there.dir = H.dir - there.blood_DNA |= bloodDNA.Copy() + if(istype(from) && from) + from.AddTracks(/obj/effect/decal/cleanable/blood/tracks/footprints,bloodDNA,0,H.dir,bloodcolor) // Going - bloodDNA = null + bloodDNA = null switch (src.wet) if(1) @@ -67,8 +81,8 @@ step(M, M.dir) M << "\blue You slipped on the wet floor!" playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) - M.Stun(8) - M.Weaken(5) + M.Stun(5) + M.Weaken(3) else M.inertia_dir = 0 return @@ -78,13 +92,13 @@ step(M, M.dir) M << "\blue You slipped on the wet floor!" playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) - M.Stun(8) - M.Weaken(5) + M.Stun(5) + M.Weaken(3) else M.inertia_dir = 0 return - if(2) //lube //can cause infinite loops - needs work + if(2) //lube //can cause infinite loops - needs work if(!istype(M, /mob/living/carbon/slime)) M.stop_pulling() step(M, M.dir) @@ -96,6 +110,29 @@ M << "\blue You slipped on the floor!" playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) M.Weaken(10) + if(3) // Ice + if(istype(M, /mob/living/carbon/human)) // Added check since monkeys don't have shoes + if ((M.m_intent == "run") && !(istype(M:shoes, /obj/item/clothing/shoes) && M:shoes.flags&NOSLIP) && prob(30)) + M.stop_pulling() + step(M, M.dir) + M << "\blue You slipped on the icy floor!" + playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) + M.Stun(4) + M.Weaken(3) + else + M.inertia_dir = 0 + return + else if(!istype(M, /mob/living/carbon/slime)) + if (M.m_intent == "run" && prob(30)) + M.stop_pulling() + step(M, M.dir) + M << "\blue You slipped on the icy floor!" + playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3) + M.Stun(4) + M.Weaken(3) + else + M.inertia_dir = 0 + return ..() @@ -107,29 +144,49 @@ for(var/obj/effect/decal/cleanable/blood/B in contents) if(!B.blood_DNA[M.dna.unique_enzymes]) B.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - if (M.virus2.len) - B.virus2 |= virus_copylist(M.virus2) return 1 //we bloodied the floor //if there isn't a blood decal already, make one. var/obj/effect/decal/cleanable/blood/newblood = new /obj/effect/decal/cleanable/blood(src) + + //Species-specific blood. + if(M.species) + newblood.basecolor = M.species.blood_color + else + newblood.basecolor = "#A10808" + newblood.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - if (M.virus2.len) - newblood.virus2 |= virus_copylist(M.virus2) + newblood.update_icon() + return 1 //we bloodied the floor // Only adds blood on the floor -- Skie /turf/simulated/proc/add_blood_floor(mob/living/carbon/M as mob) - if( istype(M, /mob/living/carbon/monkey) || istype(M, /mob/living/carbon/human)) + if(istype(M, /mob/living/carbon/monkey)) + var/obj/effect/decal/cleanable/blood/this = new /obj/effect/decal/cleanable/blood(src) this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - if (M.virus2.len) - this.virus2 = virus_copylist(M.virus2) + this.basecolor = "#A10808" + this.update_icon() + + else if(istype(M,/mob/living/carbon/human)) + + var/obj/effect/decal/cleanable/blood/this = new /obj/effect/decal/cleanable/blood(src) + var/mob/living/carbon/human/H = M + + //Species-specific blood. + if(H.species) + this.basecolor = H.species.blood_color + else + this.basecolor = "#A10808" + this.update_icon() + + this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type else if( istype(M, /mob/living/carbon/alien )) - var/obj/effect/decal/cleanable/xenoblood/this = new /obj/effect/decal/cleanable/xenoblood(src) + var/obj/effect/decal/cleanable/blood/xeno/this = new /obj/effect/decal/cleanable/blood/xeno(src) this.blood_DNA["UNKNOWN BLOOD"] = "X*" else if( istype(M, /mob/living/silicon/robot )) - new /obj/effect/decal/cleanable/oil(src) \ No newline at end of file + new /obj/effect/decal/cleanable/blood/oil(src) diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm index 201fd974ade..2e82577a4b5 100644 --- a/code/game/turfs/simulated/floor_types.dm +++ b/code/game/turfs/simulated/floor_types.dm @@ -73,7 +73,7 @@ /turf/simulated/floor/engine/n20 New() - ..() + . = ..() var/datum/gas_mixture/adding = new var/datum/gas/sleeping_agent/trace_gas = new diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index 1608a81a748..b8ff0e19916 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -42,11 +42,12 @@ msg += "Total Players: [length(Lines)]" src << msg -/client/verb/adminwho() +/client/verb/staffwho() set category = "Admin" - set name = "Adminwho" + set name = "Staffwho" var/msg = "" + var/modmsg = "" var/num_mods_online = 0 var/num_admins_online = 0 if(holder) @@ -70,7 +71,20 @@ num_admins_online++ else + modmsg += "\t[C] is a [C.holder.rank]" + + if(isobserver(C.mob)) + modmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + modmsg += " - Lobby" + else + modmsg += " - Playing" + + if(C.is_afk()) + modmsg += " (AFK)" + modmsg += "\n" num_mods_online++ + else for(var/client/C in admins) if(R_ADMIN & C.holder.rights || !(R_MOD & C.holder.rights)) @@ -78,44 +92,8 @@ msg += "\t[C] is a [C.holder.rank]\n" num_admins_online++ else + modmsg += "\t[C] is a [C.holder.rank]\n" num_mods_online++ - msg = "Current Admins ([num_admins_online]):\n" + msg - msg += "There are also [num_mods_online] moderators online. To view online moderators, type 'modwho'\n" - src << msg - -/client/verb/modwho() - set category = "Admin" - set name = "Modwho" - - var/msg = "" - var/num_admins_online = 0 - var/num_mods_online = 0 - if(holder) - for(var/client/C in admins) - if(R_ADMIN & C.holder.rights || !(R_MOD & C.holder.rights)) - num_admins_online++ - else - msg += "\t[C] is a [C.holder.rank]" - - if(isobserver(C.mob)) - msg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - msg += " - Lobby" - else - msg += " - Playing" - - if(C.is_afk()) - msg += " (AFK)" - msg += "\n" - num_mods_online++ - else - for(var/client/C in admins) - if(R_ADMIN & C.holder.rights || !(R_MOD & C.holder.rights)) - num_admins_online++ - else - msg += "\t[C] is a [C.holder.rank]\n" - - msg = "Current Moderators ([num_mods_online]):\n" + msg - msg += "There are also [num_admins_online] admins online. To view online admins, type 'adminwho'\n" - src << msg + msg = "Current Admins ([num_admins_online]):\n" + msg + "\n Current Moderators([num_mods_online]):\n" + modmsg + src << msg \ No newline at end of file diff --git a/code/global.dm b/code/global.dm index 68d1fe6aee0..9fb6de1ce71 100644 --- a/code/global.dm +++ b/code/global.dm @@ -90,6 +90,7 @@ var/datum/engine_eject/engine_eject_control = null var/host = null var/aliens_allowed = 0 var/ooc_allowed = 1 +var/dsay_allowed = 1 var/dooc_allowed = 1 var/traitor_scaling = 1 //var/goonsay_allowed = 0 diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index 83447d1a239..035b2d23096 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -58,6 +58,9 @@ var/savefile/Banlist CMinutes = (world.realtime / 10) / 60 return 1 +/hook/startup/proc/loadBans() + return LoadBans() + /proc/LoadBans() Banlist = new("data/banlist.bdb") diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index e2bf6f7be2e..3a5c7c23930 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -581,7 +581,8 @@ var/global/floorIsLava = 0 Spawn a gravitational anomaly (aka lagitational anomolag)
      Spawn wormholes
      Spawn blob
      - Trigger an Alien infestation
      + Trigger a Xenomorph infestation
      + Trigger a Cortical Borer infestation
      Spawn an Alien silently
      Trigger a Spider infestation
      Send in a space ninja
      @@ -695,7 +696,7 @@ var/global/floorIsLava = 0 /datum/admins/proc/toggleooc() set category = "Server" - set desc="Toggle dis bitch" + set desc="Globally Toggles OOC" set name="Toggle OOC" ooc_allowed = !( ooc_allowed ) if (ooc_allowed) @@ -706,6 +707,20 @@ var/global/floorIsLava = 0 message_admins("[key_name_admin(usr)] toggled OOC.", 1) feedback_add_details("admin_verb","TOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/datum/admins/proc/toggledsay() + set category = "Server" + set desc="Globally Toggles DSAY" + set name="Toggle DSAY" + dsay_allowed = !( dsay_allowed ) + if (dsay_allowed) + world << "Deadchat has been globally enabled!" + else + world << "Deadchat has been globally disabled!" + log_admin("[key_name(usr)] toggled deadchat.") + message_admins("[key_name_admin(usr)] toggled deadchat.", 1) + feedback_add_details("admin_verb","TDSAY") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc + /datum/admins/proc/toggleoocdead() set category = "Server" set desc="Toggle dis bitch" @@ -966,7 +981,11 @@ var/global/floorIsLava = 0 if(!chosen) return - new chosen(usr.loc) + if(ispath(chosen,/turf)) + var/turf/T = get_turf(usr.loc) + T.ChangeTurf(chosen) + else + new chosen(usr.loc) log_admin("[key_name(usr)] spawned [chosen] at ([usr.x],[usr.y],[usr.z])") feedback_add_details("admin_verb","SA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -1014,14 +1033,6 @@ var/global/floorIsLava = 0 message_admins("\blue [key_name_admin(usr)] toggled guests game entering [guests_allowed?"":"dis"]allowed.", 1) feedback_add_details("admin_verb","TGU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/unjobban_panel() - set name = "Unjobban Panel" - set category = "Admin" - if (src.holder) - src.holder.unjobbanpanel() - feedback_add_details("admin_verb","UJBP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - /datum/admins/proc/output_ai_laws() var/ai_number = 0 for(var/mob/living/silicon/S in mob_list) diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index e601f069c68..1c90383f40a 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -11,6 +11,10 @@ /proc/investigate_subject2file(var/subject) return file("[INVESTIGATE_DIR][subject].html") +/hook/startup/proc/resetInvestigate() + investigate_reset() + return 1 + /proc/investigate_reset() if(fdel(INVESTIGATE_DIR)) return 1 return 0 @@ -22,12 +26,12 @@ F << "[time2text(world.timeofday,"hh:mm")] \ref[src] ([x],[y],[z]) || [src] [message]
      " //ADMINVERBS -/client/proc/investigate_show( subject in list("hrefs","notes","singulo") ) +/client/proc/investigate_show( subject in list("hrefs","notes","singulo","telesci") ) set name = "Investigate" set category = "Admin" if(!holder) return switch(subject) - if("singulo") //general one-round-only stuff + if("singulo", "telesci") //general one-round-only stuff var/F = investigate_subject2file(subject) if(!F) src << "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed." diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 115fafba82d..86624e0bd2e 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -53,6 +53,10 @@ var/list/admin_ranks = list() //list of all ranks with associated rights #endif +/hook/startup/proc/loadAdmins() + load_admins() + return 1 + /proc/load_admins() //clear the datums references admin_datums.Cut() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index dd330ec00c0..664b70bcff2 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -55,6 +55,7 @@ var/list/admin_verbs_admin = list( /client/proc/secrets, /datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/ /datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/ + /datum/admins/proc/toggledsay, /*toggles dsay on/off for everyone*/ /client/proc/game_panel, /*game panel, allows to change game-mode etc*/ /client/proc/cmd_admin_say, /*admin-only ooc chat*/ /datum/admins/proc/PlayerNotes, @@ -65,17 +66,19 @@ var/list/admin_verbs_admin = list( /client/proc/cmd_admin_rejuvenate, /client/proc/toggleattacklogs, /client/proc/toggledebuglogs, + /client/proc/toggleghostwriters, /datum/admins/proc/show_skills, /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/toggle_antagHUD_use, + /client/proc/toggle_antagHUD_restrictions, + /client/proc/allow_character_respawn /* Allows a ghost to respawn */ ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, - /client/proc/jobbans, - /client/proc/unjobban_panel, - // /client/proc/DB_ban_panel + /client/proc/jobbans ) var/list/admin_verbs_sounds = list( /client/proc/play_local_sound, @@ -127,6 +130,7 @@ var/list/admin_verbs_debug = list( /client/proc/cmd_admin_list_open_jobs, /client/proc/Debug2, /client/proc/kill_air, + /client/proc/ZASSettings, /client/proc/cmd_debug_make_powernets, /client/proc/kill_airgroup, /client/proc/debug_controller, @@ -139,7 +143,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, @@ -356,14 +362,11 @@ var/list/admin_verbs_mod = list( if(mob.invisibility == INVISIBILITY_OBSERVER) mob.invisibility = initial(mob.invisibility) mob << "\red Invisimin off. Invisibility reset." - mob.icon_state = "ghost" - mob.icon = 'icons/mob/human.dmi' - mob.update_icons() + mob.alpha = max(mob.alpha + 100, 255) else mob.invisibility = INVISIBILITY_OBSERVER mob << "\blue Invisimin on. You are now as invisible as a ghost." - mob.icon_state = "ghost" - mob.icon = 'icons/mob/mob.dmi' + mob.alpha = max(mob.alpha - 100, 0) /client/proc/player_panel() @@ -724,6 +727,21 @@ var/list/admin_verbs_mod = list( usr << "You now won't get attack log messages" +/client/proc/toggleghostwriters() + set name = "Toggle ghost writers" + set category = "Server" + if(!holder) return + if(config) + if(config.cult_ghostwriter) + config.cult_ghostwriter = 0 + src << "Disallowed ghost writers." + message_admins("Admin [key_name_admin(usr)] has disabled ghost writers.", 1) + else + config.cult_ghostwriter = 1 + src << "Enabled ghost writers." + message_admins("Admin [key_name_admin(usr)] has enabled ghost writers.", 1) + + /client/proc/toggledebuglogs() set name = "Toggle Debug Log Messages" set category = "Preferences" diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index b6d1ea53b65..42326711d35 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -50,6 +50,10 @@ DEBUG jobban_loadbanfile() */ +/hook/startup/proc/loadJobBans() + jobban_loadbanfile() + return 1 + /proc/jobban_loadbanfile() if(config.ban_legacy_system) var/savefile/S=new("data/job_full.ban") @@ -101,15 +105,6 @@ DEBUG text2file(formatted_log,"data/ban_unban_log.txt") -/proc/jobban_updatelegacybans() - if(!jobban_runonce) - log_admin("Updating jobbanfile!") - // Updates bans.. Or fixes them. Either way. - for(var/T in jobban_keylist) - if(!T) continue - jobban_runonce++ //don't run this update again - - /proc/jobban_remove(X) for (var/i = 1; i <= length(jobban_keylist); i++) if( findtext(jobban_keylist[i], "[X]") ) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 6e642d8aca7..a723fe37956 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -2,7 +2,7 @@ /datum/admins/proc/create_mob(var/mob/user) if (!create_mob_html) var/mobjs = null - mobjs = dd_list2text(typesof(/mob), ";") + mobjs = list2text(typesof(/mob), ";") create_mob_html = file2text('html/create_object.html') create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"") diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm index 73e7cef9199..5b5f926e4b1 100644 --- a/code/modules/admin/create_object.dm +++ b/code/modules/admin/create_object.dm @@ -3,7 +3,7 @@ /datum/admins/proc/create_object(var/mob/user) if (!create_object_html) var/objectjs = null - objectjs = dd_list2text(typesof(/obj), ";") + objectjs = list2text(typesof(/obj), ";") create_object_html = file2text('html/create_object.html') create_object_html = replacetext(create_object_html, "null /* object types */", "\"[objectjs]\"") @@ -21,7 +21,7 @@ if (!quick_create_object_html) var/objectjs = null - objectjs = dd_list2text(typesof(path), ";") + objectjs = list2text(typesof(path), ";") quick_create_object_html = file2text('html/create_object.html') quick_create_object_html = replacetext(quick_create_object_html, "null /* object types */", "\"[objectjs]\"") diff --git a/code/modules/admin/create_turf.dm b/code/modules/admin/create_turf.dm index 56f719b47d1..0938b7bd33d 100644 --- a/code/modules/admin/create_turf.dm +++ b/code/modules/admin/create_turf.dm @@ -2,7 +2,7 @@ /datum/admins/proc/create_turf(var/mob/user) if (!create_turf_html) var/turfjs = null - turfjs = dd_list2text(typesof(/turf), ";") + turfjs = list2text(typesof(/turf), ";") create_turf_html = file2text('html/create_object.html') create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"") diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 1b55ca6b039..87ed4787058 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -479,7 +479,6 @@ dat += "Show Objective" dat += "" - /* if(ticker.mode.ninjas.len > 0) dat += "
      " for(var/datum/mind/ninja in ticker.mode.ninjas) @@ -491,7 +490,6 @@ else dat += "" dat += "
      Ninjas
      Ninja not found!
      " - */ if(ticker.mode.cult.len) dat += "
      " diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 6f25d8b05a1..e5a8c3ae86a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -511,17 +511,17 @@ jobs += "" counter = 0 - if(jobban_isbanned(M, "Internal Affairs Agent")) + if(jobban_isbanned(M, "Internal Affairs Agent")) jobs += "" else - jobs += "" + jobs += "" jobs += "
      Cultists
      Internal Affairs AgentInternal Affairs AgentInternal Affairs Agent
      " //Non-Human (Green) counter = 0 jobs += "" - jobs += "" + jobs += "" for(var/jobPos in nonhuman_positions) if(!jobPos) continue var/datum/job/job = job_master.GetJob(jobPos) @@ -539,11 +539,15 @@ counter = 0 //pAI isn't technically a job, but it goes in here. + if(jobban_isbanned(M, "pAI")) jobs += "" else jobs += "" - + if(jobban_isbanned(M, "AntagHUD")) + jobs += "" + else + jobs += "" jobs += "
      Non-human Positions
      Non-human Positions
      pAIpAIAntagHUDAntagHUD
      " //Antagonist (Orange) @@ -614,11 +618,24 @@ else jobs += "[replacetext("Infested Monkey", " ", " ")]" */ + jobs += "" + //Other races (BLUE, because I have no idea what other color to make this) + jobs += "" + jobs += "" + + if(jobban_isbanned(M, "Dionaea")) + jobs += "" + else + jobs += "" + + jobs += "
      Other Races
      DionaeaDionaea
      " + + body = "[jobs]" dat = "[header][body]" - usr << browse(dat, "window=jobban2;size=800x450") + usr << browse(dat, "window=jobban2;size=800x490") return //JOBBAN'S INNARDS @@ -787,7 +804,11 @@ if (ismob(M)) if(!check_if_greater_rights_than(M.client)) return - M << "\red You have been kicked from the server" + var/reason = input("Please enter reason") + if(!reason) + M << "\red You have been kicked from the server" + else + M << "\red You have been kicked from the server: [reason]" log_admin("[key_name(usr)] booted [key_name(M)].") message_admins("\blue [key_name_admin(usr)] booted [key_name_admin(M)].", 1) //M.client = null @@ -887,19 +908,6 @@ if("Cancel") return - else if(href_list["unjobbanf"]) - if(!check_rights(R_BAN)) return - - var/banfolder = href_list["unjobbanf"] - Banlist.cd = "/base/[banfolder]" - var/key = Banlist["key"] - if(alert(usr, "Are you sure you want to unban [key]?", "Confirmation", "Yes", "No") == "Yes") - if (RemoveBanjob(banfolder)) - unjobbanpanel() - else - alert(usr,"This ban has already been lifted / does not exist.","Error","Ok") - unjobbanpanel() - else if(href_list["mute"]) if(!check_rights(R_MOD,0) && !check_rights(R_ADMIN)) return @@ -1598,7 +1606,7 @@ alert("Select fewer object types, (max 5)") return else if(length(removed_paths)) - alert("Removed:\n" + dd_list2text(removed_paths, "\n")) + alert("Removed:\n" + list2text(removed_paths, "\n")) var/list/offset = text2list(href_list["offset"],",") var/number = dd_range(1, 100, text2num(href_list["object_count"])) @@ -1769,7 +1777,12 @@ log_admin("[key_name(usr)] spawned an alien infestation", 1) message_admins("\blue [key_name_admin(usr)] attempted an alien infestation", 1) new /datum/event/alien_infestation - + if("borers") + feedback_inc("admin_secrets_fun_used",1) + feedback_add_details("admin_secrets_fun_used","Borers") + log_admin("[key_name(usr)] spawned a cortical borer infestation.", 1) + message_admins("\blue [key_name_admin(usr)] spawned a cortical borer infestation.", 1) + new /datum/event/borer_infestation if("power") feedback_inc("admin_secrets_fun_used",1) 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/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index d6ff60c2a2f..8e3f5e29bbc 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -55,7 +55,7 @@ //get message text, limit it's length.and clean/escape html if(!msg) - msg = input(src,"Message:", "Private message to [C.key]") as text|null + msg = input(src,"Message:", "Private message to [key_name(C, 0, holder ? 1 : 0)]") as text|null if(!msg) return if(!C) @@ -80,10 +80,10 @@ //mod PMs are maroon //PMs sent from admins and mods display their rank if(holder) - if( holder.rights & R_MOD ) - recieve_color = "maroon" - else + if( holder.rights & R_ADMIN ) recieve_color = "red" + else + recieve_color = "maroon" send_pm_type = holder.rank + " " recieve_pm_type = holder.rank diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 3d9ab9dffee..086baa5877b 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -10,7 +10,7 @@ log_admin("[key_name(src)] : [msg]") if(check_rights(R_ADMIN,0)) - msg = "ADMIN: [key_name(usr, 1)] (JMP): [msg]" + msg = "ADMIN: [key_name(usr, 1)] (JMP): [msg]" for(var/client/C in admins) if(R_ADMIN & C.holder.rights) C << msg diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 0659622f6a0..241c34d5d89 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -975,14 +975,14 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that switch(input("Which list?") in list("Players","Admins","Mobs","Living Mobs","Dead Mobs", "Clients")) if("Players") - usr << dd_list2text(player_list,",") + usr << list2text(player_list,",") if("Admins") - usr << dd_list2text(admins,",") + usr << list2text(admins,",") if("Mobs") - usr << dd_list2text(mob_list,",") + usr << list2text(mob_list,",") if("Living Mobs") - usr << dd_list2text(living_mob_list,",") + usr << list2text(living_mob_list,",") if("Dead Mobs") - usr << dd_list2text(dead_mob_list,",") + usr << list2text(dead_mob_list,",") if("Clients") - usr << dd_list2text(clients,",") + usr << list2text(clients,",") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 2f1178dfbae..871567cc0ad 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -221,6 +221,128 @@ 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/get_ghosts(var/notify = 0,var/what = 2) + // what = 1, return ghosts ass list. + // what = 2, return mob list + + var/list/mobs = list() + var/list/ghosts = list() + var/list/sortmob = sortAtom(mob_list) // get the mob list. + /var/any=0 + 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) + if(notify) + 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 + if(what==1) + return ghosts + else + return mobs + + +/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 or allow them to re-enter their corpse." + if(!holder) + src << "Only administrators may use this command." + var/list/ghosts= get_ghosts(1,1) + + 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/dead/observer/G = ghosts[target] + if(G.has_enabled_antagHUD && config.antag_hud_restricted) + var/response = alert(src, "Are you sure you wish to allow this individual to play?","Ghost has used AntagHUD","Yes","No") + if(response == "No") return + G.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. + */ + G.has_enabled_antagHUD = 2 + G.can_reenter_corpse = 1 + + G: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(G)] to bypass the 30 minute respawn limit") + message_admins("Admin [key_name_admin(usr)] allowed [key_name_admin(G)] to bypass the 30 minute respawn limit", 1) + + +/client/proc/toggle_antagHUD_use() + set category = "Server" + set name = "Toggle antagHUD usage" + set desc = "Toggles antagHUD usage for observers" + + if(!holder) + src << "Only administrators may use this command." + var/action="" + if(config.antag_hud_allowed) + for(var/mob/dead/observer/g in get_ghosts()) + if(!g.client.holder) //Remove the verb from non-admin ghosts + g.verbs -= /mob/dead/observer/verb/toggle_antagHUD + if(g.antagHUD) + g.antagHUD = 0 // Disable it on those that have it enabled + g.has_enabled_antagHUD = 2 // We'll allow them to respawn + g << "\red The Administrator has disabled AntagHUD " + config.antag_hud_allowed = 0 + src << "\red AntagHUD usage has been disabled" + action = "disabled" + else + for(var/mob/dead/observer/g in get_ghosts()) + if(!g.client.holder) // Add the verb back for all non-admin ghosts + g.verbs += /mob/dead/observer/verb/toggle_antagHUD + g << "\blue The Administrator has enabled AntagHUD " // Notify all observers they can now use AntagHUD + config.antag_hud_allowed = 1 + action = "enabled" + src << "\blue AntagHUD usage has been enabled" + + + log_admin("[key_name(usr)] has [action] antagHUD usage for observers") + message_admins("Admin [key_name_admin(usr)] has [action] antagHUD usage for observers", 1) + + + +/client/proc/toggle_antagHUD_restrictions() + set category = "Server" + set name = "Toggle antagHUD Restrictions" + set desc = "Restricts players that have used antagHUD from being able to join this round." + if(!holder) + src << "Only administrators may use this command." + var/action="" + if(config.antag_hud_restricted) + for(var/mob/dead/observer/g in get_ghosts()) + g << "\blue The administrator has lifted restrictions on joining the round if you use AntagHUD" + action = "lifted restrictions" + config.antag_hud_restricted = 0 + src << "\blue AntagHUD restrictions have been lifted" + else + for(var/mob/dead/observer/g in get_ghosts()) + g << "\red The administrator has placed restrictions on joining the round if you use AntagHUD" + g << "\red Your AntagHUD has been disabled, you may choose to re-enabled it but will be under restrictions " + g.antagHUD = 0 + g.has_enabled_antagHUD = 0 + action = "placed restrictions" + config.antag_hud_restricted = 1 + src << "\red AntagHUD restrictions have been enabled" + + log_admin("[key_name(usr)] has [action] on joining the round if they use AntagHUD") + message_admins("Admin [key_name_admin(usr)] has [action] on joining the round if they use AntagHUD", 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. @@ -325,9 +447,9 @@ Traitors and the like can also be revived with the previous role mostly intact. if(record_found)//Pull up their name from database records if they did have a mind. new_character.dna = new()//Let's first give them a new DNA. new_character.dna.unique_enzymes = record_found.fields["b_dna"]//Enzymes are based on real name but we'll use the record for conformity. - new_character.dna.struc_enzymes = record_found.fields["enzymes"]//This is the default of enzymes so I think it's safe to go with. - new_character.dna.uni_identity = record_found.fields["identity"]//DNA identity is carried over. - updateappearance(new_character,new_character.dna.uni_identity)//Now we configure their appearance based on their unique identity, same as with a DNA machine or somesuch. + new_character.dna.SE = record_found.fields["enzymes"]//This is the default of enzymes so I think it's safe to go with. + new_character.dna.UpdateSE() + new_character.UpdateAppearance(record_found.fields["identity"])//Now we configure their appearance based on their unique identity, same as with a DNA machine or somesuch. else//If they have no records, we just do a random DNA for them, based on their random appearance/savefile. new_character.dna.ready_dna(new_character) diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm index 8ea48ea4898..92de9fff491 100644 --- a/code/modules/admin/verbs/striketeam.dm +++ b/code/modules/admin/verbs/striketeam.dm @@ -124,7 +124,7 @@ var/global/sent_strike_team = 0 /mob/living/carbon/human/proc/equip_death_commando(leader_selected = 0) var/obj/item/device/radio/R = new /obj/item/device/radio/headset(src) - R.set_frequency(1441) + R.set_frequency(1341) equip_to_slot_or_del(R, slot_l_ear) if (leader_selected == 0) equip_to_slot_or_del(new /obj/item/clothing/under/color/green(src), slot_w_uniform) diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 4d2c8fa53b9..5cea63edaea 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -45,6 +45,7 @@ visible_message("\red SPLAT!") M.splat() playsound(target.loc, 'sound/effects/snap.ogg', 50, 1) + layer = MOB_LAYER - 0.2 armed = 0 update_icon() pulse(0) @@ -112,4 +113,16 @@ /obj/item/device/assembly/mousetrap/armed icon_state = "mousetraparmed" - armed = 1 \ No newline at end of file + armed = 1 + + +/obj/item/device/assembly/mousetrap/verb/hide_under() + set src in oview(1) + set name = "Hide" + set category = "Object" + + if(usr.stat) + return + + layer = TURF_LAYER+0.2 + usr << "You hide [src]." \ No newline at end of file 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..cd63e415a44 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -251,14 +251,21 @@ 'nano/css/icons.css', 'nano/templates/chem_dispenser.tmpl', 'nano/templates/cryo.tmpl', + 'nano/templates/geoscanner.tmpl', 'nano/templates/dna_modifier.tmpl', + 'nano/templates/telescience_console.tmpl', + 'nano/templates/pda.tmpl', + 'nano/templates/smes.tmpl', + 'nano/templates/uplink.tmpl', 'nano/images/uiBackground.png', 'nano/images/uiIcons16.png', 'nano/images/uiIcons24.png', + 'nano/images/uiBackground-Syndicate.png', 'nano/images/uiLinkPendingIcon.gif', 'nano/images/uiMaskBackground.png', 'nano/images/uiNoticeBackground.jpg', 'nano/images/uiTitleFluff.png', + 'nano/images/uiTitleFluff-Syndicate.png', 'html/search.js', 'html/panels.css', 'icons/pda_icons/pda_atmos.png', @@ -298,9 +305,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 74116852a02..e1b0d29b2a8 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -44,6 +44,8 @@ datum/preferences var/be_special = 0 //Special role selection var/UI_style = "Midnight" var/toggles = TOGGLES_DEFAULT + var/UI_style_color = "#ffffff" + var/UI_style_alpha = 255 //character preferences var/real_name //our character's name @@ -243,10 +245,14 @@ datum/preferences dat += "
      " dat += "UI Style: [UI_style]
      " + dat += "Custom UI(recommended for White UI):
      " + dat += "-Color: [UI_style_color]
      __

      " + dat += "-Alpha(transparence): [UI_style_alpha]
      " dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"]
      " dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"]
      " dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
      " dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
      " + dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "Nearest Speakers" : "All Chatter"]
      " if(config.allow_Metadata) dat += "OOC Notes: Edit
      " @@ -264,6 +270,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 @@ -288,6 +295,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 @@ -299,6 +310,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 @@ -1087,6 +1116,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 @@ -1111,9 +1162,21 @@ datum/preferences UI_style = "Orange" if("Orange") UI_style = "old" + if("old") + UI_style = "White" else UI_style = "Midnight" + if("UIcolor") + var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!") as color|null + if(!UI_style_color_new) return + UI_style_color = UI_style_color_new + + if("UIalpha") + var/UI_style_alpha_new = input(user, "Select a new alpha(transparence) parametr for UI, between 50 and 255") as num + if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return + UI_style_alpha = UI_style_alpha_new + if("be_special") var/num = text2num(href_list["num"]) be_special ^= (1< 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/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index ae44fd6600b..a1a928f5916 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -1,5 +1,5 @@ #define SAVEFILE_VERSION_MIN 8 -#define SAVEFILE_VERSION_MAX 10 +#define SAVEFILE_VERSION_MAX 11 //handles converting savefiles to new formats //MAKE SURE YOU KEEP THIS UP TO DATE! @@ -54,14 +54,18 @@ S["be_special"] >> be_special S["default_slot"] >> default_slot S["toggles"] >> toggles + S["UI_style_color"] >> UI_style_color + S["UI_style_alpha"] >> UI_style_alpha //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) - UI_style = sanitize_inlist(UI_style, list("Midnight","Orange","old"), initial(UI_style)) + UI_style = sanitize_inlist(UI_style, list("White", "Midnight","Orange","old"), initial(UI_style)) be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) default_slot = sanitize_integer(default_slot, 1, MAX_SAVE_SLOTS, initial(default_slot)) toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) + UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color)) + UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha)) return 1 @@ -80,6 +84,8 @@ S["be_special"] << be_special S["default_slot"] << default_slot S["toggles"] << toggles + S["UI_style_color"] << UI_style_color + S["UI_style_alpha"] << UI_style_alpha return 1 diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index e59546a470f..326921c1f6a 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -17,14 +17,23 @@ prefs.save_preferences() feedback_add_details("admin_verb","TGS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/verb/toggle_ghost_radio() + set name = "Enable/Disable GhostRadio" + set category = "Preferences" + set desc = ".Toggle between hearing all radio chatter, or only from nearby speakers" + prefs.toggles ^= CHAT_GHOSTRADIO + src << "As a ghost, you will now [(prefs.toggles & CHAT_GHOSTRADIO) ? "hear all radio chat in the world" : "only hear from nearby speakers"]." + prefs.save_preferences() + feedback_add_details("admin_verb","TGR") + /client/proc/toggle_hear_radio() set name = "Show/Hide RadioChatter" set category = "Preferences" - set desc = "Toggle seeing radiochatter from nearby radios and speakers" + set desc = "Toggle seeing radiochatter from radios and speakers" if(!holder) return prefs.toggles ^= CHAT_RADIO prefs.save_preferences() - usr << "You will [(prefs.toggles & CHAT_RADIO) ? "now" : "no longer"] see radio chatter from nearby radios or speakers" + usr << "You will [(prefs.toggles & CHAT_RADIO) ? "now" : "no longer"] see radio chatter from radios or speakers" feedback_add_details("admin_verb","THR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/toggleadminhelpsound() @@ -107,10 +116,12 @@ set desc = "Toggles seeing Local OutOfCharacter chat" prefs.toggles ^= CHAT_LOOC prefs.save_preferences() + src << "You will [(prefs.toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel." feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + /client/verb/Toggle_Soundscape() //All new ambience should be added here so it works with this verb until someone better at things comes up with a fix that isn't awful set name = "Hear/Silence Ambience" set category = "Preferences" @@ -135,4 +146,42 @@ prefs.be_special ^= role_flag prefs.save_preferences() src << "You will [(prefs.be_special & role_flag) ? "now" : "no longer"] be considered for [role] events (where possible)." - feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! \ No newline at end of file + feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + + +/client/verb/change_ui() + set name = "Change UI" + set category = "Preferences" + set desc = "Configure your user interface" + + if(!ishuman(usr)) + usr << "This only for human" + return + + var/UI_style_new = input(usr, "Select a style, we recommend White for customization") in list("White", "Midnight", "Orange", "old") + if(!UI_style_new) return + + var/UI_style_alpha_new = input(usr, "Select a new alpha(transparence) parametr for UI, between 50 and 255") as num + if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return + + var/UI_style_color_new = input(usr, "Choose your UI color, dark colors are not recommended!") as color|null + if(!UI_style_color_new) return + + //update UI + var/list/icons = usr.hud_used.adding + usr.hud_used.other +usr.hud_used.hotkeybuttons + icons.Add(usr.zone_sel) + + for(var/obj/screen/I in icons) + if(I.color && I.alpha) + I.icon = ui_style2icon(UI_style_new) + I.color = UI_style_color_new + I.alpha = UI_style_alpha_new + + + + if(alert("Like it? Save changes?",,"Yes", "No") == "Yes") + prefs.UI_style = UI_style_new + prefs.UI_style_alpha = UI_style_alpha_new + prefs.UI_style_color = UI_style_color_new + prefs.save_preferences() + usr << "UI was saved" \ No newline at end of file diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 3e40aeb5d5f..7d734339bb4 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -28,7 +28,7 @@ return ..() -//Ears: currently only used for headsets and earmuffs +//Ears: headsets, earmuffs and tiny objects /obj/item/clothing/ears name = "ears" w_class = 1.0 diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index e3fff70f366..aedb20c70d6 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -73,6 +73,12 @@ holder.icon_state = "hudxeno" else if(foundVirus) holder.icon_state = "hudill" + else if(patient.has_brain_worms()) + var/mob/living/simple_animal/borer/B = patient.has_brain_worms() + if(B.controlling) + holder.icon_state = "hudbrainworm" + else + holder.icon_state = "hudhealthy" else holder.icon_state = "hudhealthy" C.images += holder diff --git a/code/modules/clothing/gloves/ninja.dm b/code/modules/clothing/gloves/ninja.dm index 15e7c40c3b3..a3cb36e8b6a 100644 --- a/code/modules/clothing/gloves/ninja.dm +++ b/code/modules/clothing/gloves/ninja.dm @@ -19,6 +19,7 @@ var/candrain = 0 var/mindrain = 200 var/maxdrain = 400 + species_restricted = null /* This runs the gamut of what ninja gloves can do diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index 9391bc85a51..65f265f23f4 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -1,6 +1,6 @@ /obj/item/clothing/head/soft name = "cargo cap" - desc = "It's a baseball hat in a tasteless yellow colour." + desc = "It's a baseball hat in a tasteless yellow color." icon_state = "cargosoft" flags = FPRINT|TABLEPASS|HEADCOVERSEYES item_state = "helmet" @@ -29,49 +29,49 @@ /obj/item/clothing/head/soft/red name = "red cap" - desc = "It's a baseball hat in a tasteless red colour." + desc = "It's a baseball hat in a tasteless red color." icon_state = "redsoft" item_color = "red" /obj/item/clothing/head/soft/blue name = "blue cap" - desc = "It's a baseball hat in a tasteless blue colour." + desc = "It's a baseball hat in a tasteless blue color." icon_state = "bluesoft" item_color = "blue" /obj/item/clothing/head/soft/green name = "green cap" - desc = "It's a baseball hat in a tasteless green colour." + desc = "It's a baseball hat in a tasteless green color." icon_state = "greensoft" item_color = "green" /obj/item/clothing/head/soft/yellow name = "yellow cap" - desc = "It's a baseball hat in a tasteless yellow colour." + desc = "It's a baseball hat in a tasteless yellow color." icon_state = "yellowsoft" item_color = "yellow" /obj/item/clothing/head/soft/grey name = "grey cap" - desc = "It's a baseball hat in a tasteful grey colour." + desc = "It's a baseball hat in a tasteful grey color." icon_state = "greysoft" item_color = "grey" /obj/item/clothing/head/soft/orange name = "orange cap" - desc = "It's a baseball hat in a tasteless orange colour." + desc = "It's a baseball hat in a tasteless orange color." icon_state = "orangesoft" item_color = "orange" /obj/item/clothing/head/soft/mime name = "white cap" - desc = "It's a baseball hat in a tasteless white colour." + desc = "It's a baseball hat in a tasteless white color." icon_state = "mimesoft" item_color = "mime" /obj/item/clothing/head/soft/purple name = "purple cap" - desc = "It's a baseball hat in a tasteless purple colour." + desc = "It's a baseball hat in a tasteless purple color." icon_state = "purplesoft" item_color = "purple" @@ -83,12 +83,12 @@ /obj/item/clothing/head/soft/sec name = "security cap" - desc = "It's baseball hat in tasteful red colour." + desc = "It's baseball hat in tasteful red color." icon_state = "secsoft" item_color = "sec" /obj/item/clothing/head/soft/sec/corp name = "corporate security cap" - desc = "It's baseball hat in corpotate colours." + desc = "It's baseball hat in corporate colors." icon_state = "corpsoft" - item_color = "corp" \ No newline at end of file + item_color = "corp" diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 5e326335973..379ef4cb6bc 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -129,7 +129,7 @@ /obj/item/clothing/shoes/swimmingfins desc = "Help you swim good." name = "swimming fins" - icon_state = "flippers" + icon_state = "flipperfeet" flags = NOSLIP slowdown = SHOES_SLOWDOWN+1 species_restricted = null diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm index a6cdefafc4c..f09f3b14e65 100644 --- a/code/modules/clothing/spacesuits/alien.dm +++ b/code/modules/clothing/spacesuits/alien.dm @@ -213,4 +213,50 @@ examine() set src in view() - ..() \ No newline at end of file + ..() + +//Species-specific Syndicate rigs. + +/obj/item/clothing/head/helmet/space/rig/syndi/tajara + icon_state = "rig0-syndie-taj" + item_state = "syndie_helm" + item_color = "syndie-taj" + species_restricted = list("Tajaran") + +/obj/item/clothing/suit/space/rig/syndi/tajara + item_state = "syndie_hardsuit" + icon_state = "rig-syndie-taj" + species_restricted = list("Tajaran") + +/obj/item/clothing/head/helmet/space/rig/syndi/unathi + icon_state = "rig0-syndie-unathi" + item_state = "syndie_helm" + item_color = "syndie-unathi" + species_restricted = list("Unathi") + +/obj/item/clothing/suit/space/rig/syndi/unathi + item_state = "syndie_hardsuit" + icon_state = "rig-syndie-unathi" + species_restricted = list("Unathi") + +/obj/item/clothing/head/helmet/space/rig/syndi/skrell + icon_state = "rig0-syndie-skrell" + item_state = "syndie_helm" + item_color = "syndie-skrell" + species_restricted = list("Skrell") + +/obj/item/clothing/suit/space/rig/syndi/skrell + item_state = "syndie_hardsuit" + icon_state = "rig-syndie-skrell" + species_restricted = list("Skrell") + +/obj/item/clothing/head/helmet/space/rig/syndi/human + icon_state = "rig0-syndie-human" + item_state = "syndie_helm" + item_color = "syndie-human" + species_restricted = list("Human") + +/obj/item/clothing/suit/space/rig/syndi/human + item_state = "syndie_hardsuit" + icon_state = "rig-syndie-human" + species_restricted = list("Human") diff --git a/code/modules/clothing/spacesuits/ninja.dm b/code/modules/clothing/spacesuits/ninja.dm index 8f49738fbfe..c146bb21a50 100644 --- a/code/modules/clothing/spacesuits/ninja.dm +++ b/code/modules/clothing/spacesuits/ninja.dm @@ -6,17 +6,18 @@ allowed = list(/obj/item/weapon/cell) armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 25) siemens_coefficient = 0.2 - + species_restricted = null /obj/item/clothing/suit/space/space_ninja name = "ninja suit" desc = "A unique, vaccum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins." icon_state = "s-ninja" item_state = "s-ninja_suit" - allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/cell) + allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank,/obj/item/weapon/cell) slowdown = 0 armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30) siemens_coefficient = 0.2 + species_restricted = null //Workaround for spawning alien ninja without internals. //Important parts of the suit. var/mob/living/carbon/affecting = null//The wearer. diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm index 027a2e3a574..cec9f6ff394 100644 --- a/code/modules/clothing/spacesuits/rig.dm +++ b/code/modules/clothing/spacesuits/rig.dm @@ -25,6 +25,10 @@ if(on) user.SetLuminosity(user.luminosity + brightness_on) else user.SetLuminosity(user.luminosity - brightness_on) + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_head() + pickup(mob/user) if(on) user.SetLuminosity(user.luminosity + brightness_on) @@ -90,7 +94,7 @@ armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 35, bio = 100, rad = 60) siemens_coefficient = 0.6 var/obj/machinery/camera/camera - + species_restricted = list("exclude","Vox") /obj/item/clothing/head/helmet/space/rig/syndi/attack_self(mob/user) if(camera) ..(user) @@ -116,6 +120,7 @@ armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 60) allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs) siemens_coefficient = 0.6 + species_restricted = list("exclude","Vox") //Wizard Rig @@ -179,7 +184,7 @@ //Atmospherics Rig (BS12) /obj/item/clothing/head/helmet/space/rig/atmos - desc = "A special helmet designed for work in a hazardou, low pressure environments. Has reduced radiation shielding and protective plating to allow for greater mobility." + desc = "A special helmet designed for work in a hazardous, low pressure environments. Has reduced radiation shielding and protective plating to allow for greater mobility." name = "atmospherics hardsuit helmet" icon_state = "rig0-atmos" item_state = "atmos_helm" diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index fd525eacdb5..f3c960cc3d0 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -77,6 +77,9 @@ allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/lighter,/obj/item/device/detective_scanner,/obj/item/device/taperecorder) armor = list(melee = 50, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0) +/obj/item/clothing/suit/storage/det_suit/black + icon_state = "detective2" + //Forensics /obj/item/clothing/suit/storage/forensics name = "jacket" diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index 0869d85b39e..6b54fbf80b2 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -5,7 +5,7 @@ item_state = "labcoat" blood_overlay_type = "coat" body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS - allowed = list(/obj/item/device/analyzer,/obj/item/stack/medical,/obj/item/weapon/dnainjector,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/syringe,/obj/item/weapon/reagent_containers/hypospray,/obj/item/device/healthanalyzer,/obj/item/device/flashlight/pen) + allowed = list(/obj/item/device/analyzer,/obj/item/stack/medical,/obj/item/weapon/dnainjector,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/syringe,/obj/item/weapon/reagent_containers/hypospray,/obj/item/device/healthanalyzer,/obj/item/device/flashlight/pen,/obj/item/weapon/reagent_containers/glass/bottle,/obj/item/weapon/reagent_containers/glass/beaker,/obj/item/weapon/reagent_containers/pill,/obj/item/weapon/storage/pill_bottle,/obj/item/weapon/paper) armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0) verb/toggle() 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/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm index 277b42d364d..d168edc4c1c 100644 --- a/code/modules/clothing/suits/wiz_robe.dm +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -35,6 +35,12 @@ icon_state = "amp" siemens_coefficient = 0.8 +/obj/item/clothing/head/wizard/cap + name = "Gentlemans Cap" + desc = "A checkered gray flat cap woven together with the rarest of threads." + icon_state = "gentcap" + siemens_coefficient = 0.8 + /obj/item/clothing/suit/wizrobe name = "wizard robe" desc = "A magnificant, gem-lined robe that seems to radiate power." @@ -79,6 +85,12 @@ icon_state = "psyamp" item_state = "psyamp" +/obj/item/clothing/suit/wizrobe/gentlecoat + name = "Gentlemans Coat" + desc = "A heavy threaded twead gray jacket. For a different sort of Gentleman." + icon_state = "gentlecoat" + item_state = "gentlecoat" + /obj/item/clothing/suit/wizrobe/fake name = "wizard robe" desc = "A rather dull, blue robe meant to mimick real wizard robes." diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm index 4ae31f9d893..549a824d541 100644 --- a/code/modules/clothing/under/jobs/medsci.dm +++ b/code/modules/clothing/under/jobs/medsci.dm @@ -10,6 +10,24 @@ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) flags = FPRINT | TABLEPASS +/obj/item/clothing/under/rank/research_director/rdalt + desc = "A dress suit and slacks stained with hard work and dedication to science. Perhaps other things as well, but mostly hard work and dedication." + name = "head researcher uniform" + icon_state = "rdalt" + item_state = "rdalt" + item_color = "rdalt" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + flags = FPRINT | TABLEPASS + +/obj/item/clothing/under/rank/research_director/dress_rd + name = "research director dress uniform" + desc = "Feminine fashion for the style concious RD. Its fabric provides minor protection from biological contaminants." + icon_state = "dress_rd" + item_color = "dress_rd" + armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) + flags = FPRINT | TABLEPASS + + /obj/item/clothing/under/rank/scientist desc = "It's made of a special fiber that provides minor protection against biohazards. It has markings that denote the wearer as a scientist." name = "scientist's jumpsuit" diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm index b279a2fd35f..e6dda9c6f76 100644 --- a/code/modules/clothing/under/jobs/security.dm +++ b/code/modules/clothing/under/jobs/security.dm @@ -71,6 +71,22 @@ flags = FPRINT | TABLEPASS siemens_coefficient = 0.9 +/obj/item/clothing/under/det/black + icon_state = "detective2" + item_color = "detective2" + +/obj/item/clothing/under/det/slob + icon_state = "polsuit" + item_color = "polsuit" + +/obj/item/clothing/under/det/slob/verb/rollup() + set name = "Roll suit sleeves" + set category = "Object" + set src in usr + item_color = item_color == "polsuit" ? "polsuit_rolled" : "polsuit" + if (ishuman(loc)) + var/mob/living/carbon/human/H = loc + H.update_inv_w_uniform(1) /obj/item/clothing/head/det_hat name = "hat" @@ -80,6 +96,10 @@ armor = list(melee = 50, bullet = 5, laser = 25,energy = 10, bomb = 0, bio = 0, rad = 0) siemens_coefficient = 0.9 +/obj/item/clothing/head/det_hat/black + icon_state = "detective2" + + /* * Head of Security */ diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 3681a43eca7..15365e1eacb 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -138,6 +138,13 @@ item_state = "psysuit" item_color = "psysuit" +/obj/item/clothing/under/gentlesuit + name = "Gentlemans Suit" + desc = "A silk black shirt with a white tie and a matching gray vest and slacks. Feels proper." + icon_state = "gentlesuit" + item_state = "gentlesuit" + item_color = "gentlesuit" + /obj/item/clothing/under/gimmick/rank/captain/suit name = "captain's suit" desc = "A green suit and yellow necktie. Exemplifies authority." @@ -285,11 +292,6 @@ icon_state = "dress_saloon" item_color = "dress_saloon" -/obj/item/clothing/under/dress/dress_rd - name = "research director dress uniform" - desc = "Feminine fashion for the style concious RD." - icon_state = "dress_rd" - item_color = "dress_rd" /obj/item/clothing/under/dress/dress_cap name = "captain dress uniform" @@ -358,7 +360,7 @@ flags_inv = HIDESHOES /obj/item/clothing/under/wedding/bride_white - name = "orange wedding dress" + name = "silky wedding dress" desc = "A white wedding gown made from the finest silk." icon_state = "bride_white" item_color = "bride_white" diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 382f4c2d108..7b18520f3ab 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" @@ -493,12 +494,6 @@ icon = 'icons/obj/custom_items.dmi' icon_state = "chal_appara_1" -/obj/item/clothing/gloves/fluff/ashley_rifler_1 //Vinceluk: Ashley Rifler - name = "Purple Glove" - desc = "A single, purple glove. Initials A.R. are written on the inside of it." - icon = 'icons/obj/custom_items.dmi' - icon_state = "ashley_rifler_1" - //////////// Eye Wear //////////// /obj/item/clothing/glasses/meson/fluff/book_berner_1 //asanadas: Book Berner @@ -590,14 +585,6 @@ icon = 'icons/obj/custom_items.dmi' icon_state = "labcoat_pink_open" -/obj/item/clothing/suit/storage/det_suit/fluff/graycoat //vinceluk: Seth Sealis - name = "gray coat" - desc = "Old, worn out coat. It's seen better days." - icon = 'icons/obj/custom_items.dmi' - icon_state = "graycoat" - item_state = "graycoat" - item_color = "graycoat" - /obj/item/clothing/suit/storage/det_suit/fluff/leatherjack //atomicdog92: Seth Sealis name = "leather jacket" desc = "A black leather coat, popular amongst punks, greasers, and other galactic scum." @@ -746,6 +733,15 @@ item_state = "wyatt_uniform" item_color = "wyatt_uniform" +////// Black Dress - Lillian Amsel - PapaDrow +/obj/item/clothing/under/fluff/lillian_amsel_1 + name = "Black Dress" + desc = "A knee-length, dark gray and black dress made of a soft, velvety material." + icon = 'icons/obj/custom_items.dmi' + icon_state = "lillian_dress" + item_state = "lillian_dress" + item_color = "lillian_dress" + //////////// Masks //////////// /* @@ -836,6 +832,15 @@ flags = FPRINT|TABLEPASS w_class = 1 +////// Apollon Pendant - Michael Guess - Dragor23 +/obj/item/clothing/mask/michael_guess_1 + name = "Apollon Pendant" + desc = "A pendant with the form of a sacrificial tripod, used in acient greece. It's a symbol of the Olympian Apollon, a god associated with oracles, poetry, the sun and healing." + icon = 'icons/obj/custom_items.dmi' + icon_state = "michael_guess_1" + flags = FPRINT|TABLEPASS + w_class = 1 + slot_flags = SLOT_MASK //////////// Shoes //////////// /obj/item/clothing/shoes/magboots/fluff/susan_harris_1 //sniperyeti: Susan Harris @@ -860,6 +865,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 @@ -919,3 +925,54 @@ if(istype(A, /obj/item/ammo_magazine)) flick("leamas-reloading",src) ..() + + +///// Custom Items coded by Iamgoofball are Below ///// +/obj/item/weapon/storage/belt/medical/fluff/nashi_belt + name = "rainbow medical belt" + desc = "A somewhat-worn, modified, rainbow belt." + icon = 'icons/obj/custom_items.dmi' + icon_state = "nashi_belt" + item_state = "fluff_rbelt" + + New() + ..() + new /obj/item/weapon/reagent_containers/glass/bottle/fluff/nashi_bottle(src, 14, "Bicaridine") + new /obj/item/weapon/reagent_containers/glass/bottle/fluff/nashi_bottle(src, 15, "Dermaline") + new /obj/item/weapon/reagent_containers/glass/bottle/fluff/nashi_bottle(src, 16, "Dylovene") + new /obj/item/weapon/reagent_containers/glass/bottle/fluff/nashi_bottle(src, 17, "Dexalin Plus") + new /obj/item/weapon/reagent_containers/glass/bottle/fluff/nashi_bottle(src, 18, "Tricordrazine") + new /obj/item/weapon/reagent_containers/syringe/(src) + new /obj/item/device/healthanalyzer(src) + +/obj/item/weapon/reagent_containers/glass/bottle/fluff/nashi_bottle + icon = 'icons/obj/chemical.dmi' + flags = FPRINT | TABLEPASS //Starting them with lids on them. Safety first! + New(loc, var/color, var/labeled) + ..() + name = "[labeled] bottle" + desc = "A small bottle. Contains [labeled]" + icon_state = "bottle[color]" + +/obj/item/weapon/reagent_containers/food/drinks/flask/fluff/yuri_kornienkovich_flask + name = "Yuri's Flask" + desc = "An old gold plated flask. Nothing noteworthy about it besides it being gold and the red star on the worn out leather around it. There is also an engraving on the cap that is rather hard to see but it looks like \"Kornienkovich\" " + icon = 'icons/obj/custom_items.dmi' + icon_state = "yuri_kornienkovich_flask" + +/obj/item/clothing/under/fluff/mai_yang_dress // Mai Yang's pretty pretty dress. + name = "White Cheongsam" + desc = "It is a white cheongsam dress." + icon = 'icons/obj/custom_items.dmi' + icon_state = "mai_yang" + item_state = "mai_yang" + item_color = "mai_yang" + +/obj/item/clothing/under/fluff/sakura_hokkaido_kimono + name = "Sakura Kimono" + desc = "A pale-pink, nearly white, kimono with a red and gold obi. There is a embroidered design of cherry blossom flowers covering the kimono." + icon = 'icons/obj/custom_items.dmi' + icon_state = "sakura_hokkaido_kimono" + item_state = "sakura_hokkaido_kimono" + item_color = "sakura_hokkaido_kimono" + diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm index ffcc19b7b76..8682f6f69e3 100644 --- a/code/modules/customitems/item_spawning.dm +++ b/code/modules/customitems/item_spawning.dm @@ -57,6 +57,23 @@ del(C) ok = M.equip_if_possible(I, slot_wear_id, 0) //if 1, last argument deletes on fail break + else if(istype(Item,/obj/item/weapon/storage/belt)) + if(M.ckey == "jakksergal" && M.real_name == "Nashi Ra'hal" && M.mind.role_alt_title && M.mind.role_alt_title != "Nurse" && M.mind.role_alt_title != "Chemist") + ok = 1 + del(Item) + goto skip + var/obj/item/weapon/storage/belt/medical/fluff/nashi_belt/I = Item + if(istype(M.belt,/obj/item/weapon/storage/belt)) + for(var/obj/item/weapon/storage/belt/B in M) + del(B) + M.belt=null + ok = M.equip_if_possible(I, slot_belt, 0) + break + if(istype(M.belt,/obj/item/device/pda)) + for(var/obj/item/device/pda/Pda in M) + M.belt=null + M.equip_if_possible(Pda, slot_l_store, 0) + ok = M.equip_if_possible(I, slot_belt, 0) else if(istype(M.back,/obj/item/weapon/storage) && M.back:contents.len < M.back:storage_slots) // Try to place it in something on the mob's back Item.loc = M.back ok = 1 @@ -70,4 +87,4 @@ skip: if (ok == 0) // Finally, since everything else failed, place it on the ground - Item.loc = get_turf(M.loc) \ No newline at end of file + Item.loc = get_turf(M.loc) diff --git a/code/modules/destilery/main.dm b/code/modules/destilery/main.dm index 1ce22ef909b..429a29afdf1 100644 --- a/code/modules/destilery/main.dm +++ b/code/modules/destilery/main.dm @@ -118,7 +118,7 @@ switch(fermenting_item.type) if(/obj/item/weapon/reagent_containers/food/drinks/flour) //Flour is still flour - var/obj/item/weapon/reagent_containers/food/drinks/beer/B = new(src) + var/obj/item/weapon/reagent_containers/food/drinks/cans/beer/B = new(src) output += B else error = 1 @@ -178,7 +178,7 @@ return //Not done yet. switch(destilling_item.type) - if(/obj/item/weapon/reagent_containers/food/drinks/beer) //Flour is still flour + if(/obj/item/weapon/reagent_containers/food/drinks/cans/beer) //Flour is still flour var/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka/V = new(src) output += V else diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm index efe2ebfa521..e8a207ca8e2 100644 --- a/code/modules/detectivework/footprints_and_rag.dm +++ b/code/modules/detectivework/footprints_and_rag.dm @@ -4,6 +4,7 @@ var/track_blood = 0 var/list/feet_blood_DNA var/track_blood_type + var/feet_blood_color /obj/item/clothing/gloves var/transfer_blood = 0 diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 52568ad005b..8ab4da04142 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -70,6 +70,7 @@ return if(istype(A,/obj/machinery/computer/forensic_scanning)) //breaks shit. return + if(istype(A,/obj/item/weapon/f_card)) user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\"" flick("forensic0",src) @@ -77,9 +78,8 @@ add_fingerprint(user) - - //Special case for blood splaters. - if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune)) + //Special case for blood splatters, runes and gibs. + if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable/blood/gibs)) if(!isnull(A.blood_DNA)) for(var/blood in A.blood_DNA) user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]" @@ -178,4 +178,4 @@ sum_list[3] = A.blood_DNA ? A.blood_DNA.Copy() : null sum_list[4] = "\The [A] in \the [get_area(A)]" stored["\ref [A]"] = sum_list - return 0 \ No newline at end of file + return 0 diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm index 398d311c189..59434f9e591 100644 --- a/code/modules/economy/ATM.dm +++ b/code/modules/economy/ATM.dm @@ -32,10 +32,14 @@ log transactions var/obj/item/weapon/card/held_card var/editing_security_level = 0 var/view_screen = NO_SCREEN + var/datum/effect/effect/system/spark_spread/spark_system /obj/machinery/atm/New() ..() machine_id = "[station_name()] RT #[num_financial_terminals++]" + spark_system = new /datum/effect/effect/system/spark_spread + spark_system.set_up(5, 0, src) + spark_system.attach(src) /obj/machinery/atm/process() if(stat & NOPOWER) @@ -60,6 +64,23 @@ log transactions /obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/weapon/card)) + if(emagged > 0) + //prevent inserting id into an emagged ATM + user << "\red \icon[src] CARD READER ERROR. This system has been compromised!" + return + else if(istype(I,/obj/item/weapon/card/emag)) + //short out the machine, shoot sparks, spew money! + emagged = 1 + spark_system.start() + spawn_money(rand(100,500),src.loc) + //we don't want to grief people by locking their id in an emagged ATM + release_held_id(user) + + //display a message to the user + var/response = pick("Initiating withdraw. Have a nice day!", "CRITICAL ERROR: Activating cash chamber panic siphon.","PIN Code accepted! Emptying account balance.", "Jackpot!") + user << "\red \icon[src] The [src] beeps: \"[response]\"" + return + var/obj/item/weapon/card/id/idcard = I if(!held_card) usr.drop_item() @@ -94,7 +115,7 @@ log transactions /obj/machinery/atm/attack_hand(mob/user as mob) if(istype(user, /mob/living/silicon)) - user << "\red Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per NanoTrasen regulation #1005." + user << "\red \icon[src] Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per NanoTrasen regulation #1005." return if(get_dist(src,user) <= 1) @@ -102,84 +123,88 @@ log transactions var/dat = "

      NanoTrasen Automatic Teller Machine

      " dat += "For all your monetary needs!
      " dat += "This terminal is [machine_id]. Report this code when contacting NanoTrasen IT Support
      " - dat += "Card: [held_card ? held_card.name : "------"]

      " - if(ticks_left_locked_down > 0) - dat += "Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled." - else if(authenticated_account) - if(authenticated_account.suspended) - dat += "\redAccess to this account has been suspended, and the funds within frozen." - else - switch(view_screen) - if(CHANGE_SECURITY_LEVEL) - dat += "Select a new security level for this account:

      " - var/text = "Zero - Either the account number or card is required to access this account. EFTPOS transactions will require a card and ask for a pin, but not verify the pin is correct." - if(authenticated_account.security_level != 0) - text = "[text]" - dat += "[text]
      " - text = "One - An account number and pin must be manually entered to access this account and process transactions." - if(authenticated_account.security_level != 1) - text = "[text]" - dat += "[text]
      " - text = "Two - In addition to account number and pin, a card is required to access this account and process transactions." - if(authenticated_account.security_level != 2) - text = "[text]" - dat += "[text]

      " - dat += "Back" - if(VIEW_TRANSACTION_LOGS) - dat += "Transaction logs
      " - dat += "Back" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - for(var/datum/transaction/T in authenticated_account.transaction_log) - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
      DateTimeTargetPurposeValueSource terminal ID
      [T.date][T.time][T.target_name][T.purpose]$[T.amount][T.source_terminal]
      " - if(TRANSFER_FUNDS) - dat += "Account balance: $[authenticated_account.money]
      " - dat += "Back

      " - dat += "
      " - dat += "" - dat += "" - dat += "Target account number:
      " - dat += "Funds to transfer:
      " - dat += "Transaction purpose:
      " - dat += "
      " - dat += "
      " - else - dat += "Welcome, [authenticated_account.owner_name].
      " - dat += "Account balance: $[authenticated_account.money]" - dat += "
      " - dat += "" - dat += "" - dat += "
      " - dat += "
      " - dat += "Change account security level
      " - dat += "Make transfer
      " - dat += "View transaction log
      " - dat += "Print balance statement
      " - dat += "Logout
      " + if(emagged > 0) + dat += "Card: LOCKED

      Unauthorized terminal access detected! This ATM has been locked. Please contact NanoTrasen IT Support." else - dat += "
      " - dat += "" - dat += "" - dat += "Account:
      " - dat += "PIN:
      " - dat += "
      " - dat += "
      " + dat += "Card: [held_card ? held_card.name : "------"]

      " + + if(ticks_left_locked_down > 0) + dat += "Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled." + else if(authenticated_account) + if(authenticated_account.suspended) + dat += "\redAccess to this account has been suspended, and the funds within frozen." + else + switch(view_screen) + if(CHANGE_SECURITY_LEVEL) + dat += "Select a new security level for this account:

      " + var/text = "Zero - Either the account number or card is required to access this account. EFTPOS transactions will require a card and ask for a pin, but not verify the pin is correct." + if(authenticated_account.security_level != 0) + text = "[text]" + dat += "[text]
      " + text = "One - An account number and pin must be manually entered to access this account and process transactions." + if(authenticated_account.security_level != 1) + text = "[text]" + dat += "[text]
      " + text = "Two - In addition to account number and pin, a card is required to access this account and process transactions." + if(authenticated_account.security_level != 2) + text = "[text]" + dat += "[text]

      " + dat += "Back" + if(VIEW_TRANSACTION_LOGS) + dat += "Transaction logs
      " + dat += "Back" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + for(var/datum/transaction/T in authenticated_account.transaction_log) + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "
      DateTimeTargetPurposeValueSource terminal ID
      [T.date][T.time][T.target_name][T.purpose]$[T.amount][T.source_terminal]
      " + if(TRANSFER_FUNDS) + dat += "Account balance: $[authenticated_account.money]
      " + dat += "Back

      " + dat += "
      " + dat += "" + dat += "" + dat += "Target account number:
      " + dat += "Funds to transfer:
      " + dat += "Transaction purpose:
      " + dat += "
      " + dat += "
      " + else + dat += "Welcome, [authenticated_account.owner_name].
      " + dat += "Account balance: $[authenticated_account.money]" + dat += "
      " + dat += "" + dat += "" + dat += "
      " + dat += "
      " + dat += "Change account security level
      " + dat += "Make transfer
      " + dat += "View transaction log
      " + dat += "Print balance statement
      " + dat += "Logout
      " + else + dat += "
      " + dat += "" + dat += "" + dat += "Account:
      " + dat += "PIN:
      " + dat += "
      " + dat += "
      " user << browse(dat,"window=atm;size=550x650") else @@ -322,20 +347,18 @@ log transactions else playsound(loc, 'sound/items/polaroid2.ogg', 50, 1) if("insert_card") - if(held_card) - held_card.loc = src.loc - authenticated_account = null - - if(ishuman(usr) && !usr.get_active_hand()) - usr.put_in_hands(held_card) - held_card = null - + if(!held_card) + //this might happen if the user had the browser window open when somebody emagged it + if(emagged > 0) + usr << "\red \icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!" + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + held_card = I else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() - I.loc = src - held_card = I + release_held_id(usr) if("logout") authenticated_account = null //usr << browse(null,"window=atm") @@ -366,4 +389,16 @@ log transactions T.time = worldtime2text() authenticated_account.transaction_log.Add(T) - view_screen = NO_SCREEN \ No newline at end of file + view_screen = NO_SCREEN + +// put the currently held id on the ground or in the hand of the user +/obj/machinery/atm/proc/release_held_id(mob/living/carbon/human/human_user as mob) + if(!held_card) + return + + held_card.loc = src.loc + authenticated_account = null + + if(ishuman(human_user) && !human_user.get_active_hand()) + human_user.put_in_hands(held_card) + held_card = null diff --git a/code/modules/economy/economy_misc.dm b/code/modules/economy/economy_misc.dm index ffe8a114717..b236c2905d2 100644 --- a/code/modules/economy/economy_misc.dm +++ b/code/modules/economy/economy_misc.dm @@ -103,7 +103,7 @@ var/global/economy_init = 0 create_department_account("Vendor") vendor_account = department_accounts["Vendor"] - current_date_string = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], 2557" + current_date_string = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], [game_year]" economy_init = 1 return 1 diff --git a/code/modules/events/borers.dm b/code/modules/events/borers.dm new file mode 100644 index 00000000000..2c6a2820fbb --- /dev/null +++ b/code/modules/events/borers.dm @@ -0,0 +1,38 @@ +//Cortical borer spawn event - care of RobRichards1997 with minor editing by Zuhayr. + +/datum/event/borer_infestation + oneShot = 1 + +/datum/event/borer_infestation + announceWhen = 400 + + var/spawncount = 1 + var/successSpawn = 0 //So we don't make a command report if nothing gets spawned. + +/datum/event/borer_infestation/setup() + announceWhen = rand(announceWhen, announceWhen + 50) + spawncount = rand(1, 3) + +/datum/event/borer_infestation/announce() + if(successSpawn) + command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert") + world << sound('sound/AI/aliens.ogg') + +/datum/event/borer_infestation/start() + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world) + if(temp_vent.loc.z == 1 && !temp_vent.welded && temp_vent.network) + //Stops cortical borers getting stuck in small networks. See: Security, Virology + if(temp_vent.network.normal_members.len > 50) + vents += temp_vent + + var/list/candidates = get_alien_candidates() + while(spawncount > 0 && vents.len && candidates.len) + var/obj/vent = pick_n_take(vents) + var/client/C = pick_n_take(candidates) + + var/mob/living/simple_animal/borer/new_borer = new(vent.loc) + new_borer.key = C.key + + spawncount-- + successSpawn = 1 \ No newline at end of file diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index fe6f56624f6..a424cdd72af 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -30,8 +30,8 @@ continue var/datum/disease/dnaspread/D = new D.strain_data["name"] = H.real_name - D.strain_data["UI"] = H.dna.uni_identity - D.strain_data["SE"] = H.dna.struc_enzymes + D.strain_data["UI"] = H.dna.UI + D.strain_data["SE"] = H.dna.SE D.carrier = 1 D.holder = H D.affected_mob = H diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm index 17c312eea2c..f610b0d2f91 100644 --- a/code/modules/events/money_spam.dm +++ b/code/modules/events/money_spam.dm @@ -94,7 +94,8 @@ if(ai.aiPDA != P && ai.aiPDA != src) ai.show_message("Intercepted message from [sender] (Unknown / spam?) to [P:owner]: [message]") - P.tnote += "← From [sender] (Unknown / spam?):
      [message]
      " + //Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window. + //P.tnote += "← From [sender] (Unknown / spam?):
      [message]
      " if (!P.silent) playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1) diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index ad79eed5164..91bf29e00af 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -34,10 +34,10 @@ H.apply_effect((rand(40,70)),IRRADIATE,0) if (prob(75)) randmutb(H) // Applies bad mutation - domutcheck(H,null,1) + domutcheck(H,null,MUTCHK_FORCED) else randmutg(H) // Applies good mutation - domutcheck(H,null,1) + domutcheck(H,null,MUTCHK_FORCED) for(var/mob/living/carbon/monkey/M in living_mob_list) diff --git a/code/modules/ext_scripts/irc.dm b/code/modules/ext_scripts/irc.dm index f4e94f3ffc4..3976904efb6 100644 --- a/code/modules/ext_scripts/irc.dm +++ b/code/modules/ext_scripts/irc.dm @@ -4,11 +4,16 @@ return /proc/send2mainirc(var/msg) - if(config.use_irc_bot && config.main_irc && config.irc_bot_host) - ext_python("ircbot_message.py", "[config.comms_password] [config.irc_bot_host] [config.main_irc] [msg]") + if(config.main_irc) + send2irc(config.main_irc, msg) return /proc/send2adminirc(var/msg) - if(config.use_irc_bot && config.admin_irc && config.irc_bot_host) - ext_python("ircbot_message.py", "[config.comms_password] [config.irc_bot_host] [config.admin_irc] [msg]") + if(config.admin_irc) + send2irc(config.admin_irc, msg) return + + +/hook/startup/proc/ircNotify() + send2mainirc("Server starting up on [config.server? "byond://[config.server]" : "byond://[world.address]:[world.port]"]") + return 1 diff --git a/code/modules/flufftext/TextFilters.dm b/code/modules/flufftext/TextFilters.dm index 6c6578bb863..44cc91a8e45 100644 --- a/code/modules/flufftext/TextFilters.dm +++ b/code/modules/flufftext/TextFilters.dm @@ -57,7 +57,7 @@ proc/NewStutter(phrase,stunned) split_phrase[index] = word - return sanitize(dd_list2text(split_phrase," ")) + return sanitize(list2text(split_phrase," ")) proc/Stagger(mob/M,d) //Technically not a filter, but it relates to drunkenness. step(M, pick(d,turn(d,90),turn(d,-90))) @@ -78,6 +78,6 @@ proc/Ellipsis(original_msg, chance = 50) else new_words += w - new_msg = dd_list2text(new_words," ") + new_msg = list2text(new_words," ") return new_msg diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index ec4ccf50f5e..8228520cb86 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -33,6 +33,15 @@ I said no! ) result = /obj/item/weapon/reagent_containers/food/snacks/boiledegg +/datum/recipe/dionaroast + reagents = list("radium" = 5) + items = list( + /obj/item/weapon/holder/diona, + /obj/item/weapon/reagent_containers/food/snacks/grown/apple + ) + result = /obj/item/weapon/reagent_containers/food/snacks/dionaroast + + /* /datum/recipe/bananaphone reagents = list("psilocybin" = 5) //Trippin' balls, man. @@ -477,6 +486,15 @@ I said no! ) result = /obj/item/weapon/reagent_containers/food/snacks/popcorn + +/datum/recipe/cookie + reagents = list("milk" = 5, "flour" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/egg, + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cookie + /datum/recipe/fortunecookie reagents = list("flour" = 5) items = list( @@ -1142,4 +1160,19 @@ I said no! /datum/recipe/cracker reagents = list("flour" = 5, "sodiumchloride" = 1) - result = /obj/item/weapon/reagent_containers/food/snacks/cracker \ No newline at end of file + result = /obj/item/weapon/reagent_containers/food/snacks/cracker + +/datum/recipe/stuffing + reagents = list("water" = 5, "sodiumchloride" = 1, "blackpepper" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/stuffing + +/datum/recipe/tofurkey + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/stuffing, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/tofurkey 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/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm new file mode 100644 index 00000000000..95df457c853 --- /dev/null +++ b/code/modules/mining/abandonedcrates.dm @@ -0,0 +1,115 @@ +/obj/structure/closet/crate/secure/loot + name = "abandoned crate" + desc = "What could be inside?" + icon_state = "securecrate" + icon_opened = "securecrateopen" + icon_closed = "securecrate" + var/code = null + var/lastattempt = null + var/attempts = 3 + locked = 1 + var/min = 1 + var/max = 10 + +/obj/structure/closet/crate/secure/loot/New() + ..() + code = rand(min,max) + var/loot = rand(1,30) + switch(loot) + if(1) + new/obj/item/weapon/reagent_containers/food/drinks/bottle/rum(src) + new/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus(src) + new/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey(src) + new/obj/item/weapon/lighter/zippo(src) + if(2) + new/obj/item/weapon/pickaxe/drill(src) + new/obj/item/device/taperecorder(src) + new/obj/item/clothing/suit/space(src) + new/obj/item/clothing/head/helmet/space(src) + if(3) + return + if(4) + new/obj/item/weapon/reagent_containers/glass/beaker/bluespace(src) + if(5 to 6) + for(var/i = 0, i < 10, i++) + new/obj/item/weapon/ore/diamond(src) + if(7) + return + if(8) + return + if(9) + for(var/i = 0, i < 3, i++) + new/obj/machinery/hydroponics(src) + if(10) + for(var/i = 0, i < 3, i++) + new/obj/item/weapon/reagent_containers/glass/beaker/noreact(src) + if(11 to 12) + for(var/i = 0, i < 9, i++) + new/obj/item/bluespace_crystal(src) + if(13) + new/obj/item/weapon/melee/classic_baton(src) + if(14) + return + if(15) + new/obj/item/clothing/under/chameleon(src) + for(var/i = 0, i < 7, i++) + new/obj/item/clothing/tie/horrible(src) + if(16) + new/obj/item/clothing/under/shorts(src) + new/obj/item/clothing/under/shorts/red(src) + new/obj/item/clothing/under/shorts/blue(src) + //Dummy crates start here. + if(17 to 29) + return + //Dummy crates end here. + if(30) + new/obj/item/weapon/melee/baton(src) + +/obj/structure/closet/crate/secure/loot/attack_hand(mob/user as mob) + if(locked) + user << "The crate is locked with a Deca-code lock." + var/input = input(usr, "Enter digit from [min] to [max].", "Deca-Code Lock", "") as num + if(in_range(src, user)) + input = Clamp(input, 0, 10) + if (input == code) + user << "The crate unlocks!" + locked = 0 + else if (input == null || input > max || input < min) + user << "You leave the crate alone." + else + user << "A red light flashes." + lastattempt = input + attempts-- + if (attempts == 0) + user << "The crate's anti-tamper system activates!" + var/turf/T = get_turf(src.loc) + explosion(T, 0, 0, 0, 1) + del(src) + return + else + user << "You attempt to interact with the device using a hand gesture, but it appears this crate is from before the DECANECT came out." + return + else + return ..() + +/obj/structure/closet/crate/secure/loot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(locked) + if (istype(W, /obj/item/weapon/card/emag)) + user << "The crate unlocks!" + locked = 0 + if (istype(W, /obj/item/device/multitool)) + user << "DECA-CODE LOCK REPORT:" + if (attempts == 1) + user << "* Anti-Tamper Bomb will activate on next failed access attempt." + else + user << "* Anti-Tamper Bomb will activate after [src.attempts] failed access attempts." + if (lastattempt == null) + user << " has been made to open the crate thus far." + return + // hot and cold + if (code > lastattempt) + user << "* Last access attempt lower than expected code." + else + user << "* Last access attempt higher than expected code." + else ..() + else ..() 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..86f844f6237 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; @@ -255,6 +273,14 @@ ore_uranium+= 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/glass)) ore_glass+= 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..749de26f338 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -1,8 +1,8 @@ /**********************Mineral deposits**************************/ -#define XENOARCH_SPAWN_CHANCE 0.5 -#define XENOARCH_SPREAD_CHANCE 15 -#define ARTIFACT_SPAWN_CHANCE 20 + +datum/controller/game_controller/var/list/artifact_spawning_turfs = list() +var/list/artifact_spawn = list() // Runtime fix for geometry loading before controller is instantiated. /turf/simulated/mineral //wall piece name = "Rock" @@ -14,599 +14,375 @@ density = 1 blocks_air = 1 temperature = TCMB - var/mineralName = "" - var/mineralAmt = 0 - var/spread = 0 //will the seam spread? - var/spreadChance = 0 //the percentual chance of an ore spreading to the neighbouring tiles + var/mineral/mineral + var/mined_ore = 0 var/last_act = 0 - var/datum/geosample/geological_data + var/datum/geosample/geologic_data var/excavation_level = 0 - var/list/finds = list() - var/list/excavation_minerals = list() + var/list/finds var/next_rock = 0 var/archaeo_overlay = "" var/excav_overlay = "" var/obj/item/weapon/last_find var/datum/artifact_find/artifact_find -/turf/simulated/mineral/Del() - return -/turf/simulated/mineral/ex_act(severity) - switch(severity) - if(3.0) + New() + . = ..() + + MineralSpread() + + spawn(1) + var/turf/T + if((istype(get_step(src, NORTH), /turf/simulated/floor)) || (istype(get_step(src, NORTH), /turf/space)) || (istype(get_step(src, NORTH), /turf/simulated/shuttle/floor))) + T = get_step(src, NORTH) + if (T) + T.overlays += image('icons/turf/walls.dmi', "rock_side_s") + if((istype(get_step(src, SOUTH), /turf/simulated/floor)) || (istype(get_step(src, SOUTH), /turf/space)) || (istype(get_step(src, SOUTH), /turf/simulated/shuttle/floor))) + T = get_step(src, SOUTH) + if (T) + T.overlays += image('icons/turf/walls.dmi', "rock_side_n", layer=6) + if((istype(get_step(src, EAST), /turf/simulated/floor)) || (istype(get_step(src, EAST), /turf/space)) || (istype(get_step(src, EAST), /turf/simulated/shuttle/floor))) + T = get_step(src, EAST) + if (T) + T.overlays += image('icons/turf/walls.dmi', "rock_side_w", layer=6) + if((istype(get_step(src, WEST), /turf/simulated/floor)) || (istype(get_step(src, WEST), /turf/space)) || (istype(get_step(src, WEST), /turf/simulated/shuttle/floor))) + T = get_step(src, WEST) + if (T) + T.overlays += image('icons/turf/walls.dmi', "rock_side_e", layer=6) + + + ex_act(severity) + switch(severity) + if(2.0) + if (prob(70)) + mined_ore = 1 //some of the stuff gets blown up + GetDrilled() + if(1.0) + mined_ore = 2 //some of the stuff gets blown up + GetDrilled() + + + Bumped(AM) + . = ..() + if(istype(AM,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + if((istype(H.l_hand,/obj/item/weapon/pickaxe)) && (!H.hand)) + attackby(H.l_hand,H) + else if((istype(H.r_hand,/obj/item/weapon/pickaxe)) && H.hand) + attackby(H.r_hand,H) + + else if(istype(AM,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = AM + if(istype(R.module_active,/obj/item/weapon/pickaxe)) + attackby(R.module_active,R) + + else if(istype(AM,/obj/mecha)) + var/obj/mecha/M = AM + if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/tool/drill)) + M.selected.action(src) + + + proc/MineralSpread() + if(mineral && mineral.spread) + for(var/trydir in cardinal) + if(prob(mineral.spread_chance)) + var/turf/simulated/mineral/random/target_turf = get_step(src, trydir) + if(istype(target_turf) && !target_turf.mineral) + target_turf.mineral = mineral + target_turf.UpdateMineral() + target_turf.MineralSpread() + + + proc/UpdateMineral() + if(!mineral) + name = "\improper Rock" + icon_state = "rock" return - if(2.0) - if (prob(70)) - src.mineralAmt -= 1 //some of the stuff gets blown up - src.gets_drilled() - if(1.0) - src.mineralAmt -= 2 //some of the stuff gets blown up - src.gets_drilled() - return - -/turf/simulated/mineral/New() - - spawn(1) - var/turf/T - if((istype(get_step(src, NORTH), /turf/simulated/floor)) || (istype(get_step(src, NORTH), /turf/space)) || (istype(get_step(src, NORTH), /turf/simulated/shuttle/floor))) - T = get_step(src, NORTH) - if (T) - T.overlays += image('icons/turf/walls.dmi', "rock_side_s") - if((istype(get_step(src, SOUTH), /turf/simulated/floor)) || (istype(get_step(src, SOUTH), /turf/space)) || (istype(get_step(src, SOUTH), /turf/simulated/shuttle/floor))) - T = get_step(src, SOUTH) - if (T) - T.overlays += image('icons/turf/walls.dmi', "rock_side_n", layer=6) - if((istype(get_step(src, EAST), /turf/simulated/floor)) || (istype(get_step(src, EAST), /turf/space)) || (istype(get_step(src, EAST), /turf/simulated/shuttle/floor))) - T = get_step(src, EAST) - if (T) - T.overlays += image('icons/turf/walls.dmi', "rock_side_w", layer=6) - if((istype(get_step(src, WEST), /turf/simulated/floor)) || (istype(get_step(src, WEST), /turf/space)) || (istype(get_step(src, WEST), /turf/simulated/shuttle/floor))) - T = get_step(src, WEST) - if (T) - T.overlays += image('icons/turf/walls.dmi', "rock_side_e", layer=6) - - if (mineralName && mineralAmt && spread && spreadChance) - for(var/trydir in list(1,2,4,8)) - if(prob(spreadChance)) - if(istype(get_step(src, trydir), /turf/simulated/mineral/random)) - var/turf/simulated/mineral/T = get_step(src, trydir) - var/turf/simulated/mineral/M = new src.type(T) - //keep any digsite data as constant as possible - if(T.finds.len && !M.finds.len) - M.finds = T.finds - if(T.archaeo_overlay) - M.overlays += archaeo_overlay + name = "\improper [mineral.display_name] deposit" + icon_state = "rock_[mineral.name]" - //---- Xenoarchaeology BEGIN + //Not even going to touch this pile of spaghetti + attackby(obj/item/weapon/W as obj, mob/user as mob) - //put into spawn so that digsite data can be preserved over the turf replacements via spreading mineral veins - spawn(0) - if(mineralAmt > 0 && !excavation_minerals.len) - for(var/i=0, i 0) - if(excavation_level < 25) - src.overlays += image('icons/obj/xenoarchaeology.dmi', "overlay_excv1_[rand(1,3)]") - else if(excavation_level < 50) - src.overlays += image('icons/obj/xenoarchaeology.dmi', "overlay_excv2_[rand(1,3)]") - else if(excavation_level < 75) - src.overlays += image('icons/obj/xenoarchaeology.dmi', "overlay_excv3_[rand(1,3)]") - else - src.overlays += image('icons/obj/xenoarchaeology.dmi', "overlay_excv4_[rand(1,3)]") - desc = "It appears to be partially excavated."*/ - - return - -/turf/simulated/mineral/random - name = "Mineral deposit" - var/mineralAmtList = list("Uranium" = 5, "Iron" = 5, "Diamond" = 5, "Gold" = 5, "Silver" = 5, "Plasma" = 5/*, "Adamantine" = 5*/) - var/mineralSpawnChanceList = list("Uranium" = 5, "Iron" = 50, "Diamond" = 1, "Gold" = 5, "Silver" = 5, "Plasma" = 25/*, "Adamantine" =5*/)//Currently, Adamantine won't spawn as it has no uses. -Durandan - var/mineralChance = 10 //means 10% chance of this plot changing to a mineral deposit - -/turf/simulated/mineral/random/New() - ..() - if (prob(mineralChance)) - var/mName = pickweight(mineralSpawnChanceList) //temp mineral name - - if (mName) - var/turf/simulated/mineral/M - switch(mName) - if("Uranium") - M = new/turf/simulated/mineral/uranium(src) - if("Iron") - M = new/turf/simulated/mineral/iron(src) - if("Diamond") - M = new/turf/simulated/mineral/diamond(src) - if("Gold") - M = new/turf/simulated/mineral/gold(src) - if("Silver") - M = new/turf/simulated/mineral/silver(src) - if("Plasma") - M = new/turf/simulated/mineral/plasma(src) - /*if("Adamantine") - M = new/turf/simulated/mineral/adamantine(src)*/ - if(M) - src = M - M.levelupdate() - - //preserve archaeo data - M.geological_data = src.geological_data - M.excavation_minerals = src.excavation_minerals - M.overlays = src.overlays - M.artifact_find = src.artifact_find - M.archaeo_overlay = src.archaeo_overlay - M.excav_overlay = src.excav_overlay - - /*else if (prob(artifactChance)) - new/obj/machinery/artifact(src)*/ - return - -/turf/simulated/mineral/random/high_chance - mineralChance = 25 - mineralSpawnChanceList = list("Uranium" = 10, "Iron" = 30, "Diamond" = 2, "Gold" = 10, "Silver" = 10, "Plasma" = 25, "Archaeo" = 2) - -/turf/simulated/mineral/random/Del() - return - -/turf/simulated/mineral/uranium - name = "Uranium deposit" - icon_state = "rock_Uranium" - mineralName = "Uranium" - mineralAmt = 5 - spreadChance = 10 - spread = 1 - - - -/turf/simulated/mineral/iron - name = "Iron deposit" - icon_state = "rock_Iron" - mineralName = "Iron" - mineralAmt = 5 - spreadChance = 25 - spread = 1 - - -/turf/simulated/mineral/diamond - name = "Diamond deposit" - icon_state = "rock_Diamond" - mineralName = "Diamond" - mineralAmt = 5 - spreadChance = 10 - spread = 1 - - -/turf/simulated/mineral/gold - name = "Gold deposit" - icon_state = "rock_Gold" - mineralName = "Gold" - mineralAmt = 5 - spreadChance = 10 - spread = 1 - - -/turf/simulated/mineral/silver - name = "Silver deposit" - icon_state = "rock_Silver" - mineralName = "Silver" - mineralAmt = 5 - spreadChance = 10 - spread = 1 - - -/turf/simulated/mineral/plasma - name = "Plasma deposit" - icon_state = "rock_Plasma" - mineralName = "Plasma" - mineralAmt = 5 - spreadChance = 25 - spread = 1 - - -/turf/simulated/mineral/clown - name = "Bananium deposit" - icon_state = "rock_Clown" - mineralName = "Clown" - mineralAmt = 3 - spreadChance = 0 - spread = 0 - -/* -commented out in r5061, I left it because of the shroom thingies - -/turf/simulated/mineral/ReplaceWithFloor() - if(!icon_old) icon_old = icon_state - var/turf/simulated/floor/plating/airless/asteroid/W - var/old_dir = dir - - for(var/direction in cardinal) - for(var/obj/effect/glowshroom/shroom in get_step(src,direction)) - if(!shroom.floor) //shrooms drop to the floor - shroom.floor = 1 - shroom.icon_state = "glowshroomf" - shroom.pixel_x = 0 - shroom.pixel_y = 0 - - var/old_lumcount = lighting_lumcount - initial(lighting_lumcount) - W = new /turf/simulated/floor/plating/airless/asteroid(src) - W.lighting_lumcount += old_lumcount - if(old_lumcount != W.lighting_lumcount) - W.lighting_changed = 1 - lighting_controller.changed_turfs += W - - W.dir = old_dir - - W.fullUpdateMineralOverlays() - W.levelupdate() - return W -*/ - -/turf/simulated/mineral/attackby(obj/item/weapon/W as obj, mob/user as mob) - - if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - usr << "\red You don't have the dexterity to do this!" - return - - if (istype(W, /obj/item/device/core_sampler)) - src.geological_data.UpdateNearbyArtifactInfo(src) - var/obj/item/device/core_sampler/C = W - C.sample_item(src, user) - return - - if (istype(W, /obj/item/device/depth_scanner)) - var/obj/item/device/depth_scanner/C = W - C.scan_atom(user, src) - return - - if (istype(W, /obj/item/device/measuring_tape)) - var/obj/item/device/measuring_tape/P = W - user.visible_message("\blue[user] extends [P] towards [src].","\blue You extend [P] towards [src].") - if(do_after(user,25)) - user << "\blue \icon[P] [src] has been excavated to a depth of [2*src.excavation_level]cm." - return - - if (istype(W, /obj/item/weapon/pickaxe)) - var/turf/T = user.loc - if (!( istype(T, /turf) )) + if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + usr << "\red You don't have the dexterity to do this!" return -/* - if (istype(W, /obj/item/weapon/pickaxe/radius)) - var/turf/T = user.loc - if (!( istype(T, /turf) )) + + if (istype(W, /obj/item/device/core_sampler)) + geologic_data.UpdateNearbyArtifactInfo(src) + var/obj/item/device/core_sampler/C = W + C.sample_item(src, user) return -*/ -//Watch your tabbing, microwave. --NEO - var/obj/item/weapon/pickaxe/P = W - if(last_act+P.digspeed > world.time)//prevents message spam + if (istype(W, /obj/item/device/depth_scanner)) + var/obj/item/device/depth_scanner/C = W + C.scan_atom(user, src) return - last_act = world.time - playsound(user, P.drill_sound, 20, 1) + if (istype(W, /obj/item/device/measuring_tape)) + var/obj/item/device/measuring_tape/P = W + user.visible_message("\blue[user] extends [P] towards [src].","\blue You extend [P] towards [src].") + if(do_after(user,25)) + user << "\blue \icon[P] [src] has been excavated to a depth of [2*excavation_level]cm." + return - //handle any archaeological finds we might uncover - var/fail_message - if(src.finds.len) - var/datum/find/F = src.finds[1] - if(src.excavation_level + P.excavation_amount > F.excavation_required) - //Chance to destroy / extract any finds here - fail_message = ", [pick("there is a crunching noise","[W] collides with some different rock","part of the rock face crumbles away","something breaks under [W]")]" - - user << "\red You start [P.drill_verb][fail_message ? fail_message : ""]." - - if(fail_message && prob(90)) - if(prob(25)) - excavate_find(5, src.finds[1]) - else if(prob(50)) - src.finds.Remove(src.finds[1]) - if(prob(50)) - artifact_debris() - - if(do_after(user,P.digspeed)) - user << "\blue You finish [P.drill_verb] the rock." - - if(finds.len) - var/datum/find/F = src.finds[1] - if(round(src.excavation_level + P.excavation_amount) == F.excavation_required) - //Chance to extract any items here perfectly, otherwise just pull them out along with the rock surrounding them - if(src.excavation_level + P.excavation_amount > F.excavation_required) - //if you can get slightly over, perfect extraction - excavate_find(100, F) - else - excavate_find(80, F) - - else if(src.excavation_level + P.excavation_amount > F.excavation_required - F.clearance_range) - //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 - 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)) - 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 (istype(W, /obj/item/weapon/pickaxe)) + var/turf/T = user.loc + if (!( istype(T, /turf) )) return - else - src.excavation_level += P.excavation_amount + + var/obj/item/weapon/pickaxe/P = W + if(last_act + P.digspeed > world.time)//prevents message spam + return + last_act = world.time + + playsound(user, P.drill_sound, 20, 1) + + //handle any archaeological finds we might uncover + var/fail_message + if(finds && finds.len) + var/datum/find/F = finds[1] + if(excavation_level + P.excavation_amount > F.excavation_required) + //Chance to destroy / extract any finds here + fail_message = ", [pick("there is a crunching noise","[W] collides with some different rock","part of the rock face crumbles away","something breaks under [W]")]" + + user << "\red You start [P.drill_verb][fail_message ? fail_message : ""]." + + if(fail_message && prob(90)) + if(prob(25)) + excavate_find(5, finds[1]) + else if(prob(50)) + finds.Remove(finds[1]) + if(prob(50)) + artifact_debris() + + if(do_after(user,P.digspeed)) + user << "\blue You finish [P.drill_verb] the rock." + + if(finds && finds.len) + var/datum/find/F = finds[1] + if(round(excavation_level + P.excavation_amount) == F.excavation_required) + //Chance to extract any items here perfectly, otherwise just pull them out along with the rock surrounding them + if(excavation_level + P.excavation_amount > F.excavation_required) + //if you can get slightly over, perfect extraction + excavate_find(100, F) + else + excavate_find(80, F) + + else if(excavation_level + P.excavation_amount > F.excavation_required - F.clearance_range) + //just pull the surrounding rock out + excavate_find(0, F) + + if( excavation_level + P.excavation_amount >= 100 ) + //if players have been excavating this turf, leave some rocky debris behind + var/obj/structure/boulder/B + if(artifact_find) + if( 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(B) + GetDrilled(0) + else + GetDrilled(1) + return + + excavation_level += P.excavation_amount //archaeo overlays - if(!archaeo_overlay && finds.len) - var/datum/find/F = src.finds[1] - if(F.excavation_required <= src.excavation_level + F.view_range) + if(!archaeo_overlay && finds && finds.len) + var/datum/find/F = finds[1] + if(F.excavation_required <= excavation_level + F.view_range) archaeo_overlay = "overlay_archaeo[rand(1,3)]" overlays += archaeo_overlay - //there's got to be a better way to do this - var/update_excav_overlay = 0 - if(src.excavation_level >= 75) - if(src.excavation_level - P.excavation_amount < 75) - update_excav_overlay = 1 - else if(src.excavation_level >= 50) - if(src.excavation_level - P.excavation_amount < 50) - update_excav_overlay = 1 - else if(src.excavation_level >= 25) - if(src.excavation_level - P.excavation_amount < 25) - update_excav_overlay = 1 + //there's got to be a better way to do this + var/update_excav_overlay = 0 + if(excavation_level >= 75) + if(excavation_level - P.excavation_amount < 75) + update_excav_overlay = 1 + else if(excavation_level >= 50) + if(excavation_level - P.excavation_amount < 50) + update_excav_overlay = 1 + else if(excavation_level >= 25) + if(excavation_level - P.excavation_amount < 25) + update_excav_overlay = 1 - //update overlays displaying excavation level - if( !(excav_overlay && excavation_level > 0) || update_excav_overlay ) - var/excav_quadrant = round(excavation_level / 25) + 1 - excav_overlay = "overlay_excv[excav_quadrant]_[rand(1,3)]" - overlays += excav_overlay + //update overlays displaying excavation level + if( !(excav_overlay && excavation_level > 0) || update_excav_overlay ) + var/excav_quadrant = round(excavation_level / 25) + 1 + excav_overlay = "overlay_excv[excav_quadrant]_[rand(1,3)]" + overlays += excav_overlay - //extract pesky minerals while we're excavating - while(excavation_minerals.len && src.excavation_level > excavation_minerals[excavation_minerals.len]) - drop_mineral() - pop(excavation_minerals) - mineralAmt-- + /* Nope. + //extract pesky minerals while we're excavating + while(excavation_minerals.len && excavation_level > excavation_minerals[excavation_minerals.len]) + DropMineral() + pop(excavation_minerals) + mineralAmt-- */ - //drop some rocks - next_rock += P.excavation_amount * 10 - while(next_rock > 100) - next_rock -= 100 - var/obj/item/weapon/ore/O = new(src) - src.geological_data.UpdateNearbyArtifactInfo(src) - O.geological_data = src.geological_data + //drop some rocks + next_rock += P.excavation_amount * 10 + while(next_rock > 100) + next_rock -= 100 + var/obj/item/weapon/ore/O = new(src) + geologic_data.UpdateNearbyArtifactInfo(src) + O.geologic_data = geologic_data - else - return attack_hand(user) - return + else + return attack_hand(user) -/turf/simulated/mineral/proc/drop_mineral() - var/obj/item/weapon/ore/O - if (src.mineralName == "Uranium") - O = new /obj/item/weapon/ore/uranium(src) - if (src.mineralName == "Iron") - O = new /obj/item/weapon/ore/iron(src) - if (src.mineralName == "Gold") - O = new /obj/item/weapon/ore/gold(src) - if (src.mineralName == "Silver") - O = new /obj/item/weapon/ore/silver(src) - if (src.mineralName == "Plasma") - O = new /obj/item/weapon/ore/plasma(src) - if (src.mineralName == "Diamond") - O = new /obj/item/weapon/ore/diamond(src) - if (src.mineralName == "Clown") - O = new /obj/item/weapon/ore/clown(src) - if(O) - src.geological_data.UpdateNearbyArtifactInfo(src) - O.geological_data = src.geological_data - return O -/turf/simulated/mineral/proc/gets_drilled(var/artifact_fail = 0) - //var/destroyed = 0 //used for breaking strange rocks - if ((src.mineralName != "") && (src.mineralAmt > 0) && (src.mineralAmt < 11)) - - //if the turf has already been excavated, some of it's ore has been removed - for (var/i=0;i[pick("A high pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fadaing away!
      " - if(pain) - flick("pain",M.pain) - if(prob(50)) - M.adjustBruteLoss(5) - else - flick("flash",M.flash) - if(prob(50)) - M.Stun(5) - M.apply_effect(25, IRRADIATE) - - var/turf/simulated/floor/plating/airless/asteroid/N = ChangeTurf(/turf/simulated/floor/plating/airless/asteroid) - N.fullUpdateMineralOverlays() - - return - -/turf/simulated/mineral/proc/excavate_find(var/prob_clean = 0, var/datum/find/F) - //with skill and luck, players can cleanly extract finds - //otherwise, they come out inside a chunk of rock - var/obj/item/weapon/X - if(prob_clean) - X = new/obj/item/weapon/archaeological_find(src, new_item_type = F.find_type) - else - X = new/obj/item/weapon/ore/strangerock(src, inside_item_type = F.find_type) - src.geological_data.UpdateNearbyArtifactInfo(src) - X:geological_data = src.geological_data - - //some find types delete the /obj/item/weapon/archaeological_find and replace it with something else, this handles when that happens - //yuck - var/display_name = "something" - if(!X) - X = last_find - if(X) - display_name = X.name - - //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted - if(prob(F.prob_delicate)) - var/obj/effect/suspension_field/S = locate() in src - if(!S || S.field_type != get_responsive_reagent(F.find_type)) - if(X) - src.visible_message("\red[pick("[display_name] crumbles away into dust","[display_name] breaks apart")].") - del(X) - - src.finds.Remove(F) - -/turf/simulated/mineral/proc/artifact_debris(var/severity = 0) - //cael's patented random limited drop componentized loot system! - severity = max(min(severity,1),0) - var/materials = 0 - var/list/viable_materials = list(1,2,4,8,16,32,64,128,256) - - var/num_materials = rand(1,3 + severity*2) - for(var/i=0, i[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)) + M.adjustBruteLoss(5) + else + flick("flash",M.flash) + if(prob(50)) + M.Stun(5) + M.apply_effect(25, IRRADIATE) + + var/turf/simulated/floor/plating/airless/asteroid/N = ChangeTurf(/turf/simulated/floor/plating/airless/asteroid) + N.fullUpdateMineralOverlays() + + if(rand(1,500) == 1) + visible_message("An old dusty crate was buried within!") + new /obj/structure/closet/crate/secure/loot(src) + + + proc/excavate_find(var/prob_clean = 0, var/datum/find/F) + //with skill and luck, players can cleanly extract finds + //otherwise, they come out inside a chunk of rock + var/obj/item/weapon/X + if(prob_clean) + X = new /obj/item/weapon/archaeological_find(src, new_item_type = F.find_type) + else + X = new /obj/item/weapon/ore/strangerock(src, inside_item_type = F.find_type) + geologic_data.UpdateNearbyArtifactInfo(src) + X:geologic_data = geologic_data + + //some find types delete the /obj/item/weapon/archaeological_find and replace it with something else, this handles when that happens + //yuck + var/display_name = "something" + if(!X) + X = last_find + if(X) + display_name = X.name + + //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted + if(prob(F.prob_delicate)) + var/obj/effect/suspension_field/S = locate() in src + if(!S || S.field_type != get_responsive_reagent(F.find_type)) + if(X) + visible_message("\red[pick("[display_name] crumbles away into dust","[display_name] breaks apart")].") + del(X) + + finds.Remove(F) + + + proc/artifact_debris(var/severity = 0) + //cael's patented random limited drop componentized loot system! + //sky's patented not-fucking-retarded overhaul! + + //Give a random amount of loot from 1 to 3 or 5, varying on severity. + for(var/j in 1 to rand(1, 3 + max(min(severity, 1), 0) * 2)) + switch(rand(1,7)) + if(1) + var/obj/item/stack/rods/R = new(src) + R.amount = rand(5,25) + + if(2) + var/obj/item/stack/tile/R = new(src) + R.amount = rand(1,5) + + if(3) + var/obj/item/stack/sheet/metal/R = new(src) + R.amount = rand(5,25) + + if(4) + var/obj/item/stack/sheet/plasteel/R = new(src) + R.amount = rand(5,25) + + if(5) + var/quantity = rand(1,3) + for(var/i=0, iAnother consciousness is in your body...It is resisting you." return - if(mind.current.ajourn && mind.current.stat != DEAD) //check if the corpse is astral-journeying (it's client ghosted using a cultist rune). + if(mind.current.ajourn && mind.current.stat != DEAD) //check if the corpse is astral-journeying (it's client ghosted using a cultist rune). var/obj/effect/rune/R = locate() in mind.current.loc //whilst corpse is alive, we can only reenter the body if it's on the rune if(!(R && R.word1 == cultwords["hell"] && R.word2 == cultwords["travel"] && R.word3 == cultwords["self"])) //astral journeying rune usr << "The astral cord that ties your body and your spirit has been severed. You are likely to wander the realm beyond until your body is finally dead and thus reunited with you." @@ -179,6 +301,45 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp mind.current.key = key return 1 +/mob/dead/observer/verb/toggle_medHUD() + set category = "Ghost" + set name = "Toggle MedicHUD" + set desc = "Toggles Medical HUD allowing you to see how everyone is doing" + if(!client) + return + if(medHUD) + medHUD = 0 + src << "\blue Medical HUD Disabled" + else + medHUD = 1 + src << "\blue Medical HUD Enabled" + +/mob/dead/observer/verb/toggle_antagHUD() + set category = "Ghost" + set name = "Toggle AntagHUD" + set desc = "Toggles AntagHUD allowing you to see who is the antagonist" + if(!config.antag_hud_allowed && !client.holder) + src << "\red Admins have disabled this for this round." + return + if(!client) + return + var/mob/dead/observer/M = src + if(jobban_isbanned(M, "AntagHUD")) + src << "\red You have been banned from using this feature" + return + if(config.antag_hud_restricted && !M.has_enabled_antagHUD &&!client.holder) + var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No") + if(response == "No") return + M.can_reenter_corpse = 0 + if(!M.has_enabled_antagHUD && !client.holder) + M.has_enabled_antagHUD = 1 + if(M.antagHUD) + M.antagHUD = 0 + src << "\blue AntagHUD Disabled" + else + M.antagHUD = 1 + src << "\blue AntagHUD Enabled" + /mob/dead/observer/proc/dead_tele() set category = "Ghost" set name = "Teleport" @@ -208,27 +369,30 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Follow" // "Haunt" set desc = "Follow and haunt a mob." - if(istype(usr, /mob/dead/observer)) - var/list/mobs = getmobs() - var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs - var/mob/target = mobs[input] - if(target && target != usr) - following = target - spawn(0) - var/turf/pos = get_turf(src) - while(src.loc == pos) + var/list/mobs = getmobs() + var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs + var/mob/target = mobs[input] + ManualFollow(target) - var/turf/T = get_turf(target) - if(!T) - break - if(following != target) - break - if(!client) - break - src.loc = T - pos = src.loc - sleep(15) - following = null +// This is the ghost's follow verb with an argument +/mob/dead/observer/proc/ManualFollow(var/atom/movable/target) + if(target && target != src) + if(following && following == target) + return + following = target + src << "\blue Now following [target]" + spawn(0) + var/turf/pos = get_turf(src) + while(loc == pos && target && following == target && client) + var/turf/T = get_turf(target) + if(!T) + break + // To stop the ghost flickering. + if(loc != T) + loc = T + pos = loc + sleep(15) + following = null /mob/dead/observer/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak @@ -280,6 +444,58 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set hidden = 1 src << "\red You are dead! You have no mind to store memory!" +/mob/dead/observer/verb/analyze_air() + set name = "Analyze Air" + set category = "Ghost" + + if(!istype(usr, /mob/dead/observer)) return + + // Shamelessly copied from the Gas Analyzers + if (!( istype(usr.loc, /turf) )) + return + + var/datum/gas_mixture/environment = usr.loc.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles() + + src << "\blue Results:" + if(abs(pressure - ONE_ATMOSPHERE) < 10) + src << "\blue Pressure: [round(pressure,0.1)] kPa" + else + src << "\red Pressure: [round(pressure,0.1)] kPa" + if(total_moles) + var/o2_concentration = environment.oxygen/total_moles + var/n2_concentration = environment.nitrogen/total_moles + var/co2_concentration = environment.carbon_dioxide/total_moles + var/plasma_concentration = environment.toxins/total_moles + + var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration) + if(abs(n2_concentration - N2STANDARD) < 20) + src << "\blue Nitrogen: [round(n2_concentration*100)]% ([round(environment.nitrogen,0.01)] moles)" + else + src << "\red Nitrogen: [round(n2_concentration*100)]% ([round(environment.nitrogen,0.01)] moles)" + + if(abs(o2_concentration - O2STANDARD) < 2) + src << "\blue Oxygen: [round(o2_concentration*100)]% ([round(environment.oxygen,0.01)] moles)" + else + src << "\red Oxygen: [round(o2_concentration*100)]% ([round(environment.oxygen,0.01)] moles)" + + if(co2_concentration > 0.01) + src << "\red CO2: [round(co2_concentration*100)]% ([round(environment.carbon_dioxide,0.01)] moles)" + else + src << "\blue CO2: [round(co2_concentration*100)]% ([round(environment.carbon_dioxide,0.01)] moles)" + + if(plasma_concentration > 0.01) + src << "\red Plasma: [round(plasma_concentration*100)]% ([round(environment.toxins,0.01)] moles)" + + if(unknown_concentration > 0.01) + src << "\red Unknown: [round(unknown_concentration*100)]% ([round(unknown_concentration*total_moles,0.01)] moles)" + + src << "\blue Temperature: [round(environment.temperature-T0C,0.1)]°C" + src << "\blue Heat Capacity: [round(environment.heat_capacity(),0.1)]" + + /mob/dead/observer/verb/toggle_darkness() set name = "Toggle Darkness" set category = "Ghost" @@ -293,6 +509,15 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Become mouse" set category = "Ghost" + if(config.disable_player_mice) + src << "Spawning as a mouse is currently disabled." + return + + var/mob/dead/observer/M = usr + if(config.antag_hud_restricted && M.has_enabled_antagHUD == 1) + src << "antagHUD restrictions prevent you from spawning in as a mouse." + return + var/timedifference = world.time - client.time_died_as_mouse if(client.time_died_as_mouse && timedifference <= mouse_respawn_time * 600) var/timedifference_text @@ -300,6 +525,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp src << "You may only spawn again as a mouse more than [mouse_respawn_time] minutes after your death. You have [timedifference_text] left." return + var/response = alert(src, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?","Squeek!","Nope!") + if(response != "Squeek!") return //Hit the wrong key...again. + + //find a viable mouse candidate var/mob/living/simple_animal/mouse/host var/obj/machinery/atmospherics/unary/vent_pump/vent_found @@ -314,6 +543,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp src << "Unable to find any unwelded vents to spawn mice at." if(host) + if(config.uneducated_mice) + host.universal_understand = 0 host.ckey = src.ckey host << "You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent." @@ -326,3 +557,79 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp dat += data_core.get_manifest() src << browse(dat, "window=manifest;size=370x420;can_close=1") + +//Used for drawing on walls with blood puddles as a spooky ghost. +/mob/dead/verb/bloody_doodle() + + set category = "Ghost" + set name = "Write in blood" + set desc = "If the round is sufficiently spooky, write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC." + + if(!(config.cult_ghostwriter)) + src << "\red That verb is not currently permitted." + return + + if (!src.stat) + return + + if (usr != src) + return 0 //something is terribly wrong + + var/ghosts_can_write + if(ticker.mode.name == "cult") + var/datum/game_mode/cult/C = ticker.mode + if(C.cult.len > config.cult_ghostwriter_req_cultists) + ghosts_can_write = 1 + + if(!ghosts_can_write) + src << "\red The veil is not thin enough for you to do that." + return + + var/list/choices = list() + for(var/obj/effect/decal/cleanable/blood/B in view(1,src)) + if(B.amount > 0) + choices += B + + if(!choices.len) + src << "There is no blood to use nearby." + return + + var/obj/effect/decal/cleanable/blood/choice = input(src,"What blood would you like to use?") in null|choices + + var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West") + var/turf/simulated/T = src.loc + if (direction != "Here") + T = get_step(T,text2dir(direction)) + + if (!istype(T)) + src << "You cannot doodle there." + return + + if(!choice || choice.amount == 0 || !(src.Adjacent(choice))) + return + + var/doodle_color = (choice.basecolor) ? choice.basecolor : "#A10808" + + var/num_doodles = 0 + for (var/obj/effect/decal/cleanable/blood/writing/W in T) + num_doodles++ + if (num_doodles > 4) + src << "There is no space to write on!" + return + + var/max_length = 50 + + var/message = stripped_input(src,"Write a message. It cannot be longer than [max_length] characters.","Blood writing", "") + + if (message) + + if (length(message) > max_length) + message += "-" + src << "You ran out of blood to write with!" + + var/obj/effect/decal/cleanable/blood/writing/W = new(T) + W.basecolor = doodle_color + W.update_icon() + W.message = message + W.add_hiddenprint(src) + W.visible_message("\red Invisible fingers crudely paint something in blood on [T]...") diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index db9cd2129c6..34a0d44d631 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -1,5 +1,5 @@ /mob/dead/observer/say(var/message) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN)) if (!message) return @@ -18,7 +18,7 @@ /mob/dead/observer/emote(var/act, var/type, var/message) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN)) if(!message) return @@ -62,4 +62,4 @@ M.show_message("You hear muffled speech... you can almost make out some words...", 2) // M.show_message("[stutter(message)]", 2) playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1) -*/ \ No newline at end of file +*/ diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 416528d3fc0..e2125ada66c 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -36,11 +36,15 @@ M.show_message(message) + // Type 1 (Visual) emotes are sent to anyone in view of the item if (m_type & 1) for (var/mob/O in viewers(src, null)) O.show_message(message, m_type) + + // Type 2 (Audible) emotes are sent to anyone in hear range + // of the *LOCATION* -- this is important for pAIs to be heard else if (m_type & 2) - for (var/mob/O in hearers(src.loc, null)) + for (var/mob/O in hearers(get_turf(src), null)) O.show_message(message, m_type) /mob/proc/emote_dead(var/message) @@ -53,6 +57,12 @@ src << "\red You have deadchat muted." return + if(!src.client.holder) + if(!dsay_allowed) + src << "\red Deadchat is globally muted" + return + + var/input if(!message) input = copytext(sanitize(input(src, "Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN) diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index ea82e57925b..c94e85658ce 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -6,7 +6,7 @@ var/name = "an unknown language" // Fluff name of language if any. var/desc = "A language." // Short description for 'Check Languages'. var/speech_verb = "says" // 'says', 'hisses', 'farts'. - var/colour = "say_quote" // CSS style to use for strings in this language. + var/colour = "body" // CSS style to use for strings in this language. var/key = "x" // Character used to speak in language eg. :o for Unathi. var/flags = 0 // Various language flags. var/native // If set, non-native speakers will have trouble speaking. @@ -54,6 +54,7 @@ /datum/language/human name = "Sol Common" desc = "A bastardized hybrid of informal English and elements of Mandarin Chinese; the common language of the Sol system." + colour = "rough" key = "1" flags = RESTRICTED @@ -62,35 +63,30 @@ name = "Tradeband" desc = "Maintained by the various trading cartels in major systems, this elegant, structured language is used for bartering and bargaining." speech_verb = "enunciates" + colour = "say_quote" key = "2" /datum/language/gutter name = "Gutter" desc = "Much like Standard, this crude pidgin tongue descended from numerous languages and serves as Tradeband for criminal elements." speech_verb = "growls" + colour = "rough" key = "3" // Language handling. /mob/proc/add_language(var/language) - for(var/datum/language/L in languages) - if(L && L.name == language) - return 0 - var/datum/language/new_language = all_languages[language] - if(!istype(new_language,/datum/language)) + if(!istype(new_language) || new_language in languages) return 0 - languages += new_language + languages.Add(new_language) return 1 /mob/proc/remove_language(var/rem_language) - for(var/datum/language/L in languages) - if(L && L.name == rem_language) - languages -= L - return 1 + languages.Remove(all_languages[rem_language]) return 0 diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm index 7487ffa6313..2b084ce8b5c 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm @@ -31,6 +31,10 @@ continue no_queen = 0 + if(src.has_brain_worms()) + src << "We cannot perform this ability at the present time!" + return + if(no_queen) adjustToxLoss(-500) src << "\green You begin to evolve!" 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/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index f8c014278c2..fa02150ab38 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -27,6 +27,8 @@ proc/request_player() for(var/mob/dead/observer/O in player_list) + if(O.has_enabled_antagHUD == 1 && config.antag_hud_restricted) + continue if(jobban_isbanned(O, "pAI")) continue if(O.client) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index dbca1091c63..feacbe4a981 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -221,99 +221,6 @@ // ++++ROCKDTBEN++++ MOB PROCS //END -/mob/living/carbon/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null) // -- TLE -- Merged by Carn - if(stat) - src << "You must be conscious to do this!" - return - if(lying) - src << "You can't vent crawl while you're stunned!" - return - - if(vent_found) // one was passed in, probably from vent/AltClick() - if(vent_found.welded) - src << "That vent is welded shut." - return - if(!vent_found.Adjacent(src)) - return // don't even acknowledge that - else - for(var/obj/machinery/atmospherics/unary/vent_pump/v in range(1,src)) - if(!v.welded) - if(v.Adjacent(src)) - vent_found = v - if(!vent_found) - src << "You'll need a non-welded vent to crawl into!" - return - - if(!vent_found.network || !vent_found.network.normal_members.len) - src << "This vent is not connected to anything." - return - - var/list/vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in vent_found.network.normal_members) - if(temp_vent.welded) - continue - if(temp_vent in loc) - continue - var/turf/T = get_turf(temp_vent) - - if(!T || T.z != loc.z) - continue - - var/i = 1 - var/index = "[T.loc.name]\[[i]\]" - while(index in vents) - i++ - index = "[T.loc.name]\[[i]\]" - vents[index] = temp_vent - if(!vents.len) - src << "\red There are no available vents to travel to, they could be welded." - return - - var/obj/selection = input("Select a destination.", "Duct System") as null|anything in sortAssoc(vents) - if(!selection) return - - if(!vent_found.Adjacent(src)) - src << "Never mind, you left." - return - - for(var/obj/item/carried_item in contents)//If the monkey got on objects. - if( !istype(carried_item, /obj/item/weapon/implant) && !istype(carried_item, /obj/item/clothing/mask/facehugger) )//If it's not an implant or a facehugger - src << "\red You can't be carrying items or have items equipped when vent crawling!" - return - if(isslime(src)) - var/mob/living/carbon/slime/S = src - if(S.Victim) - src << "\red You'll have to let [S.Victim] go or finish eating \him first." - return - - var/obj/machinery/atmospherics/unary/vent_pump/target_vent = vents[selection] - if(!target_vent) - return - - for(var/mob/O in viewers(src, null)) - O.show_message(text("[src] scrambles into the ventillation ducts!"), 1) - loc = target_vent - - var/travel_time = round(get_dist(loc, target_vent.loc) / 2) - - spawn(travel_time) - - if(!target_vent) return - for(var/mob/O in hearers(target_vent,null)) - O.show_message("You hear something squeezing through the ventilation ducts.",2) - - sleep(travel_time) - - if(!target_vent) return - if(target_vent.welded) //the vent can be welded while alien scrolled through the list or travelled. - target_vent = vent_found //travel back. No additional time required. - src << "\red The vent you were heading to appears to be welded." - loc = target_vent.loc - var/area/new_area = get_area(loc) - if(new_area) - new_area.Entered(src) - - /mob/living/carbon/clean_blood() . = ..() if(ishuman(src)) @@ -532,7 +439,7 @@ B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!" //Check for brain worms in head. -/mob/living/carbon/proc/has_brain_worms() +/mob/proc/has_brain_worms() for(var/I in contents) if(istype(I,/mob/living/simple_animal/borer)) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 95ebdf20117..289ecf67ace 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -20,7 +20,10 @@ E.droplimb(1,1) flick("gibbed-h", animation) - hgibs(loc, viruses, dna) + if(species) + hgibs(loc, viruses, dna, species.flesh_color, species.blood_color) + else + hgibs(loc, viruses, dna) spawn(15) if(animation) del(animation) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 1b1d5a72c74..c1bb0af84d3 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -243,7 +243,7 @@ if(!key && brain_op_stage != 4 && stat != DEAD) msg += "[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely\n" else if(!client && brain_op_stage != 4 && stat != DEAD) - msg += "[t_He] [t_has] a vacant, braindead stare...\n" + msg += "[t_He] [t_has] suddenly fallen asleep.\n" var/list/wound_flavor_text = list() var/list/is_destroyed = list() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 74cab645053..a8dfac9f134 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -40,11 +40,6 @@ if(!species) set_species() - if(species.language) - var/datum/language/L = all_languages[species.language] - if(L) - languages += L - var/datum/reagents/R = new/datum/reagents(1000) reagents = R R.my_atom = src @@ -776,6 +771,14 @@ if(istype(usr,/mob/living/silicon/robot)) var/mob/living/silicon/robot/U = usr R.fields[text("com_[counter]")] = text("Made by [U.name] ([U.modtype] [U.braintype]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
      [t1]") + + if (href_list["lookitem"]) + var/obj/item/I = locate(href_list["lookitem"]) + I.examine() + + if (href_list["lookmob"]) + var/mob/M = locate(href_list["lookmob"]) + M.examine() ..() return @@ -1019,17 +1022,21 @@ O.status &= ~ORGAN_BROKEN O.status &= ~ORGAN_BLEEDING O.status &= ~ORGAN_SPLINTED + O.status &= ~ORGAN_CUT_AWAY O.status &= ~ORGAN_ATTACHABLE if (!O.amputated) O.status &= ~ORGAN_DESTROYED + O.destspawn = 0 O.wounds.Cut() O.heal_damage(1000,1000,1,1) var/datum/organ/external/head/h = organs_by_name["head"] h.disfigured = 0 - vessel.add_reagent("blood",560-vessel.total_volume) - fixblood() + if(species && !(species.flags & NO_BLOOD)) + vessel.add_reagent("blood",560-vessel.total_volume) + fixblood() + for (var/obj/item/weapon/organ/head/H in world) if(H.brainmob) if(H.brainmob.real_name == src.real_name) @@ -1100,6 +1107,7 @@ return 0 //already bloodied with this blood. Cannot add more. blood_DNA[M.dna.unique_enzymes] = M.dna.b_type src.update_inv_gloves() //handles bloody hands overlays and updating + verbs += /mob/living/carbon/human/proc/bloody_doodle return 1 //we applied blood to the item /mob/living/carbon/human/clean_blood() @@ -1108,83 +1116,7 @@ del(feet_blood_DNA) return 1 -mob/living/carbon/human/yank_out_object() - set category = "Object" - set name = "Yank out object" - set desc = "Remove an embedded item at the cost of bleeding and pain." - set src in view(1) - - if(!isliving(usr) || usr.next_move > world.time) - return - usr.next_move = world.time + 20 - - if(usr.stat == 1) - usr << "You are unconcious and cannot do that!" - return - - if(usr.restrained()) - usr << "You are restrained and cannot do that!" - return - - var/list/valid_objects = list() - var/datum/organ/external/affected = null - var/mob/living/carbon/human/S = src - var/mob/living/carbon/human/U = usr - var/self = null - - if(S == U) - self = 1 // Removing object from yourself. - - valid_objects = get_visible_implants(1) - - if(!valid_objects.len) - if(self) - src << "You have nothing stuck in your wounds that is large enough to remove without surgery." - else - U << "[src] has nothing stuck in their wounds that is large enough to remove without surgery." - return - - var/obj/item/weapon/selection = input("What do you want to yank out?", "Embedded objects") in valid_objects - - for(var/datum/organ/external/organ in organs) //Grab the organ holding the implant. - for(var/obj/item/weapon/O in organ.implants) - if(O == selection) - affected = organ - if(self) - src << "You attempt to get a good grip on the [selection] in your [affected.display_name] with bloody fingers." - else - U << "You attempt to get a good grip on the [selection] in [S]'s [affected.display_name] with bloody fingers." - - if(istype(U,/mob/living/carbon/human/)) U.bloody_hands(S) - - if(!do_after(U, 80)) - return - - if(!selection || !affected || !S || !U) - return - - if(self) - visible_message("[src] rips [selection] out of their [affected.display_name] in a welter of blood.","You rip [selection] out of your [affected] in a welter of blood.") - else - visible_message("[usr] rips [selection] out of [src]'s [affected.display_name] in a welter of blood.","[usr] rips [selection] out of your [affected] in a welter of blood.") - - selection.loc = get_turf(src) - affected.implants -= selection - shock_stage+=10 - - for(var/obj/item/weapon/O in pinned) - if(O == selection) - pinned -= O - if(!pinned.len) - anchored = 0 - - if(prob(10)) //I'M SO ANEMIC I COULD JUST -DIE-. - var/datum/wound/internal_bleeding/I = new (15) - affected.wounds += I - custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 1) - return 1 - -/mob/living/carbon/human/proc/get_visible_implants(var/class = 0) +/mob/living/carbon/human/get_visible_implants(var/class = 0) var/list/visible_implants = list() for(var/datum/organ/external/organ in src.organs) @@ -1257,8 +1189,14 @@ mob/living/carbon/human/yank_out_object() if(species && (species.name && species.name == new_species)) return + if(species && species.language) + remove_language(species.language) + species = all_species[new_species] + if(species.language) + add_language(species.language) + spawn(0) update_icons() @@ -1266,3 +1204,58 @@ mob/living/carbon/human/yank_out_object() return 1 else return 0 + +/mob/living/carbon/human/proc/bloody_doodle() + set category = "IC" + set name = "Write in blood" + set desc = "Use blood on your hands to write a short message on the floor or a wall, murder mystery style." + + if (src.stat) + return + + if (usr != src) + return 0 //something is terribly wrong + + if (!bloody_hands) + verbs -= /mob/living/carbon/human/proc/bloody_doodle + + if (src.gloves) + src << "Your [src.gloves] are getting in the way." + return + + var/turf/simulated/T = src.loc + if (!istype(T)) //to prevent doodling out of mechs and lockers + src << "You cannot reach the floor." + return + + var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West") + if (direction != "Here") + T = get_step(T,text2dir(direction)) + if (!istype(T)) + src << "You cannot doodle there." + return + + var/num_doodles = 0 + for (var/obj/effect/decal/cleanable/blood/writing/W in T) + num_doodles++ + if (num_doodles > 4) + src << "There is no space to write on!" + return + + var/max_length = bloody_hands * 30 //tweeter style + + var/message = stripped_input(src,"Write a message. It cannot be longer than [max_length] characters.","Blood writing", "") + + if (message) + var/used_blood_amount = round(length(message) / 30, 1) + bloody_hands = max(0, bloody_hands - used_blood_amount) //use up some blood + + if (length(message) > max_length) + message += "-" + src << "You ran out of blood to write with!" + + var/obj/effect/decal/cleanable/blood/writing/W = new(T) + W.basecolor = (hand_blood_color) ? hand_blood_color : "#A10808" + W.update_icon() + W.message = message + W.add_fingerprint(src) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 4ca6efea54c..17fb4fc3ebe 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. @@ -245,20 +245,11 @@ This function restores all organs. if( (damage > (10*W.w_class)) && ( (sharp && !ismob(W.loc)) || prob(damage/W.w_class) ) ) organ.implants += W visible_message("\The [W] sticks in the wound!") + src.verbs += /mob/proc/yank_out_object W.add_blood(src) if(ismob(W.loc)) var/mob/living/H = W.loc H.drop_item() 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/weapon/shard/shrapnel/S = new() - S.name = "[P.name] shrapnel" - S.desc = "[S.desc] It looks like it was fired from [P.shot_from]." - S.loc = src - organ.implants += S - visible_message("The projectile sticks in the wound!") - S.add_blood(src) return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 4044c0aae1f..c7273d5d345 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -88,6 +88,19 @@ emp_act return //END TASER NERF + var/datum/organ/external/organ = get_organ(check_zone(def_zone)) + + var/armor = checkarmor(organ, "bullet") + + if((P.embed && prob(20 + max(P.damage - armor, -10))) && P.damage_type == BRUTE) + var/obj/item/weapon/shard/shrapnel/SP = new() + (SP.name) = "[P.name] shrapnel" + (SP.desc) = "[SP.desc] It looks like it was fired from [P.shot_from]." + (SP.loc) = organ + organ.implants += SP + visible_message("The projectile sticks in the wound!") + src.verbs += /mob/proc/yank_out_object + SP.add_blood(src) return (..(P , def_zone)) @@ -122,6 +135,16 @@ emp_act protection += C.armor[type] return protection +/mob/living/carbon/human/proc/check_head_coverage() + + var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) + for(var/bp in body_parts) + if(!bp) continue + if(bp && istype(bp ,/obj/item/clothing)) + var/obj/item/clothing/C = bp + if(C.body_parts_covered & HEAD) + return 1 + return 0 /mob/living/carbon/human/proc/check_shields(var/damage = 0, var/attack_text = "the attack") if(l_hand && istype(l_hand, /obj/item/weapon))//Current base is the prob(50-d/3) @@ -159,6 +182,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) ..() @@ -170,14 +196,14 @@ emp_act target_zone = user.zone_sel.selecting if(!target_zone) visible_message("\red [user] misses [src] with \the [I]!") - return + return 0 var/datum/organ/external/affecting = get_organ(target_zone) if (!affecting) - return + return 0 if(affecting.status & ORGAN_DESTROYED) user << "What [affecting.display_name]?" - return + return 0 var/hit_area = affecting.display_name if((user != src) && check_shields(I.force, "the [I.name]")) @@ -194,7 +220,7 @@ emp_act var/obj/item/weapon/card/emag/emag = I emag.uses-- affecting.sabotaged = 1 - return + return 1 if(I.attack_verb.len) visible_message("\red [src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!") @@ -249,6 +275,7 @@ emp_act if(bloody) bloody_body(src) + return 1 /mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2) if (gloves) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 315b3f40915..4611dda0d82 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. @@ -56,3 +56,4 @@ var/xylophone = 0 //For the spoooooooky xylophone cooldown var/mob/remoteview_target = null + var/hand_blood_color \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 3424bdb562d..25aff551cf1 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -1,6 +1,9 @@ /mob/living/carbon/human/movement_delay() var/tally = 0 + if(species && species.flags & IS_SLOW) + tally = 7 + if (istype(loc, /turf/space)) return -1 // It's hard to be slowed down in space by... anything handle_embedded_objects() //Moving with objects stuck in you can cause bad times. diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 2ccf4f37406..64d1ff64ef3 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -81,20 +81,20 @@ if (W == wear_suit) if(s_store) - u_equip(s_store) + drop_from_inventory(s_store) if(W) success = 1 wear_suit = null update_inv_wear_suit() else if (W == w_uniform) if (r_store) - u_equip(r_store) + drop_from_inventory(r_store) if (l_store) - u_equip(l_store) + drop_from_inventory(l_store) if (wear_id) - u_equip(wear_id) + drop_from_inventory(wear_id) if (belt) - u_equip(belt) + drop_from_inventory(belt) w_uniform = null success = 1 update_inv_w_uniform() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 19d00be7004..b2a2180eadc 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -242,7 +242,7 @@ var/rads = radiation/25 radiation -= rads nutrition += rads - heal_overall_damage(rads,rads) + adjustBruteLoss(-(rads)) adjustOxyLoss(-(rads)) adjustToxLoss(-(rads)) updatehealth() @@ -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) @@ -866,7 +866,15 @@ */ proc/handle_chemicals_in_body() - if(reagents) reagents.metabolize(src) + if(reagents) + + var/alien = 0 //Not the best way to handle it, but neater than checking this for every single reagent proc. + if(species && species.name == "Diona") + alien = 1 + else if(species && species.name == "Vox") + alien = 2 + reagents.metabolize(src,alien) + var/total_plasmaloss = 0 for(var/obj/item/I in src) if(I.contaminated) @@ -885,12 +893,15 @@ nutrition += light_amount traumatic_shock -= light_amount - if(nutrition > 500) - nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - heal_overall_damage(1,1) - adjustToxLoss(-1) - adjustOxyLoss(-1) + if(species.flags & IS_PLANT) + if(nutrition > 500) + nutrition = 500 + if(light_amount >= 3) //if there's enough light, heal + adjustBruteLoss(-(light_amount)) + adjustToxLoss(-(light_amount)) + adjustOxyLoss(-(light_amount)) + //TODO: heal wounds, heal broken limbs. + if(dna && dna.mutantrace == "shadow") var/light_amount = 0 if(isturf(loc)) @@ -960,6 +971,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 @@ -1178,6 +1192,13 @@ see_in_dark = 8 if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO if(healths) healths.icon_state = "health7" //DEAD healthmeter + if(client) + if(client.view != world.view) + if(locate(/obj/item/weapon/gun/energy/sniperrifle, contents)) + var/obj/item/weapon/gun/energy/sniperrifle/s = locate() in src + if(s.zoom) + s.zoom() + else sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) see_in_dark = species.darksight @@ -1259,7 +1280,7 @@ if(2) healths.icon_state = "health7" else //switch(health - halloss) - switch(100 - traumatic_shock) + switch(100 - ((species && species.flags & NO_PAIN) ? 0 : traumatic_shock)) if(100 to INFINITY) healths.icon_state = "health0" if(80 to 100) healths.icon_state = "health1" if(60 to 80) healths.icon_state = "health2" @@ -1335,10 +1356,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 @@ -1423,7 +1440,7 @@ handle_shock() ..() if(status_flags & GODMODE) return 0 //godmode - if(analgesic) return // analgesic avoids all traumatic shock temporarily + if(analgesic || (species && species.flags & NO_PAIN)) return // analgesic avoids all traumatic shock temporarily if(health < config.health_threshold_softcrit)// health 0 makes you immediately collapse shock_stage = max(shock_stage, 61) @@ -1433,7 +1450,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,19 +1467,33 @@ 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) + if(species && species.flags & NO_BLOOD) return PULSE_NONE //No blood, no pulse. + if(stat == DEAD) return PULSE_NONE //that's it, you're dead, nothing can influence your pulse @@ -1485,6 +1516,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/say.dm b/code/modules/mob/living/carbon/human/say.dm index ba6733010b0..f284a5fda85 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -12,7 +12,7 @@ if(findtext(temp_message[H], "*") || findtext(temp_message[H], ";") || findtext(temp_message[H], ":")) continue temp_message[H] = ninjaspeak(temp_message[H]) pick_list -= H - message = dd_list2text(temp_message, " ") + message = list2text(temp_message, " ") message = replacetext(message, "o", "¤") message = replacetext(message, "p", "þ") message = replacetext(message, "l", "£") @@ -71,4 +71,3 @@ /mob/living/carbon/human/proc/GetSpecialVoice() return special_voice - diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 7d76cc91b42..6063f544d62 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,22 @@ 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' + standing.icon = ((w_uniform.icon_override) ? w_uniform.icon_override : '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") + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "uniformblood") + bloodsies.color = w_uniform.blood_color + standing.overlays += bloodsies 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 +499,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 +510,49 @@ 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]") + var/image/standing = image("icon" = ((gloves.icon_override) ? gloves.icon_override : '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") + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands") + bloodsies.color = gloves.blood_color + standing.overlays += bloodsies 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") + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands") + bloodsies.color = hand_blood_color + overlays_standing[GLOVES_LAYER] = bloodsies 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]") + overlays_standing[GLASSES_LAYER] = image("icon" = ((glasses.icon_override) ? glasses.icon_override : '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]") + overlays_standing[EARS_LAYER] = image("icon" = ((l_ear.icon_override) ? l_ear.icon_override : '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]") + overlays_standing[EARS_LAYER] = image("icon" = ((r_ear.icon_override) ? r_ear.icon_override : '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]") + var/image/standing = image("icon" = ((shoes.icon_override) ? shoes.icon_override : '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 + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "shoeblood") + bloodsies.color = shoes.blood_color + standing.overlays += bloodsies overlays_standing[SHOES_LAYER] = standing else - overlays_lying[SHOES_LAYER] = null overlays_standing[SHOES_LAYER] = null if(update_icons) update_icons() @@ -606,11 +560,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 +570,17 @@ 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]") + standing = image("icon" = ((head.icon_override) ? head.icon_override : '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 + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood") + bloodsies.color = head.blood_color + standing.overlays += bloodsies overlays_standing[HEAD_LAYER] = standing else - overlays_lying[HEAD_LAYER] = null overlays_standing[HEAD_LAYER] = null if(update_icons) update_icons() @@ -641,10 +589,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]") + overlays_standing[BELT_LAYER] = image("icon" = ((belt.icon_override) ? belt.icon_override : '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,8 +598,7 @@ 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]") + var/image/standing = image("icon" = ((wear_suit.icon_override) ? wear_suit.icon_override : 'icons/mob/suit.dmi'), "icon_state" = "[wear_suit.icon_state]") if( istype(wear_suit, /obj/item/clothing/suit/straight_jacket) ) drop_from_inventory(handcuffed) @@ -662,16 +607,15 @@ 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") + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[S.blood_overlay_type]blood") + bloodsies.color = wear_suit.blood_color + standing.overlays += bloodsies - 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 +631,13 @@ 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]") + var/image/standing = image("icon" = ((wear_mask.icon_override) ? wear_mask.icon_override : '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 + var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "maskblood") + bloodsies.color = wear_mask.blood_color + standing.overlays += bloodsies overlays_standing[FACEMASK_LAYER] = standing else - overlays_lying[FACEMASK_LAYER] = null overlays_standing[FACEMASK_LAYER] = null if(update_icons) update_icons() @@ -703,10 +645,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]") + overlays_standing[BACK_LAYER] = image("icon" = ((back.icon_override) ? back.icon_override : '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 +663,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 +677,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 +705,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/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm index 53320e3c525..7f7f977b70b 100644 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -52,7 +52,7 @@ if(findtext(temp_message[H], "*") || findtext(temp_message[H], ";") || findtext(temp_message[H], ":")) continue temp_message[H] = ninjaspeak(temp_message[H]) pick_list -= H - message = dd_list2text(temp_message, " ") + message = list2text(temp_message, " ") message = replacetext(message, "o", "¤") message = replacetext(message, "p", "þ") message = replacetext(message, "l", "£") diff --git a/code/modules/mob/living/carbon/monkey/diona.dm b/code/modules/mob/living/carbon/monkey/diona.dm index 3780cdb6836..d26de1f9a94 100644 --- a/code/modules/mob/living/carbon/monkey/diona.dm +++ b/code/modules/mob/living/carbon/monkey/diona.dm @@ -2,14 +2,68 @@ Tiny babby plant critter plus procs. */ +//Helper object for picking dionaea (and other creatures) up. +/obj/item/weapon/holder + name = "holder" + desc = "You shouldn't ever see this." + +/obj/item/weapon/holder/diona + + name = "diona nymph" + desc = "It's a tiny plant critter." + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + slot_flags = SLOT_HEAD + origin_tech = "magnets=3;biotech=5" + +/obj/item/weapon/holder/New() + ..() + processing_objects.Add(src) + +/obj/item/weapon/holder/Del() + //Hopefully this will stop the icon from remaining on human mobs. + if(istype(loc,/mob/living)) + var/mob/living/A = src.loc + src.loc = null + A.update_icons() + processing_objects.Remove(src) + ..() + +/obj/item/weapon/holder/process() + if(!loc) return + + if(istype(loc,/turf) || !(contents.len)) + for(var/mob/M in contents) + M.loc = get_turf(src) + del(src) + +/obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob) + for(var/mob/M in src.contents) + M.attackby(W,user) + +//Mob defines. /mob/living/carbon/monkey/diona name = "diona nymph" voice_name = "diona nymph" speak_emote = list("chirrups") - ico = "nymph" + icon_state = "nymph1" var/list/donors = list() var/ready_evolve = 0 +/mob/living/carbon/monkey/diona/attack_hand(mob/living/carbon/human/M as mob) + + //Let people pick the little buggers up. + if(M.a_intent == "help") + var/obj/item/weapon/holder/diona/D = new(loc) + src.loc = D + D.name = loc.name + D.attack_hand(M) + M << "You scoop up [src]." + src << "[M] scoops you up." + return + + ..() + /mob/living/carbon/monkey/diona/New() ..() @@ -64,17 +118,28 @@ set name = "Evolve" set desc = "Grow to a more complex form." + if(!is_alien_whitelisted(src, "Diona") && config.usealienwhitelist) + src << alert("You are currently not whitelisted to play as a full diona.") + return 0 + if(donors.len < 5) src << "You are not yet ready for your growth..." return - if(reagents.get_reagent_amount("nutriment") < 5) + if(nutrition < 400) src << "You have not yet consumed enough to grow..." return src.visible_message("\red [src] begins to shift and quiver, and erupts in a shower of shed bark and twigs!","\red You begin to shift and quiver, then erupt in a shower of shed bark and twigs, attaining your adult form!") - var/mob/living/carbon/human/adult = new(loc) + + var/mob/living/carbon/human/adult = new(get_turf(src.loc)) adult.set_species("Diona") + + if(istype(loc,/obj/item/weapon/holder/diona)) + var/obj/item/weapon/holder/diona/L = loc + src.loc = L.loc + del(L) + for(var/datum/language/L in languages) adult.add_language(L.name) adult.regenerate_icons() @@ -118,8 +183,11 @@ if(donors.len == 5) ready_evolve = 1 src << "\green You feel ready to move on to your next stage of growth." - else if(donors.len == 3) + else if(donors.len == 2) + universal_understand = 1 + src << "\green You feel your awareness expand, and realize you know how to understand the creatures around you." + else if(donors.len == 4) universal_speak = 1 - src << "\green You feel your awareness expand, and realize you know how to speak to the meat-creatures around you." + src << "\green You feel your awareness expand, and realize you know how to speak with the creatures around you." else - src << "\green The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind." \ No newline at end of file + src << "\green The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind." diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index 49fea7308ae..4ec4d413062 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -13,13 +13,16 @@ set invisibility = 0 set background = 1 if (monkeyizing) return + if (update_muts) + update_muts=0 + domutcheck(src,null,MUTCHK_FORCED) ..() var/datum/gas_mixture/environment // Added to prevent null location errors-- TLE if(loc) environment = loc.return_air() - if (stat != DEAD) //still breathing + if (stat != DEAD && !istype(src,/mob/living/carbon/monkey/diona)) //still breathing //First, resolve location and get a breath if(air_master.current_cycle%4==2) //Only try to take a breath every 4 seconds, unless suffocating @@ -67,8 +70,11 @@ G.process() if(!client && stat == CONSCIOUS) - if(prob(33) && canmove && isturf(loc)) + + if(prob(33) && canmove && isturf(loc) && !pulledby) //won't move if being pulled + step(src, pick(cardinal)) + if(prob(1)) emote(pick("scratch","jump","roll","tail")) @@ -250,7 +256,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) @@ -434,7 +440,7 @@ proc/handle_chemicals_in_body() - if(istype(src,/mob/living/carbon/monkey/diona)) //Filthy check. Dionaea nymphs need light or they get sad. + if(alien) //Diona nymphs are the only alien monkey currently. var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing if(isturf(loc)) //else, there's considered to be no light var/turf/T = loc @@ -449,11 +455,11 @@ if(nutrition > 500) nutrition = 500 if(light_amount > 2) //if there's enough light, heal - heal_overall_damage(1,1) + adjustBruteLoss(-1) adjustToxLoss(-1) adjustOxyLoss(-1) - if(reagents) reagents.metabolize(src) + if(reagents) reagents.metabolize(src,alien) if (drowsyness) drowsyness-- diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index d7add5b0888..42fbb8fa02e 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -10,29 +10,32 @@ 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. + icon_state = "monkey1" + //var/uni_append = "12C4E2" // Small appearance modifier for different species. + var/list/uni_append = list(0x12C,0x4E2) // Same as above for DNA2. + var/update_muts = 1 // Monkey gene must be set at start. + var/alien = 0 //Used for reagent metabolism. /mob/living/carbon/monkey/tajara name = "farwa" voice_name = "farwa" speak_emote = list("mews") - ico = "tajkey" - uni_append = "0A0E00" + icon_state = "tajkey1" + uni_append = list(0x0A0,0xE00) // 0A0E00 /mob/living/carbon/monkey/skrell name = "neaera" voice_name = "neaera" speak_emote = list("squicks") - ico = "skrellkey" - uni_append = "01CC92" + icon_state = "skrellkey1" + uni_append = list(0x01C,0xC92) // 01CC92 /mob/living/carbon/monkey/unathi name = "stok" voice_name = "stok" speak_emote = list("hisses") - ico = "stokkey" - uni_append = "044C5D" + icon_state = "stokkey1" + uni_append = list(0x044,0xC5D) // 044C5D /mob/living/carbon/monkey/New() var/datum/reagents/R = new/datum/reagents(1000) @@ -48,16 +51,25 @@ gender = pick(MALE, FEMALE) dna = new /datum/dna( null ) dna.real_name = real_name - dna.uni_identity = "00600200A00E0110148FC01300B009" - dna.struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" + dna.ResetSE() + dna.ResetUI() + //dna.uni_identity = "00600200A00E0110148FC01300B009" + //dna.struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" dna.unique_enzymes = md5(name) - //////////blah - var/gendervar - if (gender == MALE) - gendervar = add_zero2(num2hex((rand(1,2049)),1), 3) - else - gendervar = add_zero2(num2hex((rand(2051,4094)),1), 3) - dna.uni_identity += "[gendervar][uni_append]" + + // We're a monkey + dna.SetSEState(MONKEYBLOCK, 1) + // Fix gender + dna.SetUIState(DNA_UI_GENDER, gender != MALE, 1) + + // Set the blocks to uni_append, if needed. + if(uni_append.len>0) + for(var/b=1;b<=uni_append.len;b++) + dna.SetUIValue(DNA_UI_LENGTH-(uni_append.len-b),uni_append[b], 1) + dna.UpdateUI() + + update_muts=1 + ..() update_icons() return @@ -86,6 +98,7 @@ /mob/living/carbon/monkey/diona/New() ..() + alien = 1 gender = NEUTER dna.mutantrace = "plant" greaterform = "Diona" 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/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 76ab17fbd47..cd6939831a0 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -37,6 +37,11 @@ var/flags = 0 // Various specific features. + var/list/abilities = list() // For species-derived or admin-given powers + + var/blood_color = "#A10808" //Red. + var/flesh_color = "#FFC896" //Pink. + /datum/species/human name = "Human" language = "Sol Common" @@ -44,6 +49,9 @@ flags = HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR + //If you wanted to add a species-level ability: + /*abilities = list(/client/proc/test_ability)*/ + /datum/species/unathi name = "Unathi" icobase = 'icons/mob/human_races/r_lizard.dmi' @@ -63,7 +71,9 @@ heat_level_2 = 480 //Default 400 heat_level_3 = 1100 //Default 1000 - flags = WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL + flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL + + flesh_color = "#34AF10" /datum/species/tajaran name = "Tajaran" @@ -85,7 +95,9 @@ primitive = /mob/living/carbon/monkey/tajara - flags = WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL + flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL + + flesh_color = "#AFA59E" /datum/species/skrell name = "Skrell" @@ -94,7 +106,9 @@ language = "Skrellian" primitive = /mob/living/carbon/monkey/skrell - flags = WHITELISTED | HAS_LIPS | HAS_UNDERWEAR + flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR + + flesh_color = "#8CD7A3" /datum/species/vox name = "Vox" @@ -112,7 +126,10 @@ eyes = "vox_eyes_s" breath_type = "nitrogen" - flags = NO_SCAN + flags = NO_SCAN | NO_BLOOD + + blood_color = "#2299FC" + flesh_color = "#808D11" /datum/species/diona name = "Diona" @@ -134,4 +151,8 @@ heat_level_2 = 3000 heat_level_3 = 4000 - flags = WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NON_GENDERED | NO_SCAN | IS_PLANT | RAD_ABSORB + flags = IS_WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NO_SCAN | IS_PLANT | RAD_ABSORB | NO_BLOOD | IS_SLOW | NO_PAIN + + blood_color = "#004400" + flesh_color = "#907E4A" + diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index ddfd7d16063..57bb02ce5c3 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()) @@ -435,6 +434,13 @@ var/mob/living/L = usr + //Getting out of someone's inventory. + if(istype(src.loc,/obj/item/weapon/holder)) + var/obj/item/weapon/holder/H = src.loc + src.loc = get_turf(src.loc) + del(H) + return + //Resisting control by an alien mind. if(istype(src.loc,/mob/living/simple_animal/borer)) var/mob/living/simple_animal/borer/B = src.loc @@ -620,9 +626,10 @@ for(var/mob/O in viewers(CM))// lags so hard that 40s isn't lenient enough - Quarxink O.show_message("\red [CM] manages to remove the handcuffs!", 1) CM << "\blue You successfully remove \the [CM.handcuffed]." - CM.handcuffed.loc = usr.loc + CM.drop_from_inventory(CM.handcuffed) CM.handcuffed = null CM.update_inv_handcuffed() + else if(CM.legcuffed && CM.canmove && (CM.last_special <= world.time)) CM.next_move = world.time + 100 CM.last_special = world.time + 100 @@ -658,7 +665,7 @@ for(var/mob/O in viewers(CM))// lags so hard that 40s isn't lenient enough - Quarxink O.show_message("\red [CM] manages to remove the legcuffs!", 1) CM << "\blue You successfully remove \the [CM.legcuffed]." - CM.legcuffed.loc = usr.loc + CM.drop_from_inventory(CM.legcuffed) CM.legcuffed = null CM.update_inv_legcuffed() @@ -667,4 +674,96 @@ set category = "IC" resting = !resting - src << "\blue You are now [resting ? "resting" : "getting up"]" \ No newline at end of file + src << "\blue You are now [resting ? "resting" : "getting up"]" + +/mob/living/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null) // -- TLE -- Merged by Carn + if(stat) + src << "You must be conscious to do this!" + return + if(lying) + src << "You can't vent crawl while you're stunned!" + return + + if(vent_found) // one was passed in, probably from vent/AltClick() + if(vent_found.welded) + src << "That vent is welded shut." + return + if(!vent_found.Adjacent(src)) + return // don't even acknowledge that + else + for(var/obj/machinery/atmospherics/unary/vent_pump/v in range(1,src)) + if(!v.welded) + if(v.Adjacent(src)) + vent_found = v + if(!vent_found) + src << "You'll need a non-welded vent to crawl into!" + return + + if(!vent_found.network || !vent_found.network.normal_members.len) + src << "This vent is not connected to anything." + return + + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in vent_found.network.normal_members) + if(temp_vent.welded) + continue + if(temp_vent in loc) + continue + var/turf/T = get_turf(temp_vent) + + if(!T || T.z != loc.z) + continue + + var/i = 1 + var/index = "[T.loc.name]\[[i]\]" + while(index in vents) + i++ + index = "[T.loc.name]\[[i]\]" + vents[index] = temp_vent + if(!vents.len) + src << "\red There are no available vents to travel to, they could be welded." + return + + var/obj/selection = input("Select a destination.", "Duct System") as null|anything in sortAssoc(vents) + if(!selection) return + + if(!vent_found.Adjacent(src)) + src << "Never mind, you left." + return + + for(var/obj/item/carried_item in contents)//If the monkey got on objects. + if( !istype(carried_item, /obj/item/weapon/implant) && !istype(carried_item, /obj/item/clothing/mask/facehugger) )//If it's not an implant or a facehugger + src << "\red You can't be carrying items or have items equipped when vent crawling!" + return + if(isslime(src)) + var/mob/living/carbon/slime/S = src + if(S.Victim) + src << "\red You'll have to let [S.Victim] go or finish eating \him first." + return + + var/obj/machinery/atmospherics/unary/vent_pump/target_vent = vents[selection] + if(!target_vent) + return + + for(var/mob/O in viewers(src, null)) + O.show_message(text("[src] scrambles into the ventillation ducts!"), 1) + loc = target_vent + + var/travel_time = round(get_dist(loc, target_vent.loc) / 2) + + spawn(travel_time) + + if(!target_vent) return + for(var/mob/O in hearers(target_vent,null)) + O.show_message("You hear something squeezing through the ventilation ducts.",2) + + sleep(travel_time) + + if(!target_vent) return + if(target_vent.welded) //the vent can be welded while alien scrolled through the list or travelled. + target_vent = vent_found //travel back. No additional time required. + src << "\red The vent you were heading to appears to be welded." + loc = target_vent.loc + var/area/new_area = get_area(loc) + if(new_area) + new_area.Entered(src) \ No newline at end of file diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 4c51e5f474a..13523072cab 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -108,7 +108,7 @@ var/list/department_radio_keys = list( if(client.prefs.muted & MUTE_IC) src << "\red You cannot speak in IC (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) + if (src.client.handle_spam_prevention(message, MUTE_IC)) return // Mute disability @@ -173,7 +173,7 @@ var/list/department_radio_keys = list( if(src.stunned > 2 || (traumatic_shock > 61 && prob(50))) message_mode = null //Stunned people shouldn't be able to physically turn on their radio/hold down the button to speak into it - message = capitalize(message) + message = capitalize(trim_left(message)) if (!message) return @@ -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 @@ -372,14 +373,17 @@ var/list/department_radio_keys = list( 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/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 42c4b0745b2..08d3b012a9b 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -95,6 +95,7 @@ var/list/ai_list = list() /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ /mob/living/silicon/ai/proc/toggle_camera_light) + if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. new/obj/structure/AIcore/deactivated(loc)//New empty terminal. @@ -338,9 +339,12 @@ var/list/ai_list = list() // src << text ("Switching Law [L]'s report status to []", lawcheck[L+1]) checklaws() + //Uncomment this line of code if you are enabling the AI Vocal (VOX) announcements. +/* if(href_list["say_word"]) play_vox_word(href_list["say_word"], null, src) return +*/ if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite var/L = text2num(href_list["lawi"]) diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index 57880471486..7705e5aedce 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -14,6 +14,13 @@ return 1 return ..() + + +// These Verbs are commented out since we've disabled the AI vocal (VOX) announcements. +// If you re-enable them there is 3 lines in ai.dm Topic() that you need to uncomment as well. +// just search for VOX in there. + +/* var/announcing_vox = 0 // Stores the time of the last announcement var/const/VOX_CHANNEL = 200 var/const/VOX_DELAY = 100 // 10 seconds @@ -61,7 +68,7 @@ var/const/VOX_PATH = "sound/vox/" if(!message || announcing_vox > world.time) return - var/list/words = stringsplit(trim(message), " ") + var/list/words = text2list(trim(message), " ") var/list/incorrect_words = list() if(words.len > 30) @@ -127,4 +134,7 @@ var/const/VOX_PATH = "sound/vox/" for(var/file in vox_files) // src << "Downloading [file]" var/sound/S = sound("[VOX_PATH][file]") - src << browse_rsc(S) \ No newline at end of file + src << browse_rsc(S) + + +*/ diff --git a/code/modules/mob/living/silicon/pai/hud.dm b/code/modules/mob/living/silicon/pai/hud.dm index 74d5ec8f878..07df7cd9ead 100644 --- a/code/modules/mob/living/silicon/pai/hud.dm +++ b/code/modules/mob/living/silicon/pai/hud.dm @@ -80,6 +80,12 @@ holder.icon_state = "hudxeno" else if(foundVirus) holder.icon_state = "hudill" + else if(patient.has_brain_worms()) + var/mob/living/simple_animal/borer/B = patient.has_brain_worms() + if(B.controlling) + holder.icon_state = "hudbrainworm" + else + holder.icon_state = "hudhealthy" else holder.icon_state = "hudhealthy" client.images += holder diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 863708d18c3..02c8ea04223 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -4,6 +4,7 @@ icon_state = "shadow" robot_talk_understand = 0 + emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) var/network = "SS13" var/obj/machinery/camera/current = null @@ -268,4 +269,4 @@ pai.key = src.key card.setPersonality(pai) -*/ \ No newline at end of file +*/ diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 93271aadaf1..399a94c0393 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -13,6 +13,10 @@ var/datum/paiController/paiController // Global handler for pAI candidates var/ready = 0 +/hook/startup/proc/paiControllerSetup() + paiController = new /datum/paiController() + return 1 + /datum/paiController var/list/pai_candidates = list() @@ -191,6 +195,8 @@ var/datum/paiController/paiController // Global handler for pAI candidates proc/requestRecruits() for(var/mob/dead/observer/O in player_list) + if(O.has_enabled_antagHUD == 1 && config.antag_hud_restricted) + continue if(jobban_isbanned(O, "pAI")) continue if(asked.Find(O.key)) diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 325bff53f57..1e23637b56a 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -124,11 +124,11 @@ /obj/item/broken_device name = "broken component" - icon = 'icons/robot_component.dmi' + icon = 'icons/obj/robot_component.dmi' icon_state = "broken" /obj/item/robot_parts/robot_component - icon = 'icons/robot_component.dmi' + icon = 'icons/obj/robot_component.dmi' icon_state = "working" construction_time = 200 construction_cost = list("metal"=5000) @@ -214,4 +214,4 @@ if(H.emagged && prob(5)) user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1) src.add_fingerprint(user) - return + return diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 611243f6548..2e03b9ffd04 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -275,8 +275,11 @@ if(Entry[1] == src.ckey && Entry[2] == src.real_name) //They're in the list? Custom sprite time, var and icon change required custom_sprite = 1 icon = 'icons/mob/custom-synthetic.dmi' + if(icon_state == "robot") + icon_state = "[src.ckey]-Standard" /mob/living/silicon/robot/verb/Namepick() + set category = "Robot Commands" if(custom_name) return 0 @@ -1161,6 +1164,9 @@ var/turf/tile = loc if(isturf(tile)) tile.clean_blood() + if (istype(tile, /turf/simulated)) + var/turf/simulated/S = tile + S.dirt = 0 for(var/A in tile) if(istype(A, /obj/effect)) if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay)) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index ab4080ed501..df259c21972 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -169,7 +169,7 @@ New() ..() - src.modules += new /obj/item/weapon/reagent_containers/food/drinks/beer(src) + src.modules += new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src) src.modules += new /obj/item/weapon/reagent_containers/food/condiment/enzyme(src) src.modules += new /obj/item/weapon/pen/robopen(src) @@ -185,7 +185,7 @@ src.modules += new /obj/item/weapon/tray/robotray(src) src.modules += new /obj/item/weapon/reagent_containers/food/drinks/shaker(src) - src.emag = new /obj/item/weapon/reagent_containers/food/drinks/beer(src) + src.emag = new /obj/item/weapon/reagent_containers/food/drinks/cans/beer(src) var/datum/reagents/R = new/datum/reagents(50) src.emag.reagents = R 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/borer.dm b/code/modules/mob/living/simple_animal/borer.dm index d3166dd974f..d3e0ea9518e 100644 --- a/code/modules/mob/living/simple_animal/borer.dm +++ b/code/modules/mob/living/simple_animal/borer.dm @@ -16,6 +16,12 @@ src << "You whisper silently, \"[message]\"" B.host << "The captive mind of [src] whispers, \"[message]\"" + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + M << "The captive mind of [src] whispers, \"[message]\"" + /mob/living/captive_brain/emote(var/message) return @@ -40,28 +46,53 @@ wander = 0 pass_flags = PASSTABLE + var/used_dominate var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. var/mob/living/carbon/human/host // Human host for the brain worm. var/truename // Name used for brainworm-speak. var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. var/controlling // Used in human death check. + var/docile = 0 // Sugar can stop borers from acting. /mob/living/simple_animal/borer/Life() ..() + + if(host) + if(!stat && !host.stat) + + if(host.reagents.has_reagent("sugar")) + if(!docile) + if(controlling) + host << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility." + else + src << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility." + docile = 1 + else + if(docile) + if(controlling) + host << "\blue You shake off your lethargy as the sugar leaves your host's blood." + else + src << "\blue You shake off your lethargy as the sugar leaves your host's blood." + docile = 0 + if(chemicals < 250) chemicals++ if(controlling) + + if(docile) + host << "\blue You are feeling far too docile to continue controlling your host..." + host.release_control() + return + if(prob(5)) host.adjustBrainLoss(rand(1,2)) if(prob(host.brainloss/20)) host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]") - //if(host.brainloss > 100) - /mob/living/simple_animal/borer/New() ..() truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" @@ -104,6 +135,13 @@ src << "You drop words into [host]'s mind: \"[message]\"" host << "Your own thoughts speak: \"[message]\"" + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + M << "[src.truename] whispers to [host], \"[message]\"" + + /mob/living/simple_animal/borer/Stat() ..() statpanel("Status") @@ -127,6 +165,46 @@ if(M.mind && (istype(M, /mob/living/simple_animal/borer) || istype(M, /mob/dead/observer))) M << "Cortical link, [truename]: [copytext(message, 2)]" +/mob/living/simple_animal/borer/verb/dominate_victim() + set category = "Alien" + set name = "Dominate Victim" + set desc = "Freeze the limbs of a potential host with supernatural fear." + + if(world.time - used_dominate < 300) + src << "You cannot use that ability again so soon." + return + + if(host) + src << "You cannot do that from within a host body." + return + + if(src.stat) + src << "You cannot do that in your current state." + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(3,src)) + if(C.stat != 2) + choices += C + + if(world.time - used_dominate < 300) + src << "You cannot use that ability again so soon." + return + + var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices + + if(!M || !src) return + + if(M.has_brain_worms()) + src << "You cannot infest someone who is already infested!" + return + + src << "\red You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread." + M << "\red You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing." + M.Weaken(3) + + used_dominate = world.time + /mob/living/simple_animal/borer/verb/bond_brain() set category = "Alien" set name = "Assume Control" @@ -140,12 +218,20 @@ src << "You cannot do that in your current state." return + if(host.internal_organs_by_name["brain"]) //this should only run in admin-weirdness situations, but it's here non the less - RR + src << "There is no brain here for us to command!" + return + + if(docile) + src << "\blue You are feeling far too docile to do that." + return + src << "You begin delicately adjusting your connection to the host brain..." spawn(300+(host.brainloss*5)) - if(!host || !src || controlling) return - + if(!host || !src || controlling) + return else src << "\red You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system." host << "\red You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours." @@ -170,10 +256,14 @@ if(stat) src << "You cannot secrete chemicals in your current state." + if(docile) + src << "\blue You are feeling far too docile to do that." + return + if(chemicals < 50) src << "You don't have enough chemicals!" - var/chem = input("Select a chemical to secrete.", "Chemicals") in list("bicaridine","tramadol","hyperzine") + var/chem = input("Select a chemical to secrete.", "Chemicals") in list("bicaridine","tramadol","hyperzine","alkysine") if(chemicals < 50 || !host || controlling || !src || stat) //Sanity check. return @@ -194,6 +284,9 @@ if(stat) src << "You cannot leave your host in your current state." + if(docile) + src << "\blue You are feeling far too docile to do that." + return if(!host || !src) return @@ -262,17 +355,25 @@ mob/living/simple_animal/borer/proc/detatch() var/list/choices = list() for(var/mob/living/carbon/C in view(1,src)) - if(C.stat != 2) + if(C.stat != 2 && src.Adjacent(C)) choices += C var/mob/living/carbon/M = input(src,"Who do you wish to infest?") in null|choices if(!M || !src) return + if(!(src.Adjacent(M))) return + if(M.has_brain_worms()) src << "You cannot infest someone who is already infested!" return + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.check_head_coverage()) + src << "You cannot get through that host's protective gear." + return + M << "Something slimy begins probing at the opening of your ear canal..." src << "You slither up [M] and begin probing at their ear canal..." diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index ccc0cd705fb..80fafbf80ee 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -1,13 +1,13 @@ /mob/living/simple_animal/construct name = "Construct" - real_name = "Contruct" + real_name = "Construct" desc = "" speak_emote = list("hisses") emote_hear = list("wails","screeches") response_help = "thinks better of touching" response_disarm = "flails at" - response_harm = "punches the" + response_harm = "punches" icon_dead = "shade_dead" speed = -1 a_intent = "harm" @@ -24,18 +24,24 @@ max_n2 = 0 minbodytemp = 0 faction = "cult" + var/list/construct_spells = list() - -/mob/living/simple_animal/construct/Life() +/mob/living/simple_animal/construct/New() ..() - if(stat == 2) - new /obj/item/weapon/ectoplasm (src.loc) - for(var/mob/M in viewers(src, null)) - if((M.client && !( M.blinded ))) - M.show_message("\red [src] collapses in a shattered heap ") - ghostize() - del src - return + name = text("[initial(name)] ([rand(1, 1000)])") + real_name = name + for(var/spell in construct_spells) + spell_list += new spell(src) + +/mob/living/simple_animal/construct/Die() + ..() + new /obj/item/weapon/ectoplasm (src.loc) + for(var/mob/M in viewers(src, null)) + if((M.client && !( M.blinded ))) + M.show_message("\red [src] collapses in a shattered heap. ") + ghostize() + del src + return /mob/living/simple_animal/construct/examine() set src in oview() @@ -54,45 +60,37 @@ return /mob/living/simple_animal/construct/Bump(atom/movable/AM as mob|obj, yes) - spawn( 0 ) - if ((!( yes ) || now_pushing)) - return - now_pushing = 1 - if(ismob(AM)) - var/mob/tmob = AM - if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations)) - if(prob(5)) - src << "\red You fail to push [tmob]'s fat ass out of the way." - now_pushing = 0 - return - if(!(tmob.status_flags & CANPUSH)) - now_pushing = 0 - return - - tmob.LAssailant = src - now_pushing = 0 - ..() - if (!( istype(AM, /atom/movable) )) - return - if (!( now_pushing )) - now_pushing = 1 - if (!( AM.anchored )) - var/t = get_dir(src, AM) - if (istype(AM, /obj/structure/window)) - if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST) - for(var/obj/structure/window/win in get_step(AM,t)) - now_pushing = 0 - return - step(AM, t) - now_pushing = null + if ((!( yes ) || now_pushing)) return - return + now_pushing = 1 + if(ismob(AM)) + var/mob/tmob = AM + if(!(tmob.status_flags & CANPUSH)) + now_pushing = 0 + return + + tmob.LAssailant = src + now_pushing = 0 + ..() + if (!istype(AM, /atom/movable)) + return + if (!( now_pushing )) + now_pushing = 1 + if (!( AM.anchored )) + var/t = get_dir(src, AM) + if (istype(AM, /obj/structure/window)) + if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST) + for(var/obj/structure/window/win in get_step(AM,t)) + now_pushing = 0 + return + step(AM, t) + now_pushing = null /mob/living/simple_animal/construct/attack_animal(mob/living/simple_animal/M as mob) if(istype(M, /mob/living/simple_animal/construct/builder)) health += 5 - M.emote("mends some of \the [src]'s wounds") + M.emote("mends some of \the [src]'s wounds.") else if(M.melee_damage_upper <= 0) M.emote("[M.friendly] \the [src]") @@ -103,23 +101,24 @@ O.show_message("\The [M] [M.attacktext] \the [src]!", 1) M.attack_log += text("\[[time_stamp()]\] attacked [src.name] ([src.ckey])") src.attack_log += text("\[[time_stamp()]\] was attacked by [M.name] ([M.ckey])") + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - health -= damage + adjustBruteLoss(damage) /mob/living/simple_animal/construct/attackby(var/obj/item/O as obj, var/mob/user as mob) if(O.force) var/damage = O.force if (O.damtype == HALLOSS) damage = 0 - health -= damage + adjustBruteLoss(damage) for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red \b [src] has been attacked with the [O] by [user]. ") + M.show_message("\red \b [src] has been attacked with [O] by [user]. ") else usr << "\red This weapon is ineffective, it does no damage." for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red [user] gently taps [src] with the [O]. ") + M.show_message("\red [user] gently taps [src] with [O]. ") @@ -136,7 +135,7 @@ icon_living = "behemoth" maxHealth = 250 health = 250 - response_harm = "harmlessly punches the" + response_harm = "harmlessly punches" harm_intent_damage = 0 melee_damage_lower = 30 melee_damage_upper = 30 @@ -145,6 +144,7 @@ wall_smash = 1 attack_sound = 'sound/weapons/punch3.ogg' status_flags = 0 + construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) /mob/living/simple_animal/construct/armoured/attackby(var/obj/item/O as obj, var/mob/user as mob) if(O.force) @@ -152,22 +152,46 @@ var/damage = O.force if (O.damtype == HALLOSS) damage = 0 - health -= damage + adjustBruteLoss(damage) for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red \b [src] has been attacked with the [O] by [user]. ") + M.show_message("\red \b [src] has been attacked with [O] by [user]. ") else for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red \b The [O] bounces harmlessly off of [src]. ") + M.show_message("\red \b [O] bounces harmlessly off of [src]. ") else usr << "\red This weapon is ineffective, it does no damage." for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red [user] gently taps [src] with the [O]. ") + M.show_message("\red [user] gently taps [src] with [O]. ") +/mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) + if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) + var/reflectchance = 80 - round(P.damage/3) + if(prob(reflectchance)) + adjustBruteLoss(P.damage * 0.5) + visible_message("The [P.name] gets reflected by [src]'s shell!", \ + "The [P.name] gets reflected by [src]'s shell!") + // Find a turf near or on the original location to bounce to + if(P.starting) + var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3) + var/turf/curloc = get_turf(src) + + // redirect the projectile + P.original = locate(new_x, new_y, P.z) + P.starting = curloc + P.current = curloc + P.firer = src + P.yo = new_y - curloc.y + P.xo = new_x - curloc.x + + return -1 // complete projectile permutation + + return (..(P)) @@ -190,6 +214,7 @@ speed = -1 see_in_dark = 7 attack_sound = 'sound/weapons/bladeslice.ogg' + construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) @@ -214,6 +239,11 @@ speed = 0 wall_smash = 1 attack_sound = 'sound/weapons/punch2.ogg' + construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser, + /obj/effect/proc_holder/spell/aoe_turf/conjure/wall, + /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, + /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, + /obj/effect/proc_holder/spell/targeted/projectile/magic_missile) /////////////////////////////Behemoth///////////////////////// @@ -229,7 +259,7 @@ maxHealth = 750 health = 750 speak_emote = list("rumbles") - response_harm = "harmlessly punches the" + response_harm = "harmlessly punches" harm_intent_damage = 0 melee_damage_lower = 50 melee_damage_upper = 50 @@ -240,25 +270,25 @@ var/energy = 0 var/max_energy = 1000 -/mob/living/simple_animal/constructbehemoth/attackby(var/obj/item/O as obj, var/mob/user as mob) +/mob/living/simple_animal/construct/behemoth/attackby(var/obj/item/O as obj, var/mob/user as mob) if(O.force) if(O.force >= 11) var/damage = O.force if (O.damtype == HALLOSS) damage = 0 - health -= damage + adjustBruteLoss(damage) for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red \b [src] has been attacked with the [O] by [user]. ") + M.show_message("\red \b [src] has been attacked with [O] by [user]. ") else for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red \b The [O] bounces harmlessly off of [src]. ") + M.show_message("\red \b [O] bounces harmlessly off of [src]. ") else usr << "\red This weapon is ineffective, it does no damage." for(var/mob/M in viewers(src, null)) if ((M.client && !( M.blinded ))) - M.show_message("\red [user] gently taps [src] with the [O]. ") + M.show_message("\red [user] gently taps [src] with [O]. ") @@ -290,4 +320,4 @@ if (cultist == usr) //just to be sure. return cultist.loc = usr.loc - usr.visible_message("\red [cultist] appears in a flash of red light as [usr] glows with power")*/ \ No newline at end of file + usr.visible_message("/red [cultist] appears in a flash of red light as [usr] glows with power")*/ \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index d858a200e17..92a27c27b7a 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -63,6 +63,6 @@ //RUNTIME IS ALIVE! SQUEEEEEEEE~ /mob/living/simple_animal/cat/Runtime name = "Runtime" - desc = "Its fur has the look and feel of velvet, and it's tail quivers occasionally." + desc = "Its fur has the look and feel of velvet, and its tail quivers occasionally." diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm index 54431d86f75..8c98daaa872 100644 --- a/code/modules/mob/living/simple_animal/friendly/corgi.dm +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -22,12 +22,12 @@ var/obj/item/inventory_back var/facehugger +/* /mob/living/simple_animal/corgi/Life() ..() regenerate_icons() /mob/living/simple_animal/corgi/show_inv(mob/user as mob) - /* If you're turning this back on, scroll down and uncomment target_updated user.set_machine(src) if(user.stat) return @@ -43,7 +43,6 @@ user << browse(dat, text("window=mob[];size=325x500", name)) onclose(user, "mob[real_name]") - */ return /mob/living/simple_animal/corgi/attackby(var/obj/item/O as obj, var/mob/user as mob) @@ -255,6 +254,7 @@ if(/obj/item/clothing/head/soft) name = "Corgi Tech [real_name]" desc = "The reason your yellow gloves have chew-marks." +*/ //IAN! SQUEEEEEEEEE~ diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index af36a591626..2687827d385 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -27,6 +27,7 @@ minbodytemp = 223 //Below -50 Degrees Celcius maxbodytemp = 323 //Above 50 Degrees Celcius universal_speak = 0 + universal_understand = 1 /mob/living/simple_animal/mouse/Life() ..() @@ -50,6 +51,7 @@ /mob/living/simple_animal/mouse/New() ..() + name = "[name] ([rand(1, 1000)])" if(!body_color) body_color = pick( list("brown","gray","white") ) icon_state = "mouse_[body_color]" @@ -63,61 +65,15 @@ src.stat = DEAD src.icon_dead = "mouse_[body_color]_splat" src.icon_state = "mouse_[body_color]_splat" + layer = MOB_LAYER if(client) client.time_died_as_mouse = world.time -//copy paste from alien/larva, if that func is updated please update this one also /mob/living/simple_animal/mouse/verb/ventcrawl() set name = "Crawl through Vent" set desc = "Enter an air vent and crawl through the pipe system." set category = "Mouse" - -// if(!istype(V,/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent)) -// return - - if(src.stat != CONSCIOUS) return - - var/obj/machinery/atmospherics/unary/vent_pump/vent_found - var/welded = 0 - for(var/obj/machinery/atmospherics/unary/vent_pump/v in range(1,src)) - if(!v.welded) - vent_found = v - break - else - welded = 1 - if(vent_found) - if(vent_found.network&&vent_found.network.normal_members.len) - var/list/vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in vent_found.network.normal_members) - if(temp_vent.loc == loc) - continue - vents.Add(temp_vent) - var/list/choices = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/vent in vents) - if(vent.loc.z != loc.z) - continue - var/atom/a = get_turf(vent) - choices.Add(a.loc) - var/turf/startloc = loc - var/obj/selection = input("Select a destination.", "Duct System") in choices - var/selection_position = choices.Find(selection) - if(loc==startloc) - var/obj/target_vent = vents[selection_position] - if(target_vent) - /* - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[src] scrambles into the ventillation ducts!"), 1) - */ - loc = target_vent.loc - else - src << "\blue You need to remain still while entering a vent." - else - src << "\blue This vent is not connected to anything." - else if(welded) - src << "\red That vent is welded." - else - src << "\blue You must be standing on or beside an air vent to enter it." + handle_ventcrawl() return //copy paste from alien/larva, if that func is updated please update this one alsoghost @@ -179,6 +135,7 @@ ..() /mob/living/simple_animal/mouse/Die() + layer = MOB_LAYER if(client) client.time_died_as_mouse = world.time ..() diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index 6fd7db5d10e..b375755f546 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -79,7 +79,7 @@ if(stance_step in list(1,4,7)) //every 3 ticks var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) ) if(action) - emote(action) + custom_emote(1,action) if(!found_mob) stance_step-- @@ -90,7 +90,7 @@ if(HOSTILE_STANCE_ATTACKING) if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest - emote( "is worn out and needs to rest" ) + custom_emote(1, "is worn out and needs to rest" ) stance = HOSTILE_STANCE_TIRED stance_step = 0 walk(src, 0) //This stops the bear's walking @@ -118,14 +118,16 @@ /mob/living/simple_animal/hostile/bear/FindTarget() . = ..() if(.) - emote("stares alertly at [.]") + custom_emote(1,"stares alertly at [.]") stance = HOSTILE_STANCE_ALERT /mob/living/simple_animal/hostile/bear/LoseTarget() ..(5) /mob/living/simple_animal/hostile/bear/AttackingTarget() - emote( pick( list("slashes at [target_mob]", "bites [target_mob]") ) ) + if(!Adjacent(target_mob)) + return + custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) ) var/damage = rand(20,30) diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index 353ca6156f3..f1a5c15c4b9 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -44,7 +44,7 @@ /mob/living/simple_animal/hostile/carp/FindTarget() . = ..() if(.) - emote("nashes at [.]") + custom_emote(1,"nashes at [.]") /mob/living/simple_animal/hostile/carp/AttackingTarget() . =..() diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index c7f0cd845ba..cdefaa644e7 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -47,7 +47,7 @@ /mob/living/simple_animal/hostile/hivebot/Die() ..() visible_message("[src] blows apart!") - new /obj/effect/decal/cleanable/robot_debris(src.loc) + new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) s.start() @@ -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/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 403c31b17f2..2dcbe0d949f 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -87,6 +87,8 @@ return 1 /mob/living/simple_animal/hostile/proc/AttackingTarget() + if(!Adjacent(target_mob)) + return if(isliving(target_mob)) var/mob/living/L = target_mob L.attack_animal(src) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 1c3498802d1..b6b7edb7298 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -24,6 +24,7 @@ log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).") /mob/Login() + player_list |= src update_Login_details() world.update_status() @@ -44,4 +45,13 @@ client.eye = src client.perspective = MOB_PERSPECTIVE + //Clear ability list and update from mob. + client.verbs -= ability_verbs + if(abilities) + client.verbs |= abilities + + if(istype(src,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = src + if(H.species && H.species.abilities) + client.verbs |= H.species.abilities \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 8f9623565f3..ecec6dca4c2 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -344,10 +344,15 @@ var/list/slot_equipment_priority = list( \ usr << "\blue You must be dead to use this!" return if (ticker.mode.name == "meteor" || ticker.mode.name == "epidemic") //BS12 EDIT - usr << "\blue Respawn is disabled." + usr << "\blue Respawn is disabled for this roundtype." return else var/deathtime = world.time - src.timeofdeath + if(istype(src,/mob/dead/observer)) + var/mob/dead/observer/G = src + if(G.has_enabled_antagHUD == 1 && config.antag_hud_restricted) + usr << "\blue Upon using the antagHUD you forfeighted the ability to join the round." + return var/deathtimeminutes = round(deathtime / 600) var/pluralcheck = "minute" if(deathtimeminutes == 0) @@ -358,6 +363,7 @@ var/list/slot_equipment_priority = list( \ pluralcheck = " [deathtimeminutes] minutes and" var/deathtimeseconds = round((deathtime - deathtimeminutes * 600) / 10,1) usr << "You have been dead for[pluralcheck] [deathtimeseconds] seconds." + if (deathtime < 18000) usr << "You must wait 30 minutes to respawn!" return @@ -748,6 +754,10 @@ note dizziness decrements automatically in the mob's Life() proc. else if( stunned ) // lying = 0 canmove = 0 + else if(captured) + anchored = 1 + canmove = 0 + lying = 0 else lying = !can_stand canmove = has_limbs @@ -885,7 +895,14 @@ note dizziness decrements automatically in the mob's Life() proc. /mob/proc/flash_weak_pain() flick("weak_pain",pain) -mob/verb/yank_out_object() +/mob/proc/get_visible_implants(var/class = 0) + var/list/visible_implants = list() + for(var/obj/item/O in embedded) + if(O.w_class > class) + visible_implants += O + return visible_implants + +mob/proc/yank_out_object() set category = "Object" set name = "Yank out object" set desc = "Remove an embedded item at the cost of bleeding and pain." @@ -911,10 +928,7 @@ mob/verb/yank_out_object() if(S == U) self = 1 // Removing object from yourself. - for(var/obj/item/weapon/W in embedded) - if(W.w_class >= 2) - valid_objects += W - + valid_objects = get_visible_implants(1) if(!valid_objects.len) if(self) src << "You have nothing stuck in your body that is large enough to remove." @@ -938,6 +952,29 @@ mob/verb/yank_out_object() visible_message("[src] rips [selection] out of their body.","You rip [selection] out of your body.") else visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.") + valid_objects = get_visible_implants(0) + if(valid_objects.len == 1) //Yanking out last object - removing verb. + src.verbs -= /mob/proc/yank_out_object + + if(istype(src,/mob/living/carbon/human)) + + var/mob/living/carbon/human/H = src + var/datum/organ/external/affected + + for(var/datum/organ/external/organ in H.organs) //Grab the organ holding the implant. + for(var/obj/item/weapon/O in organ.implants) + if(O == selection) + affected = organ + + affected.implants -= selection + H.shock_stage+=10 + H.bloody_hands(S) + + if(prob(10)) //I'M SO ANEMIC I COULD JUST -DIE-. + var/datum/wound/internal_bleeding/I = new (15) + affected.wounds += I + H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 1) + return 1 selection.loc = get_turf(src) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 5f7c707635f..06d8e9d02ff 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -81,14 +81,15 @@ 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 - var/list/pinned = list() //List of things pinning this creature to walls (see living_defense.dm) - var/list/embedded = list() //Embedded items, since simple mobs don't have organs. + var/list/pinned = list() // List of things pinning this creature to walls (see living_defense.dm) + var/list/embedded = list() // Embedded items, since simple mobs don't have organs. var/list/languages = list() // For speaking/listening. - var/list/speak_emote = list("says") //Verbs used when speaking. Defaults to 'say' if speak_emote is null. + var/list/abilities = list() // For species-derived or admin-given powers. + var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null. + var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes var/name_archive //For admin things like possession @@ -157,7 +158,7 @@ var/voice_name = "unidentifiable voice" var/faction = "neutral" //Used for checking whether hostile simple animals will attack you, possibly more stuff later - + var/captured = 0 //Functionally, should give the same effect as being buckled into a chair when true. //Generic list for proc holders. Only way I can see to enable certain verbs/procs. Should be modified if needed. var/proc_holder_list[] = list()//Right now unused. @@ -207,6 +208,7 @@ //Whether or not mobs can understand other mobtypes. These stay in /mob so that ghosts can hear everything. var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE + var/universal_understand = 0 // Set to 1 to enable the mob to understand everyone, not necessarily speak var/robot_talk_understand = 0 var/alien_talk_understand = 0 @@ -216,3 +218,5 @@ var/immune_to_ssd = 0 var/turf/listed_turf = null //the current turf being examined in the stat panel + + var/list/active_genes=list() diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 1ea768d0056..59721a24ab4 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -186,6 +186,12 @@ if(L.incorporeal_move)//Move though walls Process_Incorpmove(direct) return + if(mob.client) + if(mob.client.view != world.view) + if(locate(/obj/item/weapon/gun/energy/sniperrifle, mob.contents)) // If mob moves while zoomed in with sniper rifle, unzoom them. + var/obj/item/weapon/gun/energy/sniperrifle/s = locate() in mob + if(s.zoom) + s.zoom() if(Process_Grab()) return @@ -447,4 +453,4 @@ prob_slip = 0 // Changing this to zero to make it line up with the comment. prob_slip = round(prob_slip) - return(prob_slip) \ No newline at end of file + return(prob_slip) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 77b4dbd884d..6ef470d4cde 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -114,6 +114,7 @@ spawning = 1 src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS cant last forever yo + observer.started_as_observer = 1 close_spawn_windows() var/obj/O = locate("landmark*Observer-Start") @@ -129,8 +130,11 @@ client.prefs.real_name = random_name(client.prefs.gender) observer.real_name = client.prefs.real_name observer.name = observer.real_name + if(!client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. + observer.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing! observer.key = key del(src) + return 1 if(href_list["late_join"]) @@ -283,6 +287,9 @@ src << alert("[rank] is not available. Please try another.") return 0 + spawning = 1 + close_spawn_windows() + job_master.AssignRole(src, rank, 1) var/mob/living/carbon/human/character = create_character() //creates the human and transfers vars and mind @@ -353,10 +360,8 @@ if(client.prefs.species) chosen_species = all_species[client.prefs.species] if(chosen_species) - if(is_alien_whitelisted(src, client.prefs.species) || !config.usealienwhitelist || !(chosen_species.flags & WHITELISTED) || (client.holder.rights & R_ADMIN) )// Have to recheck admin due to no usr at roundstart. Latejoins are fine though. + if(is_alien_whitelisted(src, client.prefs.species) || !config.usealienwhitelist || !(chosen_species.flags & IS_WHITELISTED) || (client.holder.rights & R_ADMIN) )// Have to recheck admin due to no usr at roundstart. Latejoins are fine though. new_character.set_species(client.prefs.species) - if(chosen_species.language) - new_character.add_language(chosen_species.language) var/datum/language/chosen_language if(client.prefs.language) @@ -387,9 +392,13 @@ new_character.dna.b_type = client.prefs.b_type if(client.prefs.disabilities) - new_character.dna.struc_enzymes = setblock(new_character.dna.struc_enzymes,GLASSESBLOCK,toggledblock(getblock(new_character.dna.struc_enzymes,GLASSESBLOCK,3)),3) + // Set defer to 1 if you add more crap here so it only recalculates struc_enzymes once. - N3X + new_character.dna.SetSEState(GLASSESBLOCK,1,0) new_character.disabilities |= NEARSIGHTED + // And uncomment this, too. + //new_character.dna.UpdateSE() + new_character.key = key //Manually transfer the key to log them in return new_character diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index caa104a98a5..230eca4cdf7 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -7,7 +7,7 @@ Enjoy! - Doohl - Notice: This all gets automatically compiled in a list in dna.dm, so you do not + Notice: This all gets automatically compiled in a list in dna2.dm, so you do not have to define any UI values for sprite accessories manually for hair and facial hair. Just add in new hair types and the game will naturally adapt. @@ -61,6 +61,10 @@ name = "Cut Hair" icon_state = "hair_c" + flair + name = "Flaired Hair" + icon_state = "hair_flair" + long name = "Shoulder-length Hair" icon_state = "hair_b" @@ -114,6 +118,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 +250,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 +278,11 @@ icon_state = "hair_braid" gender = FEMALE + braid2 + name = "Long Braid" + icon_state = "hair_hbraid" + gender = FEMALE + odango name = "Odango" icon_state = "hair_odango" @@ -405,7 +424,7 @@ una_frills_short name = "Short Unathi Frills" - icon_state = "soghun_shortfrill" + icon_state = "soghun_shortfrills" species_allowed = list("Unathi") do_colouration = 0 @@ -469,6 +488,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/say.dm b/code/modules/mob/say.dm index f4a99e097fd..63ea3485bb9 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -25,7 +25,7 @@ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) if(use_me) - usr.emote("me",1,message) + usr.emote("me",usr.emote_type,message) else usr.emote(message) @@ -37,6 +37,11 @@ usr << "\red Speech is currently admin-disabled." return + if(!src.client.holder) + if(!dsay_allowed) + src << "\red Deadchat is globally muted" + return + if(client && !(client.prefs.toggles & CHAT_DEAD)) usr << "\red You have deadchat muted." return @@ -66,7 +71,7 @@ if(!other) return 1 //Universal speak makes everything understandable, for obvious reasons. - else if(other.universal_speak || src.universal_speak) + else if(other.universal_speak || src.universal_speak || src.universal_understand) return 1 else if (src.stat == 2) return 1 @@ -83,11 +88,11 @@ else return 0 - else if(other.universal_speak || src.universal_speak) + else if(other.universal_speak || src.universal_speak || src.universal_understand) return 1 else if(isAI(src) && ispAI(other)) return 1 - else if (istype(other, src.type) || istype(src, other.type)) + else if (istype(other, src.type) || istype(src, other.type)) return 1 return 0 @@ -98,30 +103,28 @@ //tcomms code is still runtiming somewhere here var/ending = copytext(text, length(text)) - var/speechverb = "" + var/speech_verb = "says" + var/speech_style = "body" if (speaking) - speechverb = "[speaking.speech_verb], \"" + speech_verb = speaking.speech_verb + speech_style = speaking.colour else if(speak_emote && speak_emote.len) - speechverb = "[pick(speak_emote)], \"" + speech_verb = pick(speak_emote) else if (src.stuttering) - speechverb = "stammers, \"" + speech_verb = "stammers" else if (src.slurring) - speechverb = "slurrs, \"" + speech_verb = "slurrs" else if (ending == "?") - speechverb = "asks, \"" + speech_verb = "asks" else if (ending == "!") - speechverb = "exclaims, \"" + speech_verb = "exclaims" else if(isliving(src)) var/mob/living/L = src if (L.getBrainLoss() >= 60) - speechverb = "gibbers, \"" - else - speechverb = "says, \"" - else - speechverb = "says, \"" + speech_verb = "gibbers" - return "[speechverb][text]\"" + return "[speech_verb], \"[text]\"" /mob/proc/emote(var/act, var/type, var/message) if(act == "me") diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index bb5ed93e2ab..5ae6f0a7a30 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -30,8 +30,10 @@ O = new species.primitive(loc) O.dna = dna - O.dna.uni_identity = "000000000000000000DC00000660004DA0A0E00" - O.dna.struc_enzymes = "[copytext(O.dna.struc_enzymes,1,1+3*(STRUCDNASIZE-1))]BB8" + //O.dna.uni_identity = "000000000000000000DC00000660004DA0A0E00" + //O.dna.struc_enzymes = "[copytext(O.dna.struc_enzymes,1,1+3*(STRUCDNASIZE-1))]BB8" + O.dna.SetSEState(MONKEYBLOCK,1) + O.loc = loc O.viruses = viruses O.a_intent = "hurt" @@ -171,9 +173,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/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm index fed8cb4c4f7..2331debd9be 100644 --- a/code/modules/nano/nanoexternal.dm +++ b/code/modules/nano/nanoexternal.dm @@ -13,7 +13,7 @@ var/datum/nanoui/ui = locate(uiref) - if (ui) + if (istype(ui)) ui.close() if(ui.ref) diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm index 7a09e7ffd3b..b7b45060bb7 100644 --- a/code/modules/nano/nanomanager.dm +++ b/code/modules/nano/nanomanager.dm @@ -1,8 +1,9 @@ // This is the window/UI manager for Nano UI // There should only ever be one (global) instance of nanomanger /datum/nanomanager - // the list of current open /nanoui UIs + // a list of current open /nanoui UIs, grouped by src_object and ui_key var/open_uis[0] + // a list of current open /nanoui UIs, not grouped, for use in processing var/list/processing_uis = list() /** @@ -13,6 +14,29 @@ /datum/nanomanager/New() return + /** + * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data + * + * @param user /mob The mob who opened/owns the ui + * @param src_object /obj|/mob The obj or mob which the ui belongs to + * @param ui_key string A string key used for the ui + * @param ui /datum/nanoui An existing instance of the ui (can be null) + * @param data list The data to be passed to the ui, if it exists + * + * @return /nanoui Returns the found ui, for null if none exists + */ +/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data) + if (isnull(ui)) // no ui has been passed, so we'll search for one + { + ui = get_open_ui(user, src_object, ui_key) + } + if (!isnull(ui)) + // The UI is already open so push the data to it + ui.push_data(data) + return ui + + return null + /** * Get an open /nanoui ui for the current user, src_object and ui_key * @@ -20,7 +44,7 @@ * @param src_object /obj|/mob The obj or mob which the ui belongs to * @param ui_key string A string key used for the ui * - * @return /nanoui Returns the found ui, for null if none exists + * @return /nanoui Returns the found ui, or null if none exists */ /datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key) var/src_object_key = "\ref[src_object]" @@ -38,7 +62,7 @@ /** * Update all /nanoui uis attached to src_object * - * @param src_object /obj|/mob The obj or mob which the uis belong to + * @param src_object /obj|/mob The obj or mob which the uis are attached to * * @return int The number of uis updated */ @@ -54,6 +78,48 @@ ui.process(1) update_count++ return update_count + + /** + * Update /nanoui uis belonging to user + * + * @param user /mob The mob who owns the uis + * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional) + * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional) + * + * @return int The number of uis updated + */ +/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null) + if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + return 0 // has no open uis + + var/update_count = 0 + for (var/datum/nanoui/ui in user.open_uis) + if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.process(1) + update_count++ + + return update_count + + /** + * Close /nanoui uis belonging to user + * + * @param user /mob The mob who owns the uis + * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional) + * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional) + * + * @return int The number of uis closed + */ +/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null) + if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + return 0 // has no open uis + + var/close_count = 0 + for (var/datum/nanoui/ui in user.open_uis) + if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.close() + close_count++ + + return close_count /** * Add a /nanoui ui to the list of open uis @@ -106,11 +172,29 @@ // /datum/nanomanager/proc/user_logout(var/mob/user) - if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + return close_user_uis(user) + + /** + * This is called when a player transfers from one mob to another + * Transfers all open UIs to the new mob + * + * @param oldMob /mob The user's old mob + * @param newMob /mob The user's new mob + * + * @return nothing + */ +/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob) + if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0) return 0 // has no open uis - for (var/datum/nanoui/ui in user.open_uis) - ui.close(); + if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list)) + newMob.open_uis = list() + for (var/datum/nanoui/ui in oldMob.open_uis) + ui.user = newMob + newMob.open_uis.Add(ui) + oldMob.open_uis.Cut() + + return 1 // success diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 474e955f57a..1a3257ed24b 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -92,8 +92,8 @@ nanoui is used to open and update nano browser uis */ /datum/nanoui/proc/add_common_assets() add_script("libraries.min.js") // The jQuery library + add_script("nano_config.js") // The NanoConfig JS, this is used to store configuration values. add_script("nano_update.js") // The NanoUpdate JS, this is used to receive updates and apply them. - add_script("nano_config.js") // The NanoUpdate JS, this is used to receive updates and apply them. add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all templates add_stylesheet("shared.css") // this CSS sheet is common to all UIs add_stylesheet("icons.css") // this CSS sheet is common to all UIs @@ -135,11 +135,13 @@ nanoui is used to open and update nano browser uis if (dist > 4) close() return - + if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat)) set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility) else if (user.restrained() || user.lying) set_status(STATUS_UPDATE, push_update) // update only (orange visibility) + else if (istype(src_object, /obj/item/device/uplink/hidden)) // You know what if they have the uplink open let them use the UI + set_status(STATUS_INTERACTIVE, push_update) // Will build in distance checks on the topics for sanity. else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0 set_status(STATUS_DISABLED, push_update) // interactive (green visibility) else if (dist <= 1) @@ -256,8 +258,12 @@ nanoui is used to open and update nano browser uis */ /datum/nanoui/proc/get_header() var/head_content = "" + + for (var/filename in scripts) + head_content += " " + for (var/filename in stylesheets) - head_content += "" + head_content += " " var/templatel_data[0] for (var/key in templates) @@ -277,35 +283,24 @@ nanoui is used to open and update nano browser uis - [head_content] - - + [head_content] + +
      [title ? "
      [title]
      " : ""]
      +
      Initiating...
      "} /** @@ -314,13 +309,8 @@ nanoui is used to open and update nano browser uis * @return string HTML footer content */ /datum/nanoui/proc/get_footer() - var/scriptsContent = "" - - for (var/filename in scripts) - scriptsContent += "" return {" - [scriptsContent]
      @@ -349,6 +339,7 @@ nanoui is used to open and update nano browser uis window_size = "size=[width]x[height];" update_status(0) user << browse(get_html(), "window=[window_id];[window_size][window_options]") + winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map on_close_winset() //onclose(user, window_id) nanomanager.ui_opened(src) @@ -402,7 +393,7 @@ nanoui is used to open and update nano browser uis if (status != STATUS_INTERACTIVE || user != usr) // If UI is not interactive or usr calling Topic is not the UI user return - if (src_object.Topic(href, href_list)) + if (src_object && src_object.Topic(href, href_list)) nanomanager.update_uis(src_object) // update all UIs attached to src_object /** @@ -414,6 +405,10 @@ nanoui is used to open and update nano browser uis * @return nothing */ /datum/nanoui/proc/process(update = 0) + if (!src_object || !user) + close() + return + if (status && (update || is_auto_updating)) src_object.ui_interact(user, ui_key, src) // Update the UI (update_status() is called whenever a UI is updated) else diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index dd31d28ac76..c3e623271bc 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -12,10 +12,16 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 //Initializes blood vessels /mob/living/carbon/human/proc/make_blood() - if (vessel) + + if(vessel) return + vessel = new/datum/reagents(600) vessel.my_atom = src + + if(species && species.flags & NO_BLOOD) //We want the var for safety but we can do without the actual blood. + return + vessel.add_reagent("blood",560) spawn(1) fixblood() @@ -29,6 +35,10 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 // Takes care blood loss and regeneration /mob/living/carbon/human/proc/handle_blood() + + if(species && species.flags & NO_BLOOD) + return + if(stat != DEAD && bodytemperature >= 170) //Dead or cryosleep people do not pump the blood. var/blood_volume = round(vessel.get_reagent_amount("blood")) @@ -54,13 +64,13 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 // Damaged heart virtually reduces the blood volume, as the blood isn't // being pumped properly anymore. var/datum/organ/internal/heart/heart = internal_organs["heart"] - switch(heart.damage) - if(5 to 10) - blood_volume *= 0.8 - if(11 to 20) - blood_volume *= 0.5 - if(21 to INFINITY) - blood_volume *= 0.3 + + if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) + blood_volume *= 0.8 + else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage) + blood_volume *= 0.6 + else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY) + blood_volume *= 0.3 //Effects of bloodloss switch(blood_volume) @@ -93,7 +103,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]" @@ -126,6 +136,10 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 //Makes a blood drop, leaking certain amount of blood from the mob /mob/living/carbon/human/proc/drip(var/amt as num) + + if(species && species.flags & NO_BLOOD) //TODO: Make drips come from the reagents instead. + return + if(!amt) return @@ -145,6 +159,9 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 this.icon_state = pick(iconL) this.blood_DNA = list() this.blood_DNA[dna.unique_enzymes] = dna.b_type + if (species) this.basecolor = species.blood_color + this.update_icon() + else for(var/obj/effect/decal/cleanable/blood/drip/G in nums) del G @@ -156,6 +173,7 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 //Gets blood from mob to the container, preserving all data in it. /mob/living/carbon/proc/take_blood(obj/item/weapon/reagent_containers/container, var/amount) + var/datum/reagent/B = get_blood(container.reagents) if(!B) B = new /datum/reagent/blood B.holder = container @@ -184,8 +202,13 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 //For humans, blood does not appear from blue, it comes from vessels. /mob/living/carbon/human/take_blood(obj/item/weapon/reagent_containers/container, var/amount) + + if(species && species.flags & NO_BLOOD) + return null + if(vessel.get_reagent_amount("blood") < amount) return null + . = ..() vessel.remove_reagent("blood",amount) // Removes blood if human @@ -207,8 +230,16 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 //Transfers blood from container ot vessels, respecting blood types compatability. /mob/living/carbon/human/inject_blood(obj/item/weapon/reagent_containers/container, var/amount) - var/datum/reagent/blood/our = get_blood(vessel) + var/datum/reagent/blood/injected = get_blood(container.reagents) + + if(species && species.flags & NO_BLOOD) + reagents.add_reagent("blood", amount, injected.data) + reagents.update_total() + return + + var/datum/reagent/blood/our = get_blood(vessel) + if (!injected || !our) return if(blood_incompatible(injected.data["blood_type"],our.data["blood_type"]) ) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 33ce1131c54..eec57edea9a 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] @@ -102,7 +104,7 @@ 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]"]!") + emote("me", 1, "[(species && species.flags & NO_PAIN) ? "" : "screams in pain and"] drops what they were holding in their [E.display_name?"[E.display_name]":"[E]"]!") if(malfunction) emote("me", 1, "drops what they were holding, their [E.display_name?"[E.display_name]":"[E]"] malfunctioning!") var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() @@ -118,7 +120,8 @@ // standing is poor if(leg_tally <= 0 && !paralysis && !(lying || resting) && prob(5)) - emote("scream") + if(species && species.flags & NO_PAIN) + emote("scream") emote("collapse") paralysis = 10 diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 14171bd8697..42612998483 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 @@ -239,7 +240,7 @@ This function completely restores a damaged organ to perfect condition. //Possibly trigger an internal wound, too. var/local_damage = brute_dam + burn_dam + damage - if(damage > 10 && type != BURN && local_damage > 20 && prob(damage) && !(status & ORGAN_ROBOT)) + if(damage > 15 && type != BURN && local_damage > 30 && prob(damage) && !(status & ORGAN_ROBOT)) var/datum/wound/internal_bleeding/I = new (15) wounds += I owner.custom_pain("You feel something rip in your [display_name]!", 1) @@ -297,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) @@ -346,6 +352,9 @@ 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)) @@ -582,7 +591,10 @@ This function completely restores a damaged organ to perfect condition. if(status & ORGAN_BROKEN) return owner.visible_message("\red You hear a loud cracking sound coming from \the [owner].","\red Something feels like it shattered in your [display_name]!","You hear a sickening crack.") - owner.emote("scream") + + if(owner.species && !(owner.species.flags & NO_PAIN)) + owner.emote("scream") + status |= ORGAN_BROKEN broken_description = pick("broken","fracture","hairline fracture") perma_injury = brute_dam @@ -591,9 +603,11 @@ This function completely restores a damaged organ to perfect condition. src.status &= ~ORGAN_BROKEN src.status &= ~ORGAN_BLEEDING src.status &= ~ORGAN_SPLINTED + src.status &= ~ORGAN_CUT_AWAY src.status &= ~ORGAN_ATTACHABLE src.status &= ~ORGAN_DESTROYED src.status |= ORGAN_ROBOT + src.destspawn = 0 for (var/datum/organ/external/T in children) if(T) T.robotize() @@ -616,10 +630,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() @@ -781,8 +798,6 @@ obj/item/weapon/organ/New(loc, mob/living/carbon/human/H) base = icon('icons/mob/human_races/r_human.dmi') if(base) - base = base.MakeLying() - //Changing limb's skin tone to match owner if(!H.species || H.species.flags & HAS_SKIN_TONE) if (H.s_tone >= 0) @@ -790,28 +805,9 @@ obj/item/weapon/organ/New(loc, mob/living/carbon/human/H) else base.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT) - //this is put here since I can't easially edit the same icon from head's constructor - if(istype(src, /obj/item/weapon/organ/head)) - //Add (facial) hair. - if(H.f_style) - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style] - if(facial_hair_style) - var/icon/facial = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_l") - if(facial_hair_style.do_colouration) - facial.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) - - base.Blend(facial, ICON_OVERLAY) - - if(H.h_style && !(H.head && (H.head.flags & BLOCKHEADHAIR))) - var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] - if(hair_style) - var/icon/hair = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_l") - if(hair_style.do_colouration) - hair.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) - - base.Blend(hair, ICON_OVERLAY) - icon = base + dir = SOUTH + src.transform = turn(src.transform, rand(70,130)) /**************************************************** @@ -852,6 +848,24 @@ obj/item/weapon/organ/head/New(loc, mob/living/carbon/human/H) if(istype(H)) src.icon_state = H.gender == MALE? "head_m" : "head_f" ..() + //Add (facial) hair. + if(H.f_style) + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style] + if(facial_hair_style) + var/icon/facial = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") + if(facial_hair_style.do_colouration) + facial.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) + + overlays.Add(facial) // icon.Blend(facial, ICON_OVERLAY) + + if(H.h_style && !(H.head && (H.head.flags & BLOCKHEADHAIR))) + var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] + if(hair_style) + var/icon/hair = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + if(hair_style.do_colouration) + hair.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) + + overlays.Add(hair) //icon.Blend(hair, ICON_OVERLAY) spawn(5) if(brainmob && brainmob.client) brainmob.client.screen.len = null //clear the hud @@ -866,8 +880,8 @@ obj/item/weapon/organ/head/New(loc, mob/living/carbon/human/H) H.regenerate_icons() - H.stat = 2 - H.death() + brainmob.stat = 2 + brainmob.death() obj/item/weapon/organ/head/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->head brainmob = new(src) @@ -883,17 +897,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 @@ -902,20 +916,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..250e9b984de 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")) @@ -53,6 +55,9 @@ mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0 // flash_strength is 0 for weak pain flash, 1 for strong pain flash mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength) if(stat >= 1) return + + if(species && species.flags & NO_PAIN) return + if(reagents.has_reagent("tramadol")) return if(reagents.has_reagent("oxycodone")) @@ -71,6 +76,9 @@ mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength) mob/living/carbon/human/proc/handle_pain() // not when sleeping + + if(species && species.flags & NO_PAIN) return + if(stat >= 2) return if(reagents.has_reagent("tramadol")) return diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm index 379377072bc..1c491c126da 100644 --- a/code/modules/paperwork/folders.dm +++ b/code/modules/paperwork/folders.dm @@ -61,7 +61,7 @@ if(href_list["remove"]) var/obj/item/P = locate(href_list["remove"]) - if(P) + if(P && P.loc == src) P.loc = usr.loc usr.put_in_hands(P) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 66cbc91419a..1c546c01d0c 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -42,6 +42,8 @@ return /obj/item/weapon/paper/update_icon() + if(icon_state == "paper_talisman") + return if(info) icon_state = "paper_words" return @@ -227,6 +229,30 @@ \[hr\] : Adds a horizontal rule. "}, "window=paper_help") +/obj/item/weapon/paper/proc/burnpaper(obj/item/weapon/lighter/P, mob/user) + var/class = "" + + if(P.lit && !user.restrained()) + if(istype(P, /obj/item/weapon/lighter/zippo)) + class = "" + + user.visible_message("[class][user] holds \the [P] up to \the [src], it looks like \he's trying to burn it!", \ + "[class]You hold \the [P] up to \the [src], burning it slowly.") + + spawn(20) + if(get_dist(src, user) < 2 && user.get_active_hand() == P && P.lit) + user.visible_message("[class][user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "[class]You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + + if(user.get_inactive_hand() == src) + user.drop_from_inventory(src) + + new /obj/effect/decal/cleanable/ash(src.loc) + del(src) + + else + user << "\red You must hold \the [P] steady to burn \the [src]." + /obj/item/weapon/paper/Topic(href, href_list) ..() @@ -286,6 +312,7 @@ user << browse("[name][info_links][stamps]", "window=[name]") //openhelp(user) return + else if(istype(P, /obj/item/weapon/stamp)) if((!in_range(src, usr) && loc != user && !( istype(loc, /obj/item/weapon/clipboard) ) && loc.loc != user && user.get_active_hand() != P)) return @@ -310,6 +337,9 @@ user << "You stamp the paper with your rubber stamp." + else if(istype(P, /obj/item/weapon/lighter)) + burnpaper(P, user) + add_fingerprint(user) return diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 9b0a931a838..2695556c717 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -152,12 +152,12 @@ del(src) else if(toner > 0) - new /obj/effect/decal/cleanable/oil(get_turf(src)) + new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) toner = 0 else if(prob(50)) if(toner > 0) - new /obj/effect/decal/cleanable/oil(get_turf(src)) + new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) toner = 0 return @@ -166,7 +166,7 @@ del(src) else if(toner > 0) - new /obj/effect/decal/cleanable/oil(get_turf(src)) + new /obj/effect/decal/cleanable/blood/oil(get_turf(src)) toner = 0 return diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7a68873fd1e..560590cbad0 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -218,6 +218,7 @@ if (istype(user, /mob/living/silicon) && get_dist(src,user)>1) return src.attack_hand(user) + src.add_fingerprint(user) if (istype(W, /obj/item/weapon/crowbar) && opened) if (has_electronics==1) if (terminal) @@ -800,7 +801,8 @@ if(!can_use(usr, 1)) return src.add_fingerprint(usr) - usr.set_machine(src) + if(usingUI) // If we set their machine and they're not using the UI, it'll cause the UI to pop up. + usr.set_machine(src) if (href_list["apcwires"]) var/t1 = text2num(href_list["apcwires"]) if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) )) @@ -962,7 +964,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/power.dm b/code/modules/power/power.dm index b94901a6373..986f81d6c84 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -79,6 +79,9 @@ // rebuild all power networks from scratch +/hook/startup/proc/buildPowernets() + return makepowernets() + /proc/makepowernets() for(var/datum/powernet/PN in powernets) del(PN) @@ -101,6 +104,8 @@ if(!M.powernet) continue // APCs have powernet=0 so they don't count as network nodes directly M.powernet.nodes[M] = M + return 1 + // returns a list of all power-related objects (nodes, cable, junctions) in turf, // excluding source, that match the direction d diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 885947f90df..2ff0125b7ed 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -32,7 +32,7 @@ var/global/list/rad_collectors = list() P.air_contents.toxins = 0 eject() else - P.air_contents.toxins -= 0.001*drainratio + P.air_contents.adjust(tx = -0.001*drainratio) return diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index a5e0f52d726..3c0ec85ce84 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -21,7 +21,7 @@ var/chargecount = 0 var/chargelevel = 50000 var/online = 1 - var/n_tag = null + var/name_tag = null var/obj/machinery/power/terminal/terminal = null //Holders for powerout event. var/last_output = 0 @@ -122,7 +122,6 @@ if(last_disp != chargedisplay() || last_chrg != charging || last_onln != online) updateicon() - updateDialog() return // called after all power processes are finished @@ -164,48 +163,45 @@ /obj/machinery/power/smes/attack_ai(mob/user) add_fingerprint(user) - if(stat & BROKEN) return - interact(user) + ui_interact(user) /obj/machinery/power/smes/attack_hand(mob/user) add_fingerprint(user) - if(stat & BROKEN) return - interact(user) + ui_interact(user) + + +/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) - -/obj/machinery/power/smes/interact(mob/user) - if(get_dist(src, user) > 1 && !istype(user, /mob/living/silicon)) - user.unset_machine() - user << browse(null, "window=smes") + if(stat & BROKEN) return - user.set_machine(src) - - var/t = "SMES Power Storage Unit [n_tag? "([n_tag])" : null]
      "
      -
      -	t += "Stored capacity : [round(100.0*charge/capacity, 0.1)]%

      " - - t += "Input: [charging ? "Charging" : "Not Charging"] [chargemode ? "Auto Off" : "Auto Off "]
      " - - - t += "Input level: M - - - [add_lspace(chargelevel,5)] + + + M
      " - - t += "

      " - - t += "Output: [online ? "Online Offline" : "Online Offline "]
      " - - t += "Output level: M - - - [add_lspace(output,5)] + + + M
      " - - t += "Output load: [round(loaddemand)] W
      " - - t += "

      Close" - - t += "
      " - user << browse(t, "window=smes;size=460x300") - onclose(user, "smes") - return + // this is the data which will be sent to the ui + var/data[0] + data["nameTag"] = name_tag + data["storedCapacity"] = round(100.0*charge/capacity, 0.1) + data["charging"] = charging + data["chargeMode"] = chargemode + data["chargeLevel"] = chargelevel + data["chargeMax"] = SMESMAXCHARGELEVEL + data["outputOnline"] = online + data["outputLevel"] = output + data["outputMax"] = SMESMAXOUTPUT + data["outputLoad"] = round(loaddemand) + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "smes.tmpl", "SMES Power Storage Unit", 540, 380) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + /obj/machinery/power/smes/Topic(href, href_list) ..() @@ -219,85 +215,42 @@ //world << "[href] ; [href_list[href]]" - if (( usr.machine==src && ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + if (!istype(src.loc, /turf) && !istype(usr, /mob/living/silicon/)) + return 0 // Do not update ui + if( href_list["cmode"] ) + chargemode = !chargemode + if(!chargemode) + charging = 0 + updateicon() - if( href_list["close"] ) - usr << browse(null, "window=smes") - usr.unset_machine() - return + else if( href_list["online"] ) + online = !online + updateicon() + else if( href_list["input"] ) + switch( href_list["input"] ) + if("min") + chargelevel = 0 + if("max") + chargelevel = SMESMAXCHARGELEVEL //30000 + if("set") + chargelevel = input(usr, "Enter new input level (0-[SMESMAXCHARGELEVEL])", "SMES Input Power Control", chargelevel) as num + chargelevel = max(0, min(SMESMAXCHARGELEVEL, chargelevel)) // clamp to range - else if( href_list["cmode"] ) - chargemode = !chargemode - if(!chargemode) - charging = 0 - updateicon() - - else if( href_list["online"] ) - online = !online - updateicon() - else if( href_list["input"] ) - - var/i = text2num(href_list["input"]) - - var/d = 0 - switch(i) - if(-4) - chargelevel = 0 - if(4) - chargelevel = SMESMAXCHARGELEVEL //30000 - - if(1) - d = 100 - if(-1) - d = -100 - if(2) - d = 1000 - if(-2) - d = -1000 - if(3) - d = 10000 - if(-3) - d = -10000 - - chargelevel += d - chargelevel = max(0, min(SMESMAXCHARGELEVEL, chargelevel)) // clamp to range - - else if( href_list["output"] ) - - var/i = text2num(href_list["output"]) - - var/d = 0 - switch(i) - if(-4) - output = 0 - if(4) - output = SMESMAXOUTPUT //30000 - - if(1) - d = 100 - if(-1) - d = -100 - if(2) - d = 1000 - if(-2) - d = -1000 - if(3) - d = 10000 - if(-3) - d = -10000 - - output += d - output = max(0, min(SMESMAXOUTPUT, output)) // clamp to range - - investigate_log("input/output; [chargelevel>output?"":""][chargelevel]/[output] | Output-mode: [online?"on":"off"] | Input-mode: [chargemode?"auto":"off"] by [usr.key]","singulo") - src.updateUsrDialog() - - else - usr << browse(null, "window=smes") - usr.unset_machine() - return + else if( href_list["output"] ) + switch( href_list["output"] ) + if("min") + output = 0 + if("max") + output = SMESMAXOUTPUT //30000 + if("set") + output = input(usr, "Enter new output level (0-[SMESMAXOUTPUT])", "SMES Output Power Control", output) as num + output = max(0, min(SMESMAXOUTPUT, output)) // clamp to range + investigate_log("input/output; [chargelevel>output?"":""][chargelevel]/[output] | Output-mode: [online?"on":"off"] | Input-mode: [chargemode?"auto":"off"] by [usr.key]","singulo") + + return 1 + /obj/machinery/power/smes/proc/ion_act() if(src.z == 1) @@ -306,7 +259,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() @@ -324,7 +277,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/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm index fa7567bcb28..ecbea58fc2d 100644 --- a/code/modules/projectiles/ammunition/boxes.dm +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -14,6 +14,25 @@ multiple_sprites = 1 +/obj/item/ammo_magazine/c45m + name = "magazine (.45)" + icon_state = "45" + ammo_type = "/obj/item/ammo_casing/c45" + max_ammo = 7 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c45/empty + max_ammo = 0 + +/obj/item/ammo_magazine/c45r + name = "magazine (.45 rubber)" + icon_state = "45" + ammo_type = "/obj/item/ammo_casing/c45r" + max_ammo = 7 + multiple_sprites = 1 + +/obj/item/ammo_magazine/c45r/empty + max_ammo = 0 /obj/item/ammo_magazine/a418 name = "ammo box (.418)" diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm index 41443469d38..0063d0b2a94 100644 --- a/code/modules/projectiles/ammunition/bullets.dm +++ b/code/modules/projectiles/ammunition/bullets.dm @@ -43,6 +43,10 @@ caliber = ".45" projectile_type = "/obj/item/projectile/bullet/midbullet" +/obj/item/ammo_casing/c45r + desc = "A .45 rubber bullet casing." + caliber = ".45" + projectile_type = "/obj/item/projectile/bullet/weakbullet" /obj/item/ammo_casing/a12mm desc = "A 12mm bullet casing." @@ -94,3 +98,10 @@ desc = "A 7.62 bullet casing." caliber = "a762" projectile_type = "/obj/item/projectile/bullet/a762" + +/obj/item/ammo_casing/rocket + name = "rocket shell" + desc = "A high explosive designed to be fired from a launcher." + icon_state = "rocketshell" + projectile_type = "/obj/item/missile" + caliber = "rocket" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index d6c4913f0e8..2971e0f88f0 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/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index bcc619851c7..24476611096 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -193,4 +193,66 @@ obj/item/weapon/gun/energy/staff/focus charge_cost = 100 user << "\red The [src.name] will now strike only a single person." projectile_type = "/obj/item/projectile/forcebolt" - */ \ No newline at end of file + */ + +/obj/item/weapon/gun/energy/toxgun + name = "plasma pistol" + desc = "A specialized firearm designed to fire lethal bolts of toxins." + icon_state = "toxgun" + fire_sound = 'sound/effects/stealthoff.ogg' + w_class = 3.0 + origin_tech = "combat=5;plasmatech=4" + projectile_type = "/obj/item/projectile/energy/plasma" + +/obj/item/weapon/gun/energy/sniperrifle + name = "L.W.A.P. Sniper Rifle" + desc = "A rifle constructed of lightweight materials, fitted with a SMART aiming-system scope." + icon = 'icons/obj/gun.dmi' + icon_state = "sniper" + fire_sound = 'sound/weapons/marauder.ogg' + origin_tech = "combat=6;materials=5;powerstorage=4" + projectile_type = "/obj/item/projectile/beam/sniper" + slot_flags = SLOT_BACK + charge_cost = 250 + fire_delay = 35 + w_class = 4.0 + var/zoom = 0 + +/obj/item/weapon/gun/energy/sniperrifle/dropped(mob/user) + user.client.view = world.view + + + +/* +This is called from +modules/mob/mob_movement.dm if you move you will be zoomed out +modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. +*/ + +/obj/item/weapon/gun/energy/sniperrifle/verb/zoom() + set category = "Object" + set name = "Use Sniper Scope" + set popup_menu = 0 + if(usr.stat || !(istype(usr,/mob/living/carbon/human))) + usr << "You are unable to focus down the scope of the rifle." + return + if(!zoom && global_hud.darkMask[1] in usr.client.screen) + usr << "Your welding equipment gets in the way of you looking down the scope" + return + if(!zoom && usr.get_active_hand() != src) + usr << "You are too distracted to look down the scope, perhaps if it was in your active hand this might work better" + return + + if(usr.client.view == world.view) + if(!usr.hud_used.hud_shown) + usr.button_pressed_F12(1) // If the user has already limited their HUD this avoids them having a HUD when they zoom in + usr.button_pressed_F12(1) + usr.client.view = 12 + zoom = 1 + else + usr.client.view = world.view + if(!usr.hud_used.hud_shown) + usr.button_pressed_F12(1) + zoom = 0 + usr << "Zoom mode [zoom?"en":"dis"]abled." + return diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index 685122e05c5..18be233b9b9 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -51,6 +51,9 @@ if(istype(A, /obj/item/ammo_magazine)) if((load_method == MAGAZINE) && loaded.len) return var/obj/item/ammo_magazine/AM = A + if(AM.stored_ammo.len <= 0) + user << "The magazine is empty!" + return for(var/obj/item/ammo_casing/AC in AM.stored_ammo) if(loaded.len >= max_shells) break @@ -93,6 +96,7 @@ AM.loc = get_turf(src) empty_mag = null update_icon() + AM.update_icon() user << "\blue You unload magazine from \the [src]!" else user << "\red Nothing loaded in \the [src]!" diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index 0f6fca68b2b..07bf9bd0f6c 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -54,7 +54,7 @@ caliber = "357" desc = "The barrel and chamber assembly seems to have been modified." user << "You reinforce the barrel of [src]! Now it will fire .357 rounds." - else + else if (caliber == "357") user << "You begin to revert the modifications to [src]." if(loaded.len) afterattack(user, user) //and again @@ -70,6 +70,27 @@ user << "You remove the modifications on [src]! Now it will fire .38 rounds." +/obj/item/weapon/gun/projectile/detective/semiauto + desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds." + name = "\improper Colt M1911" + icon_state = "colt" + max_shells = 7 + caliber = ".45" + ammo_type = "/obj/item/ammo_casing/c45r" + load_method = 2 + +/obj/item/weapon/gun/projectile/detective/semiauto/New() + ..() + empty_mag = new /obj/item/ammo_magazine/c45r/empty(src) + return + +/obj/item/weapon/gun/projectile/detective/semiauto/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag) + ..() + if(!loaded.len && empty_mag) + empty_mag.loc = get_turf(src.loc) + empty_mag = null + user << "The Magazine falls out and clatters on the floor!" + return /obj/item/weapon/gun/projectile/mateba diff --git a/code/modules/projectiles/guns/projectile/rocket.dm b/code/modules/projectiles/guns/projectile/rocket.dm new file mode 100644 index 00000000000..a1575b937ce --- /dev/null +++ b/code/modules/projectiles/guns/projectile/rocket.dm @@ -0,0 +1,53 @@ +/obj/item/weapon/gun/rocketlauncher + var/projectile + name = "rocket launcher" + desc = "MAGGOT." + icon_state = "rocket" + item_state = "rocket" + w_class = 4.0 + throw_speed = 2 + throw_range = 10 + force = 5.0 + flags = FPRINT | TABLEPASS | CONDUCT | USEDELAY + slot_flags = 0 + origin_tech = "combat=8;materials=5" + projectile = /obj/item/missile + var/missile_speed = 2 + var/missile_range = 30 + var/max_rockets = 1 + var/list/rockets = new/list() + +/obj/item/weapon/gun/rocketlauncher/examine() + set src in view() + ..() + if (!(usr in view(2)) && usr!=src.loc) return + usr << "\blue [rockets.len] / [max_rockets] rockets." + +/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/ammo_casing/rocket)) + if(rockets.len < max_rockets) + user.drop_item() + I.loc = src + rockets += I + user << "\blue You put the rocket in [src]." + user << "\blue [rockets.len] / [max_rockets] rockets." + else + usr << "\red [src] cannot hold more rockets." + +/obj/item/weapon/gun/rocketlauncher/can_fire() + return rockets.len + +/obj/item/weapon/gun/rocketlauncher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) + if(rockets.len) + var/obj/item/ammo_casing/rocket/I = rockets[1] + var/obj/item/missile/M = new projectile(user.loc) + playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) + M.primed = 1 + M.throw_at(target, missile_range, missile_speed) + message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]).") + log_game("[key_name_admin(user)] used a rocket launcher ([src.name]).") + rockets -= I + del(I) + return + else + usr << "\red [src] is empty." \ No newline at end of file diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 9dbcabc47d9..d8ff676708d 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -49,7 +49,7 @@ var/eyeblur = 0 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 @@ -86,15 +86,14 @@ loc = A.loc return 0// nope.avi - //Lower accurancy/longer range tradeoff. Distance matters a lot here, so at - // close distance, actually RAISE the chance to hit. var/distance = get_dist(starting,loc) var/miss_modifier = -30 + if (istype(shot_from,/obj/item/weapon/gun)) //If you aim at someone beforehead, it'll hit more often. var/obj/item/weapon/gun/daddy = shot_from //Kinda balanced by fact you need like 2 seconds to aim if (daddy.target && original in daddy.target) //As opposed to no-delay pew pew miss_modifier += -30 - def_zone = get_zone_with_miss_chance(def_zone, M, -30 + 8*distance) + def_zone = get_zone_with_miss_chance(def_zone, M, miss_modifier + 15*distance) if(!def_zone) visible_message("\blue \The [src] misses [M] narrowly!") diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 3024ea1aa41..f9d2ea73f1d 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -160,4 +160,12 @@ var/list/beam_master = list() var/mob/living/carbon/human/M = target if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag))) M.Weaken(5) - return 1 \ No newline at end of file + return 1 + +/obj/item/projectile/beam/sniper + name = "sniper beam" + icon_state = "xray" + damage = 60 + stun = 5 + weaken = 5 + stutter = 5 \ No newline at end of file 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/change.dm b/code/modules/projectiles/projectile/change.dm index 31c7389fefd..9f5036dea17 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -13,6 +13,8 @@ /obj/item/projectile/change/proc/wabbajack (mob/M as mob in living_mob_list) if(istype(M, /mob/living) && M.stat != DEAD) if(M.monkeyizing) return + if(M.has_brain_worms()) return //Borer stuff - RR + M.monkeyizing = 1 M.canmove = 0 M.icon = null diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index b8789eca59a..6f719dafc98 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -59,5 +59,10 @@ damage_type = TOX weaken = 5 - +/obj/item/projectile/energy/plasma + name = "plasma bolt" + icon_state = "energy" + damage = 20 + damage_type = TOX + irradiate = 20 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/projectiles/targeting.dm b/code/modules/projectiles/targeting.dm index b8905e1ae25..06f25a7e18b 100644 --- a/code/modules/projectiles/targeting.dm +++ b/code/modules/projectiles/targeting.dm @@ -269,6 +269,7 @@ client/proc/add_gun_icons() screen += usr.gun_run_icon client/proc/remove_gun_icons() + if(isnull(usr)) return 1 // Runtime prevention on N00k agents spawning with SMG screen -= usr.item_use_icon screen -= usr.gun_move_icon if (target_can_move) diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 504461fed7f..970a6b293f5 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -199,11 +199,12 @@ datum return total_transfered */ - metabolize(var/mob/M) + metabolize(var/mob/M,var/alien) + for(var/A in reagent_list) var/datum/reagent/R = A if(M && R) - R.on_mob_life(M) + R.on_mob_life(M,alien) update_total() conditional_update_move(var/atom/A, var/Running = 0) diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 854cacb7dfa..9db39f296b7 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -10,14 +10,19 @@ icon_state = "dispenser" use_power = 0 idle_power_usage = 40 + var/ui_title = "Chem Dispenser 5000" var/energy = 100 var/max_energy = 100 var/amount = 30 + var/accept_glass = 0 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 @@ -38,7 +43,7 @@ /obj/machinery/chem_dispenser/process() - if(recharged < 0) + if(recharged <= 0) recharge() recharged = 15 else @@ -49,6 +54,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." + stat |= BROKEN + 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,11 +101,13 @@ * * @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",var/datum/nanoui/ui = null) + if(broken_requirements.len) + user << "[src] is broken. [broken_requirements[broken_requirements[1]]]" + return if(stat & (BROKEN|NOPOWER)) return if(user.stat || user.restrained()) return @@ -88,7 +117,7 @@ data["energy"] = energy data["maxEnergy"] = max_energy data["isBeakerLoaded"] = beaker ? 1 : 0 - + data["glass"] = accept_glass var beakerContents[0] var beakerCurrentVolume = 0 if(beaker && beaker:reagents && beaker:reagents.reagent_list.len) @@ -110,21 +139,17 @@ if(temp) chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("dispense" = temp.id)))) // list in a list because Byond merges the first list... data["chemicals"] = chemicals - - if (!ui) // no ui has been passed, so we'll search for one - { - ui = nanomanager.get_open_ui(user, src, ui_key) - } + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) 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) - // When the UI is first opened this is the data it will use - ui.set_initial_data(data) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "chem_dispenser.tmpl", ui_title, 370, 605) + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window ui.open() - else - // The UI is already open so push the new data to it - ui.push_data(data) - return /obj/machinery/chem_dispenser/Topic(href, href_list) if(stat & (NOPOWER|BROKEN)) @@ -139,7 +164,7 @@ if(href_list["dispense"]) if (dispensable_reagents.Find(href_list["dispense"]) && beaker != null) - var/obj/item/weapon/reagent_containers/glass/B = src.beaker + var/obj/item/weapon/reagent_containers/B = src.beaker var/datum/reagents/R = B.reagents var/space = R.maximum_volume - R.total_volume @@ -148,29 +173,41 @@ if(href_list["ejectBeaker"]) if(beaker) - var/obj/item/weapon/reagent_containers/glass/B = beaker + var/obj/item/weapon/reagent_containers/B = beaker B.loc = loc beaker = null add_fingerprint(usr) return 1 // update UIs attached to this object -/obj/machinery/chem_dispenser/attackby(var/obj/item/weapon/reagent_containers/glass/B as obj, var/mob/user as mob) +/obj/machinery/chem_dispenser/attackby(var/obj/item/weapon/reagent_containers/B as obj, var/mob/user as mob) 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) + if(broken_requirements.len==0) + stat ^= BROKEN 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) || istype(B, /obj/item/weapon/reagent_containers/food)) + if(!accept_glass && istype(B,/obj/item/weapon/reagent_containers/food)) + user << "This machine only accepts beakers" + 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 +221,55 @@ 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." + ui_title = "Soda Dispens-o-matic" + energy = 100 + accept_glass = 1 + max_energy = 100 + dispensable_reagents = list("water","ice","coffee","cream","tea","icetea","cola","spacemountainwind","dr_gibb","space_up","tonic","sodawater","lemon_lime","sugar","orangejuice","limejuice","watermelonjuice") + + /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" + ui_title = "Booze Portal 9001" + energy = 100 + accept_glass = 1 + 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("lemon_lime","sugar","orangejuice","limejuice","sodawater","tonic","beer","kahlua","whiskey","wine","vodka","gin","rum","tequilla","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 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -348,7 +434,6 @@ reagents.clear_reagents() icon_state = "mixer0" else if (href_list["createpill"] || href_list["createpill_multiple"]) - var/count = 1 if(reagents.total_volume/count < 1) //Sanity checking. @@ -362,14 +447,14 @@ 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)")) if(reagents.total_volume/count < 1) //Sanity checking. return - 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) @@ -382,9 +467,9 @@ 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-Antidepressants.dm b/code/modules/reagents/Chemistry-Reagents-Antidepressants.dm index 4c7c2e4fe5f..0a722a436ac 100644 --- a/code/modules/reagents/Chemistry-Reagents-Antidepressants.dm +++ b/code/modules/reagents/Chemistry-Reagents-Antidepressants.dm @@ -1,5 +1,3 @@ -Methylphenidate - #define ANTIDEPRESSANT_MESSAGE_DELAY 5*60*10 /datum/reagent/antidepressant/methylphenidate diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index e4382699c39..c9666d98f00 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -5,6 +5,10 @@ #define REAGENTS_OVERDOSE 30 #define REM REAGENTS_EFFECT_MULTIPLIER +//Some on_mob_life() procs check for alien races. +#define IS_DIONA 1 +#define IS_VOX 2 + //The reaction procs must ALWAYS set src = null, this detaches the proc from the object (the reagent) //so that it can continue working when the reagent is deleted while the proc is still active. @@ -31,7 +35,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) @@ -68,7 +72,7 @@ datum src = null return - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(!istype(M, /mob/living)) return //Noticed runtime errors from pacid trying to damage ghosts, this should fix. --NEO if( (overdose > 0) && (volume >= overdose))//Overdosing, wooo @@ -153,7 +157,7 @@ datum newVirus.holder = blood_prop else if(istype(self.data["donor"], /mob/living/carbon/alien)) - var/obj/effect/decal/cleanable/xenoblood/blood_prop = locate() in T + var/obj/effect/decal/cleanable/blood/xeno/blood_prop = locate() in T if(!blood_prop) blood_prop = new(T) blood_prop.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" @@ -400,10 +404,15 @@ datum color = "#C8A5DC" // rgb: 200, 165, 220 overdose = REAGENTS_OVERDOSE*2 - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(!M) M = holder.my_atom - if(M.losebreath >= 10) - M.losebreath = max(10, M.losebreath-5) + + if(alien && alien == IS_VOX) + M.adjustToxLoss(REAGENTS_METABOLISM) + else + if(M.losebreath >= 10) + M.losebreath = max(10, M.losebreath-5) + holder.remove_reagent(src.id, 0.5 * REAGENTS_METABOLISM) return @@ -484,6 +493,14 @@ datum custom_metabolism = 0.01 + on_mob_life(var/mob/living/M as mob, var/alien) + if(M.stat == 2) return + if(alien && alien == IS_VOX) + M.adjustToxLoss(REAGENTS_METABOLISM) + holder.remove_reagent(src.id, REAGENTS_METABOLISM) //By default it slowly disappears. + return + ..() + copper name = "Copper" id = "copper" @@ -501,6 +518,14 @@ datum custom_metabolism = 0.01 + on_mob_life(var/mob/living/M as mob, var/alien) + if(M.stat == 2) return + if(alien && alien == IS_VOX) + M.adjustOxyLoss(-2*REM) + holder.remove_reagent(src.id, REAGENTS_METABOLISM) //By default it slowly disappears. + return + ..() + hydrogen name = "Hydrogen" id = "hydrogen" @@ -539,7 +564,7 @@ datum sulfur name = "Sulfur" id = "sulfur" - description = "A chemical element." + description = "A chemical element with a pungent smell." reagent_state = SOLID color = "#BF8C00" // rgb: 191, 140, 0 @@ -548,7 +573,7 @@ datum carbon name = "Carbon" id = "carbon" - description = "A chemical element." + description = "A chemical element, the builing block of life." reagent_state = SOLID color = "#1C1300" // rgb: 30, 20, 0 @@ -562,7 +587,7 @@ datum chlorine name = "Chlorine" id = "chlorine" - description = "A chemical element." + description = "A chemical element with a characteristic odour." reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 overdose = REAGENTS_OVERDOSE @@ -590,7 +615,7 @@ datum sodium name = "Sodium" id = "sodium" - description = "A chemical element." + description = "A chemical element, readily reacts with water." reagent_state = SOLID color = "#808080" // rgb: 128, 128, 128 @@ -599,7 +624,7 @@ datum phosphorus name = "Phosphorus" id = "phosphorus" - description = "A chemical element." + description = "A chemical element, the backbone of biological energy carriers." reagent_state = SOLID color = "#832828" // rgb: 131, 40, 40 @@ -608,7 +633,7 @@ datum lithium name = "Lithium" id = "lithium" - description = "A chemical element." + description = "A chemical element, used as antidepressant." reagent_state = SOLID color = "#808080" // rgb: 128, 128, 128 overdose = REAGENTS_OVERDOSE @@ -671,7 +696,10 @@ datum if(prob(5)) if(prob(50)) M.radiation += 50 // curing it that way may kill you instead - M.adjustToxLoss(100) + var/mob/living/carbon/human/H + if(istype(C,/mob/living/carbon/human)) + H = C + if(!H || (H.species && !(H.species.flags & RAD_ABSORB))) M.adjustToxLoss(100) M:antibodies |= V.antigen ..() return @@ -687,7 +715,7 @@ datum ryetalyn name = "Ryetalyn" id = "ryetalyn" - description = "Ryetalyn can cure all genetic abnomalities." + description = "Ryetalyn can cure all genetic abnomalities via a catalytic process." reagent_state = SOLID color = "#C8A5DC" // rgb: 200, 165, 220 overdose = REAGENTS_OVERDOSE @@ -731,13 +759,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 +789,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" @@ -884,6 +934,9 @@ datum for(var/mob/living/carbon/slime/M in T) M.adjustToxLoss(rand(5,10)) + reaction_turf(var/turf/simulated/S, var/volume) + if(volume >= 1) + S.dirt = 0 reaction_mob(var/mob/M, var/method=TOUCH, var/volume) if(iscarbon(M)) @@ -958,6 +1011,7 @@ datum if(M.stat == 2.0) return if(!M) M = holder.my_atom + //This needs a diona check but if one is added they won't be able to heal burn damage at all. M.heal_organ_damage(0,2*REM) ..() return @@ -970,11 +1024,12 @@ datum color = "#C8A5DC" // rgb: 200, 165, 220 overdose = REAGENTS_OVERDOSE/2 - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(M.stat == 2.0) //THE GUY IS **DEAD**! BEREFT OF ALL LIFE HE RESTS IN PEACE etc etc. He does NOT metabolise shit anymore, god DAMN return if(!M) M = holder.my_atom - M.heal_organ_damage(0,3*REM) + if(!alien || alien != IS_DIONA) + M.heal_organ_damage(0,3*REM) ..() return @@ -986,11 +1041,16 @@ datum color = "#C8A5DC" // rgb: 200, 165, 220 overdose = REAGENTS_OVERDOSE - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(M.stat == 2.0) return //See above, down and around. --Agouri if(!M) M = holder.my_atom - M.adjustOxyLoss(-2*REM) + + if(alien && alien == IS_VOX) + M.adjustToxLoss(2*REM) + else if(!alien || alien != IS_DIONA) + M.adjustOxyLoss(-2*REM) + if(holder.has_reagent("lexorin")) holder.remove_reagent("lexorin", 2*REM) ..() @@ -999,16 +1059,21 @@ datum dexalinp name = "Dexalin Plus" id = "dexalinp" - description = "Dexalin Plus is used in the treatment of oxygen deprivation. Its highly effective." + description = "Dexalin Plus is used in the treatment of oxygen deprivation. It is highly effective." reagent_state = LIQUID color = "#C8A5DC" // rgb: 200, 165, 220 overdose = REAGENTS_OVERDOSE/2 - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(M.stat == 2.0) return if(!M) M = holder.my_atom - M.adjustOxyLoss(-M.getOxyLoss()) + + if(alien && alien == IS_VOX) + M.adjustOxyLoss() + else if(!alien || alien != IS_DIONA) + M.adjustOxyLoss(-M.getOxyLoss()) + if(holder.has_reagent("lexorin")) holder.remove_reagent("lexorin", 2*REM) ..() @@ -1021,14 +1086,15 @@ datum reagent_state = LIQUID color = "#C8A5DC" // rgb: 200, 165, 220 - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(M.stat == 2.0) return if(!M) M = holder.my_atom - if(M.getOxyLoss() && prob(80)) 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) + if(!alien || alien != IS_DIONA) + 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) ..() return @@ -1039,12 +1105,13 @@ datum reagent_state = LIQUID color = "#C8A5DC" // rgb: 200, 165, 220 - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(!M) M = holder.my_atom - M.reagents.remove_all_type(/datum/reagent/toxin, 1*REM, 0, 1) - M.drowsyness = max(M.drowsyness-2*REM, 0) - M.hallucination = max(0, M.hallucination - 5*REM) - M.adjustToxLoss(-2*REM) + if(!alien || alien != IS_DIONA) + M.reagents.remove_all_type(/datum/reagent/toxin, 1*REM, 0, 1) + M.drowsyness = max(M.drowsyness-2*REM, 0) + M.hallucination = max(0, M.hallucination - 5*REM) + M.adjustToxLoss(-2*REM) ..() return @@ -1069,7 +1136,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 +1255,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 @@ -1203,11 +1291,12 @@ datum color = "#C8A5DC" // rgb: 200, 165, 220 overdose = REAGENTS_OVERDOSE - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob, var/alien) if(M.stat == 2.0) return if(!M) M = holder.my_atom - M.heal_organ_damage(2*REM,0) + if(alien != IS_DIONA) + M.heal_organ_damage(2*REM,0) ..() return @@ -1246,7 +1335,7 @@ datum clonexadone name = "Clonexadone" id = "clonexadone" - description = "A liquid compound similar to that used in the cloning process. Can be used to 'finish' clones that get ejected early when used in conjunction with a cryo tube." + description = "A liquid compound similar to that used in the cloning process. Can be used to 'finish' the cloning process when used in conjunction with a cryo tube." reagent_state = LIQUID color = "#C8A5DC" // rgb: 200, 165, 220 @@ -1307,7 +1396,7 @@ datum holywater name = "Holy Water" id = "holywater" - description = "A ubiquitous chemical substance that is composed of hydrogen and oxygen." + description = "This was once water, but has been altered by higher powers." reagent_state = LIQUID color = "#535E66" // rgb: 83, 94, 102 @@ -1437,7 +1526,7 @@ datum if(prob(98)) randmutb(M) else randmutg(M) domutcheck(M, null) - updateappearance(M,M.dna.uni_identity) + M.UpdateAppearance() return on_mob_life(var/mob/living/carbon/M) if(!istype(M)) return @@ -1553,7 +1642,7 @@ datum toxin/carpotoxin name = "Carpotoxin" id = "carpotoxin" - description = "A deadly neurotoxin produced by the dreaded spess carp." + description = "A deadly neurotoxin produced by the dreaded space carp." reagent_state = LIQUID color = "#003333" // rgb: 0, 51, 51 toxpwr = 2 @@ -1585,7 +1674,7 @@ datum toxin/mindbreaker name = "Mindbreaker Toxin" id = "mindbreaker" - description = "A powerful hallucinogen. Not a thing to be messed with." + description = "A powerful hallucinogen, it can cause fatal effects in users." reagent_state = LIQUID color = "#B31008" // rgb: 139, 166, 233 toxpwr = 0 @@ -1638,7 +1727,7 @@ datum var/mob/living/carbon/human/H = M if(H.dna) if(H.species.flags & IS_PLANT) //plantmen take a LOT of damage - H.adjustToxLoss(10) + H.adjustToxLoss(50) toxin/stoxin name = "Sleep Toxin" @@ -1658,10 +1747,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 +1764,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,18 +1777,57 @@ 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 toxin/beer2 //disguised as normal beer for use by emagged brobots name = "Beer" id = "beer2" - description = "An alcoholic beverage made from malted grains, hops, yeast, and water." + description = "An alcoholic beverage made from malted grains, hops, yeast, and water. The fermentation appears to be imcomplete." //If the players manage to analyze this, they deserve to know something is wrong. reagent_state = LIQUID color = "#664300" // rgb: 102, 67, 0 custom_metabolism = 0.15 // Sleep toxins should always be consumed pretty fast @@ -1721,7 +1852,7 @@ datum toxin/acid name = "Sulphuric acid" id = "sacid" - description = "A strong mineral acid with the molecular formula H2SO4." + description = "A very corrosive mineral acid with the molecular formula H2SO4." reagent_state = LIQUID color = "#DB5008" // rgb: 219, 80, 8 toxpwr = 1 @@ -1975,7 +2106,7 @@ datum frostoil name = "Frost Oil" id = "frostoil" - description = "A special oil that noticably chills the body. Extraced from Icepeppers." + description = "A special oil that noticably chills the body. Extracted from Ice Peppers." reagent_state = LIQUID color = "#B31008" // rgb: 139, 166, 233 @@ -2038,7 +2169,7 @@ datum hot_coco name = "Hot Chocolate" id = "hot_coco" - description = "Made with love! And coco beans." + description = "Made with love! And cocoa beans." reagent_state = LIQUID nutriment_factor = 2 * REAGENTS_METABOLISM color = "#403010" // rgb: 64, 48, 16 @@ -2092,12 +2223,13 @@ datum on_mob_life(var/mob/living/M as mob) M.nutrition += nutriment_factor - if(istype(M, /mob/living/carbon/human) && M.job in list("Security Officer", "Head of Security", "Detective", "Warden")) + /*if(istype(M, /mob/living/carbon/human) && M.job in list("Security Officer", "Head of Security", "Detective", "Warden")) if(!M) M = holder.my_atom M.heal_organ_damage(1,1) M.nutrition += nutriment_factor ..() return + */ ..() /* //removed because of meta bullshit. this is why we can't have nice things. @@ -2348,6 +2480,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" @@ -2423,7 +2562,7 @@ datum drink/hot_coco name = "Hot Chocolate" id = "hot_coco" - description = "Made with love! And coco beans." + description = "Made with love! And cocoa beans." nutriment_factor = 2 * FOOD_METABOLISM color = "#403010" // rgb: 64, 48, 16 adj_temp = 5 @@ -2533,7 +2672,7 @@ datum color = "#619494" // rgb: 97, 148, 148 drink/cold/space_cola - name = "Cola" + name = "Space Cola" id = "cola" description = "A refreshing beverage." reagent_state = LIQUID @@ -2556,7 +2695,7 @@ datum return drink/cold/spacemountainwind - name = "Space Mountain Wind" + name = "Mountain Wind" id = "spacemountainwind" description = "Blows right through you like a space wind." color = "#102000" // rgb: 16, 32, 0 @@ -2598,7 +2737,7 @@ datum drink/cold/brownstar name = "Brown Star" - description = "Its not what it sounds like..." + description = "It's not what it sounds like..." id = "brownstar" color = "#9F3400" // rgb: 159, 052, 000 adj_temp = - 2 @@ -2636,7 +2775,7 @@ datum drink/cold/rewriter name = "Rewriter" - description = "The secert of the sanctuary of the Libarian..." + description = "The secret of the sanctuary of the Libarian..." id = "rewriter" color = "#485000" // rgb:72, 080, 0 @@ -2742,7 +2881,7 @@ datum return hippies_delight - name = "Hippie's Delight" + name = "Hippies' Delight" id = "hippiesdelight" description = "You just don't get it maaaan." reagent_state = LIQUID @@ -2849,12 +2988,12 @@ datum if(istype(O,/obj/item/weapon/paper)) var/obj/item/weapon/paper/paperaffected = O paperaffected.clearpaper() - usr << "The solution melts away the ink on the paper." + usr << "The solution dissolves the ink on the paper." if(istype(O,/obj/item/weapon/book)) if(volume >= 5) var/obj/item/weapon/book/affectedbook = O affectedbook.dat = null - usr << "The solution melts away the ink on the book." + usr << "The solution dissolves the ink on the book." else usr << "It wasn't enough..." return @@ -3047,29 +3186,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) @@ -3133,7 +3272,7 @@ datum ethanol/cuba_libre name = "Cuba Libre" id = "cubalibre" - description = "Rum, mixed with cola. Viva la revolution." + description = "Rum, mixed with cola. Viva la revolucion." color = "#3E1B00" // rgb: 62, 27, 0 boozepwr = 1.5 @@ -3203,7 +3342,7 @@ datum ethanol/toxins_special name = "Toxins Special" id = "toxinsspecial" - description = "This thing is ON FIRE!. CALL THE DAMN SHUTTLE!" + description = "This thing is ON FIRE! CALL THE DAMN SHUTTLE!" reagent_state = LIQUID color = "#664300" // rgb: 102, 67, 0 boozepwr = 5 @@ -3420,14 +3559,14 @@ datum ethanol/red_mead name = "Red Mead" id = "red_mead" - description = "The true Viking drink! Even though it has a strange red color." + description = "The true Viking's drink! Even though it has a strange red color." color = "#C73C00" // rgb: 199, 60, 0 boozepwr = 1.5 ethanol/mead name = "Mead" id = "mead" - description = "A Vikings drink, though a cheap one." + description = "A Viking's drink, though a cheap one." reagent_state = LIQUID color = "#664300" // rgb: 102, 67, 0 boozepwr = 1.5 @@ -3464,7 +3603,7 @@ datum ethanol/andalusia name = "Andalusia" id = "andalusia" - description = "A nice, strange named drink." + description = "A nice, strangely named drink." color = "#664300" // rgb: 102, 67, 0 boozepwr = 3 @@ -3516,7 +3655,7 @@ datum ethanol/erikasurprise name = "Erika Surprise" id = "erikasurprise" - description = "The surprise is, it's green!" + description = "The surprise is it's green!" color = "#2E6671" // rgb: 46, 102, 113 boozepwr = 3 diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 07c1c778690..c06117a08bb 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" @@ -229,7 +252,7 @@ datum name = "Dexalin" id = "dexalin" result = "dexalin" - required_reagents = list("oxygen" = 2) + required_reagents = list("oxygen" = 2, "plasma" = 0.1) required_catalysts = list("plasma" = 5) result_amount = 1 @@ -279,7 +302,7 @@ datum name = "Clonexadone" id = "clonexadone" result = "clonexadone" - required_reagents = list("cryoxadone" = 1, "sodium" = 1) + required_reagents = list("cryoxadone" = 1, "sodium" = 1, "plasma" = 0.1) required_catalysts = list("plasma" = 5) result_amount = 2 @@ -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" + result = "potassium_chloride" + required_reagents = list("sodiumchloride" = 1, "potassium" = 1) + result_amount = 2 + + potassium_chlorophoride + name = "Potassium Chlorophoride" + id = "potassium_chlorophoride" + result = "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" @@ -470,7 +514,7 @@ datum id = "mindbreaker" result = "mindbreaker" required_reagents = list("silicon" = 1, "hydrogen" = 1, "anti_toxin" = 1) - result_amount = 5 + result_amount = 3 lipozine name = "Lipozine" @@ -1791,6 +1835,14 @@ datum required_reagents = list("berryjuice" = 1, "cream" = 1, "vermouth" = 1) result_amount = 3 + grapesoda + 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/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm index 96e037a23a6..17f8d1ce11e 100644 --- a/code/modules/reagents/reagent_containers/dropper.dm +++ b/code/modules/reagents/reagent_containers/dropper.dm @@ -12,7 +12,7 @@ var/filled = 0 afterattack(obj/target, mob/user , flag) - if(!target.reagents) return + if(!target.reagents || !flag) return if(filled) @@ -105,4 +105,4 @@ //////////////////////////////////////////////////////////////////////////////// /// Droppers. END -//////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////// diff --git a/code/modules/reagents/reagent_containers/food.dm b/code/modules/reagents/reagent_containers/food.dm index 4f14338886f..53bdeca5f84 100644 --- a/code/modules/reagents/reagent_containers/food.dm +++ b/code/modules/reagents/reagent_containers/food.dm @@ -4,6 +4,7 @@ /obj/item/weapon/reagent_containers/food possible_transfer_amounts = null volume = 50 //Sets the default container amount for all food items. + var/filling_color = "#FFFFFF" //Used by sandwiches. /obj/item/weapon/reagent_containers/food/New() ..() diff --git a/code/modules/reagents/reagent_containers/food/cans.dm b/code/modules/reagents/reagent_containers/food/cans.dm new file mode 100644 index 00000000000..6f3b3f3901d --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/cans.dm @@ -0,0 +1,266 @@ +/obj/item/weapon/reagent_containers/food/drinks/cans + var canopened = 0 + + attack_self(mob/user as mob) + if (canopened == 0) + playsound(src.loc,'sound/effects/canopen.ogg', rand(10,50), 1) + user << "You open the drink with an audible pop!" + canopened = 1 + else + return + + attack(mob/M as mob, mob/user as mob, def_zone) + if (canopened == 0) + user << " You need to open the drink!" + return + var/datum/reagents/R = src.reagents + var/fillevel = gulp_size + + if(!R.total_volume || !R) + user << "\red None of [src] left, oh no!" + return 0 + + if(M == user) + M << "\blue You swallow a gulp of [src]." + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, gulp_size) + + playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) + return 1 + else if( istype(M, /mob/living/carbon/human) ) + + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] attempts to feed [M] [src].", 1) + if(!do_mob(user, M)) return + for(var/mob/O in viewers(world.view, user)) + O.show_message("\red [user] feeds [M] [src].", 1) + + M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") + user.attack_log += text("\[[time_stamp()]\] Fed [M.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]") + log_attack("[user.name] ([user.ckey]) fed [M.name] ([M.ckey]) with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)]) (JMP)") + + if(reagents.total_volume) + reagents.reaction(M, INGEST) + spawn(5) + reagents.trans_to(M, gulp_size) + + if(isrobot(user)) //Cyborg modules that include drinks automatically refill themselves, but drain the borg's cell + var/mob/living/silicon/robot/bro = user + bro.cell.use(30) + var/refill = R.get_master_reagent_id() + spawn(600) + R.add_reagent(refill, fillevel) + + playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) + return 1 + + return 0 + + + afterattack(obj/target, mob/user, proximity) + if(!proximity) return + + if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us. + + if(!target.reagents.total_volume) + 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()) //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/datum/reagent/refill + var/datum/reagent/refillName + if(isrobot(user)) + refill = reagents.get_master_reagent_id() + refillName = reagents.get_master_reagent_name() + + var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this) + user << "\blue You transfer [trans] units of the solution to [target]." + + if(isrobot(user)) //Cyborg modules that include drinks automatically refill themselves, but drain the borg's cell + var/mob/living/silicon/robot/bro = user + var/chargeAmount = max(30,4*trans) + bro.cell.use(chargeAmount) + user << "Now synthesizing [trans] units of [refillName]..." + + + spawn(300) + reagents.add_reagent(refill, trans) + user << "Cyborg [src] refilled." + + return + +/* examine() + set src in view() + ..() + if (!(usr in range(0)) && usr!=src.loc) return + if(!reagents || reagents.total_volume==0) + usr << "\blue \The [src] is empty!" + else if (reagents.total_volume<=src.volume/4) + usr << "\blue \The [src] is almost empty!" + else if (reagents.total_volume<=src.volume*0.66) + usr << "\blue \The [src] is half full!" + else if (reagents.total_volume<=src.volume*0.90) + usr << "\blue \The [src] is almost full!" + else + usr << "\blue \The [src] is full!"*/ + + +//DRINKS + +/obj/item/weapon/reagent_containers/food/drinks/cans/cola + name = "Space Cola" + desc = "Cola. in space." + icon_state = "cola" + New() + ..() + reagents.add_reagent("cola", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle + name = "Bottled Water" + desc = "Introduced to the vending machines by Skrellian request, this water comes straight from the Martian poles." + icon_state = "waterbottle" + New() + ..() + reagents.add_reagent("water", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/beer + name = "Space Beer" + desc = "Contains only water, malt and hops." + icon_state = "beer" + New() + ..() + reagents.add_reagent("beer", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/ale + name = "Magm-Ale" + desc = "A true dorf's drink of choice." + icon_state = "alebottle" + item_state = "beer" + New() + ..() + reagents.add_reagent("ale", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind + name = "Space Mountain Wind" + desc = "Blows right through you like a space wind." + icon_state = "space_mountain_wind" + New() + ..() + reagents.add_reagent("spacemountainwind", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko + name = "Thirteen Loko" + desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsibly." + icon_state = "thirteen_loko" + New() + ..() + reagents.add_reagent("thirteenloko", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb + name = "Dr. Gibb" + desc = "A delicious mixture of 42 different flavors." + icon_state = "dr_gibb" + New() + ..() + reagents.add_reagent("dr_gibb", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/starkist + name = "Star-kist" + desc = "The taste of a star in liquid form. And, a bit of tuna...?" + icon_state = "starkist" + New() + ..() + reagents.add_reagent("cola", 15) + reagents.add_reagent("orangejuice", 15) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/space_up + name = "Space-Up" + desc = "Tastes like a hull breach in your mouth." + icon_state = "space-up" + New() + ..() + reagents.add_reagent("space_up", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime + name = "Lemon-Lime" + desc = "You wanted ORANGE. It gave you Lemon Lime." + icon_state = "lemon-lime" + New() + ..() + reagents.add_reagent("lemon_lime", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea + name = "Vrisk Serket Iced Tea" + desc = "That sweet, refreshing southern earthy flavor. That's where it's from, right? South Earth?" + icon_state = "ice_tea_can" + New() + ..() + reagents.add_reagent("icetea", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice + name = "Grapel Juice" + desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" + icon_state = "purple_can" + New() + ..() + reagents.add_reagent("grapejuice", 30) + src.pixel_x = rand(-10.0, 10) + src.pixel_y = rand(-10.0, 10) + +/obj/item/weapon/reagent_containers/food/drinks/cans/tonic + name = "T-Borg's Tonic Water" + desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." + icon_state = "tonic" + New() + ..() + reagents.add_reagent("tonic", 50) + +/obj/item/weapon/reagent_containers/food/drinks/cans/sodawater + name = "Soda Water" + desc = "A can of soda water. Still water's more refreshing cousin." + icon_state = "sodawater" + New() + ..() + reagents.add_reagent("sodawater", 50) \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index 86bd97d7eaa..fe49ad0262a 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -242,128 +242,6 @@ src.pixel_x = rand(-10.0, 10) src.pixel_y = rand(-10.0, 10) -/obj/item/weapon/reagent_containers/food/drinks/cola - name = "Space Cola" - desc = "Cola. in space." - icon_state = "cola" - New() - ..() - reagents.add_reagent("cola", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/waterbottle - name = "Bottled Water" - desc = "Introduced to the vending machines on health nut protest, taste fresh, pure glacial* water! *Note: Might be tapwater." - icon_state = "waterbottle" - New() - ..() - reagents.add_reagent("water", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/beer - name = "Space Beer" - desc = "Beer. In space." - icon_state = "beer" - New() - ..() - reagents.add_reagent("beer", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/ale - name = "Magm-Ale" - desc = "A true dorf's drink of choice." - icon_state = "alebottle" - item_state = "beer" - New() - ..() - reagents.add_reagent("ale", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - - -/obj/item/weapon/reagent_containers/food/drinks/space_mountain_wind - name = "Space Mountain Wind" - desc = "Blows right through you like a space wind." - icon_state = "space_mountain_wind" - New() - ..() - reagents.add_reagent("spacemountainwind", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/thirteenloko - name = "Thirteen Loko" - desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkeness, or even death. Please Drink Responsably." - icon_state = "thirteen_loko" - New() - ..() - reagents.add_reagent("thirteenloko", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/dr_gibb - name = "Dr. Gibb" - desc = "A delicious mixture of 42 different flavors." - icon_state = "dr_gibb" - New() - ..() - reagents.add_reagent("dr_gibb", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/starkist - name = "Star-kist" - desc = "The taste of a star in liquid form. And, a bit of tuna...?" - icon_state = "starkist" - New() - ..() - reagents.add_reagent("cola", 15) - reagents.add_reagent("orangejuice", 15) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/space_up - name = "Space-Up" - desc = "Tastes like a hull breach in your mouth." - icon_state = "space-up" - New() - ..() - reagents.add_reagent("space_up", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/lemon_lime - name = "Lemon-Lime" - desc = "You wanted ORANGE. It gave you Lemon Lime." - icon_state = "lemon-lime" - New() - ..() - reagents.add_reagent("lemon_lime", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/iced_tea - name = "Vrisk Serket Iced Tea" - desc = "That sweet, refreshing southern earthy flavor. That's where it's from, right? South Earth? Whatever!!!!!!!!" - icon_state = "ice_tea_can" - New() - ..() - reagents.add_reagent("icetea", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) - -/obj/item/weapon/reagent_containers/food/drinks/grape_juice - name = "Grapel Juice" - desc = "500 pages of rules of how to appropriately enter into a combat with this juice!" - icon_state = "purple_can" - New() - ..() - reagents.add_reagent("grapejuice", 30) - src.pixel_x = rand(-10.0, 10) - src.pixel_y = rand(-10.0, 10) /obj/item/weapon/reagent_containers/food/drinks/sillycup name = "Paper Cup" @@ -381,21 +259,7 @@ else icon_state = "water_cup_e" -/obj/item/weapon/reagent_containers/food/drinks/tonic - name = "T-Borg's Tonic Water" - desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away." - icon_state = "tonic" - New() - ..() - reagents.add_reagent("tonic", 50) -/obj/item/weapon/reagent_containers/food/drinks/sodawater - name = "Soda Water" - desc = "A can of soda water. Why not make a scotch and soda?" - icon_state = "sodawater" - New() - ..() - reagents.add_reagent("sodawater", 50) //////////////////////////drinkingglass and shaker// //Note by Darem: This code handles the mixing of drinks. New drinks go in three places: In Chemistry-Reagents.dm (for the drink // itself), in Chemistry-Recipes.dm (for the reaction that changes the components into the drink), and here (for the drinking glass @@ -428,12 +292,12 @@ /obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask name = "vacuum flask" - desc = "Keeping your drinks at the perfect temperature since 2321." + desc = "Keeping your drinks at the perfect temperature since 1892." icon_state = "vacuumflask" volume = 60 /obj/item/weapon/reagent_containers/food/drinks/britcup name = "cup" - desc = "A cup with the british flag emblazoned on it." + desc = "A cup with the British flag emblazoned on it." icon_state = "britcup" volume = 30 \ No newline at end of file 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/sandwich.dm b/code/modules/reagents/reagent_containers/food/sandwich.dm new file mode 100644 index 00000000000..48decfb6968 --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/sandwich.dm @@ -0,0 +1,101 @@ +/obj/item/weapon/reagent_containers/food/snacks/breadslice/attackby(obj/item/W as obj, mob/user as mob) + + if(istype(W,/obj/item/weapon/shard) || istype(W,/obj/item/weapon/reagent_containers/food/snacks)) + var/obj/item/weapon/reagent_containers/food/snacks/csandwich/S = new(get_turf(src)) + S.attackby(W,user) + del(src) + ..() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich + name = "sandwich" + desc = "The best thing since sliced bread." + icon_state = "breadslice" + trash = /obj/item/trash/plate + bitesize = 2 + + var/list/ingredients = list() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/attackby(obj/item/W as obj, mob/user as mob) + + var/sandwich_limit = 4 + for(var/obj/item/O in ingredients) + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/breadslice)) + sandwich_limit += 4 + + if(src.contents.len > sandwich_limit) + user << "\red If you put anything else on \the [src] it's going to collapse." + return + else if(istype(W,/obj/item/weapon/shard)) + user << "\blue You hide [W] in \the [src]." + user.drop_item() + W.loc = src + update() + return + else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks)) + user << "\blue You layer [W] over \the [src]." + var/obj/item/weapon/reagent_containers/F = W + F.reagents.trans_to(src, F.reagents.total_volume) + user.drop_item() + W.loc = src + ingredients += W + update() + return + ..() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/proc/update() + var/fullname = "" //We need to build this from the contents of the var. + var/i = 0 + + overlays.Cut() + + for(var/obj/item/weapon/reagent_containers/food/snacks/O in ingredients) + + i++ + if(i == 1) + fullname += "[O.name]" + else if(i == ingredients.len) + fullname += " and [O.name]" + else + fullname += ", [O.name]" + + var/image/I = new(src.icon, "sandwich_filling") + I.color = O.filling_color + I.pixel_x = pick(list(-1,0,1)) + I.pixel_y = (i*2)+1 + overlays += I + + var/image/T = new(src.icon, "sandwich_top") + T.pixel_x = pick(list(-1,0,1)) + T.pixel_y = (ingredients.len * 2)+1 + overlays += T + + name = lowertext("[fullname] sandwich") + if(length(name) > 80) name = "[pick(list("absurd","colossal","enormous","ridiculous"))] sandwich" + w_class = n_ceil(Clamp((ingredients.len/2),1,3)) + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/Del() + for(var/obj/item/O in ingredients) + del(O) + ..() + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/examine() + ..() + var/obj/item/O = pick(contents) + usr << "\blue You think you can see [O.name] in there." + +/obj/item/weapon/reagent_containers/food/snacks/csandwich/attack(mob/M as mob, mob/user as mob, def_zone) + + var/obj/item/shard + for(var/obj/item/O in contents) + if(istype(O,/obj/item/weapon/shard)) + shard = O + break + + var/mob/living/H + if(istype(M,/mob/living)) + H = M + + if(H && shard && M == user) //This needs a check for feeding the food to other people, but that could be abusable. + H << "\red You lacerate your mouth on a [shard.name] in the sandwich!" + H.adjustBruteLoss(5) //TODO: Target head if human. + ..() \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 771d49a2da8..4476eb6d4f1 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -249,6 +249,8 @@ desc = "Probably too incredible for mortal men to fully enjoy." icon_state = "aesirsalad" trash = /obj/item/trash/snack_bowl + filling_color = "#468C00" + New() ..() reagents.add_reagent("nutriment", 8) @@ -261,6 +263,8 @@ desc = "Nougat love it or hate it." icon_state = "candy" trash = /obj/item/trash/candy + filling_color = "#7D5F46" + New() ..() reagents.add_reagent("nutriment", 1) @@ -281,6 +285,8 @@ name = "candy corn" desc = "It's a handful of candy corn. Can be stored in a detective's hat." icon_state = "candy_corn" + filling_color = "#FFFCB0" + New() ..() reagents.add_reagent("nutriment", 4) @@ -292,6 +298,8 @@ desc = "Commander Riker's What-The-Crisps" icon_state = "chips" trash = /obj/item/trash/chips + filling_color = "#E8C31E" + New() ..() reagents.add_reagent("nutriment", 3) @@ -301,6 +309,8 @@ name = "cookie" desc = "COOKIE!!!" icon_state = "COOKIE!!!" + filling_color = "#DBC94F" + New() ..() reagents.add_reagent("nutriment", 5) @@ -310,6 +320,8 @@ name = "Chocolate Bar" desc = "Such, sweet, fattening food." icon_state = "chocolatebar" + filling_color = "#7D5F46" + New() ..() reagents.add_reagent("nutriment", 2) @@ -321,6 +333,8 @@ name = "Chocolate Egg" desc = "Such, sweet, fattening food." icon_state = "chocolateegg" + filling_color = "#7D5F46" + New() ..() reagents.add_reagent("nutriment", 3) @@ -332,6 +346,7 @@ name = "donut" desc = "Goes great with Robust Coffee." icon_state = "donut1" + filling_color = "#D9C386" /obj/item/weapon/reagent_containers/food/snacks/donut/normal name = "donut" @@ -351,6 +366,8 @@ name = "Chaos Donut" desc = "Like life, it never quite tastes the same." icon_state = "donut1" + filling_color = "#ED11E6" + New() ..() reagents.add_reagent("nutriment", 2) @@ -388,6 +405,8 @@ name = "Jelly Donut" desc = "You jelly?" icon_state = "jdonut1" + filling_color = "#ED1169" + New() ..() reagents.add_reagent("nutriment", 3) @@ -403,6 +422,8 @@ name = "Jelly Donut" desc = "You jelly?" icon_state = "jdonut1" + filling_color = "#ED1169" + New() ..() reagents.add_reagent("nutriment", 3) @@ -418,6 +439,8 @@ name = "Jelly Donut" desc = "You jelly?" icon_state = "jdonut1" + filling_color = "#ED1169" + New() ..() reagents.add_reagent("nutriment", 3) @@ -433,6 +456,8 @@ name = "egg" desc = "An egg!" icon_state = "egg" + filling_color = "#FDFFD1" + New() ..() reagents.add_reagent("nutriment", 1) @@ -495,6 +520,8 @@ name = "Fried egg" desc = "A fried egg, with a touch of salt and pepper." icon_state = "friedegg" + filling_color = "#FFDF78" + New() ..() reagents.add_reagent("nutriment", 2) @@ -506,6 +533,8 @@ name = "Boiled egg" desc = "A hard boiled egg." icon_state = "egg" + filling_color = "#FFFFFF" + New() ..() reagents.add_reagent("nutriment", 2) @@ -523,6 +552,8 @@ desc = "An appendix which looks perfectly healthy." icon = 'icons/obj/surgery.dmi' icon_state = "appendix" + filling_color = "#E00D34" + New() ..() reagents.add_reagent("nutriment", 3) @@ -532,21 +563,48 @@ name = "inflamed appendix" desc = "An appendix which appears to be inflamed." icon_state = "appendixinflamed" + filling_color = "#E00D7A" /obj/item/weapon/reagent_containers/food/snacks/tofu name = "Tofu" icon_state = "tofu" desc = "We all love tofu." + filling_color = "#FFFEE0" + New() ..() reagents.add_reagent("nutriment", 3) src.bitesize = 3 +/obj/item/weapon/reagent_containers/food/snacks/tofurkey + name = "Tofurkey" + desc = "A fake turkey made from tofu." + icon_state = "tofurkey" + filling_color = "#FFFEE0" + + New() + ..() + reagents.add_reagent("nutriment", 12) + reagents.add_reagent("stoxin", 3) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/stuffing + name = "Stuffing" + desc = "Moist, peppery breadcrumbs for filling the body cavities of dead birds. Dig in!" + icon_state = "stuffing" + filling_color = "#C9AC83" + + New() + ..() + reagents.add_reagent("nutriment", 3) + bitesize = 1 /obj/item/weapon/reagent_containers/food/snacks/carpmeat name = "carp fillet" desc = "A fillet of spess carp meat" icon_state = "fishfillet" + filling_color = "#FFDEFE" + New() ..() reagents.add_reagent("nutriment", 3) @@ -557,6 +615,8 @@ name = "Fish Fingers" desc = "A finger of fish." icon_state = "fishfingers" + filling_color = "#FFDEFE" + New() ..() reagents.add_reagent("nutriment", 4) @@ -567,6 +627,8 @@ name = "huge mushroom slice" desc = "A slice from a huge mushroom." icon_state = "hugemushroomslice" + filling_color = "#E0D7C5" + New() ..() reagents.add_reagent("nutriment", 3) @@ -577,6 +639,8 @@ name = "tomato slice" desc = "A slice from a huge tomato" icon_state = "tomatomeat" + filling_color = "#DB0000" + New() ..() reagents.add_reagent("nutriment", 3) @@ -586,6 +650,8 @@ name = "bear meat" desc = "A very manly slab of meat." icon_state = "bearmeat" + filling_color = "#DB0000" + New() ..() reagents.add_reagent("nutriment", 12) @@ -596,6 +662,8 @@ name = "meat" desc = "A slab of meat" icon_state = "xenomeat" + filling_color = "#43DE18" + New() ..() reagents.add_reagent("nutriment", 3) @@ -605,6 +673,8 @@ name = "Faggot" desc = "A great meal all round. Not a cord of wood." icon_state = "faggot" + filling_color = "#DB0000" + New() ..() reagents.add_reagent("nutriment", 3) @@ -614,6 +684,8 @@ name = "Sausage" desc = "A piece of mixed, long meat." icon_state = "sausage" + filling_color = "#DB0000" + New() ..() reagents.add_reagent("nutriment", 6) @@ -623,6 +695,8 @@ name = "Donk-pocket" desc = "The food of choice for the seasoned traitor." icon_state = "donkpocket" + filling_color = "#DEDEAB" + New() ..() reagents.add_reagent("nutriment", 4) @@ -640,6 +714,8 @@ name = "brainburger" desc = "A strange looking burger. It looks almost sentient." icon_state = "brainburger" + filling_color = "#F2B6EA" + New() ..() reagents.add_reagent("nutriment", 6) @@ -650,6 +726,8 @@ name = "Ghost Burger" desc = "Spooky! It doesn't look very filling." icon_state = "ghostburger" + filling_color = "#FFF2FF" + New() ..() reagents.add_reagent("nutriment", 2) @@ -659,6 +737,7 @@ /obj/item/weapon/reagent_containers/food/snacks/human var/hname = "" var/job = null + filling_color = "#D63C3C" /obj/item/weapon/reagent_containers/food/snacks/human/burger name = "-burger" @@ -673,6 +752,8 @@ name = "burger" desc = "The cornerstone of every nutritious breakfast." icon_state = "hburger" + filling_color = "#D63C3C" + New() ..() reagents.add_reagent("nutriment", 6) @@ -682,6 +763,8 @@ name = "Fillet -o- Carp Sandwich" desc = "Almost like a carp is yelling somewhere... Give me back that fillet -o- carp, give me that carp." icon_state = "fishburger" + filling_color = "#FFDEFE" + New() ..() reagents.add_reagent("nutriment", 6) @@ -692,6 +775,8 @@ name = "Tofu Burger" desc = "What.. is that meat?" icon_state = "tofuburger" + filling_color = "#FFFEE0" + New() ..() reagents.add_reagent("nutriment", 6) @@ -701,6 +786,8 @@ name = "roburger" desc = "The lettuce is the only organic component. Beep." icon_state = "roburger" + filling_color = "#CCCCCC" + New() ..() reagents.add_reagent("nanites", 2) @@ -710,7 +797,9 @@ name = "roburger" desc = "This massive patty looks like poison. Beep." icon_state = "roburger" + filling_color = "#CCCCCC" volume = 100 + New() ..() reagents.add_reagent("nanites", 100) @@ -720,6 +809,8 @@ name = "xenoburger" desc = "Smells caustic. Tastes like heresy." icon_state = "xburger" + filling_color = "#43DE18" + New() ..() reagents.add_reagent("nutriment", 8) @@ -729,6 +820,8 @@ name = "Clown Burger" desc = "This tastes funny..." icon_state = "clownburger" + filling_color = "#FF00FF" + New() ..() /* @@ -743,6 +836,8 @@ name = "Mime Burger" desc = "Its taste defies language." icon_state = "mimeburger" + filling_color = "#FFFFFF" + New() ..() reagents.add_reagent("nutriment", 6) @@ -753,6 +848,8 @@ desc = "That's all you can say!" icon_state = "omelette" trash = /obj/item/trash/plate + filling_color = "#FFF9A8" + //var/herp = 0 New() ..() @@ -790,6 +887,8 @@ name = "Muffin" desc = "A delicious and spongy little cake" icon_state = "muffin" + filling_color = "#E0CF9B" + New() ..() reagents.add_reagent("nutriment", 6) @@ -800,6 +899,7 @@ desc = "Just like back home, on clown planet! HONK!" icon_state = "pie" trash = /obj/item/trash/plate + filling_color = "#FBFFB8" /obj/item/weapon/reagent_containers/food/snacks/pie/New() ..() @@ -829,6 +929,8 @@ desc = "Mmm, waffles" icon_state = "waffles" trash = /obj/item/trash/waffles + filling_color = "#E6DEB5" + New() ..() reagents.add_reagent("nutriment", 8) @@ -839,6 +941,8 @@ desc = "The only good recipe for eggplant." icon_state = "eggplantparm" trash = /obj/item/trash/plate + filling_color = "#4D2F5E" + New() ..() reagents.add_reagent("nutriment", 6) @@ -849,6 +953,8 @@ desc = "Not made of people. Honest." //Totally people. icon_state = "soylent_green" trash = /obj/item/trash/waffles + filling_color = "#B8E6B5" + New() ..() reagents.add_reagent("nutriment", 10) @@ -859,6 +965,8 @@ desc = "Not made of people. Honest." //Actually honest for once. icon_state = "soylent_yellow" trash = /obj/item/trash/waffles + filling_color = "#E6FA61" + New() ..() reagents.add_reagent("nutriment", 10) @@ -870,6 +978,8 @@ icon_state = "meatpie" desc = "An old barber recipe, very delicious!" trash = /obj/item/trash/plate + filling_color = "#948051" + New() ..() reagents.add_reagent("nutriment", 10) @@ -880,6 +990,8 @@ icon_state = "meatpie" desc = "A delicious tofu pie." trash = /obj/item/trash/plate + filling_color = "#FFFEE0" + New() ..() reagents.add_reagent("nutriment", 10) @@ -889,6 +1001,8 @@ name = "amanita pie" desc = "Sweet and tasty poison pie." icon_state = "amanita_pie" + filling_color = "#FFCCCC" + New() ..() reagents.add_reagent("nutriment", 5) @@ -900,6 +1014,8 @@ name = "plump pie" desc = "I bet you love stuff made out of plump helmets!" icon_state = "plump_pie" + filling_color = "#B8279B" + New() ..() if(prob(10)) @@ -917,6 +1033,8 @@ icon_state = "xenomeatpie" desc = "A delicious meatpie. Probably heretical." trash = /obj/item/trash/plate + filling_color = "#43DE18" + New() ..() reagents.add_reagent("nutriment", 10) @@ -927,6 +1045,8 @@ desc = "A savory dish of alien wing wang in soy." icon_state = "wingfangchu" trash = /obj/item/trash/snack_bowl + filling_color = "#43DE18" + New() ..() reagents.add_reagent("nutriment", 6) @@ -938,6 +1058,8 @@ icon_state = "kabob" desc = "A human meat, on a stick." trash = /obj/item/stack/rods + filling_color = "#A85340" + New() ..() reagents.add_reagent("nutriment", 8) @@ -948,6 +1070,8 @@ icon_state = "kabob" desc = "Delicious meat, on a stick." trash = /obj/item/stack/rods + filling_color = "#A85340" + New() ..() reagents.add_reagent("nutriment", 8) @@ -958,6 +1082,8 @@ icon_state = "kabob" desc = "Vegan meat, on a stick." trash = /obj/item/stack/rods + filling_color = "#FFFEE0" + New() ..() reagents.add_reagent("nutriment", 8) @@ -968,6 +1094,8 @@ desc = "A grifftastic sandwich that burns your tongue and then leaves it numb!" icon_state = "cubancarp" trash = /obj/item/trash/plate + filling_color = "#E9ADFF" + New() ..() reagents.add_reagent("nutriment", 6) @@ -981,6 +1109,8 @@ icon_state = "popcorn" trash = /obj/item/trash/popcorn var/unpopped = 0 + filling_color = "#FFFAD4" + New() ..() unpopped = rand(1,10) @@ -998,6 +1128,8 @@ icon_state = "sosjerky" desc = "Beef jerky made from the finest space cows." trash = /obj/item/trash/sosjerky + filling_color = "#631212" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1008,6 +1140,8 @@ icon_state = "4no_raisins" desc = "Best raisins in the universe. Not sure why." trash = /obj/item/trash/raisins + filling_color = "#343834" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1016,6 +1150,8 @@ name = "Space Twinkie" icon_state = "space_twinkie" desc = "Guaranteed to survive longer then you will." + filling_color = "#FFE591" + New() ..() reagents.add_reagent("sugar", 4) @@ -1026,6 +1162,8 @@ icon_state = "cheesie_honkers" desc = "Bite sized cheesie snacks that will honk all over your mouth" trash = /obj/item/trash/cheesie + filling_color = "#FFA305" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1035,6 +1173,8 @@ name = "Syndi-Cakes" icon_state = "syndi_cakes" desc = "An extremely moist snack cake that tastes just as good after being nuked." + filling_color = "#FF5D05" + trash = /obj/item/trash/syndi_cakes New() ..() @@ -1046,6 +1186,8 @@ name = "Loaded Baked Potato" desc = "Totally baked." icon_state = "loadedbakedpotato" + filling_color = "#9C7A68" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1056,6 +1198,8 @@ desc = "AKA: French Fries, Freedom Fries, etc" icon_state = "fries" trash = /obj/item/trash/plate + filling_color = "#EDDD00" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1066,6 +1210,8 @@ desc = "Dope from a soy." icon_state = "soydope" trash = /obj/item/trash/plate + filling_color = "#C4BF76" + New() ..() reagents.add_reagent("nutriment", 2) @@ -1075,6 +1221,8 @@ name = "Spagetti" desc = "Now thats a nice pasta!" icon_state = "spagetti" + filling_color = "#EDDD00" + New() ..() reagents.add_reagent("nutriment", 1) @@ -1085,6 +1233,8 @@ desc = "Fries. Covered in cheese. Duh." icon_state = "cheesyfries" trash = /obj/item/trash/plate + filling_color = "#EDDD00" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1094,6 +1244,8 @@ name = "Fortune cookie" desc = "A true prophecy in each cookie!" icon_state = "fortune_cookie" + filling_color = "#E8E79E" + New() ..() reagents.add_reagent("nutriment", 3) @@ -1103,6 +1255,8 @@ name = "Burned mess" desc = "Someone should be demoted from chef for this." icon_state = "badrecipe" + filling_color = "#211F02" + New() ..() reagents.add_reagent("toxin", 1) @@ -1114,6 +1268,8 @@ desc = "A piece of hot spicy meat." icon_state = "meatstake" trash = /obj/item/trash/plate + filling_color = "#7A3D11" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1126,6 +1282,8 @@ desc = "Jello gelatin, from Alfred Hubbard's cookbook" icon_state = "spacylibertyduff" trash = /obj/item/trash/snack_bowl + filling_color = "#42B873" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1137,6 +1295,8 @@ desc = "Looks curiously toxic" icon_state = "amanitajelly" trash = /obj/item/trash/snack_bowl + filling_color = "#ED0758" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1149,6 +1309,8 @@ desc = "It's all twisted up!" icon_state = "poppypretzel" bitesize = 2 + filling_color = "#916E36" + New() ..() reagents.add_reagent("nutriment", 5) @@ -1160,6 +1322,8 @@ desc = "You've got balls kid, BALLS!" icon_state = "meatballsoup" trash = /obj/item/trash/snack_bowl + filling_color = "#785210" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1170,6 +1334,8 @@ name = "slime soup" desc = "If no water is available, you may substitute tears." icon_state = "slimesoup" + filling_color = "#C4DBA0" + New() ..() reagents.add_reagent("slimejelly", 5) @@ -1180,6 +1346,8 @@ name = "Tomato soup" desc = "Smells like copper" icon_state = "tomatosoup" + filling_color = "#FF0000" + New() ..() reagents.add_reagent("nutriment", 2) @@ -1191,6 +1359,8 @@ name = "Clown's Tears" desc = "Not very funny." icon_state = "clownstears" + filling_color = "#C4FBFF" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1203,6 +1373,8 @@ desc = "A true vegan meal" //TODO icon_state = "vegetablesoup" trash = /obj/item/trash/snack_bowl + filling_color = "#AFC4B5" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1214,6 +1386,8 @@ desc = "To think, the botanist would've beat you to death with one of these." icon_state = "nettlesoup" trash = /obj/item/trash/snack_bowl + filling_color = "#AFC4B5" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1226,6 +1400,8 @@ desc = "The mystery is, why aren't you eating it?" icon_state = "mysterysoup" trash = /obj/item/trash/snack_bowl + filling_color = "#F082FF" + New() ..() var/mysteryselect = pick(1,2,3,4,5,6,7,8,9,10) @@ -1271,6 +1447,8 @@ desc = "I wish this was soup." icon_state = "wishsoup" trash = /obj/item/trash/snack_bowl + filling_color = "#D1F4FF" + New() ..() reagents.add_reagent("water", 10) @@ -1284,6 +1462,8 @@ desc = "A five alarm Texan Chili!" icon_state = "hotchili" trash = /obj/item/trash/snack_bowl + filling_color = "#FF3C00" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1296,6 +1476,8 @@ name = "Cold Chili" desc = "This slush is barely a liquid!" icon_state = "coldchili" + filling_color = "#2B00FF" + trash = /obj/item/trash/snack_bowl New() ..() @@ -1326,6 +1508,8 @@ desc = "Just add water!" icon_state = "monkeycube" bitesize = 12 + filling_color = "#ADAC7F" + var/wrapped = 0 var/monkey_type = null @@ -1401,6 +1585,8 @@ name = "Spell Burger" desc = "This is absolutely Ei Nath." icon_state = "spellburger" + filling_color = "#D505FF" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1410,6 +1596,8 @@ name = "Big Bite Burger" desc = "Forget the Big Mac. THIS is the future!" icon_state = "bigbiteburger" + filling_color = "#E3D681" + New() ..() reagents.add_reagent("nutriment", 14) @@ -1420,6 +1608,8 @@ desc = "Viva La Mexico!" icon_state = "enchiladas" trash = /obj/item/trash/tray + filling_color = "#A36A1F" + New() ..() reagents.add_reagent("nutriment",8) @@ -1431,6 +1621,8 @@ desc = "Eeee Eee!" icon_state = "monkeysdelight" trash = /obj/item/trash/tray + filling_color = "#5C3C11" + New() ..() reagents.add_reagent("nutriment", 10) @@ -1443,6 +1635,8 @@ name = "Baguette" desc = "Bon appetit!" icon_state = "baguette" + filling_color = "#E3D796" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1454,6 +1648,8 @@ name = "Fish and Chips" desc = "I do say so myself chap." icon_state = "fishandchips" + filling_color = "#E3D796" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1465,6 +1661,8 @@ desc = "A grand creation of meat, cheese, bread, and several leaves of lettuce! Arthur Dent would be proud." icon_state = "sandwich" trash = /obj/item/trash/plate + filling_color = "#D9BE29" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1475,6 +1673,8 @@ desc = "Now if you only had a pepper bar." icon_state = "toastedsandwich" trash = /obj/item/trash/plate + filling_color = "#D9BE29" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1486,6 +1686,8 @@ desc = "Goes great with Tomato soup!" icon_state = "toastedsandwich" trash = /obj/item/trash/plate + filling_color = "#D9BE29" + New() ..() reagents.add_reagent("nutriment", 7) @@ -1496,6 +1698,8 @@ desc = "Drinking this feels like being a vampire! A tomato vampire..." icon_state = "tomatosoup" trash = /obj/item/trash/snack_bowl + filling_color = "#D92929" + New() ..() reagents.add_reagent("nutriment", 5) @@ -1507,6 +1711,8 @@ desc = "Waffles from Roffle. Co." icon_state = "rofflewaffles" trash = /obj/item/trash/waffles + filling_color = "#FF00F7" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1517,6 +1723,8 @@ name = "Stew" desc = "A nice and warm stew. Healthy and strong." icon_state = "stew" + filling_color = "#9E673A" + New() ..() reagents.add_reagent("nutriment", 10) @@ -1530,6 +1738,8 @@ desc = "A slice of bread covered with delicious jam." icon_state = "jellytoast" trash = /obj/item/trash/plate + filling_color = "#B572AB" + New() ..() reagents.add_reagent("nutriment", 1) @@ -1549,6 +1759,8 @@ name = "Jelly Burger" desc = "Culinary delight..?" icon_state = "jellyburger" + filling_color = "#B572AB" + New() ..() reagents.add_reagent("nutriment", 5) @@ -1590,6 +1802,8 @@ desc = "A plain dish of noodles, this sucks." icon_state = "spagettiboiled" trash = /obj/item/trash/plate + filling_color = "#FCEE81" + New() ..() reagents.add_reagent("nutriment", 2) @@ -1600,6 +1814,8 @@ desc = "A boring dish of boring rice." icon_state = "boiledrice" trash = /obj/item/trash/snack_bowl + filling_color = "#FFFBDB" + New() ..() reagents.add_reagent("nutriment", 2) @@ -1610,6 +1826,8 @@ desc = "Where's the Jam!" icon_state = "rpudding" trash = /obj/item/trash/snack_bowl + filling_color = "#FFFBDB" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1620,6 +1838,8 @@ desc = "Spaghetti and crushed tomatoes. Just like your abusive father used to make!" icon_state = "pastatomato" trash = /obj/item/trash/plate + filling_color = "#DE4545" + New() ..() reagents.add_reagent("nutriment", 6) @@ -1631,6 +1851,8 @@ desc = "Now thats a nic'e meatball!" icon_state = "meatballspagetti" trash = /obj/item/trash/plate + filling_color = "#DE4545" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1640,6 +1862,8 @@ name = "Spesslaw" desc = "A lawyers favourite" icon_state = "spesslaw" + filling_color = "#DE4545" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1649,6 +1873,8 @@ name = "Poppy Pretzel" desc = "A large soft pretzel full of POP!" icon_state = "poppypretzel" + filling_color = "#AB7D2E" + New() ..() reagents.add_reagent("nutriment", 5) @@ -1659,6 +1885,8 @@ desc = "Tasty fries from fresh Carrots." icon_state = "carrotfries" trash = /obj/item/trash/plate + filling_color = "#FAA005" + New() ..() reagents.add_reagent("nutriment", 3) @@ -1669,6 +1897,8 @@ name = "Super Bite Burger" desc = "This is a mountain of a burger. FOOD!" icon_state = "superbiteburger" + filling_color = "#CCA26A" + New() ..() reagents.add_reagent("nutriment", 40) @@ -1678,6 +1908,8 @@ name = "Candied Apple" desc = "An apple coated in sugary sweetness." icon_state = "candiedapple" + filling_color = "#F21873" + New() ..() reagents.add_reagent("nutriment", 3) @@ -1687,6 +1919,8 @@ name = "Apple Pie" desc = "A pie containing sweet sweet love...or apple." icon_state = "applepie" + filling_color = "#E0EDC5" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1697,6 +1931,8 @@ name = "Cherry Pie" desc = "Taste so good, make a grown man cry." icon_state = "cherrypie" + filling_color = "#FF525A" + New() ..() reagents.add_reagent("nutriment", 4) @@ -1706,6 +1942,8 @@ name = "Two Bread" desc = "It is very bitter and winy." icon_state = "twobread" + filling_color = "#DBCC9A" + New() ..() reagents.add_reagent("nutriment", 2) @@ -1716,6 +1954,8 @@ desc = "You wish you had some peanut butter to go with this..." icon_state = "jellysandwich" trash = /obj/item/trash/plate + filling_color = "#9E3A78" + New() ..() reagents.add_reagent("nutriment", 2) @@ -1744,6 +1984,8 @@ name = "mint" desc = "it is only wafer thin." icon_state = "mint" + filling_color = "#F2F2F2" + New() ..() reagents.add_reagent("minttoxin", 1) @@ -1754,6 +1996,8 @@ desc = "A delicious and hearty mushroom soup." icon_state = "mushroomsoup" trash = /obj/item/trash/snack_bowl + filling_color = "#E386BF" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1763,6 +2007,8 @@ name = "plump helmet biscuit" desc = "This is a finely-prepared plump helmet biscuit. The ingredients are exceptionally minced plump helmet, and well-minced dwarven wheat flour." icon_state = "phelmbiscuit" + filling_color = "#CFB4C4" + New() ..() if(prob(10)) @@ -1780,6 +2026,8 @@ desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat." icon_state = "chawanmushi" trash = /obj/item/trash/snack_bowl + filling_color = "#F0F2E4" + New() ..() reagents.add_reagent("nutriment", 5) @@ -1790,6 +2038,8 @@ desc = "Wait, how do you spell it again..?" icon_state = "beetsoup" trash = /obj/item/trash/snack_bowl + filling_color = "#FAC9FF" + New() ..() switch(rand(1,6)) @@ -1813,6 +2063,8 @@ desc = "A proper salad, basic and simple, with little bits of carrot, tomato and apple intermingled. Vegan!" icon_state = "herbsalad" trash = /obj/item/trash/snack_bowl + filling_color = "#76B87F" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1823,6 +2075,8 @@ desc = "It's just a salad of questionable 'herbs' with meatballs and fried potato slices. Nothing suspicious about it." icon_state = "validsalad" trash = /obj/item/trash/snack_bowl + filling_color = "#76B87F" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1833,6 +2087,8 @@ desc = "A tasty dessert that won't make it through a metal detector." icon_state = "gappletart" trash = /obj/item/trash/plate + filling_color = "#FFFF00" + New() ..() reagents.add_reagent("nutriment", 8) @@ -1850,6 +2106,7 @@ icon_state = "meatbread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/meatbreadslice slices_num = 5 + filling_color = "#FF7575" New() ..() reagents.add_reagent("nutriment", 30) @@ -1860,6 +2117,7 @@ desc = "A slice of delicious meatbread." icon_state = "meatbreadslice" trash = /obj/item/trash/plate + filling_color = "#FF7575" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread @@ -1868,6 +2126,7 @@ icon_state = "xenomeatbread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/xenomeatbreadslice slices_num = 5 + filling_color = "#8AFF75" New() ..() reagents.add_reagent("nutriment", 30) @@ -1878,6 +2137,7 @@ desc = "A slice of delicious meatbread. Extra Heretical." icon_state = "xenobreadslice" trash = /obj/item/trash/plate + filling_color = "#8AFF75" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread @@ -1886,6 +2146,7 @@ icon_state = "bananabread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/bananabreadslice slices_num = 5 + filling_color = "#EDE5AD" New() ..() reagents.add_reagent("banana", 20) @@ -1897,6 +2158,7 @@ desc = "A slice of delicious banana bread." icon_state = "bananabreadslice" trash = /obj/item/trash/plate + filling_color = "#EDE5AD" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread @@ -1905,6 +2167,7 @@ icon_state = "tofubread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/tofubreadslice slices_num = 5 + filling_color = "#F7FFE0" New() ..() reagents.add_reagent("nutriment", 30) @@ -1915,6 +2178,7 @@ desc = "A slice of delicious tofubread." icon_state = "tofubreadslice" trash = /obj/item/trash/plate + filling_color = "#F7FFE0" bitesize = 2 @@ -1924,6 +2188,7 @@ icon_state = "carrotcake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice slices_num = 5 + filling_color = "#FFD675" New() ..() reagents.add_reagent("nutriment", 25) @@ -1935,6 +2200,7 @@ desc = "Carrotty slice of Carrot Cake, carrots are good for your eyes! Also not a lie." icon_state = "carrotcake_slice" trash = /obj/item/trash/plate + filling_color = "#FFD675" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake @@ -1943,6 +2209,7 @@ icon_state = "braincake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/braincakeslice slices_num = 5 + filling_color = "#E6AEDB" New() ..() reagents.add_reagent("nutriment", 25) @@ -1954,6 +2221,7 @@ desc = "Lemme tell you something about prions. THEY'RE DELICIOUS." icon_state = "braincakeslice" trash = /obj/item/trash/plate + filling_color = "#E6AEDB" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake @@ -1962,6 +2230,7 @@ icon_state = "cheesecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice slices_num = 5 + filling_color = "#FAF7AF" New() ..() reagents.add_reagent("nutriment", 25) @@ -1972,6 +2241,7 @@ desc = "Slice of pure cheestisfaction" icon_state = "cheesecake_slice" trash = /obj/item/trash/plate + filling_color = "#FAF7AF" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake @@ -1980,6 +2250,7 @@ icon_state = "plaincake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/plaincakeslice slices_num = 5 + filling_color = "#F7EDD5" New() ..() reagents.add_reagent("nutriment", 20) @@ -1989,6 +2260,7 @@ desc = "Just a slice of cake, it is enough for everyone." icon_state = "plaincake_slice" trash = /obj/item/trash/plate + filling_color = "#F7EDD5" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake @@ -1997,6 +2269,7 @@ icon_state = "orangecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/orangecakeslice slices_num = 5 + filling_color = "#FADA8E" New() ..() reagents.add_reagent("nutriment", 20) @@ -2006,6 +2279,7 @@ desc = "Just a slice of cake, it is enough for everyone." icon_state = "orangecake_slice" trash = /obj/item/trash/plate + filling_color = "#FADA8E" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake @@ -2014,6 +2288,7 @@ icon_state = "limecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/limecakeslice slices_num = 5 + filling_color = "#CBFA8E" New() ..() reagents.add_reagent("nutriment", 20) @@ -2023,6 +2298,7 @@ desc = "Just a slice of cake, it is enough for everyone." icon_state = "limecake_slice" trash = /obj/item/trash/plate + filling_color = "#CBFA8E" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake @@ -2031,6 +2307,7 @@ icon_state = "lemoncake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice slices_num = 5 + filling_color = "#FAFA8E" New() ..() reagents.add_reagent("nutriment", 20) @@ -2040,6 +2317,7 @@ desc = "Just a slice of cake, it is enough for everyone." icon_state = "lemoncake_slice" trash = /obj/item/trash/plate + filling_color = "#FAFA8E" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake @@ -2048,6 +2326,7 @@ icon_state = "chocolatecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice slices_num = 5 + filling_color = "#805930" New() ..() reagents.add_reagent("nutriment", 20) @@ -2057,6 +2336,7 @@ desc = "Just a slice of cake, it is enough for everyone." icon_state = "chocolatecake_slice" trash = /obj/item/trash/plate + filling_color = "#805930" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel @@ -2065,6 +2345,7 @@ icon_state = "cheesewheel" slice_path = /obj/item/weapon/reagent_containers/food/snacks/cheesewedge slices_num = 5 + filling_color = "#FFF700" New() ..() reagents.add_reagent("nutriment", 20) @@ -2074,6 +2355,7 @@ name = "Cheese wedge" desc = "A wedge of delicious Cheddar. The cheese wheel it was cut from can't have gone far." icon_state = "cheesewedge" + filling_color = "#FFF700" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake @@ -2082,6 +2364,7 @@ icon_state = "birthdaycake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice slices_num = 5 + filling_color = "#FFD6D6" New() ..() reagents.add_reagent("nutriment", 20) @@ -2093,6 +2376,7 @@ desc = "A slice of your birthday" icon_state = "birthdaycakeslice" trash = /obj/item/trash/plate + filling_color = "#FFD6D6" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread @@ -2101,6 +2385,8 @@ icon_state = "bread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/breadslice slices_num = 5 + filling_color = "#FFE396" + New() ..() reagents.add_reagent("nutriment", 6) @@ -2111,6 +2397,7 @@ desc = "A slice of home." icon_state = "breadslice" trash = /obj/item/trash/plate + filling_color = "#D27332" bitesize = 2 @@ -2120,6 +2407,7 @@ icon_state = "creamcheesebread" slice_path = /obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice slices_num = 5 + filling_color = "#FFF896" New() ..() reagents.add_reagent("nutriment", 20) @@ -2130,6 +2418,7 @@ desc = "A slice of yum!" icon_state = "creamcheesebreadslice" trash = /obj/item/trash/plate + filling_color = "#FFF896" bitesize = 2 @@ -2137,6 +2426,7 @@ name = "Watermelon Slice" desc = "A slice of watery goodness." icon_state = "watermelonslice" + filling_color = "#FF3867" bitesize = 2 @@ -2146,6 +2436,7 @@ icon_state = "applecake" slice_path = /obj/item/weapon/reagent_containers/food/snacks/applecakeslice slices_num = 5 + filling_color = "#EBF5B8" New() ..() reagents.add_reagent("nutriment", 15) @@ -2155,6 +2446,7 @@ desc = "A slice of heavenly cake." icon_state = "applecakeslice" trash = /obj/item/trash/plate + filling_color = "#EBF5B8" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie @@ -2163,6 +2455,8 @@ icon_state = "pumpkinpie" slice_path = /obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice slices_num = 5 + filling_color = "#F5B951" + New() ..() reagents.add_reagent("nutriment", 15) @@ -2172,12 +2466,14 @@ desc = "A slice of pumpkin pie, with whipped cream on top. Perfection." icon_state = "pumpkinpieslice" trash = /obj/item/trash/plate + filling_color = "#F5B951" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/cracker name = "Cracker" desc = "It's a salted cracker." icon_state = "cracker" + filling_color = "#F5DEB8" New() ..() @@ -2189,6 +2485,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza slices_num = 6 + filling_color = "#BAA14C" /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita name = "Margherita" @@ -2206,6 +2503,7 @@ name = "Margherita slice" desc = "A slice of the most cheezy pizza in galaxy" icon_state = "pizzamargheritaslice" + filling_color = "#BAA14C" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza @@ -2224,6 +2522,7 @@ name = "Meatpizza slice" desc = "A slice of " //TODO: icon_state = "meatpizzaslice" + filling_color = "#BAA14C" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza @@ -2241,6 +2540,7 @@ name = "Mushroompizza slice" desc = "Maybe it is the last slice of pizza in your life." icon_state = "mushroompizzaslice" + filling_color = "#BAA14C" bitesize = 2 /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza @@ -2260,6 +2560,7 @@ name = "Vegetable pizza slice" desc = "A slice of the most green pizza of all pizzas not containing green ingredients " icon_state = "vegetablepizzaslice" + filling_color = "#BAA14C" bitesize = 2 /obj/item/pizzabox @@ -2437,3 +2738,16 @@ /obj/item/pizzabox/meat/New() pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza(src) boxtag = "Meatlover's Supreme" + +/obj/item/weapon/reagent_containers/food/snacks/dionaroast + name = "roast diona" + desc = "It's like an enormous, leathery carrot. With an eye." + icon_state = "dionaroast" + trash = /obj/item/trash/plate + filling_color = "#75754B" + + New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("radium", 2) + bitesize = 2 \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/snacks/grown.dm b/code/modules/reagents/reagent_containers/food/snacks/grown.dm index c47103e2821..b28ec8dbbf9 100644 --- a/code/modules/reagents/reagent_containers/food/snacks/grown.dm +++ b/code/modules/reagents/reagent_containers/food/snacks/grown.dm @@ -113,6 +113,7 @@ desc = "Needs some butter!" icon_state = "corn" potency = 40 + filling_color = "#FFEE00" trash = /obj/item/weapon/corncob New() @@ -126,6 +127,7 @@ name = "cherries" desc = "Great for toppings!" icon_state = "cherry" + filling_color = "#FF0000" gender = PLURAL New() ..() @@ -140,6 +142,7 @@ desc = "Long-used as a symbol of rest, peace, and death." icon_state = "poppy" potency = 30 + filling_color = "#CC6464" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -153,6 +156,7 @@ desc = "\"I'll sweeten thy sad grave: thou shalt not lack the flower that's like thy face, pale primrose, nor the azured hare-bell, like thy veins; no, nor the leaf of eglantine, whom not to slander, out-sweeten’d not thy breath.\"" icon_state = "harebell" potency = 1 + filling_color = "#D4B2C9" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -165,6 +169,7 @@ desc = "Boil 'em! Mash 'em! Stick 'em in a stew!" icon_state = "potato" potency = 25 + filling_color = "#E6E8DA" New() ..() reagents.add_reagent("nutriment", 1+round((potency / 10), 1)) @@ -189,6 +194,7 @@ name = "bunch of grapes" desc = "Nutritious!" icon_state = "grapes" + filling_color = "#A332AD" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -202,6 +208,7 @@ desc = "Nutritious!" icon_state = "greengrapes" potency = 25 + filling_color = "#A6FFA3" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -215,6 +222,7 @@ desc = "Ewwwwwwwwww. Cabbage." icon_state = "cabbage" potency = 25 + filling_color = "#A2B5A1" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -226,6 +234,7 @@ name = "bunch of berries" desc = "Nutritious!" icon_state = "berrypile" + filling_color = "#C2C9FF" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -237,18 +246,66 @@ name = "clump of plastellium" desc = "Hmm, needs some processing" icon_state = "plastellium" + filling_color = "#C4C4C4" New() ..() spawn(5) //So potency can be set in the proc that creates these crops 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 its native Ahdomai. Smells strongly like wax." + icon_state = "shand" + filling_color = "#70C470" + 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" + filling_color = "#70C470" + 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" desc = "Nutritious!" var/light_on = 1 var/brightness_on = 2 //luminosity when on + filling_color = "#D3FF9E" icon_state = "glowberrypile" New() ..() @@ -276,6 +333,7 @@ desc = "Fattening... Mmmmm... chucklate." icon_state = "cocoapod" potency = 50 + filling_color = "#9C8E54" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -289,6 +347,7 @@ desc = "Sickly sweet." icon_state = "sugarcane" potency = 50 + filling_color = "#C0C9AD" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -301,6 +360,7 @@ icon_state = "poisonberrypile" gender = PLURAL potency = 15 + filling_color = "#B422C7" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -315,6 +375,7 @@ icon_state = "deathberrypile" gender = PLURAL potency = 50 + filling_color = "#4E0957" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -329,6 +390,7 @@ desc = "This is a plant containing various healing chemicals." icon_state = "ambrosiavulgaris" potency = 10 + filling_color = "#125709" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -345,6 +407,7 @@ desc = "Eating this makes you feel immortal!" icon_state = "ambrosiadeus" potency = 10 + filling_color = "#229E11" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -361,6 +424,7 @@ desc = "It's a little piece of Eden." icon_state = "apple" potency = 15 + filling_color = "#DFE88B" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -374,6 +438,7 @@ desc = "It's a little piece of Eden." icon_state = "apple" potency = 15 + filling_color = "#B3BD5E" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -387,6 +452,7 @@ desc = "Emblazoned upon the apple is the word 'Kallisti'." icon_state = "goldapple" potency = 15 + filling_color = "#F5CB42" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -406,6 +472,7 @@ desc = "It's full of watery goodness." icon_state = "watermelon" potency = 10 + filling_color = "#FA2863" slice_path = /obj/item/weapon/reagent_containers/food/snacks/watermelonslice slices_num = 5 New() @@ -420,6 +487,7 @@ desc = "It's large and scary." icon_state = "pumpkin" potency = 10 + filling_color = "#FAB728" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -441,6 +509,7 @@ desc = "It's so sour, your face will twist." icon_state = "lime" potency = 20 + filling_color = "#28FA59" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -453,6 +522,7 @@ desc = "When life gives you lemons, be grateful they aren't limes." icon_state = "lemon" potency = 20 + filling_color = "#FAF328" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -465,6 +535,7 @@ desc = "It's an tangy fruit." icon_state = "orange" potency = 20 + filling_color = "#FAAD28" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -477,6 +548,7 @@ desc = "You can't beat white-beet." icon_state = "whitebeet" potency = 15 + filling_color = "#FFFCCC" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -491,6 +563,7 @@ icon = 'icons/obj/items.dmi' icon_state = "banana" item_state = "banana" + filling_color = "#FCF695" trash = /obj/item/weapon/bananapeel New() @@ -506,6 +579,7 @@ name = "chili" desc = "It's spicy! Wait... IT'S BURNING ME!!" icon_state = "chilipepper" + filling_color = "#FF0000" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -523,6 +597,7 @@ name = "eggplant" desc = "Maybe there's a chicken inside?" icon_state = "eggplant" + filling_color = "#550F5C" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -534,6 +609,7 @@ name = "soybeans" desc = "It's pretty bland, but oh the possibilities..." gender = PLURAL + filling_color = "#E6E8B7" icon_state = "soybeans" New() ..() @@ -546,6 +622,7 @@ name = "tomato" desc = "I say to-mah-to, you say tom-mae-to." icon_state = "tomato" + filling_color = "#FF0000" potency = 10 New() ..() @@ -566,6 +643,7 @@ desc = "I say to-mah-to, you say tom-mae-to... OH GOD IT'S EATING MY LEGS!!" icon_state = "killertomato" potency = 10 + filling_color = "#FF0000" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -595,6 +673,7 @@ desc = "So bloody...so...very...bloody....AHHHH!!!!" icon_state = "bloodtomato" potency = 10 + filling_color = "#FF0000" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -618,6 +697,7 @@ desc = "I say blue-mah-to, you say blue-mae-to." icon_state = "bluetomato" potency = 10 + filling_color = "#586CFC" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -627,7 +707,7 @@ throw_impact(atom/hit_atom) ..() - new/obj/effect/decal/cleanable/oil(src.loc) + new/obj/effect/decal/cleanable/blood/oil(src.loc) src.visible_message("The [src.name] has been squashed.","You hear a smack.") src.reagents.reaction(get_turf(hit_atom)) for(var/atom/A in get_turf(hit_atom)) @@ -653,6 +733,7 @@ desc = "Sigh... wheat... a-grain?" gender = PLURAL icon_state = "wheat" + filling_color = "#F7E186" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -665,6 +746,7 @@ desc = "Rice to see you." gender = PLURAL icon_state = "rice" + filling_color = "#FFF8DB" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -676,6 +758,7 @@ name = "kudzu pod" desc = "Pueraria Virallis: An invasive species with vines that rapidly creep and wrap around whatever they contact." icon_state = "kudzupod" + filling_color = "#59691B" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -689,6 +772,7 @@ desc = "It's a mutant strain of chili" icon_state = "icepepper" potency = 20 + filling_color = "#66CEED" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -707,6 +791,7 @@ desc = "It's good for the eyes!" icon_state = "carrot" potency = 10 + filling_color = "#FFC400" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -720,6 +805,7 @@ desc = "Ganoderma lucidum: A special fungus believed to help relieve stress." icon_state = "reishi" potency = 10 + filling_color = "#FF4800" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -740,6 +826,7 @@ desc = "Amanita Muscaria: Learn poisonous mushrooms by heart. Only pick mushrooms you know." icon_state = "amanita" potency = 10 + filling_color = "#FF0000" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -760,6 +847,7 @@ desc = "Amanita Virosa: Deadly poisonous basidiomycete fungus filled with alpha amatoxins." icon_state = "angel" potency = 35 + filling_color = "#FFDEDE" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -780,6 +868,7 @@ desc = "Psilocybe Semilanceata: Liberate yourself!" icon_state = "libertycap" potency = 15 + filling_color = "#F714BE" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -797,6 +886,7 @@ name = "plump-helmet" desc = "Plumus Hellmus: Plump, soft and s-so inviting~" icon_state = "plumphelmet" + filling_color = "#F714BE" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -808,6 +898,7 @@ name = "walking mushroom" desc = "Plumus Locomotus: The beginning of the great walk." icon_state = "walkingmushroom" + filling_color = "#FFBFEF" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -836,6 +927,7 @@ name = "chanterelle cluster" desc = "Cantharellus Cibarius: These jolly yellow little shrooms sure look tasty!" icon_state = "chanterelle" + filling_color = "#FFE991" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -847,6 +939,7 @@ name = "glowshroom cluster" desc = "Mycena Bregprox: This species of mushroom glows in the dark. Or does it?" icon_state = "glowshroom" + filling_color = "#DAFF91" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -944,6 +1037,7 @@ icon_state = "bluespacetomato" potency = 20 origin_tech = "bluespace=3" + filling_color = "#91F8FF" New() ..() spawn(5) //So potency can be set in the proc that creates these crops @@ -959,7 +1053,7 @@ var/list/turfs = new/list() var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread if(inner_teleport_radius < 1) //Wasn't potent enough, it just splats. - new/obj/effect/decal/cleanable/oil(src.loc) + new/obj/effect/decal/cleanable/blood/oil(src.loc) src.visible_message("The [src.name] has been squashed.","You hear a smack.") del(src) return @@ -996,7 +1090,7 @@ sleep(1) s.set_up(3, 1, A) s.start() - new/obj/effect/decal/cleanable/oil(src.loc) + new/obj/effect/decal/cleanable/blood/oil(src.loc) src.visible_message("The [src.name] has been squashed, causing a distortion in space-time.","You hear a splat and a crackle.") del(src) return diff --git a/code/modules/reagents/reagent_containers/food/snacks/meat.dm b/code/modules/reagents/reagent_containers/food/snacks/meat.dm index cc9af086000..5a4dacbf05c 100644 --- a/code/modules/reagents/reagent_containers/food/snacks/meat.dm +++ b/code/modules/reagents/reagent_containers/food/snacks/meat.dm @@ -3,6 +3,7 @@ desc = "A slab of meat" icon_state = "meat" health = 180 + filling_color = "#FF1C1C" New() ..() reagents.add_reagent("nutriment", 3) diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index ad68c27b67c..21384ffd59d 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -1,318 +1,338 @@ - -//////////////////////////////////////////////////////////////////////////////// -/// (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() || !flag) + 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/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 9279fbfb0e1..2f345463e85 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -89,7 +89,15 @@ user << "\red You are unable to locate any blood." return - var/datum/reagent/B = T.take_blood(src,amount) + var/datum/reagent/B + if(istype(T,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = T + if(H.species && H.species.flags & NO_BLOOD) + H.reagents.trans_to(src,amount) + else + B = T.take_blood(src,amount) + else + B = T.take_blood(src,amount) if (B) src.reagents.reagent_list += B 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/disposal.dm b/code/modules/recycling/disposal.dm index 94bb46e3545..04eff0de6ea 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -1325,7 +1325,7 @@ src.streak(dirs) -/obj/effect/decal/cleanable/robot_debris/gib/pipe_eject(var/direction) +/obj/effect/decal/cleanable/blood/gibs/robot/pipe_eject(var/direction) var/list/dirs if(direction) dirs = list( direction, turn(direction, -45), turn(direction, 45)) 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/designs.dm b/code/modules/research/designs.dm index ac144533166..bcd33b2a792 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -1340,6 +1340,64 @@ datum/design/nanopaste build_type = PROTOLATHE materials = list("$metal" = 7000, "$glass" = 7000) build_path = "/obj/item/stack/nanopaste" + +datum/design/implant_loyal + name = "loyalty implant" + desc = "Makes you loyal or such." + id = "implant_loyal" + req_tech = list("materials" = 2, "biotech" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 7000, "$glass" = 7000) + build_path = "/obj/item/weapon/implant/loyalty" + +datum/design/implant_chem + name = "chemical implant" + desc = "Injects things." + id = "implant_chem" + req_tech = list("materials" = 2, "biotech" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/implant/chem" + +datum/design/implant_free + name = "freedom implant" + desc = "Use this to escape from those evil Red Shirts." + id = "implant_free" + req_tech = list("syndicate" = 2, "biotech" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/implant/freedom" + +datum/design/chameleon + name = "Chameleon Jumpsuit" + desc = "It's a plain jumpsuit. It seems to have a small dial on the wrist." + id = "chameleon" + req_tech = list("syndicate" = 2) + build_type = PROTOLATHE + materials = list("$metal" = 500) + build_path = "/obj/item/clothing/under/chameleon" + + +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" + +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///////////////// ///////////////////////////////////////// @@ -1384,17 +1442,17 @@ datum/design/decloner materials = list("$gold" = 5000,"$uranium" = 10000, "mutagen" = 40) build_path = "/obj/item/weapon/gun/energy/decloner" locked = 1 -/* + datum/design/chemsprayer name = "Chem Sprayer" desc = "An advanced chem spraying device." id = "chemsprayer" - req_tech = list("combat" = 3, "materials" = 3, "engineering" = 3, "biotech" = 2) + req_tech = list("materials" = 3, "engineering" = 3, "biotech" = 2) build_type = PROTOLATHE materials = list("$metal" = 5000, "$glass" = 1000) reliability_base = 100 - build_path = "/obj/item/weapon/chemsprayer" -*/ + build_path = "/obj/item/weapon/reagent_containers/spray/chemsprayer" + datum/design/rapidsyringe name = "Rapid Syringe Gun" desc = "A gun that fires many syringes." @@ -1470,6 +1528,14 @@ datum/design/stunshell materials = list("$metal" = 4000) build_path = "/obj/item/ammo_casing/shotgun/stunshell" +datum/design/plasmapistol + name = "plasma pistol" + desc = "A specialized firearm designed to fire lethal bolts of toxins." + id = "ppistol" + req_tech = list("combat" = 5, "plasmatech" = 4) + build_type = PROTOLATHE + materials = list("$metal" = 5000, "$glass" = 1000, "$plasma" = 3000) + build_path = "/obj/item/weapon/gun/energy/toxgun" ///////////////////////////////////////// /////////////////Mining////////////////// ///////////////////////////////////////// @@ -1553,6 +1619,16 @@ datum/design/bag_holding reliability_base = 80 build_path = "/obj/item/weapon/storage/backpack/holding" +datum/design/bluespace_crystal + name = "Artificial Bluespace Crystal" + desc = "A small blue crystal with mystical properties." + id = "bluespace_crystal" + req_tech = list("bluespace" = 5, "materials" = 7) + build_type = PROTOLATHE + materials = list("$gold" = 1500, "$diamond" = 3000, "$plasma" = 1500) + reliability_base = 100 + build_path = "/obj/item/bluespace_crystal/artificial" + ///////////////////////////////////////// /////////////////HUDs//////////////////// ///////////////////////////////////////// @@ -1620,3 +1696,171 @@ datum/design/borg_syndicate_module req_tech = list("combat" = 4, "syndicate" = 3) build_path = "/obj/item/borg/upgrade/syndicate" category = "Cyborg Upgrade Modules" + +///////////////////////////////////////// +/////////////PDA and Radio stuff///////// +///////////////////////////////////////// +datum/design/binaryencrypt + name = "Binary Encrpytion Key" + desc = "An encyption key for a radio headset. Contains cypherkeys." + id = "binaryencrypt" + req_tech = list("syndicate" = 2) + build_type = PROTOLATHE + materials = list("$metal" = 300, "$glass" = 300) + build_path = "/obj/item/device/encryptionkey/binary" +datum/design/pda + name = "PDA" + desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." + id = "pda" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/device/pda" +datum/design/cart_basic + name = "Generic Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_basic" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge" +datum/design/cart_engineering + name = "Power-ON Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_engineering" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/engineering" +datum/design/cart_atmos + name = "BreatheDeep Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_atmos" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/atmos" +datum/design/cart_medical + name = "Med-U Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_medical" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/medical" +datum/design/cart_chemistry + name = "ChemWhiz Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_chemistry" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/chemistry" +datum/design/cart_security + name = "R.O.B.U.S.T. Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_security" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/security" + locked = 1 +datum/design/cart_janitor + name = "CustodiPRO Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_janitor" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/janitor" + +/* +datum/design/cart_clown + name = "Honkworks 5.0 Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_clown" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/clown" +datum/design/cart_mime + name = "Gestur-O 1000 Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_mime" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/mime" +*/ + +datum/design/cart_toxins + name = "Signal Ace 2 Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_toxins" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/toxins" +datum/design/cart_quartermaster + name = "Space Parts & Space Vendors Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_quartermaster" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/quartermaster" + locked = 1 +datum/design/cart_hop + name = "Human Resources 9001 Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_hop" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/hop" + locked = 1 +datum/design/cart_hos + name = "R.O.B.U.S.T. DELUXE Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_hos" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/hos" + locked = 1 +datum/design/cart_ce + name = "Power-On DELUXE Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_ce" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/ce" + locked = 1 +datum/design/cart_cmo + name = "Med-U DELUXE Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_cmo" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/cmo" + locked = 1 +datum/design/cart_rd + name = "Signal Ace DELUXE Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_rd" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/rd" + locked = 1 +datum/design/cart_captain + name = "Value-PAK Cartridge" + desc = "A data cartridge for portable microcomputers." + id = "cart_captain" + req_tech = list("engineering" = 2, "powerstorage" = 3) + build_type = PROTOLATHE + materials = list("$metal" = 50, "$glass" = 50) + build_path = "/obj/item/weapon/cartridge/captain" + locked = 1 diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm index 15aafd77e98..6f3c5378d0a 100644 --- a/code/modules/research/destructive_analyzer.dm +++ b/code/modules/research/destructive_analyzer.dm @@ -72,10 +72,10 @@ Note: Must be placed within 3 tiles of the R&D Console if (disabled) return if (!linked_console) - user << "\red The protolathe must be linked to an R&D console first!" + user << "\red The destructive analyzer must be linked to an R&D console first!" return if (busy) - user << "\red The protolathe is busy right now." + user << "\red The destructive analyzer is busy right now." return if (istype(O, /obj/item) && !loaded_item) if(isrobot(user)) //Don't put your module items in there! @@ -88,7 +88,7 @@ Note: Must be placed within 3 tiles of the R&D Console user << "\red You cannot deconstruct this item!" return if(O.reliability < 90 && O.crit_fail == 0) - usr << "\red Item is neither reliable enough or broken enough to learn from." + usr << "\red Item is neither reliable enough nor broken enough to learn from." return busy = 1 loaded_item = O diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 4cc18d6434c..103969bdd11 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -394,10 +394,10 @@ won't update every console in existence) but it's more of a hassle to do. Also, new_item.investigate_log("built by [key]","singulo") new_item.reliability = being_built.reliability if(linked_lathe.hacked) being_built.reliability = max((reliability / 2), 0) - if(being_built.locked) + /*if(being_built.locked) var/obj/item/weapon/storage/lockbox/L = new/obj/item/weapon/storage/lockbox(linked_lathe.loc) new_item.loc = L - L.name += " ([new_item.name])" + L.name += " ([new_item.name])"*/ else new_item.loc = linked_lathe.loc linked_lathe.busy = 0 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_gigadrill.dm b/code/modules/research/xenoarchaeology/artifact/artifact_gigadrill.dm index 9d52c9c2dc0..c9d14ce2379 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_gigadrill.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_gigadrill.dm @@ -29,7 +29,7 @@ anchored = 1 spawn(drill_time) if(get_turf(src) == drilling_turf && active) - M.gets_drilled() + M.GetDrilled() src.loc = M drilling_turf = null anchored = 0 diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm b/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm index 0030e31b21e..a0762ff51e3 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm @@ -114,6 +114,11 @@ var/list/valid_secondary_effect_types = list(\ #define TRIGGER_NITRO 12 /obj/machinery/artifact/process() + + var/turf/L = loc + if(isnull(L) || !istype(L)) // We're inside a container or on null turf, either way stop processing effects + return + if(my_effect) my_effect.process() if(secondary_effect) 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/chemistry.dm b/code/modules/research/xenoarchaeology/chemistry.dm index e4701247544..9e0e646234a 100644 --- a/code/modules/research/xenoarchaeology/chemistry.dm +++ b/code/modules/research/xenoarchaeology/chemistry.dm @@ -7,48 +7,42 @@ datum id = "tungsten" description = "A chemical element, and a strong oxidising agent." reagent_state = SOLID - color = "#808080" // rgb: 128, 128, 128 - //todo: make this silvery grey + color = "#DCDCDC" // rgb: 220, 220, 220, silver lithiumsodiumtungstate name = "Lithium Sodium Tungstate" id = "lithiumsodiumtungstate" description = "A reducing agent for geological compounds." reagent_state = LIQUID - color = "#808080" // rgb: 128, 128, 128 - //todo: make this silvery grey + color = "#C0C0C0" // rgb: 192, 192, 192, darker silver ground_rock name = "Ground Rock" id = "ground_rock" description = "A fine dust made of ground up rock." reagent_state = SOLID - color = "#C81040" //rgb: 200, 16, 64 - //todo: make this brown + color = "#A0522D" //rgb: 160, 82, 45, brown density_separated_sample name = "Density separated sample" id = "density_separated_sample" description = "A watery paste used in chemical analysis, there are some chunks floating in it." reagent_state = LIQUID - color = "#C81040" //rgb: 200, 16, 64 - //todo: make this browny-white + color = "#DEB887" //rgb: 222, 184, 135, light brown analysis_sample name = "Analysis liquid" id = "analysis_sample" description = "A watery paste used in chemical analysis." reagent_state = LIQUID - color = "#C81040" //rgb: 200, 16, 64 - //todo: make this white + color = "#F5FFFA" //rgb: 245, 255, 250, almost white chemical_waste name = "Chemical Waste" id = "chemical_waste" description = "A viscous, toxic liquid left over from many chemical processes." reagent_state = LIQUID - color = "#C81040" //rgb: 200, 16, 64 - //todo: make this fluoro/bright green + color = "#ADFF2F" //rgb: 173, 255, 47, toxic green datum chemical_reaction 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/finds/finds_talkingitem.dm b/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm index 46f78087e69..f5180300758 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_talkingitem.dm @@ -30,7 +30,7 @@ /*var/l = lentext(msg) if(findtext(msg," ",l,l+1)==0) msg+=" "*/ - seperate = stringsplit(msg, " ") + seperate = text2list(msg, " ") for(var/Xa = 1,Xa 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..eaf92181b23 --- /dev/null +++ b/code/modules/research/xenoarchaeology/machinery/geosample_scanner.dm @@ -0,0 +1,362 @@ + +/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 = "main", var/datum/nanoui/ui = null) + + 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 + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + 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) + // open the new ui window + ui.open() + // auto update every Master Controller tick + ui.set_auto_update(1) + +/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.geologic_data) + G = O.geologic_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 = {"