diff --git a/.gitignore b/.gitignore index 7daab15618..8a1fc47c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.rsc *.dmb *.lk +data/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..87eeb862d5 --- /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 5005fcd90f..77e1d829ff 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/README.md b/README.md index 2c1859126c..01fec91ca6 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ The more complicated and easier to update method is using git. You'll need to d This will take a while to download, but it provides an easier method for updating. +Once the repository is in place, run this command: +```bash +cd Baystation12 +git update-index --assume-unchanged baystation12.int +``` +Now git will ignore changes to the file baystation12.int. + ### INSTALLATION First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from [here](http://www.byond.com/). diff --git a/baystation12.dme b/baystation12.dme index b3c331e3a9..73fa788cc0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -16,7 +16,6 @@ #include "code\setup.dm" #include "code\stylesheet.dm" #include "code\world.dm" -#include "code\__HELPERS\bygex.dm" #include "code\__HELPERS\files.dm" #include "code\__HELPERS\game.dm" #include "code\__HELPERS\global_lists.dm" @@ -53,6 +52,7 @@ #include "code\ATMOSPHERICS\datum_pipe_network.dm" #include "code\ATMOSPHERICS\datum_pipeline.dm" #include "code\ATMOSPHERICS\he_pipes.dm" +#include "code\ATMOSPHERICS\mainspipe.dm" #include "code\ATMOSPHERICS\pipes.dm" #include "code\ATMOSPHERICS\components\portables_connector.dm" #include "code\ATMOSPHERICS\components\tvalve.dm" @@ -79,6 +79,7 @@ #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" @@ -184,8 +185,13 @@ #include "code\game\area\areas.dm" #include "code\game\area\Space Station 13 areas.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" @@ -320,6 +326,7 @@ #include "code\game\machinery\bots\bots.dm" #include "code\game\machinery\bots\cleanbot.dm" #include "code\game\machinery\bots\ed209bot.dm" +#include "code\game\machinery\bots\farmbot.dm" #include "code\game\machinery\bots\floorbot.dm" #include "code\game\machinery\bots\medbot.dm" #include "code\game\machinery\bots\mulebot.dm" @@ -372,11 +379,9 @@ #include "code\game\machinery\doors\shutters.dm" #include "code\game\machinery\doors\unpowered.dm" #include "code\game\machinery\doors\windowdoor.dm" -#include "code\game\machinery\embedded_controller\access_controller.dm" -#include "code\game\machinery\embedded_controller\airlock_controller.dm" +#include "code\game\machinery\embedded_controller\airlock_controllers.dm" +#include "code\game\machinery\embedded_controller\airlock_program.dm" #include "code\game\machinery\embedded_controller\embedded_controller_base.dm" -#include "code\game\machinery\embedded_controller\simple_vent_controller.dm" -#include "code\game\machinery\embedded_controller\smart_airlock_controller.dm" #include "code\game\machinery\kitchen\gibber.dm" #include "code\game\machinery\kitchen\juicer.dm" #include "code\game\machinery\kitchen\microwave.dm" @@ -423,6 +428,7 @@ #include "code\game\objects\closets\walllocker.dm" #include "code\game\objects\effects\aliens.dm" #include "code\game\objects\effects\bump_teleporter.dm" +#include "code\game\objects\effects\chemsmoke.dm" #include "code\game\objects\effects\effect_system.dm" #include "code\game\objects\effects\gibs.dm" #include "code\game\objects\effects\glowshroom.dm" @@ -445,6 +451,8 @@ #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\decals\posters\bs12.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" @@ -558,7 +566,9 @@ #include "code\game\objects\items\weapons\storage\briefcase.dm" #include "code\game\objects\items\weapons\storage\fancy.dm" #include "code\game\objects\items\weapons\storage\firstaid.dm" +#include "code\game\objects\items\weapons\storage\internal.dm" #include "code\game\objects\items\weapons\storage\lockbox.dm" +#include "code\game\objects\items\weapons\storage\misc.dm" #include "code\game\objects\items\weapons\storage\secure.dm" #include "code\game\objects\items\weapons\storage\storage.dm" #include "code\game\objects\items\weapons\storage\toolbox.dm" @@ -568,7 +578,6 @@ #include "code\game\objects\items\weapons\tanks\tank_types.dm" #include "code\game\objects\items\weapons\tanks\tanks.dm" #include "code\game\objects\random\random.dm" -#include "code\game\objects\storage\coat.dm" #include "code\game\objects\structures\barsign.dm" #include "code\game\objects\structures\bedsheet_bin.dm" #include "code\game\objects\structures\coathanger.dm" @@ -580,6 +589,7 @@ #include "code\game\objects\structures\flora.dm" #include "code\game\objects\structures\girders.dm" #include "code\game\objects\structures\grille.dm" +#include "code\game\objects\structures\inflatable.dm" #include "code\game\objects\structures\janicart.dm" #include "code\game\objects\structures\kitchen_spike.dm" #include "code\game\objects\structures\ladders.dm" @@ -618,6 +628,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" @@ -756,6 +767,7 @@ #include "code\modules\clothing\suits\jobs.dm" #include "code\modules\clothing\suits\labcoat.dm" #include "code\modules\clothing\suits\miscellaneous.dm" +#include "code\modules\clothing\suits\storage.dm" #include "code\modules\clothing\suits\utility.dm" #include "code\modules\clothing\suits\wiz_robe.dm" #include "code\modules\clothing\under\chameleon.dm" @@ -787,6 +799,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" @@ -836,6 +849,7 @@ #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" @@ -843,6 +857,7 @@ #include "code\modules\mob\abilities.dm" #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" +#include "code\modules\mob\hear_say.dm" #include "code\modules\mob\inventory.dm" #include "code\modules\mob\language.dm" #include "code\modules\mob\login.dm" @@ -990,6 +1005,12 @@ #include "code\modules\mob\living\silicon\robot\robot_modules.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" #include "code\modules\mob\living\silicon\robot\wires.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_console.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_items.dm" +#include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" #include "code\modules\mob\living\simple_animal\bees.dm" #include "code\modules\mob\living\simple_animal\borer.dm" #include "code\modules\mob\living\simple_animal\constructs.dm" @@ -1050,11 +1071,13 @@ #include "code\modules\organs\organ_internal.dm" #include "code\modules\organs\pain.dm" #include "code\modules\organs\wound.dm" +#include "code\modules\paperwork\carbonpaper.dm" #include "code\modules\paperwork\clipboard.dm" #include "code\modules\paperwork\filingcabinet.dm" #include "code\modules\paperwork\folders.dm" #include "code\modules\paperwork\handlabeler.dm" #include "code\modules\paperwork\paper.dm" +#include "code\modules\paperwork\paper_bundle.dm" #include "code\modules\paperwork\paperbin.dm" #include "code\modules\paperwork\pen.dm" #include "code\modules\paperwork\photocopier.dm" @@ -1100,6 +1123,7 @@ #include "code\modules\projectiles\targeting.dm" #include "code\modules\projectiles\ammunition\boxes.dm" #include "code\modules\projectiles\ammunition\bullets.dm" +#include "code\modules\projectiles\guns\alien.dm" #include "code\modules\projectiles\guns\energy.dm" #include "code\modules\projectiles\guns\projectile.dm" #include "code\modules\projectiles\guns\energy\laser.dm" @@ -1113,6 +1137,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" @@ -1143,8 +1168,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" @@ -1174,7 +1201,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" @@ -1248,21 +1274,19 @@ #include "code\modules\scripting\Scanner\Tokens.dm" #include "code\modules\security levels\keycard authentication.dm" #include "code\modules\security levels\security levels.dm" +#include "code\modules\supermatter\supermatter.dm" #include "code\modules\surgery\appendix.dm" #include "code\modules\surgery\bones.dm" #include "code\modules\surgery\braincore.dm" #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" @@ -1274,6 +1298,11 @@ #include "code\modules\virus2\helpers.dm" #include "code\modules\virus2\isolator.dm" #include "code\modules\virus2\items_devices.dm" +#include "code\TriDimension\controller.dm" +#include "code\TriDimension\Movement.dm" +#include "code\TriDimension\Pipes.dm" +#include "code\TriDimension\Structures.dm" +#include "code\TriDimension\Turfs.dm" #include "code\WorkInProgress\autopsy.dm" #include "code\WorkInProgress\buildmode.dm" #include "code\WorkInProgress\explosion_particles.dm" @@ -1313,24 +1342,29 @@ #include "code\WorkInProgress\Cael_Aislinn\Supermatter\LaserComputer.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\WorkInProgress\Wrongnumber\weldbackpack.dm" +#include "code\ZAS\_docs.dm" +#include "code\ZAS\_gas_mixture.dm" #include "code\ZAS\Airflow.dm" +#include "code\ZAS\Atom.dm" #include "code\ZAS\Connection.dm" +#include "code\ZAS\ConnectionGroup.dm" +#include "code\ZAS\ConnectionManager.dm" +#include "code\ZAS\Controller.dm" #include "code\ZAS\Debug.dm" -#include "code\ZAS\FEA_gas_mixture.dm" -#include "code\ZAS\FEA_system.dm" +#include "code\ZAS\Diagnostic.dm" #include "code\ZAS\Fire.dm" -#include "code\ZAS\Functions.dm" -#include "code\ZAS\Plasma.dm" +#include "code\ZAS\Phoron.dm" +#include "code\ZAS\Turf.dm" #include "code\ZAS\Variable Settings.dm" -#include "code\ZAS\ZAS_Turfs.dm" -#include "code\ZAS\ZAS_Zones.dm" +#include "code\ZAS\Zone.dm" #include "interface\interface.dm" #include "interface\skin.dmf" #include "maps\tgstation2.dmm" diff --git a/bygex.dll b/bygex.dll deleted file mode 100644 index e7bdd9f9a7..0000000000 Binary files a/bygex.dll and /dev/null differ diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm index f7de10c2a9..ac451871dc 100644 --- a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm @@ -154,8 +154,8 @@ if("power_toggle" in signal.data) on = !on - if("set_direction" in signal.data) - pump_direction = text2num(signal.data["set_direction"]) + if("direction" in signal.data) + pump_direction = text2num(signal.data["direction"]) if("checks" in signal.data) pressure_checks = text2num(signal.data["checks"]) diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index acc528e611..ef0f656781 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -5,8 +5,6 @@ obj/machinery/atmospherics/trinary/filter name = "Gas filter" - req_access = list(access_atmospherics) - var/on = 0 var/temp = null // -- TLE @@ -16,7 +14,7 @@ obj/machinery/atmospherics/trinary/filter /* Filter types: -1: Nothing - 0: Carbon Molecules: Plasma Toxin, Oxygen Agent B + 0: Phoron: Phoron, Oxygen Agent B 1: Oxygen: Oxygen ONLY 2: Nitrogen: Nitrogen ONLY 3: Carbon Dioxide: Carbon Dioxide ONLY @@ -86,8 +84,8 @@ Filter types: switch(filter_type) if(0) //removing hydrocarbons - filtered_out.toxins = removed.toxins - removed.toxins = 0 + filtered_out.phoron = removed.phoron + removed.phoron = 0 if(removed.trace_gases.len>0) for(var/datum/gas/trace_gas in removed.trace_gases) @@ -172,7 +170,7 @@ obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE var/current_filter_type switch(filter_type) if(0) - current_filter_type = "Carbon Molecules" + current_filter_type = "Phoron" if(1) current_filter_type = "Oxygen" if(2) @@ -190,7 +188,7 @@ obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE Power: [on?"On":"Off"]
Filtering: [current_filter_type]

Set Filter Type:

- Carbon Molecules
+ Phoron
Oxygen
Nitrogen
Carbon Dioxide
@@ -236,4 +234,45 @@ obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE */ return +obj/machinery/atmospherics/trinary/filter/m_filter + icon = 'icons/obj/atmospherics/m_filter.dmi' + icon_state = "intact_off" + dir = SOUTH + initialize_directions = SOUTH|NORTH|EAST + +obj/machinery/atmospherics/trinary/filter/m_filter/New() + ..() + switch(dir) + if(NORTH) + initialize_directions = WEST|NORTH|SOUTH + if(SOUTH) + initialize_directions = SOUTH|EAST|NORTH + if(EAST) + initialize_directions = EAST|WEST|NORTH + if(WEST) + initialize_directions = WEST|SOUTH|EAST + +obj/machinery/atmospherics/trinary/filter/m_filter/initialize() + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -180) + var/node2_connect = turn(dir, 90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 6d532286de..3b16042fca 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -5,8 +5,6 @@ obj/machinery/atmospherics/trinary/mixer name = "Gas mixer" - req_access = list(access_atmospherics) - var/on = 0 var/target_pressure = ONE_ATMOSPHERE @@ -162,3 +160,93 @@ obj/machinery/atmospherics/trinary/mixer src.update_icon() src.updateUsrDialog() return + +obj/machinery/atmospherics/trinary/mixer/t_mixer + icon = 'icons/obj/atmospherics/t_mixer.dmi' + icon_state = "intact_off" + + dir = SOUTH + initialize_directions = SOUTH|EAST|WEST + + //node 3 is the outlet, nodes 1 & 2 are intakes + +obj/machinery/atmospherics/trinary/mixer/t_mixer/New() + ..() + switch(dir) + if(NORTH) + initialize_directions = EAST|NORTH|WEST + if(SOUTH) + initialize_directions = SOUTH|WEST|EAST + if(EAST) + initialize_directions = EAST|NORTH|SOUTH + if(WEST) + initialize_directions = WEST|NORTH|SOUTH + +obj/machinery/atmospherics/trinary/mixer/t_mixer/initialize() + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -90) + var/node2_connect = turn(dir, 90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() + +obj/machinery/atmospherics/trinary/mixer/m_mixer + icon = 'icons/obj/atmospherics/m_mixer.dmi' + icon_state = "intact_off" + + dir = SOUTH + initialize_directions = SOUTH|NORTH|EAST + + //node 3 is the outlet, nodes 1 & 2 are intakes + +obj/machinery/atmospherics/trinary/mixer/m_mixer/New() + ..() + switch(dir) + if(NORTH) + initialize_directions = WEST|NORTH|SOUTH + if(SOUTH) + initialize_directions = SOUTH|EAST|NORTH + if(EAST) + initialize_directions = EAST|WEST|NORTH + if(WEST) + initialize_directions = WEST|SOUTH|EAST + +obj/machinery/atmospherics/trinary/mixer/m_mixer/initialize() + if(node1 && node2 && node3) return + + var/node1_connect = turn(dir, -180) + var/node2_connect = turn(dir, 90) + var/node3_connect = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + break + + update_icon() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm index 01438c32d9..2d3e9b67a8 100644 --- a/code/ATMOSPHERICS/components/unary/heat_source.dm +++ b/code/ATMOSPHERICS/components/unary/heat_source.dm @@ -26,7 +26,7 @@ process() ..() - if(!on) + if(!on || !network) return 0 var/air_heat_capacity = air_contents.heat_capacity() var/combined_heat_capacity = current_heat_capacity + air_heat_capacity diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index 4a633030c2..1550eb7ae9 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -100,7 +100,7 @@ if(pressure_checks&2) pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound)) - if(pressure_delta > 0) + if(pressure_delta > 0.5) if(air_contents.temperature > 0) var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION) @@ -118,7 +118,7 @@ if(pressure_checks&2) pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure())) - if(pressure_delta > 0) + if(pressure_delta > 0.5) if(environment.temperature > 0) var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION) @@ -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/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 4c386f44ec..3845b9ad61 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -70,7 +70,7 @@ "scrubbing" = scrubbing, "panic" = panic, "filter_co2" = scrub_CO2, - "filter_toxins" = scrub_Toxins, + "filter_phoron" = scrub_Toxins, "filter_n2o" = scrub_N2O, "sigtype" = "status" ) @@ -104,7 +104,7 @@ var/datum/gas_mixture/environment = loc.return_air() if(scrubbing) - if((environment.toxins>0) || (environment.carbon_dioxide>0) || (environment.trace_gases.len>0)) + if((environment.phoron>0.001) || (environment.carbon_dioxide>0.001) || (environment.trace_gases.len>0)) var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() //Take a gas sample @@ -116,8 +116,8 @@ var/datum/gas_mixture/filtered_out = new filtered_out.temperature = removed.temperature if(scrub_Toxins) - filtered_out.toxins = removed.toxins - removed.toxins = 0 + filtered_out.phoron = removed.phoron + removed.phoron = 0 if(scrub_CO2) filtered_out.carbon_dioxide = removed.carbon_dioxide removed.carbon_dioxide = 0 diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm index bff2d0ee5e..168e5521b6 100644 --- a/code/ATMOSPHERICS/datum_pipe_network.dm +++ b/code/ATMOSPHERICS/datum_pipe_network.dm @@ -54,8 +54,6 @@ datum/pipe_network for(var/datum/pipeline/line_member in giver.line_members) line_member.network = src - del(giver) - update_network_gases() return 1 @@ -82,7 +80,7 @@ datum/pipe_network air_transient.oxygen = 0 air_transient.nitrogen = 0 - air_transient.toxins = 0 + air_transient.phoron = 0 air_transient.carbon_dioxide = 0 @@ -96,7 +94,7 @@ datum/pipe_network air_transient.oxygen += gas.oxygen air_transient.nitrogen += gas.nitrogen - air_transient.toxins += gas.toxins + air_transient.phoron += gas.phoron air_transient.carbon_dioxide += gas.carbon_dioxide if(gas.trace_gases.len) @@ -124,7 +122,7 @@ datum/pipe_network for(var/datum/gas_mixture/gas in gases) gas.oxygen = air_transient.oxygen*gas.volume/air_transient.volume gas.nitrogen = air_transient.nitrogen*gas.volume/air_transient.volume - gas.toxins = air_transient.toxins*gas.volume/air_transient.volume + gas.phoron = air_transient.phoron*gas.volume/air_transient.volume gas.carbon_dioxide = air_transient.carbon_dioxide*gas.volume/air_transient.volume gas.temperature = air_transient.temperature @@ -151,7 +149,7 @@ proc/equalize_gases(datum/gas_mixture/list/gases) var/total_oxygen = 0 var/total_nitrogen = 0 - var/total_toxins = 0 + var/total_phoron = 0 var/total_carbon_dioxide = 0 var/list/total_trace_gases = list() @@ -164,7 +162,7 @@ proc/equalize_gases(datum/gas_mixture/list/gases) total_oxygen += gas.oxygen total_nitrogen += gas.nitrogen - total_toxins += gas.toxins + total_phoron += gas.phoron total_carbon_dioxide += gas.carbon_dioxide if(gas.trace_gases.len) @@ -188,7 +186,7 @@ proc/equalize_gases(datum/gas_mixture/list/gases) for(var/datum/gas_mixture/gas in gases) gas.oxygen = total_oxygen*gas.volume/total_volume gas.nitrogen = total_nitrogen*gas.volume/total_volume - gas.toxins = total_toxins*gas.volume/total_volume + gas.phoron = total_phoron*gas.volume/total_volume gas.carbon_dioxide = total_carbon_dioxide*gas.volume/total_volume gas.temperature = temperature diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index 5ade345e08..61d7a48d5f 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -39,7 +39,7 @@ datum/pipeline member.air_temporary.oxygen = air.oxygen*member.volume/air.volume member.air_temporary.nitrogen = air.nitrogen*member.volume/air.volume - member.air_temporary.toxins = air.toxins*member.volume/air.volume + member.air_temporary.phoron = air.phoron*member.volume/air.volume member.air_temporary.carbon_dioxide = air.carbon_dioxide*member.volume/air.volume member.air_temporary.temperature = air.temperature @@ -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/WorkInProgress/Tastyfish/mainspipe.dm b/code/ATMOSPHERICS/mainspipe.dm similarity index 99% rename from code/WorkInProgress/Tastyfish/mainspipe.dm rename to code/ATMOSPHERICS/mainspipe.dm index e2b3acde64..631f3530a2 100644 --- a/code/WorkInProgress/Tastyfish/mainspipe.dm +++ b/code/ATMOSPHERICS/mainspipe.dm @@ -36,8 +36,9 @@ obj/machinery/atmospherics/mains_pipe icon = 'icons/obj/atmospherics/mainspipe.dmi' layer = 2.4 //under wires with their 2.5 + force = 20 + var/volume = 0 - var/force = 20 var/alert_pressure = 80*ONE_ATMOSPHERE @@ -535,6 +536,8 @@ obj/machinery/atmospherics/mains_pipe/cap level = 2 icon_state = "cap" +//TODO: Get Mains valves working! +/* obj/machinery/atmospherics/mains_pipe/valve icon_state = "mvalve0" @@ -700,4 +703,5 @@ obj/machinery/atmospherics/mains_pipe/valve if(open) close() else - open() \ No newline at end of file + open() +*/ \ No newline at end of file diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 131eb8d8be..c1fa2b0e9e 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -12,1105 +12,49 @@ obj/machinery/atmospherics/pipe var/alert_pressure = 80*ONE_ATMOSPHERE //minimum pressure before check_pressure(...) should be called - proc/pipeline_expansion() - return null +obj/machinery/atmospherics/pipe/proc/pipeline_expansion() + return null - proc/check_pressure(pressure) - //Return 1 if parent should continue checking other pipes - //Return null if parent should stop checking other pipes. Recall: del(src) will by default return null +obj/machinery/atmospherics/pipe/proc/check_pressure(pressure) + //Return 1 if parent should continue checking other pipes + //Return null if parent should stop checking other pipes. Recall: del(src) will by default return null - return 1 + return 1 - return_air() - if(!parent) - parent = new /datum/pipeline() - parent.build_pipeline(src) +obj/machinery/atmospherics/pipe/return_air() + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) - return parent.air + return parent.air - build_network() - if(!parent) - parent = new /datum/pipeline() - parent.build_pipeline(src) +obj/machinery/atmospherics/pipe/build_network() + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) - return parent.return_network() + return parent.return_network() - network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) - if(!parent) - parent = new /datum/pipeline() - parent.build_pipeline(src) +obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference) + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) - return parent.network_expand(new_network, reference) + return parent.network_expand(new_network, reference) - return_network(obj/machinery/atmospherics/reference) - if(!parent) - parent = new /datum/pipeline() - parent.build_pipeline(src) +obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference) + if(!parent) + parent = new /datum/pipeline() + parent.build_pipeline(src) - return parent.return_network(reference) + return parent.return_network(reference) - Del() - del(parent) - if(air_temporary) - loc.assume_air(air_temporary) - - ..() - - simple - icon = 'icons/obj/pipes.dmi' - icon_state = "intact-f" - - name = "pipe" - desc = "A one meter section of regular pipe" - - volume = 70 - - dir = SOUTH - initialize_directions = SOUTH|NORTH - - var/obj/machinery/atmospherics/node1 - var/obj/machinery/atmospherics/node2 - - var/minimum_temperature_difference = 300 - var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No - - var/maximum_pressure = 70*ONE_ATMOSPHERE - var/fatigue_pressure = 55*ONE_ATMOSPHERE - alert_pressure = 55*ONE_ATMOSPHERE - - - level = 1 - - New() - ..() - switch(dir) - if(SOUTH || NORTH) - initialize_directions = SOUTH|NORTH - if(EAST || WEST) - initialize_directions = EAST|WEST - if(NORTHEAST) - initialize_directions = NORTH|EAST - if(NORTHWEST) - initialize_directions = NORTH|WEST - if(SOUTHEAST) - initialize_directions = SOUTH|EAST - if(SOUTHWEST) - initialize_directions = SOUTH|WEST - - - hide(var/i) - if(level == 1 && istype(loc, /turf/simulated)) - invisibility = i ? 101 : 0 - update_icon() - - process() - if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle - ..() - else - . = PROCESS_KILL - - /*if(!node1) - parent.mingle_with_turf(loc, volume) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - - else if(!node2) - parent.mingle_with_turf(loc, volume) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 - - - else if(parent) - var/environment_temperature = 0 - - if(istype(loc, /turf/simulated/)) - if(loc:blocks_air) - environment_temperature = loc:temperature - else - var/datum/gas_mixture/environment = loc.return_air() - environment_temperature = environment.temperature - - else - environment_temperature = loc:temperature - - var/datum/gas_mixture/pipe_air = return_air() - - if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) - parent.temperature_interact(loc, volume, thermal_conductivity) - */ //Screw you heat lag - - check_pressure(pressure) - var/datum/gas_mixture/environment = loc.return_air() - - var/pressure_difference = pressure - environment.return_pressure() - - if(pressure_difference > maximum_pressure) - burst() - - else if(pressure_difference > fatigue_pressure) - //TODO: leak to turf, doing pfshhhhh - if(prob(5)) - burst() - - else return 1 - - proc/burst() - src.visible_message("\red \bold [src] bursts!"); - playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) - var/datum/effect/effect/system/smoke_spread/smoke = new - smoke.set_up(1,0, src.loc, 0) - smoke.start() - del(src) - - proc/normalize_dir() - if(dir==3) - dir = 1 - else if(dir==12) - dir = 4 - - Del() - if(node1) - node1.disconnect(src) - if(node2) - node2.disconnect(src) - - ..() - - pipeline_expansion() - return list(node1, node2) - - update_icon() - if(node1&&node2) - var/C = "" - switch(pipe_color) - if ("red") C = "-r" - if ("blue") C = "-b" - if ("cyan") C = "-c" - if ("green") C = "-g" - if ("yellow") C = "-y" - if ("purple") C = "-p" - icon_state = "intact[C][invisibility ? "-f" : "" ]" - - //var/node1_direction = get_dir(src, node1) - //var/node2_direction = get_dir(src, node2) - - //dir = node1_direction|node2_direction - - else - if(!node1&&!node2) - del(src) //TODO: silent deleting looks weird - var/have_node1 = node1?1:0 - var/have_node2 = node2?1:0 - icon_state = "exposed[have_node1][have_node2][invisibility ? "-f" : "" ]" - - - initialize() - normalize_dir() - var/node1_dir - var/node2_dir - - for(var/direction in cardinal) - if(direction&initialize_directions) - if (!node1_dir) - node1_dir = direction - else if (!node2_dir) - node2_dir = direction - - for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) - if(target.initialize_directions & get_dir(target,src)) - node2 = target - break - - - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) - update_icon() - //update_icon() - - disconnect(obj/machinery/atmospherics/reference) - if(reference == node1) - if(istype(node1, /obj/machinery/atmospherics/pipe)) - del(parent) - node1 = null - - if(reference == node2) - if(istype(node2, /obj/machinery/atmospherics/pipe)) - del(parent) - node2 = null - - update_icon() - - return null - - simple/scrubbers - name="Scrubbers pipe" - pipe_color="red" - icon_state = "" - - simple/supply - name="Air supply pipe" - pipe_color="blue" - icon_state = "" - - simple/supplymain - name="Main air supply pipe" - pipe_color="purple" - icon_state = "" - - simple/general - name="Pipe" - pipe_color="" - icon_state = "" - - simple/scrubbers/visible - level = 2 - icon_state = "intact-r" - - simple/scrubbers/hidden - level = 1 - icon_state = "intact-r-f" - - simple/supply/visible - level = 2 - icon_state = "intact-b" - - simple/supply/hidden - level = 1 - icon_state = "intact-b-f" - - simple/supplymain/visible - level = 2 - icon_state = "intact-p" - - simple/supplymain/hidden - level = 1 - icon_state = "intact-p-f" - - simple/general/visible - level = 2 - icon_state = "intact" - - simple/general/hidden - level = 1 - icon_state = "intact-f" - - simple/yellow - name="Pipe" - pipe_color="yellow" - icon_state = "" - - simple/yellow/visible - level = 2 - icon_state = "intact-y" - - simple/yellow/hidden - level = 1 - icon_state = "intact-y-f" - - - - simple/insulated - icon = 'icons/obj/atmospherics/red_pipe.dmi' - icon_state = "intact" - - minimum_temperature_difference = 10000 - thermal_conductivity = 0 - maximum_pressure = 1000*ONE_ATMOSPHERE - fatigue_pressure = 900*ONE_ATMOSPHERE - alert_pressure = 900*ONE_ATMOSPHERE - - level = 2 - - - tank - icon = 'icons/obj/atmospherics/pipe_tank.dmi' - icon_state = "intact" - - name = "Pressure Tank" - desc = "A large vessel containing pressurized gas." - - volume = 2000 //in liters, 1 meters by 1 meters by 2 meters - - dir = SOUTH - initialize_directions = SOUTH - density = 1 - - var/obj/machinery/atmospherics/node1 - - New() - initialize_directions = dir - ..() - - process() - if(!parent) - ..() - else - . = PROCESS_KILL -/* if(!node1) - parent.mingle_with_turf(loc, 200) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ - carbon_dioxide - name = "Pressure Tank (Carbon Dioxide)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - - toxins - icon = 'icons/obj/atmospherics/orange_pipe_tank.dmi' - name = "Pressure Tank (Plasma)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.toxins = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - - oxygen_agent_b - icon = 'icons/obj/atmospherics/red_orange_pipe_tank.dmi' - name = "Pressure Tank (Oxygen + Plasma)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T0C - - var/datum/gas/oxygen_agent_b/trace_gas = new - trace_gas.moles = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - air_temporary.trace_gases += trace_gas - - ..() - - oxygen - icon = 'icons/obj/atmospherics/blue_pipe_tank.dmi' - name = "Pressure Tank (Oxygen)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.oxygen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - - nitrogen - icon = 'icons/obj/atmospherics/red_pipe_tank.dmi' - name = "Pressure Tank (Nitrogen)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.nitrogen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - - air - icon = 'icons/obj/atmospherics/red_pipe_tank.dmi' - name = "Pressure Tank (Air)" - - New() - air_temporary = new - air_temporary.volume = volume - air_temporary.temperature = T20C - - air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - ..() - - Del() - if(node1) - node1.disconnect(src) - - ..() - - pipeline_expansion() - return list(node1) - - update_icon() - if(node1) - icon_state = "intact" - - dir = get_dir(src, node1) - - else - icon_state = "exposed" - - initialize() - - var/connect_direction = dir - - for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - - update_icon() - - disconnect(obj/machinery/atmospherics/reference) - if(reference == node1) - if(istype(node1, /obj/machinery/atmospherics/pipe)) - del(parent) - node1 = null - - update_icon() - - return null - - attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (istype(W, /obj/item/device/analyzer) && get_dist(user, src) <= 1) - for (var/mob/O in viewers(user, null)) - O << "\red [user] has used the analyzer on \icon[icon]" - - var/pressure = parent.air.return_pressure() - var/total_moles = parent.air.total_moles() - - user << "\blue Results of analysis of \icon[icon]" - if (total_moles>0) - var/o2_concentration = parent.air.oxygen/total_moles - var/n2_concentration = parent.air.nitrogen/total_moles - var/co2_concentration = parent.air.carbon_dioxide/total_moles - var/plasma_concentration = parent.air.toxins/total_moles - - var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration) - - user << "\blue Pressure: [round(pressure,0.1)] kPa" - user << "\blue Nitrogen: [round(n2_concentration*100)]%" - user << "\blue Oxygen: [round(o2_concentration*100)]%" - user << "\blue CO2: [round(co2_concentration*100)]%" - user << "\blue Plasma: [round(plasma_concentration*100)]%" - if(unknown_concentration>0.01) - user << "\red Unknown: [round(unknown_concentration*100)]%" - user << "\blue Temperature: [round(parent.air.temperature-T0C)]°C" - else - user << "\blue Tank is empty!" - - vent - icon = 'icons/obj/atmospherics/pipe_vent.dmi' - icon_state = "intact" - - name = "Vent" - desc = "A large air vent" - - level = 1 - - volume = 250 - - dir = SOUTH - initialize_directions = SOUTH - - var/build_killswitch = 1 - - var/obj/machinery/atmospherics/node1 - New() - initialize_directions = dir - ..() - - high_volume - name = "Larger vent" - volume = 1000 - - process() - if(!parent) - if(build_killswitch <= 0) - . = PROCESS_KILL - else - build_killswitch-- - ..() - return - else - parent.mingle_with_turf(loc, volume) -/* - if(!node1) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ - Del() - if(node1) - node1.disconnect(src) - - ..() - - pipeline_expansion() - return list(node1) - - update_icon() - if(node1) - icon_state = "intact" - - dir = get_dir(src, node1) - - else - icon_state = "exposed" - - initialize() - var/connect_direction = dir - - for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - - update_icon() - - disconnect(obj/machinery/atmospherics/reference) - if(reference == node1) - if(istype(node1, /obj/machinery/atmospherics/pipe)) - del(parent) - node1 = null - - update_icon() - - return null - - hide(var/i) //to make the little pipe section invisible, the icon changes. - if(node1) - icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" - dir = get_dir(src, node1) - else - icon_state = "exposed" - - manifold - icon = 'icons/obj/atmospherics/pipe_manifold.dmi' - icon_state = "manifold-f" - - name = "pipe manifold" - desc = "A manifold composed of regular pipes" - - volume = 105 - - dir = SOUTH - initialize_directions = EAST|NORTH|WEST - - var/obj/machinery/atmospherics/node1 - var/obj/machinery/atmospherics/node2 - var/obj/machinery/atmospherics/node3 - - level = 1 - layer = 2.4 //under wires with their 2.44 - - New() - switch(dir) - if(NORTH) - initialize_directions = EAST|SOUTH|WEST - if(SOUTH) - initialize_directions = WEST|NORTH|EAST - if(EAST) - initialize_directions = SOUTH|WEST|NORTH - if(WEST) - initialize_directions = NORTH|EAST|SOUTH - - ..() - - - - hide(var/i) - if(level == 1 && istype(loc, /turf/simulated)) - invisibility = i ? 101 : 0 - update_icon() - - pipeline_expansion() - return list(node1, node2, node3) - - process() - if(!parent) - ..() - else - . = PROCESS_KILL -/* - if(!node1) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node2) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node3) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ - Del() - if(node1) - node1.disconnect(src) - if(node2) - node2.disconnect(src) - if(node3) - node3.disconnect(src) - - ..() - - disconnect(obj/machinery/atmospherics/reference) - if(reference == node1) - if(istype(node1, /obj/machinery/atmospherics/pipe)) - del(parent) - node1 = null - - if(reference == node2) - if(istype(node2, /obj/machinery/atmospherics/pipe)) - del(parent) - node2 = null - - if(reference == node3) - if(istype(node3, /obj/machinery/atmospherics/pipe)) - del(parent) - node3 = null - - update_icon() - - ..() - - update_icon() - if(node1&&node2&&node3) - var/C = "" - switch(pipe_color) - if ("red") C = "-r" - if ("blue") C = "-b" - if ("cyan") C = "-c" - if ("green") C = "-g" - if ("yellow") C = "-y" - if ("purple") C = "-p" - icon_state = "manifold[C][invisibility ? "-f" : ""]" - - else - var/connected = 0 - var/unconnected = 0 - var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) - - if(node1) - connected |= get_dir(src, node1) - if(node2) - connected |= get_dir(src, node2) - if(node3) - connected |= get_dir(src, node3) - - unconnected = (~connected)&(connect_directions) - - icon_state = "manifold_[connected]_[unconnected]" - - if(!connected) - del(src) - - return - - initialize() - var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) - - for(var/direction in cardinal) - if(direction&connect_directions) - for(var/obj/machinery/atmospherics/target in get_step(src,direction)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - connect_directions &= ~direction - break - if (node1) - break - - - for(var/direction in cardinal) - if(direction&connect_directions) - for(var/obj/machinery/atmospherics/target in get_step(src,direction)) - if(target.initialize_directions & get_dir(target,src)) - node2 = target - connect_directions &= ~direction - break - if (node2) - break - - - for(var/direction in cardinal) - if(direction&connect_directions) - for(var/obj/machinery/atmospherics/target in get_step(src,direction)) - if(target.initialize_directions & get_dir(target,src)) - node3 = target - connect_directions &= ~direction - break - if (node3) - break - - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) - //update_icon() - update_icon() - - manifold/scrubbers - name="Scrubbers pipe" - pipe_color="red" - icon_state = "" - - manifold/supply - name="Air supply pipe" - pipe_color="blue" - icon_state = "" - - manifold/supplymain - name="Main air supply pipe" - pipe_color="purple" - icon_state = "" - - manifold/general - name="Air supply pipe" - pipe_color="gray" - icon_state = "" - - manifold/yellow - name="Air supply pipe" - pipe_color="yellow" - icon_state = "" - - manifold/scrubbers/visible - level = 2 - icon_state = "manifold-r" - - manifold/scrubbers/hidden - level = 1 - icon_state = "manifold-r-f" - - manifold/supply/visible - level = 2 - icon_state = "manifold-b" - - manifold/supply/hidden - level = 1 - icon_state = "manifold-b-f" - - manifold/supplymain/visible - level = 2 - icon_state = "manifold-p" - - manifold/supplymain/hidden - level = 1 - icon_state = "manifold-p-f" - - manifold/general/visible - level = 2 - icon_state = "manifold" - - manifold/general/hidden - level = 1 - icon_state = "manifold-f" - - manifold/yellow/visible - level = 2 - icon_state = "manifold-y" - - manifold/yellow/hidden - level = 1 - icon_state = "manifold-y-f" - - manifold4w - icon = 'icons/obj/atmospherics/pipe_manifold.dmi' - icon_state = "manifold4w-f" - - name = "4-way pipe manifold" - desc = "A manifold composed of regular pipes" - - volume = 140 - - dir = SOUTH - initialize_directions = NORTH|SOUTH|EAST|WEST - - var/obj/machinery/atmospherics/node1 - var/obj/machinery/atmospherics/node2 - var/obj/machinery/atmospherics/node3 - var/obj/machinery/atmospherics/node4 - - level = 1 - layer = 2.4 //under wires with their 2.44 - - hide(var/i) - if(level == 1 && istype(loc, /turf/simulated)) - invisibility = i ? 101 : 0 - update_icon() - - pipeline_expansion() - return list(node1, node2, node3, node4) - - process() - if(!parent) - ..() - else - . = PROCESS_KILL -/* - if(!node1) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node2) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if(!node3) - parent.mingle_with_turf(loc, 70) - if(!nodealert) - //world << "Missing node from [src] at [src.x],[src.y],[src.z]" - nodealert = 1 - else if (nodealert) - nodealert = 0 -*/ - Del() - if(node1) - node1.disconnect(src) - if(node2) - node2.disconnect(src) - if(node3) - node3.disconnect(src) - if(node4) - node4.disconnect(src) - - ..() - - disconnect(obj/machinery/atmospherics/reference) - if(reference == node1) - if(istype(node1, /obj/machinery/atmospherics/pipe)) - del(parent) - node1 = null - - if(reference == node2) - if(istype(node2, /obj/machinery/atmospherics/pipe)) - del(parent) - node2 = null - - if(reference == node3) - if(istype(node3, /obj/machinery/atmospherics/pipe)) - del(parent) - node3 = null - - if(reference == node4) - if(istype(node4, /obj/machinery/atmospherics/pipe)) - del(parent) - node4 = null - - update_icon() - - ..() - - update_icon() - overlays.Cut() - if(node1&&node2&&node3&&node4) - var/C = "" - switch(pipe_color) - if ("red") C = "-r" - if ("blue") C = "-b" - if ("cyan") C = "-c" - if ("green") C = "-g" - if ("yellow") C = "-y" - if ("purple") C = "-p" - icon_state = "manifold4w[C][invisibility ? "-f" : ""]" - - else - icon_state = "manifold4w_ex" - var/icon/con = new/icon('icons/obj/atmospherics/pipe_manifold.dmi',"manifold4w_con") //Since 4-ways are supposed to be directionless, they need an overlay instead it seems. - - if(node1) - overlays += new/image(con,dir=1) - if(node2) - overlays += new/image(con,dir=2) - if(node3) - overlays += new/image(con,dir=4) - if(node4) - overlays += new/image(con,dir=8) - - if(!node1 && !node2 && !node3 && !node4) - del(src) - return - - initialize() - - for(var/obj/machinery/atmospherics/target in get_step(src,1)) - if(target.initialize_directions & 2) - node1 = target - break - - for(var/obj/machinery/atmospherics/target in get_step(src,2)) - if(target.initialize_directions & 1) - node2 = target - break - - for(var/obj/machinery/atmospherics/target in get_step(src,4)) - if(target.initialize_directions & 8) - node3 = target - break - - for(var/obj/machinery/atmospherics/target in get_step(src,8)) - if(target.initialize_directions & 4) - node4 = target - break - - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) - //update_icon() - update_icon() - - manifold4w/scrubbers - name="Scrubbers pipe" - pipe_color="red" - icon_state = "" - - manifold4w/supply - name="Air supply pipe" - pipe_color="blue" - icon_state = "" - - manifold4w/supplymain - name="Main air supply pipe" - pipe_color="purple" - icon_state = "" - - manifold4w/general - name="Air supply pipe" - pipe_color="gray" - icon_state = "" - - manifold4w/scrubbers/visible - level = 2 - icon_state = "manifold4w-r" - - manifold4w/scrubbers/hidden - level = 1 - icon_state = "manifold4w-r-f" - - manifold4w/supply/visible - level = 2 - icon_state = "manifold4w-b" - - manifold4w/supply/hidden - level = 1 - icon_state = "manifold4w-b-f" - - manifold4w/supplymain/visible - level = 2 - icon_state = "manifold4w-p" - - manifold4w/supplymain/hidden - level = 1 - icon_state = "manifold4w-p-f" - - manifold4w/general/visible - level = 2 - icon_state = "manifold4w" - - manifold4w/general/hidden - level = 1 - icon_state = "manifold4w-f" - - cap - name = "pipe endcap" - desc = "An endcap for pipes" - icon = 'icons/obj/pipes.dmi' - icon_state = "cap" - level = 2 - layer = 2.4 //under wires with their 2.44 - - volume = 35 - - dir = SOUTH - initialize_directions = NORTH - - var/obj/machinery/atmospherics/node - - New() - ..() - switch(dir) - if(SOUTH) - initialize_directions = NORTH - if(NORTH) - initialize_directions = SOUTH - if(WEST) - initialize_directions = EAST - if(EAST) - initialize_directions = WEST - - hide(var/i) - if(level == 1 && istype(loc, /turf/simulated)) - invisibility = i ? 101 : 0 - update_icon() - - pipeline_expansion() - return list(node) - - process() - if(!parent) - ..() - else - . = PROCESS_KILL - Del() - if(node) - node.disconnect(src) - - ..() - - disconnect(obj/machinery/atmospherics/reference) - if(reference == node) - if(istype(node, /obj/machinery/atmospherics/pipe)) - del(parent) - node = null - - update_icon() - - ..() - - update_icon() - overlays = new() - - icon_state = "cap[invisibility ? "-f" : ""]" - return - - initialize() - for(var/obj/machinery/atmospherics/target in get_step(src, dir)) - if(target.initialize_directions & get_dir(target,src)) - node = target - break - - var/turf/T = src.loc // hide if turf is not intact - hide(T.intact) - //update_icon() - update_icon() - - visible - level = 2 - icon_state = "cap" - - hidden - level = 1 - icon_state = "cap-f" +obj/machinery/atmospherics/pipe/Del() + del(parent) + if(air_temporary) + loc.assume_air(air_temporary) + ..() obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) if (istype(src, /obj/machinery/atmospherics/pipe/tank)) @@ -1119,7 +63,7 @@ obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/u return ..() if(istype(W,/obj/item/device/pipe_painter)) - return 1 + return 0 if (!istype(W, /obj/item/weapon/wrench)) return ..() @@ -1130,7 +74,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) @@ -1146,3 +90,1021 @@ obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/u new /obj/item/pipe_meter(T) del(meter) del(src) + + +obj/machinery/atmospherics/pipe/simple + icon = 'icons/obj/pipes.dmi' + + name = "pipe" + desc = "A one meter section of regular pipe" + + volume = 70 + + dir = SOUTH + initialize_directions = SOUTH|NORTH + + var/obj/machinery/atmospherics/node1 + var/obj/machinery/atmospherics/node2 + + var/minimum_temperature_difference = 300 + var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No + + var/maximum_pressure = 70*ONE_ATMOSPHERE + var/fatigue_pressure = 55*ONE_ATMOSPHERE + alert_pressure = 55*ONE_ATMOSPHERE + + + level = 1 + +obj/machinery/atmospherics/pipe/simple/New() + ..() + alpha = 255 + switch(dir) + if(SOUTH || NORTH) + initialize_directions = SOUTH|NORTH + if(EAST || WEST) + initialize_directions = EAST|WEST + if(NORTHEAST) + initialize_directions = NORTH|EAST + if(NORTHWEST) + initialize_directions = NORTH|WEST + if(SOUTHEAST) + initialize_directions = SOUTH|EAST + if(SOUTHWEST) + initialize_directions = SOUTH|WEST + + +obj/machinery/atmospherics/pipe/simple/hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + invisibility = i ? 101 : 0 + update_icon() + +obj/machinery/atmospherics/pipe/simple/process() + if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle + ..() + else + . = PROCESS_KILL + + /*if(!node1) + parent.mingle_with_turf(loc, volume) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + + else if(!node2) + parent.mingle_with_turf(loc, volume) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if (nodealert) + nodealert = 0 + + + else if(parent) + var/environment_temperature = 0 + + if(istype(loc, /turf/simulated/)) + if(loc:blocks_air) + environment_temperature = loc:temperature + else + var/datum/gas_mixture/environment = loc.return_air() + environment_temperature = environment.temperature + + else + environment_temperature = loc:temperature + + var/datum/gas_mixture/pipe_air = return_air() + + if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) + parent.temperature_interact(loc, volume, thermal_conductivity) + */ //Screw you heat lag + +obj/machinery/atmospherics/pipe/simple/check_pressure(pressure) + var/datum/gas_mixture/environment = loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > maximum_pressure) + burst() + + else if(pressure_difference > fatigue_pressure) + //TODO: leak to turf, doing pfshhhhh + if(prob(5)) + burst() + + else return 1 + +obj/machinery/atmospherics/pipe/simple/proc/burst() + src.visible_message("\red \bold [src] bursts!"); + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + var/datum/effect/effect/system/smoke_spread/smoke = new + smoke.set_up(1,0, src.loc, 0) + smoke.start() + del(src) + +obj/machinery/atmospherics/pipe/simple/proc/normalize_dir() + if(dir==3) + dir = 1 + else if(dir==12) + dir = 4 + +obj/machinery/atmospherics/pipe/simple/Del() + if(node1) + node1.disconnect(src) + if(node2) + node2.disconnect(src) + + ..() + +obj/machinery/atmospherics/pipe/simple/pipeline_expansion() + return list(node1, node2) + +obj/machinery/atmospherics/pipe/simple/update_icon() + if(node1&&node2) + switch(pipe_color) + if ("red") color = COLOR_RED + if ("blue") color = COLOR_BLUE + if ("cyan") color = COLOR_CYAN + if ("green") color = COLOR_GREEN + if ("yellow") color = "#FFCC00" + if ("purple") color = "#5C1EC0" + if ("grey") color = null + icon_state = "intact[invisibility ? "-f" : "" ]" + + //var/node1_direction = get_dir(src, node1) + //var/node2_direction = get_dir(src, node2) + + //dir = node1_direction|node2_direction + + else + if(!node1&&!node2) + del(src) //TODO: silent deleting looks weird + var/have_node1 = node1?1:0 + var/have_node2 = node2?1:0 + icon_state = "exposed[have_node1][have_node2][invisibility ? "-f" : "" ]" + + +obj/machinery/atmospherics/pipe/simple/initialize() + normalize_dir() + var/node1_dir + var/node2_dir + + for(var/direction in cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + break + + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + update_icon() + //update_icon() + +obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + del(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + del(parent) + node2 = null + + update_icon() + + return null + + + + +obj/machinery/atmospherics/pipe/simple/visible + level = 2 + icon_state = "intact" + +obj/machinery/atmospherics/pipe/simple/visible/scrubbers + name="Scrubbers pipe" + color=COLOR_RED + +obj/machinery/atmospherics/pipe/simple/visible/supply + name="Air supply pipe" + color=COLOR_BLUE + +obj/machinery/atmospherics/pipe/simple/visible/yellow + color="#FFCC00" + +obj/machinery/atmospherics/pipe/simple/visible/cyan + color=COLOR_CYAN + +obj/machinery/atmospherics/pipe/simple/visible/green + color=COLOR_GREEN + + +obj/machinery/atmospherics/pipe/simple/hidden + level = 1 + icon_state = "intact-f" + alpha = 192 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + +obj/machinery/atmospherics/pipe/simple/hidden/scrubbers + name="Scrubbers pipe" + color=COLOR_RED + +obj/machinery/atmospherics/pipe/simple/hidden/supply + name="Air supply pipe" + color=COLOR_BLUE + +obj/machinery/atmospherics/pipe/simple/hidden/yellow + color="#FFCC00" + +obj/machinery/atmospherics/pipe/simple/hidden/cyan + color=COLOR_CYAN + +obj/machinery/atmospherics/pipe/simple/hidden/green + color=COLOR_GREEN + + +obj/machinery/atmospherics/pipe/simple/insulated + icon = 'icons/obj/atmospherics/red_pipe.dmi' + icon_state = "intact" + + minimum_temperature_difference = 10000 + thermal_conductivity = 0 + maximum_pressure = 1000*ONE_ATMOSPHERE + fatigue_pressure = 900*ONE_ATMOSPHERE + alert_pressure = 900*ONE_ATMOSPHERE + + level = 2 + + +obj/machinery/atmospherics/pipe/manifold + icon = 'icons/obj/atmospherics/pipe_manifold.dmi' + + name = "pipe manifold" + desc = "A manifold composed of regular pipes" + + volume = 105 + + dir = SOUTH + initialize_directions = EAST|NORTH|WEST + + var/obj/machinery/atmospherics/node1 + var/obj/machinery/atmospherics/node2 + var/obj/machinery/atmospherics/node3 + + level = 1 + layer = 2.4 //under wires with their 2.44 + +obj/machinery/atmospherics/pipe/manifold/New() + alpha = 255 + switch(dir) + if(NORTH) + initialize_directions = EAST|SOUTH|WEST + if(SOUTH) + initialize_directions = WEST|NORTH|EAST + if(EAST) + initialize_directions = SOUTH|WEST|NORTH + if(WEST) + initialize_directions = NORTH|EAST|SOUTH + + ..() + + + +obj/machinery/atmospherics/pipe/manifold/hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + invisibility = i ? 101 : 0 + update_icon() + +obj/machinery/atmospherics/pipe/manifold/pipeline_expansion() + return list(node1, node2, node3) + +obj/machinery/atmospherics/pipe/manifold/process() + if(!parent) + ..() + else + . = PROCESS_KILL +/* + if(!node1) + parent.mingle_with_turf(loc, 70) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if(!node2) + parent.mingle_with_turf(loc, 70) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if(!node3) + parent.mingle_with_turf(loc, 70) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if (nodealert) + nodealert = 0 +*/ +obj/machinery/atmospherics/pipe/manifold/Del() + if(node1) + node1.disconnect(src) + if(node2) + node2.disconnect(src) + if(node3) + node3.disconnect(src) + + ..() + +obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + del(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + del(parent) + node2 = null + + if(reference == node3) + if(istype(node3, /obj/machinery/atmospherics/pipe)) + del(parent) + node3 = null + + update_icon() + + ..() + +obj/machinery/atmospherics/pipe/manifold/update_icon() + if(node1&&node2&&node3) + switch(pipe_color) + if ("red") color = COLOR_RED + if ("blue") color = COLOR_BLUE + if ("cyan") color = COLOR_CYAN + if ("green") color = COLOR_GREEN + if ("yellow") color = "#FFCC00" + if ("purple") color = "#5C1EC0" + if ("grey") color = null + icon_state = "manifold[invisibility ? "-f" : "" ]" + + else + var/connected = 0 + var/unconnected = 0 + var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) + + if(node1) + connected |= get_dir(src, node1) + if(node2) + connected |= get_dir(src, node2) + if(node3) + connected |= get_dir(src, node3) + + unconnected = (~connected)&(connect_directions) + + icon_state = "manifold_[connected]_[unconnected]" + + if(!connected) + del(src) + + return + +obj/machinery/atmospherics/pipe/manifold/initialize() + var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir) + + for(var/direction in cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + connect_directions &= ~direction + break + if (node1) + break + + + for(var/direction in cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + node2 = target + connect_directions &= ~direction + break + if (node2) + break + + + for(var/direction in cardinal) + if(direction&connect_directions) + for(var/obj/machinery/atmospherics/target in get_step(src,direction)) + if(target.initialize_directions & get_dir(target,src)) + node3 = target + connect_directions &= ~direction + break + if (node3) + break + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + //update_icon() + update_icon() + + +obj/machinery/atmospherics/pipe/manifold/visible + level = 2 + icon_state = "manifold" + +obj/machinery/atmospherics/pipe/manifold/visible/supply + name="Air supply pipe" + color=COLOR_BLUE + +obj/machinery/atmospherics/pipe/manifold/visible/scrubbers + name="Scrubbers pipe" + color=COLOR_RED + +obj/machinery/atmospherics/pipe/manifold/visible/yellow + color="#FFCC00" + +obj/machinery/atmospherics/pipe/manifold/visible/cyan + color=COLOR_CYAN + +obj/machinery/atmospherics/pipe/manifold/visible/green + color=COLOR_GREEN + + +obj/machinery/atmospherics/pipe/manifold/hidden + level = 1 + icon_state = "manifold-f" + alpha = 192 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + +obj/machinery/atmospherics/pipe/manifold/hidden/supply + name="Air supply pipe" + color=COLOR_BLUE + +obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers + name="Scrubbers pipe" + color = COLOR_RED + +obj/machinery/atmospherics/pipe/manifold/hidden/yellow + color="#FFCC00" + +obj/machinery/atmospherics/pipe/manifold/hidden/cyan + color=COLOR_CYAN + +obj/machinery/atmospherics/pipe/manifold/hidden/green + color=COLOR_GREEN + + + +obj/machinery/atmospherics/pipe/manifold4w + icon = 'icons/obj/atmospherics/pipe_manifold.dmi' + + name = "4-way pipe manifold" + desc = "A manifold composed of regular pipes" + + volume = 140 + + dir = SOUTH + initialize_directions = NORTH|SOUTH|EAST|WEST + + var/obj/machinery/atmospherics/node1 + var/obj/machinery/atmospherics/node2 + var/obj/machinery/atmospherics/node3 + var/obj/machinery/atmospherics/node4 + + level = 1 + layer = 2.4 //under wires with their 2.44 + +obj/machinery/atmospherics/pipe/manifold4w/New() + ..() + alpha = 255 + +obj/machinery/atmospherics/pipe/manifold4w/hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + invisibility = i ? 101 : 0 + update_icon() + +obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion() + return list(node1, node2, node3, node4) + +obj/machinery/atmospherics/pipe/manifold4w/process() + if(!parent) + ..() + else + . = PROCESS_KILL +/* + if(!node1) + parent.mingle_with_turf(loc, 70) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if(!node2) + parent.mingle_with_turf(loc, 70) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if(!node3) + parent.mingle_with_turf(loc, 70) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if (nodealert) + nodealert = 0 +*/ +obj/machinery/atmospherics/pipe/manifold4w/Del() + if(node1) + node1.disconnect(src) + if(node2) + node2.disconnect(src) + if(node3) + node3.disconnect(src) + if(node4) + node4.disconnect(src) + + ..() + +obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + del(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + del(parent) + node2 = null + + if(reference == node3) + if(istype(node3, /obj/machinery/atmospherics/pipe)) + del(parent) + node3 = null + + if(reference == node4) + if(istype(node4, /obj/machinery/atmospherics/pipe)) + del(parent) + node4 = null + + update_icon() + + ..() + +obj/machinery/atmospherics/pipe/manifold4w/update_icon() + overlays.Cut() + if(node1&&node2&&node3&&node4) + switch(pipe_color) + if ("red") color = COLOR_RED + if ("blue") color = COLOR_BLUE + if ("cyan") color = COLOR_CYAN + if ("green") color = COLOR_GREEN + if ("yellow") color = "#FFCC00" + if ("purple") color = "#5C1EC0" + if ("grey") color = null + icon_state = "manifold4w[invisibility ? "-f" : "" ]" + + else + icon_state = "manifold4w_ex" + var/icon/con = new/icon('icons/obj/atmospherics/pipe_manifold.dmi',"manifold4w_con") //Since 4-ways are supposed to be directionless, they need an overlay instead it seems. + + if(node1) + overlays += new/image(con,dir=1) + if(node2) + overlays += new/image(con,dir=2) + if(node3) + overlays += new/image(con,dir=4) + if(node4) + overlays += new/image(con,dir=8) + + if(!node1 && !node2 && !node3 && !node4) + del(src) + return + +obj/machinery/atmospherics/pipe/manifold4w/initialize() + + for(var/obj/machinery/atmospherics/target in get_step(src,1)) + if(target.initialize_directions & 2) + node1 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,2)) + if(target.initialize_directions & 1) + node2 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,4)) + if(target.initialize_directions & 8) + node3 = target + break + + for(var/obj/machinery/atmospherics/target in get_step(src,8)) + if(target.initialize_directions & 4) + node4 = target + break + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + //update_icon() + update_icon() + + +obj/machinery/atmospherics/pipe/manifold4w/visible + level = 2 + icon_state = "manifold4w" + +obj/machinery/atmospherics/pipe/manifold4w/visible/supply + name="Air supply pipe" + color=COLOR_BLUE + +obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers + name="Scrubbers pipe" + color=COLOR_RED + +obj/machinery/atmospherics/pipe/manifold4w/visible/yellow + color="#FFCC00" + +obj/machinery/atmospherics/pipe/manifold4w/visible/cyan + color=COLOR_CYAN + +obj/machinery/atmospherics/pipe/manifold4w/visible/green + color=COLOR_GREEN + + +obj/machinery/atmospherics/pipe/manifold4w/hidden + level = 1 + icon_state = "manifold4w-f" + alpha = 192 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game + +obj/machinery/atmospherics/pipe/manifold4w/hidden/supply + name="Air supply pipe" + color=COLOR_BLUE + +obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers + name="Scrubbers pipe" + color=COLOR_RED + +obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow + color="#FFCC00" + +obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan + color=COLOR_CYAN + +obj/machinery/atmospherics/pipe/manifold4w/hidden/green + color=COLOR_GREEN + + +obj/machinery/atmospherics/pipe/cap + name = "pipe endcap" + desc = "An endcap for pipes" + icon = 'icons/obj/pipes.dmi' + icon_state = "cap" + level = 2 + layer = 2.4 //under wires with their 2.44 + + volume = 35 + + dir = SOUTH + initialize_directions = NORTH + + var/obj/machinery/atmospherics/node + +obj/machinery/atmospherics/pipe/cap/New() + ..() + switch(dir) + if(SOUTH) + initialize_directions = NORTH + if(NORTH) + initialize_directions = SOUTH + if(WEST) + initialize_directions = EAST + if(EAST) + initialize_directions = WEST + +obj/machinery/atmospherics/pipe/cap/hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + invisibility = i ? 101 : 0 + update_icon() + +obj/machinery/atmospherics/pipe/cap/pipeline_expansion() + return list(node) + +obj/machinery/atmospherics/pipe/cap/process() + if(!parent) + ..() + else + . = PROCESS_KILL +obj/machinery/atmospherics/pipe/cap/Del() + if(node) + node.disconnect(src) + + ..() + +obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference) + if(reference == node) + if(istype(node, /obj/machinery/atmospherics/pipe)) + del(parent) + node = null + + update_icon() + + ..() + +obj/machinery/atmospherics/pipe/cap/update_icon() + overlays = new() + + icon_state = "cap[invisibility ? "-f" : ""]" + return + +obj/machinery/atmospherics/pipe/cap/initialize() + for(var/obj/machinery/atmospherics/target in get_step(src, dir)) + if(target.initialize_directions & get_dir(target,src)) + node = target + break + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + //update_icon() + update_icon() + +obj/machinery/atmospherics/pipe/cap/visible + level = 2 + icon_state = "cap" + +obj/machinery/atmospherics/pipe/cap/hidden + level = 1 + icon_state = "cap-f" + + +obj/machinery/atmospherics/pipe/tank + icon = 'icons/obj/atmospherics/pipe_tank.dmi' + icon_state = "intact" + + name = "Pressure Tank" + desc = "A large vessel containing pressurized gas." + + volume = 2000 //in liters, 1 meters by 1 meters by 2 meters + + dir = SOUTH + initialize_directions = SOUTH + density = 1 + + var/obj/machinery/atmospherics/node1 + +obj/machinery/atmospherics/pipe/tank/New() + initialize_directions = dir + ..() + +obj/machinery/atmospherics/pipe/tank/process() + if(!parent) + ..() + else + . = PROCESS_KILL +/* if(!node1) + parent.mingle_with_turf(loc, 200) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if (nodealert) + nodealert = 0 +*/ +obj/machinery/atmospherics/pipe/tank/carbon_dioxide + name = "Pressure Tank (Carbon Dioxide)" + + New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + +obj/machinery/atmospherics/pipe/tank/phoron + icon = 'icons/obj/atmospherics/orange_pipe_tank.dmi' + name = "Pressure Tank (Phoron)" + + New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.phoron = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + +obj/machinery/atmospherics/pipe/tank/oxygen_agent_b + icon = 'icons/obj/atmospherics/red_orange_pipe_tank.dmi' + name = "Pressure Tank (Oxygen + Phoron)" + + New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T0C + + var/datum/gas/oxygen_agent_b/trace_gas = new + trace_gas.moles = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + air_temporary.trace_gases += trace_gas + + ..() + +obj/machinery/atmospherics/pipe/tank/oxygen + icon = 'icons/obj/atmospherics/blue_pipe_tank.dmi' + name = "Pressure Tank (Oxygen)" + + New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.oxygen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + +obj/machinery/atmospherics/pipe/tank/nitrogen + icon = 'icons/obj/atmospherics/red_pipe_tank.dmi' + name = "Pressure Tank (Nitrogen)" + + New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.nitrogen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + +obj/machinery/atmospherics/pipe/tank/air + icon = 'icons/obj/atmospherics/red_pipe_tank.dmi' + name = "Pressure Tank (Air)" + + New() + air_temporary = new + air_temporary.volume = volume + air_temporary.temperature = T20C + + air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + + ..() + +obj/machinery/atmospherics/pipe/tank/Del() + if(node1) + node1.disconnect(src) + + ..() + +obj/machinery/atmospherics/pipe/tank/pipeline_expansion() + return list(node1) + +obj/machinery/atmospherics/pipe/tank/update_icon() + if(node1) + icon_state = "intact" + + dir = get_dir(src, node1) + + else + icon_state = "exposed" + +obj/machinery/atmospherics/pipe/tank/initialize() + + var/connect_direction = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + update_icon() + +obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + del(parent) + node1 = null + + update_icon() + + return null + +obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (istype(W, /obj/item/device/analyzer) && get_dist(user, src) <= 1) + for (var/mob/O in viewers(user, null)) + O << "\red [user] has used the analyzer on \icon[icon]" + + var/pressure = parent.air.return_pressure() + var/total_moles = parent.air.total_moles() + + user << "\blue Results of analysis of \icon[icon]" + if (total_moles>0) + var/o2_concentration = parent.air.oxygen/total_moles + var/n2_concentration = parent.air.nitrogen/total_moles + var/co2_concentration = parent.air.carbon_dioxide/total_moles + var/phoron_concentration = parent.air.phoron/total_moles + + var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+phoron_concentration) + + user << "\blue Pressure: [round(pressure,0.1)] kPa" + user << "\blue Nitrogen: [round(n2_concentration*100)]%" + user << "\blue Oxygen: [round(o2_concentration*100)]%" + user << "\blue CO2: [round(co2_concentration*100)]%" + user << "\blue Phoron: [round(phoron_concentration*100)]%" + if(unknown_concentration>0.01) + user << "\red Unknown: [round(unknown_concentration*100)]%" + user << "\blue Temperature: [round(parent.air.temperature-T0C)]°C" + else + user << "\blue Tank is empty!" + +obj/machinery/atmospherics/pipe/vent + icon = 'icons/obj/atmospherics/pipe_vent.dmi' + icon_state = "intact" + + name = "Vent" + desc = "A large air vent" + + level = 1 + + volume = 250 + + dir = SOUTH + initialize_directions = SOUTH + + var/build_killswitch = 1 + + var/obj/machinery/atmospherics/node1 + +obj/machinery/atmospherics/pipe/vent/New() + initialize_directions = dir + ..() + +obj/machinery/atmospherics/pipe/vent/high_volume + name = "Larger vent" + volume = 1000 + +obj/machinery/atmospherics/pipe/vent/process() + if(!parent) + if(build_killswitch <= 0) + . = PROCESS_KILL + else + build_killswitch-- + ..() + return + else + parent.mingle_with_turf(loc, volume) +/* + if(!node1) + if(!nodealert) + //world << "Missing node from [src] at [src.x],[src.y],[src.z]" + nodealert = 1 + else if (nodealert) + nodealert = 0 +*/ +obj/machinery/atmospherics/pipe/vent/Del() + if(node1) + node1.disconnect(src) + + ..() + +obj/machinery/atmospherics/pipe/vent/pipeline_expansion() + return list(node1) + +obj/machinery/atmospherics/pipe/vent/update_icon() + if(node1) + icon_state = "intact" + + dir = get_dir(src, node1) + + else + icon_state = "exposed" + +obj/machinery/atmospherics/pipe/vent/initialize() + var/connect_direction = dir + + for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + update_icon() + +obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + del(parent) + node1 = null + + update_icon() + + return null + +obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes. + if(node1) + icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact" + dir = get_dir(src, node1) + else + icon_state = "exposed" diff --git a/code/TriDimension/Movement.dm b/code/TriDimension/Movement.dm index dfb529df5b..5f451a1038 100644 --- a/code/TriDimension/Movement.dm +++ b/code/TriDimension/Movement.dm @@ -1,49 +1,52 @@ -var/maxZ = 6 -var/minZ = 2 - -// Maybe it's best to have this hardcoded for whatever we'd add to the map, in order to avoid exploits -// (such as mining base => admin station) -// Note that this assumes the ship's top is at z=1 and bottom at z=4 -/obj/item/weapon/tank/jetpack/proc/move_z(cardinal, mob/user as mob) - if (user.z > 1) - user << "\red There is nothing of interest in that direction." - return - if(allow_thrust(0.01, user)) - switch(cardinal) - if (UP) // Going up! - if(user.z > maxZ) // If we aren't at the very top of the ship - var/turf/T = locate(user.x, user.y, user.z - 1) - // You can only jetpack up if there's space above, and you're sitting on either hull (on the exterior), or space - //if(T && istype(T, /turf/space) && (istype(user.loc, /turf/space) || istype(user.loc, /turf/space/*/hull*/))) - //check through turf contents to make sure there's nothing blocking the way - if(T && istype(T, /turf/space)) - var/blocked = 0 - for(var/atom/A in T.contents) - if(T.density) - blocked = 1 - user << "\red You bump into [T.name]." - break - if(!blocked) - user.Move(T) - else - user << "\red You bump into the ship's plating." +/obj/item/weapon/tank/jetpack/verb/moveup() + set name = "Move Upwards" + set category = "Object" + if(allow_thrust(0.01, usr)) + var/turf/controllerlocation = locate(1, 1, usr.z) + var/legal = 0 + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + legal = controller.up + if (controller.up) + var/turf/T = locate(usr.x, usr.y, controller.up_target) + if(T && (istype(T, /turf/space) || istype(T, /turf/simulated/floor/open))) + var/blocked = 0 + for(var/atom/A in T.contents) + if(A.density) + blocked = 1 + usr << "\red You bump into [A.name]." + break + if(!blocked) + usr.Move(T) + usr << "You move upwards." else - user << "\red The ship's gravity well keeps you in orbit!" // Assuming the ship starts on z level 1, you don't want to go past it + usr << "\red There is something in your way." + if (legal == 0) + usr << "There is nothing of interest in this direction." + return 1 - if (DOWN) // Going down! - if (user.z < 1) // If we aren't at the very bottom of the ship, or out in space - var/turf/T = locate(user.x, user.y, user.z + 1) - // You can only jetpack down if you're sitting on space and there's space down below, or hull - if(T && (istype(T, /turf/space) || istype(T, /turf/space/*/hull*/)) && istype(user.loc, /turf/space)) - var/blocked = 0 - for(var/atom/A in T.contents) - if(T.density) - blocked = 1 - user << "\red You bump into [T.name]." - break - if(!blocked) - user.Move(T) - else - user << "\red You bump into the ship's plating." +/obj/item/weapon/tank/jetpack/verb/movedown() + set name = "Move Downwards" + set category = "Object" + if(allow_thrust(0.01, usr)) + var/turf/controllerlocation = locate(1, 1, usr.z) + var/legal = 0 + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + legal = controller.down + if (controller.down == 1) + var/turf/T = locate(usr.x, usr.y, controller.down_target) + var/turf/S = locate(usr.x, usr.y, usr.z) + if(T && (istype(S, /turf/space) || istype(S, /turf/simulated/floor/open))) + var/blocked = 0 + for(var/atom/A in T.contents) + if(A.density) + blocked = 1 + usr << "\red You bump into [A.name]." + break + if(!blocked) + usr.Move(T) + usr << "You move downwards." else - user << "\red The ship's gravity well keeps you in orbit!" \ No newline at end of file + usr << "\red You cant move through the floor." + if (legal == 0) + usr << "There is nothing of interest in this direction." + return 1 diff --git a/code/TriDimension/Pipes.dm b/code/TriDimension/Pipes.dm index e69de29bb2..efba6b96da 100644 --- a/code/TriDimension/Pipes.dm +++ b/code/TriDimension/Pipes.dm @@ -0,0 +1,191 @@ +//////////////////////////// +// parent class for pipes // +//////////////////////////// +obj/machinery/atmospherics/pipe/zpipe + icon = 'icons/obj/structures.dmi' + icon_state = "up" + + name = "upwards pipe" + desc = "A pipe segment to connect upwards." + + volume = 70 + + dir = SOUTH + initialize_directions = SOUTH + + var/obj/machinery/atmospherics/node1 //connection on the same Z + var/obj/machinery/atmospherics/node2 //connection on the other Z + + var/minimum_temperature_difference = 300 + var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No + + var/maximum_pressure = 70*ONE_ATMOSPHERE + var/fatigue_pressure = 55*ONE_ATMOSPHERE + alert_pressure = 55*ONE_ATMOSPHERE + + + level = 1 + +obj/machinery/atmospherics/pipe/zpipe/New() + ..() + switch(dir) + if(SOUTH) + initialize_directions = SOUTH + if(NORTH) + initialize_directions = NORTH + if(WEST) + initialize_directions = WEST + if(EAST) + initialize_directions = EAST + if(NORTHEAST) + initialize_directions = NORTH + if(NORTHWEST) + initialize_directions = WEST + if(SOUTHEAST) + initialize_directions = EAST + if(SOUTHWEST) + initialize_directions = SOUTH + initialize() + + +obj/machinery/atmospherics/pipe/zpipe/hide(var/i) + if(level == 1 && istype(loc, /turf/simulated)) + invisibility = i ? 101 : 0 + update_icon() + +obj/machinery/atmospherics/pipe/up/process() + if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle + ..() + else + . = PROCESS_KILL + +obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure) + var/datum/gas_mixture/environment = loc.return_air() + + var/pressure_difference = pressure - environment.return_pressure() + + if(pressure_difference > maximum_pressure) + burst() + + else if(pressure_difference > fatigue_pressure) + //TODO: leak to turf, doing pfshhhhh + if(prob(5)) + burst() + + else return 1 + +obj/machinery/atmospherics/pipe/zpipe/proc/burst() + src.visible_message("\red \bold [src] bursts!"); + playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) + var/datum/effect/effect/system/smoke_spread/smoke = new + smoke.set_up(1,0, src.loc, 0) + smoke.start() + del(src) + +obj/machinery/atmospherics/pipe/zpipe/proc/normalize_dir() + if(dir==3) + dir = 1 + else if(dir==12) + dir = 4 + +obj/machinery/atmospherics/pipe/zpipe/Del() + if(node1) + node1.disconnect(src) + if(node2) + node2.disconnect(src) + ..() + +obj/machinery/atmospherics/pipe/zpipe/pipeline_expansion() + return list(node1, node2) + +obj/machinery/atmospherics/pipe/zpipe/update_icon() + return + +obj/machinery/atmospherics/pipe/zpipe/disconnect(obj/machinery/atmospherics/reference) + if(reference == node1) + if(istype(node1, /obj/machinery/atmospherics/pipe)) + del(parent) + node1 = null + + if(reference == node2) + if(istype(node2, /obj/machinery/atmospherics/pipe)) + del(parent) + node2 = null + + return null +///////////////////////// +// the elusive up pipe // +///////////////////////// +obj/machinery/atmospherics/pipe/zpipe/up + icon = 'icons/obj/structures.dmi' + icon_state = "up" + + name = "upwards pipe" + desc = "A pipe segment to connect upwards." + +obj/machinery/atmospherics/pipe/zpipe/up/initialize() + normalize_dir() + var/node1_dir + + for(var/direction in cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + var/turf/controllerlocation = locate(1, 1, src.z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.up) + var/turf/above = locate(src.x, src.y, controller.up_target) + if(above) + for(var/obj/machinery/atmospherics/target in above) + if(target.initialize_directions && istype(target, /obj/machinery/atmospherics/pipe/zpipe/down)) + node2 = target + break + + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) + +/////////////////////// +// and the down pipe // +/////////////////////// + +obj/machinery/atmospherics/pipe/zpipe/down + icon = 'icons/obj/structures.dmi' + icon_state = "down" + + name = "downwards pipe" + desc = "A pipe segment to connect downwards." + +obj/machinery/atmospherics/pipe/zpipe/down/initialize() + normalize_dir() + var/node1_dir + + for(var/direction in cardinal) + if(direction&initialize_directions) + if (!node1_dir) + node1_dir = direction + + for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + + var/turf/controllerlocation = locate(1, 1, src.z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.down) + var/turf/below = locate(src.x, src.y, controller.down_target) + if(below) + for(var/obj/machinery/atmospherics/target in below) + if(target.initialize_directions && istype(target, /obj/machinery/atmospherics/pipe/zpipe/up)) + node2 = target + break + + + var/turf/T = src.loc // hide if turf is not intact + hide(T.intact) \ No newline at end of file diff --git a/code/TriDimension/Structures.dm b/code/TriDimension/Structures.dm index 85e499f7ad..942945e684 100644 --- a/code/TriDimension/Structures.dm +++ b/code/TriDimension/Structures.dm @@ -3,11 +3,10 @@ /////////////////////////////////////// /obj/multiz - icon = 'code/TriDimension/multiz.dmi' + icon = 'icons/obj/structures.dmi' density = 0 opacity = 0 anchored = 1 - var/obj/multiz/target CanPass(obj/mover, turf/source, height, airflow) return airflow || !density @@ -15,64 +14,140 @@ /obj/multiz/ladder icon_state = "ladderdown" name = "ladder" - desc = "A Ladder. You climb up and down it." + desc = "A ladder. You climb up and down it." - var/top_icon_state = "ladderdown" - var/bottom_icon_state = "ladderup" + var/d_state = 1 + var/obj/multiz/target New() . = ..() - spawn(1) //Allow map to load - if(z in levels_3d) - if(!target) - var/list/adjacent_to_me = global_adjacent_z_levels["[z]"] - if("up" in adjacent_to_me) - target = locate() in locate(x,y,adjacent_to_me["up"]) - if(istype(target)) - icon_state = bottom_icon_state - else if("down" in adjacent_to_me) - target = locate() in locate(x,y,adjacent_to_me["down"]) - if(istype(target)) - icon_state = top_icon_state - else - del src - else - del src - else if("down" in adjacent_to_me) - target = locate() in locate(x,y,adjacent_to_me["down"]) - if(istype(target)) - icon_state = bottom_icon_state - else - del src - else - del src - if(target) - target.icon_state = ( icon_state == top_icon_state ? bottom_icon_state : top_icon_state) - target.target = src - else - del src + + proc/connect() + if(icon_state == "ladderdown") // the upper will connect to the lower + d_state = 1 + var/turf/controllerlocation = locate(1, 1, z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.down) + var/turf/below = locate(src.x, src.y, controller.down_target) + for(var/obj/multiz/ladder/L in below) + if(L.icon_state == "ladderup") + target = L + L.target = src + d_state = 0 + break + return + +/* ex_act(severity) + switch(severity) + if(1.0) + if(icon_state == "ladderup" && prob(10)) + Del() + if(2.0) + if(prob(50)) + Del() + if(3.0) + Del() + return*/ Del() spawn(1) - if(target) + if(target && icon_state == "ladderdown") del target return ..() attack_paw(var/mob/M) return attack_hand(M) - attackby(var/W, var/mob/M) - return attack_hand(M) + attackby(obj/item/C as obj, mob/user as mob) + (..) + +// construction commented out for balance concerns +/* if (!target && istype(C, /obj/item/stack/rods)) + var/turf/controllerlocation = locate(1, 1, z) + var/found = 0 + var/obj/item/stack/rods/S = C + if(S.amount < 2) + user << "You dont have enough rods to finish the ladder." + return + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.down) + found = 1 + var/turf/below = locate(src.x, src.y, controller.down_target) + var/blocked = 0 + for(var/atom/A in below.contents) + if(A.density) + blocked = 1 + break + if(!blocked && !istype(below, /turf/simulated/wall)) + var/obj/multiz/ladder/X = new /obj/multiz/ladder(below) + S.amount = S.amount - 2 + if(S.amount == 0) S.Del() + X.icon_state = "ladderup" + connect() + user << "You finish the ladder." + else + user << "The area below is blocked." + if(!found) + user << "You cant build a ladder down there." + return + + else if (icon_state == "ladderdown" && d_state == 0 && istype(C, /obj/item/weapon/wrench)) + user << "You start loosening the anchoring bolts which secure the ladder to the frame." + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + + sleep(30) + if(!user || !C) return + + src.d_state = 1 + if(target) + var/obj/item/stack/rods/R = new /obj/item/stack/rods(target.loc) + R.amount = 2 + target.Del() + + user << "You remove the bolts anchoring the ladder." + return + + else if (icon_state == "ladderdown" && d_state == 1 && istype(C, /obj/item/weapon/weldingtool) ) + var/obj/item/weapon/weldingtool/WT = C + if( WT.remove_fuel(0,user) ) + + user << "You begin to remove the ladder." + playsound(src.loc, 'sound/items/Welder.ogg', 100, 1) + + sleep(60) + if(!user || !WT || !WT.isOn()) return + + var/obj/item/stack/sheet/metal/S = new /obj/item/stack/sheet/metal( src ) + S.amount = 2 + user << "You remove the ladder and close the hole." + Del() + else + user << "You need more welding fuel to complete this task." + return + + else + src.attack_hand(user) + return*/ + src.attack_hand(user) + return attack_hand(var/mob/M) if(!target || !istype(target.loc, /turf)) - del src - var/list/adjacent_to_me = global_adjacent_z_levels["[z]"] - M.visible_message("\blue \The [M] climbs [target.z == adjacent_to_me["up"] ? "up" : "down"] \the [src]!", "You climb [target.z == adjacent_to_me["up"] ? "up" : "down"] \the [src]!", "You hear some grunting, and clanging of a metal ladder being used.") - M.Move(target.loc) + M << "The ladder is incomplete and can't be climbed." + else + var/turf/T = target.loc + var/blocked = 0 + for(var/atom/A in T.contents) + if(A.density) + blocked = 1 + break + if(blocked || istype(T, /turf/simulated/wall)) + M << "Something is blocking the ladder." + else + M.visible_message("\blue \The [M] climbs [src.icon_state == "ladderup" ? "up" : "down"] \the [src]!", "You climb [src.icon_state == "ladderup" ? "up" : "down"] \the [src]!", "You hear some grunting, and clanging of a metal ladder being used.") + M.Move(target.loc) - - hatch +/* hatch icon_state = "hatchdown" name = "hatch" desc = "A hatch. You climb down it, and it will automatically seal against pressure loss behind you." @@ -125,81 +200,48 @@ spawn(7) top_hatch.icon_state = top_icon_state bottom_hatch.overlays -= red_overlay - active = 0 + active = 0*/ /obj/multiz/stairs name = "Stairs" desc = "Stairs. You walk up and down them." - icon_state = "ramptop" - var/top_icon_state = "ramptop" - var/bottom_icon_state = "rampbottom" + icon_state = "rampbottom" + var/obj/multiz/stairs/connected + var/turf/target - active - density = 1 + New() + ..() + var/turf/cl= locate(1, 1, src.z) + for(var/obj/effect/landmark/zcontroller/c in cl) + if(c.up) + var/turf/O = locate(src.x, src.y, c.up_target) + if(istype(O, /turf/space)) + O.ChangeTurf(/turf/simulated/floor/open) - - New() - . = ..() - spawn(1) - if(z in levels_3d) - if(!target) - var/list/adjacent_to_me = global_adjacent_z_levels["[z]"] - if("up" in adjacent_to_me) - target = locate() in locate(x,y,adjacent_to_me["up"]) - if(istype(target)) - icon_state = bottom_icon_state - else if("down" in adjacent_to_me) - target = locate() in locate(x,y,adjacent_to_me["down"]) - if(istype(target)) - icon_state = top_icon_state - else - del src - else - del src - else if("down" in adjacent_to_me) - target = locate() in locate(x,y,adjacent_to_me["down"]) - if(istype(target)) - icon_state = bottom_icon_state - else - del src - else - del src - if(target) - target.icon_state = ( icon_state == top_icon_state ? bottom_icon_state : top_icon_state) - target.target = src - var/obj/multiz/stairs/lead_in = locate() in get_step(src, reverse_direction(dir)) - if(lead_in) - lead_in.icon_state = ( icon_state == top_icon_state ? bottom_icon_state : top_icon_state) - else - del src - - - Del() - spawn(1) + spawn(1) + for(var/dir in cardinal) + var/turf/T = get_step(src.loc,dir) + for(var/obj/multiz/stairs/S in T) + if(S && S.icon_state == "rampbottom" && !S.connected) + S.dir = dir + src.dir = dir + S.connected = src + src.connected = S + src.icon_state = "ramptop" + src.density = 1 + var/turf/controllerlocation = locate(1, 1, src.z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.up) + var/turf/above = locate(src.x, src.y, controller.up_target) + if(istype(above,/turf/space) || istype(above,/turf/simulated/floor/open)) + src.target = above + break if(target) - del target - return ..() - + break Bumped(var/atom/movable/M) - if(target.z > z && istype(src, /obj/multiz/stairs/active) && !locate(/obj/multiz/stairs) in M.loc) - return //If on bottom, only let them go up stairs if they've moved to the entry tile first. - //If it's the top, they can fall down just fine. - - if(!target || !istype(target.loc, /turf)) - del src - - if(ismob(M) && M:client) - M:client.moving = 1 - M.Move(target.loc) - if (ismob(M) && M:client) - M:client.moving = 0 - - Click() - if(!istype(usr,/mob/dead/observer)) - return ..() - if(!target || !istype(target.loc, /turf)) - del src - usr.client.moving = 1 - usr.Move(target.loc) - usr.client.moving = 0 \ No newline at end of file + if(connected && target && istype(src, /obj/multiz/stairs) && locate(/obj/multiz/stairs) in M.loc) + var/obj/multiz/stairs/Con = locate(/obj/multiz/stairs) in M.loc + if(Con == src.connected) //make sure the atom enters from the approriate lower stairs tile + M.Move(target) + return diff --git a/code/TriDimension/Turfs.dm b/code/TriDimension/Turfs.dm index 1e49e4dc80..ae7bf8202e 100644 --- a/code/TriDimension/Turfs.dm +++ b/code/TriDimension/Turfs.dm @@ -1,27 +1,3 @@ -atom/movable/var/list/adjacent_z_levels -atom/movable/var/archived_z_level - -atom/movable/Move() //Hackish - - if(adjacent_z_levels && adjacent_z_levels["up"]) - var/turf/above_me = locate(x,y,adjacent_z_levels["up"]) - if(istype(above_me, /turf/simulated/floor/open)) - above_me:RemoveImage(src) - - . = ..() - - if(archived_z_level != z) - archived_z_level = z - if(z in levels_3d) - adjacent_z_levels = global_adjacent_z_levels["[z]"] - else - adjacent_z_levels = null - - if(adjacent_z_levels && adjacent_z_levels["up"]) - var/turf/above_me = locate(x,y,adjacent_z_levels["up"]) - if(istype(above_me, /turf/simulated/floor/open)) - above_me:AddImage(src) - /turf/simulated/floor/open name = "open space" intact = 0 @@ -31,66 +7,116 @@ atom/movable/Move() //Hackish var/icon/darkoverlays = null var/turf/floorbelow var/list/overlay_references - mouse_opacity = 2 New() ..() - spawn(1) - if(!(z in levels_3d)) - ReplaceWithSpace() - var/list/adjacent_to_me = global_adjacent_z_levels["[z]"] - if(!("down" in adjacent_to_me)) - ReplaceWithSpace() - - floorbelow = locate(x, y, adjacent_to_me["down"]) - if(floorbelow) - if(!istype(floorbelow,/turf)) - del src - else if(floorbelow.density) - ReplaceWithPlating() - else - set_up() - else - ReplaceWithSpace() - + getbelow() + return Enter(var/atom/movable/AM) if (..()) //TODO make this check if gravity is active (future use) - Sukasa spawn(1) + // only fall down in defined areas (read: areas with artificial gravitiy) + if(!floorbelow) //make sure that there is actually something below + if(!getbelow()) + return if(AM) - AM.Move(floorbelow) - if (istype(AM, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = AM - var/damage = rand(5,15) - H.apply_damage(2*damage, BRUTE, "head") - H.apply_damage(2*damage, BRUTE, "chest") - H.apply_damage(0.5*damage, BRUTE, "l_leg") - H.apply_damage(0.5*damage, BRUTE, "r_leg") - H.apply_damage(0.5*damage, BRUTE, "l_arm") - H.apply_damage(0.5*damage, BRUTE, "r_arm") - H:weakened = max(H:weakened,2) - H:updatehealth() + var/area/areacheck = get_area(src) + var/blocked = 0 + var/soft = 0 + for(var/atom/A in floorbelow.contents) + if(A.density) + blocked = 1 + break + if(istype(A, /obj/machinery/atmospherics/pipe/zpipe/up) && istype(AM,/obj/item/pipe)) + blocked = 1 + break + if(istype(A, /obj/structure/disposalpipe/up) && istype(AM,/obj/item/pipe)) + blocked = 1 + break + if(istype(A, /obj/multiz/stairs)) + soft = 1 + //dont break here, since we still need to be sure that it isnt blocked + + if (soft || (!blocked && !(areacheck.name == "Space"))) + AM.Move(floorbelow) + if (!soft && istype(AM, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + var/damage = 5 + H.apply_damage(min(rand(-damage,damage),0), BRUTE, "head") + H.apply_damage(min(rand(-damage,damage),0), BRUTE, "chest") + H.apply_damage(min(rand(-damage,damage),0), BRUTE, "l_leg") + H.apply_damage(min(rand(-damage,damage),0), BRUTE, "r_leg") + H.apply_damage(min(rand(-damage,damage),0), BRUTE, "l_arm") + H.apply_damage(min(rand(-damage,damage),0), BRUTE, "r_arm") + H:weakened = max(H:weakened,2) + H:updatehealth() return ..() - attackby() - return //nothing +/turf/proc/hasbelow() + var/turf/controllerlocation = locate(1, 1, z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.down) + return 1 + return 0 - proc/set_up() //Update the overlays to make the openspace turf show what's down a level - if(!overlay_references) - overlay_references = list() - if(!floorbelow) return - overlays += floorbelow - for(var/obj/o in floorbelow) - var/image/o_img = image(o, dir=o.dir, layer = TURF_LAYER+0.05*o.layer) - overlays += o_img - overlay_references[o] = o_img +/turf/simulated/floor/open/proc/getbelow() + var/turf/controllerlocation = locate(1, 1, z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + // check if there is something to draw below + if(!controller.down) + src.ChangeTurf(/turf/space) + return 0 + else + floorbelow = locate(src.x, src.y, controller.down_target) + return 1 + return 1 - proc/AddImage(var/atom/movable/o) - var/o_img = image(o, dir=o.dir, layer = TURF_LAYER+0.05*o.layer) - overlays += o_img - overlay_references[o] = o_img +// override to make sure nothing is hidden +/turf/simulated/floor/open/levelupdate() + for(var/obj/O in src) + if(O.level == 1) + O.hide(0) - proc/RemoveImage(var/atom/movable/o) - var/o_img = overlay_references[o] - overlays -= o_img - overlay_references -= o \ No newline at end of file +//overwrite the attackby of space to transform it to openspace if necessary +/turf/space/attackby(obj/item/C as obj, mob/user as mob) + if (istype(C, /obj/item/weapon/cable_coil) && src.hasbelow()) + var/turf/simulated/floor/open/W = src.ChangeTurf(/turf/simulated/floor/open) + W.attackby(C, user) + return + ..() + +/turf/simulated/floor/open/ex_act(severity) + // cant destroy empty space with an ordinary bomb + return + +/turf/simulated/floor/open/attackby(obj/item/C as obj, mob/user as mob) + (..) + if (istype(C, /obj/item/weapon/cable_coil)) + var/obj/item/weapon/cable_coil/cable = C + cable.turf_place(src, user) + return + + if (istype(C, /obj/item/stack/rods)) + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + return + var/obj/item/stack/rods/R = C + user << "\blue Constructing support lattice ..." + playsound(src.loc, 'sound/weapons/Genhit.ogg', 50, 1) + ReplaceWithLattice() + R.use(1) + return + + if (istype(C, /obj/item/stack/tile/plasteel)) + var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) + if(L) + var/obj/item/stack/tile/plasteel/S = C + del(L) + playsound(src.loc, 'sound/weapons/Genhit.ogg', 50, 1) + S.build(src) + S.use(1) + return + else + user << "\red The plating is going to need some support." + return diff --git a/code/TriDimension/controller.dm b/code/TriDimension/controller.dm new file mode 100644 index 0000000000..528c2c76ba --- /dev/null +++ b/code/TriDimension/controller.dm @@ -0,0 +1,263 @@ +/obj/effect/landmark/zcontroller + name = "Z-Level Controller" + var/initialized = 0 // when set to 1, turfs will report to the controller + var/up = 0 // 1 allows up movement + var/up_target = 0 // the Z-level that is above the current one + var/down = 0 // 1 allows down movement + var/down_target = 0 // the Z-level that is below the current one + + var/list/slow = list() + var/list/normal = list() + var/list/fast = list() + + var/slow_time + var/normal_time + var/fast_time + +/obj/effect/landmark/zcontroller/New() + ..() + for (var/turf/T in world) + if (T.z == z) + fast += T + slow_time = world.time + 3000 + normal_time = world.time + 600 + fast_time = world.time + 10 + + processing_objects.Add(src) + + initialized = 1 + return 1 + +/obj/effect/landmark/zcontroller/Del() + processing_objects.Remove(src) + return + +/obj/effect/landmark/zcontroller/process() + if (world.time > fast_time) + calc(fast) + fast_time = world.time + 10 + + if (world.time > normal_time) + calc(normal) + normal_time = world.time + 600 + +/* if (world.time > slow_time) + calc(slow) + slow_time = world.time + 3000 */ + return + +/obj/effect/landmark/zcontroller/proc/add(var/list/L, var/I, var/transfer) + while (L.len) + var/turf/T = pick(L) + + L -= T + slow -= T + normal -= T + fast -= T + + if(!T || !istype(T, /turf)) + continue + + switch (I) + if(1) slow += T + if(2) normal += T + if(3) fast += T + + if(transfer > 0) + if(up) + var/turf/controller_up = locate(1, 1, up_target) + for(var/obj/effect/landmark/zcontroller/c_up in controller_up) + var/list/temp = list() + temp += locate(T.x, T.y, up_target) + c_up.add(temp, I, transfer-1) + + if(down) + var/turf/controller_down = locate(1, 1, down_target) + for(var/obj/effect/landmark/zcontroller/c_down in controller_down) + var/list/temp = list() + temp += locate(T.x, T.y, down_target) + c_down.add(temp, I, transfer-1) + return + +/turf + var/list/z_overlays = list() + +/turf/New() + ..() + + var/turf/controller = locate(1, 1, z) + for(var/obj/effect/landmark/zcontroller/c in controller) + if(c.initialized) + var/list/turf = list() + turf += src + c.add(turf,3,1) + +/turf/space/New() + ..() + + var/turf/controller = locate(1, 1, z) + for(var/obj/effect/landmark/zcontroller/c in controller) + if(c.initialized) + var/list/turf = list() + turf += src + c.add(turf,3,1) + +atom/movable/Move() //Hackish + . = ..() + + var/turf/controllerlocation = locate(1, 1, src.z) + for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) + if(controller.up || controller.down) + var/list/temp = list() + temp += locate(src.x, src.y, src.z) + controller.add(temp,3,1) + +/obj/effect/landmark/zcontroller/proc/calc(var/list/L) + var/list/slowholder = list() + var/list/normalholder = list() + var/list/fastholder = list() + var/new_list + + while(L.len) + var/turf/T = pick(L) + new_list = 0 + + if(!T || !istype(T, /turf)) + L -= T + continue + + T.overlays -= T.z_overlays + T.z_overlays -= T.z_overlays + + if(down && (istype(T, /turf/space) || istype(T, /turf/simulated/floor/open))) + var/turf/below = locate(T.x, T.y, down_target) + if(below) + if(!(istype(below, /turf/space) || istype(below, /turf/simulated/floor/open))) + var/image/t_img = list() + new_list = 1 + + var/image/temp = image(below, dir=below.dir, layer = TURF_LAYER + 0.04) + + temp.color = rgb(127,127,127) + temp.overlays += below.overlays + t_img += temp + T.overlays += t_img + T.z_overlays += t_img + + // get objects + var/image/o_img = list() + for(var/obj/o in below) + // ingore objects that have any form of invisibility + if(o.invisibility) continue + new_list = 2 + var/image/temp2 = image(o, dir=o.dir, layer = TURF_LAYER+0.05*o.layer) + temp2.color = rgb(127,127,127) + temp2.overlays += o.overlays + o_img += temp2 + // you need to add a list to .overlays or it will not display any because space + T.overlays += o_img + T.z_overlays += o_img + + // get mobs + var/image/m_img = list() + for(var/mob/m in below) + // ingore mobs that have any form of invisibility + if(m.invisibility) continue + // only add this tile to fastprocessing if there is a living mob, not a dead one + if(istype(m, /mob/living)) new_list = 3 + var/image/temp2 = image(m, dir=m.dir, layer = TURF_LAYER+0.05*m.layer) + temp2.color = rgb(127,127,127) + temp2.overlays += m.overlays + m_img += temp2 + // you need to add a list to .overlays or it will not display any because space + T.overlays += m_img + T.z_overlays += m_img + + T.overlays -= below.z_overlays + T.z_overlays -= below.z_overlays + + // this is sadly impossible to use right now + // the overlay is always opaque to mouseclicks and thus prevents interactions with everything except the turf + /*if(up) + var/turf/above = locate(T.x, T.y, up_target) + if(above) + var/eligeable = 0 + for(var/d in cardinal) + var/turf/mT = get_step(above,d) + if(istype(mT, /turf/space) || istype(mT, /turf/simulated/floor/open)) + eligeable = 1 + /*if(mT.opacity == 0) + for(var/f in cardinal) + var/turf/nT = get_step(mT,f) + if(istype(nT, /turf/space) || istype(nT, /turf/simulated/floor/open)) + eligeable = 1*/ + if(istype(above, /turf/space) || istype(above, /turf/simulated/floor/open)) eligeable = 1 + if(eligeable == 1) + if(!(istype(above, /turf/space) || istype(above, /turf/simulated/floor/open))) + var/image/t_img = list() + if(new_list < 1) new_list = 1 + + above.overlays -= above.z_overlays + var/image/temp = image(above, dir=above.dir, layer = 5 + 0.04) + above.overlays += above.z_overlays + + temp.alpha = 100 + temp.overlays += above.overlays + temp.overlays -= above.z_overlays + t_img += temp + T.overlays += t_img + T.z_overlays += t_img + + // get objects + var/image/o_img = list() + for(var/obj/o in above) + // ingore objects that have any form of invisibility + if(o.invisibility) continue + if(new_list < 2) new_list = 2 + var/image/temp2 = image(o, dir=o.dir, layer = 5+0.05*o.layer) + temp2.alpha = 100 + temp2.overlays += o.overlays + o_img += temp2 + // you need to add a list to .overlays or it will not display any because space + T.overlays += o_img + T.z_overlays += o_img + + // get mobs + var/image/m_img = list() + for(var/mob/m in above) + // ingore mobs that have any form of invisibility + if(m.invisibility) continue + // only add this tile to fastprocessing if there is a living mob, not a dead one + if(istype(m, /mob/living) && new_list < 3) new_list = 3 + var/image/temp2 = image(m, dir=m.dir, layer = 5+0.05*m.layer) + temp2.alpha = 100 + temp2.overlays += m.overlays + m_img += temp2 + // you need to add a list to .overlays or it will not display any because space + T.overlays += m_img + T.z_overlays += m_img + + T.overlays -= above.z_overlays + T.z_overlays -= above.z_overlays*/ + + L -= T + + if(new_list == 1) + slowholder += T + if(new_list == 2) + normalholder += T + if(new_list == 3) + fastholder += T + for(var/d in cardinal) + var/turf/mT = get_step(T,d) + if(!(mT in fastholder)) + fastholder += mT + for(var/f in cardinal) + var/turf/nT = get_step(mT,f) + if(!(nT in fastholder)) + fastholder += nT + + add(slowholder,1, 0) + add(normalholder, 2, 0) + add(fastholder, 3, 0) + return diff --git a/code/TriDimension/multiz.dmi b/code/TriDimension/multiz.dmi deleted file mode 100644 index 13b118ce9f..0000000000 Binary files a/code/TriDimension/multiz.dmi and /dev/null differ diff --git a/code/TriDimension/multiz_pipe.dmi b/code/TriDimension/multiz_pipe.dmi deleted file mode 100644 index a3bbbee0b2..0000000000 Binary files a/code/TriDimension/multiz_pipe.dmi and /dev/null differ diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/falsewall.dm b/code/WorkInProgress/Cael_Aislinn/Jungle/falsewall.dm index a83711609d..1a5d46371a 100644 --- a/code/WorkInProgress/Cael_Aislinn/Jungle/falsewall.dm +++ b/code/WorkInProgress/Cael_Aislinn/Jungle/falsewall.dm @@ -7,11 +7,11 @@ name = "wall" anchored = 1 icon = 'icons/turf/walls.dmi' - icon_state = "plasma0" + icon_state = "phoron0" opacity = 1 var/closed_wall_dir = 0 var/opening = 0 - var/mineral = "plasma" + var/mineral = "phoron" var/is_metal = 0 /obj/structure/temple_falsewall/New() diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dm b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dm index ccfe4c1e65..421e803ec4 100644 --- a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dm +++ b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dm @@ -60,9 +60,9 @@ my_ladder.id = rand(999) my_ladder.height = -1 - //loop over the walls in the temple and make them a random pre-chosen mineral (null is a stand in for plasma, which the walls already are) - //treat plasma slightly differently because it's the default wall type - var/mineral = pick("uranium","sandstone","gold","iron","silver","diamond","clown","plasma") + //loop over the walls in the temple and make them a random pre-chosen mineral (null is a stand in for phoron, which the walls already are) + //treat phoron slightly differently because it's the default wall type + var/mineral = pick("uranium","sandstone","gold","iron","silver","diamond","clown","phoron") //world << "init [mineral]" var/area/my_area = get_area(src) var/list/temple_turfs = get_area_turfs(my_area.type) @@ -86,8 +86,8 @@ del(D) for(var/turf/unsimulated/wall/T in temple_turfs) - if(mineral != "plasma") - T.icon_state = replacetext(T.icon_state, "plasma", mineral) + if(mineral != "phoron") + T.icon_state = replacetext(T.icon_state, "phoron", mineral) /*for(var/obj/effect/landmark/falsewall_spawner/F in T.contents) //world << "falsewall_spawner found in wall" diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm index 43292f02f2..7408663f44 100644 --- a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm +++ b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm @@ -204,13 +204,13 @@ 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, \ /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, \ /obj/item/weapon/reagent_containers/food/snacks/cookie, \ - /obj/item/weapon/reagent_containers/food/snacks/faggot, \ + /obj/item/weapon/reagent_containers/food/snacks/meatball, \ /obj/item/weapon/reagent_containers/food/snacks/plump_pie, \ ) for(var/i=0,i 0 && held_plasma.toxins) - var/heat_capacity = held_plasma.heat_capacity()//200 * number of plasma moles + if(mega_energy > 0 && held_phoron.phoron) + var/heat_capacity = held_phoron.heat_capacity()//200 * number of phoron moles if(heat_capacity > 0.0003) //formerly MINIMUM_HEAT_CAPACITY - held_plasma.temperature = (heat_capacity + mega_energy * 35000)/heat_capacity + held_phoron.temperature = (heat_capacity + mega_energy * 35000)/heat_capacity - //if there is too much plasma in the field, lose some - /*if( held_plasma.toxins > (MOLES_CELLSTANDARD * 7) * (50 / field_strength) ) - LosePlasma()*/ - if(held_plasma.toxins > 1) - //lose a random amount of plasma back into the air, increased by the field strength (want to switch this over to frequency eventually) + //if there is too much phoron in the field, lose some + /*if( held_phoron.phoron > (MOLES_CELLSTANDARD * 7) * (50 / field_strength) ) + LosePhoron()*/ + if(held_phoron.phoron > 1) + //lose a random amount of phoron back into the air, increased by the field strength (want to switch this over to frequency eventually) var/loss_ratio = rand() * (0.05 + (0.05 * 50 / field_strength)) - //world << "lost [loss_ratio*100]% of held plasma" + //world << "lost [loss_ratio*100]% of held phoron" // - var/datum/gas_mixture/plasma_lost = new - plasma_lost.temperature = held_plasma.temperature + var/datum/gas_mixture/phoron_lost = new + phoron_lost.temperature = held_phoron.temperature // - plasma_lost.toxins = held_plasma.toxins * loss_ratio - //plasma_lost.update_values() - held_plasma.toxins -= held_plasma.toxins * loss_ratio - //held_plasma.update_values() + phoron_lost.phoron = held_phoron.phoron * loss_ratio + //phoron_lost.update_values() + held_phoron.phoron -= held_phoron.phoron * loss_ratio + //held_phoron.update_values() // - environment.merge(plasma_lost) + environment.merge(phoron_lost) radiation += loss_ratio * mega_energy * 0.1 mega_energy -= loss_ratio * mega_energy * 0.1 else - held_plasma.toxins = 0 - //held_plasma.update_values() + held_phoron.phoron = 0 + //held_phoron.update_values() //handle some reactants formatting for(var/reactant in dormant_reactant_quantities) @@ -256,9 +256,9 @@ Deuterium-tritium fusion: 4.5 x 10^7 K radiation += mega_energy mega_energy = 0 - //lose all held plasma back into the air + //lose all held phoron back into the air var/datum/gas_mixture/environment = loc.return_air() - environment.merge(held_plasma) + environment.merge(held_phoron) /obj/effect/rust_em_field/proc/change_size(var/newsize = 1) // diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm b/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm index 72dddd6fe0..88cf6fd441 100644 --- a/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm +++ b/code/WorkInProgress/Cael_Aislinn/Rust/core_gen.dm @@ -2,7 +2,7 @@ /* when the core is turned on, it generates [creates] an electromagnetic field -the em field attracts plasma, and suspends it in a controlled torus (doughnut) shape, oscillating around the core +the em field attracts phoron, and suspends it in a controlled torus (doughnut) shape, oscillating around the core the field strength is directly controllable by the user field strength = sqrt(energy used by the field generator) @@ -16,27 +16,27 @@ the size of the EM field = field strength / k 7 tilewidth = between 20T and 50T (can't go higher than 40T) -energy is added by a gyrotron, and lost when plasma escapes +energy is added by a gyrotron, and lost when phoron escapes energy transferred from the gyrotron beams is reduced by how different the frequencies are (closer frequencies = more energy transferred) -frequency = field strength * (stored energy / stored moles of plasma) * x +frequency = field strength * (stored energy / stored moles of phoron) * x (where x is an arbitrary constant to make the frequency something realistic) -the gyrotron beams' frequency and energy are hardcapped low enough that they won't heat the plasma much +the gyrotron beams' frequency and energy are hardcapped low enough that they won't heat the phoron much energy is generated in considerable amounts by fusion reactions from injected particles fusion reactions only occur when the existing energy is above a certain level, and it's near the max operating level of the gyrotron. higher energy reactions only occur at higher energy levels a small amount of energy constantly bleeds off in the form of radiation -the field is constantly pulling in plasma from the surrounding [local] atmosphere -at random intervals, the field releases a random percentage of stored plasma in addition to a percentage of energy as intense radiation +the field is constantly pulling in phoron from the surrounding [local] atmosphere +at random intervals, the field releases a random percentage of stored phoron in addition to a percentage of energy as intense radiation -the amount of plasma is a percentage of the field strength, increased by frequency +the amount of phoron is a percentage of the field strength, increased by frequency */ /* - VALUES - -max volume of plasma storeable by the field = the total volume of a number of tiles equal to the (field tilewidth)^2 +max volume of phoron storeable by the field = the total volume of a number of tiles equal to the (field tilewidth)^2 */ diff --git a/code/WorkInProgress/Cael_Aislinn/ShieldGen/circuits_and_designs.dm b/code/WorkInProgress/Cael_Aislinn/ShieldGen/circuits_and_designs.dm index b85be8f74a..0d948d1cde 100644 --- a/code/WorkInProgress/Cael_Aislinn/ShieldGen/circuits_and_designs.dm +++ b/code/WorkInProgress/Cael_Aislinn/ShieldGen/circuits_and_designs.dm @@ -3,10 +3,10 @@ // External Shield Generator /obj/item/weapon/circuitboard/shield_gen_ex - name = "Circuit board (Experimental hull shield generator)" + name = "Circuit board (Hull shield generator)" board_type = "machine" build_path = "/obj/machinery/shield_gen/external" - origin_tech = "bluespace=4;plasmatech=3" + origin_tech = "bluespace=4;phorontech=3" frame_desc = "Requires 2 Pico Manipulators, 1 Subspace Transmitter, 5 Pieces of cable, 1 Subspace Crystal, 1 Subspace Amplifier and 1 Console Screen." req_components = list( "/obj/item/weapon/stock_parts/manipulator/pico" = 2, @@ -20,19 +20,19 @@ datum/design/shield_gen_ex name = "Circuit Design (Experimental hull shield generator)" desc = "Allows for the construction of circuit boards used to build an experimental hull shield generator." id = "shield_gen" - req_tech = list("bluespace" = 4, "plasmatech" = 3) + req_tech = list("bluespace" = 4, "phorontech" = 3) build_type = IMPRINTER - materials = list("$glass" = 2000, "sacid" = 20, "$plasma" = 10000, "$diamond" = 5000, "$gold" = 10000) + materials = list("$glass" = 2000, "sacid" = 20, "$phoron" = 10000, "$diamond" = 5000, "$gold" = 10000) build_path = "/obj/machinery/shield_gen/external" //////////////////////////////////////// // Shield Generator /obj/item/weapon/circuitboard/shield_gen - name = "Circuit board (Experimental shield generator)" + name = "Circuit board (Bubble shield generator)" board_type = "machine" build_path = "/obj/machinery/shield_gen/external" - origin_tech = "bluespace=4;plasmatech=3" + origin_tech = "bluespace=4;phorontech=3" frame_desc = "Requires 2 Pico Manipulators, 1 Subspace Transmitter, 5 Pieces of cable, 1 Subspace Crystal, 1 Subspace Amplifier and 1 Console Screen." req_components = list( "/obj/item/weapon/stock_parts/manipulator/pico" = 2, @@ -43,19 +43,19 @@ datum/design/shield_gen_ex "/obj/item/weapon/cable_coil" = 5) datum/design/shield_gen - name = "Circuit Design (Experimental shield generator)" + name = "Circuit Design (Bubble shield generator)" desc = "Allows for the construction of circuit boards used to build an experimental shield generator." id = "shield_gen" - req_tech = list("bluespace" = 4, "plasmatech" = 3) + req_tech = list("bluespace" = 4, "phorontech" = 3) build_type = IMPRINTER - materials = list("$glass" = 2000, "sacid" = 20, "$plasma" = 10000, "$diamond" = 5000, "$gold" = 10000) + materials = list("$glass" = 2000, "sacid" = 20, "$phoron" = 10000, "$diamond" = 5000, "$gold" = 10000) build_path = "/obj/machinery/shield_gen/external" //////////////////////////////////////// // Shield Capacitor /obj/item/weapon/circuitboard/shield_cap - name = "Circuit board (Experimental shield capacitor)" + name = "Circuit board (Shield capacitor)" board_type = "machine" build_path = "/obj/machinery/shield_capacitor" origin_tech = "magnets=3;powerstorage=4" @@ -69,10 +69,10 @@ datum/design/shield_gen "/obj/item/weapon/cable_coil" = 5) datum/design/shield_cap - name = "Circuit Design (Experimental shield capacitor)" + name = "Circuit Design (Shield capacitor)" desc = "Allows for the construction of circuit boards used to build an experimental shielding capacitor." id = "shield_cap" req_tech = list("magnets" = 3, "powerstorage" = 4) build_type = IMPRINTER - materials = list("$glass" = 2000, "sacid" = 20, "$plasma" = 10000, "$diamond" = 5000, "$silver" = 10000) + materials = list("$glass" = 2000, "sacid" = 20, "$phoron" = 10000, "$diamond" = 5000, "$silver" = 10000) build_path = "/obj/machinery/shield_gen/external" diff --git a/code/WorkInProgress/Cael_Aislinn/ShieldGen/energy_field.dm b/code/WorkInProgress/Cael_Aislinn/ShieldGen/energy_field.dm index 4ebfda0024..a8bda3d14f 100644 --- a/code/WorkInProgress/Cael_Aislinn/ShieldGen/energy_field.dm +++ b/code/WorkInProgress/Cael_Aislinn/ShieldGen/energy_field.dm @@ -11,6 +11,7 @@ density = 0 invisibility = 101 var/strength = 0 + var/ticks_recovering = 10 /obj/effect/energy_field/ex_act(var/severity) Stress(0.5 + severity) @@ -27,9 +28,12 @@ strength -= severity //if we take too much damage, drop out - the generator will bring us back up if we have enough power + ticks_recovering = min(ticks_recovering + 2, 10) if(strength < 1) invisibility = 101 density = 0 + ticks_recovering = 10 + strength = 0 else if(strength >= 1) invisibility = 0 density = 1 diff --git a/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_capacitor.dm b/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_capacitor.dm index 25825c489a..b95c0ffb6f 100644 --- a/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_capacitor.dm +++ b/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_capacitor.dm @@ -9,12 +9,10 @@ icon_state = "capacitor" var/active = 1 density = 1 - anchored = 1 var/stored_charge = 0 var/time_since_fail = 100 - var/max_charge = 1000000 - var/max_charge_rate = 100000 - var/min_charge_rate = 0 + var/max_charge = 5e6 + var/charge_limit = 200000 var/locked = 0 // use_power = 1 //0 use nothing @@ -23,6 +21,7 @@ idle_power_usage = 10 active_power_usage = 100 var/charge_rate = 100 + var/obj/machinery/shield_gen/owned_gen /obj/machinery/shield_capacitor/New() spawn(10) @@ -55,17 +54,17 @@ src.anchored = !src.anchored src.visible_message("\blue \icon[src] [src] has been [anchored ? "bolted to the floor" : "unbolted from the floor"] by [user].") - spawn(0) - for(var/obj/machinery/shield_gen/gen in range(1, src)) - if(get_dir(src, gen) == src.dir) - if(!src.anchored && gen.owned_capacitor == src) - gen.owned_capacitor = null - break - else if(src.anchored && !gen.owned_capacitor) - gen.owned_capacitor = src - break - gen.updateDialog() - updateDialog() + if(anchored) + spawn(0) + for(var/obj/machinery/shield_gen/gen in range(1, src)) + if(get_dir(src, gen) == src.dir && !gen.owned_capacitor) + owned_gen = gen + owned_gen.owned_capacitor = src + owned_gen.updateDialog() + else + if(owned_gen && owned_gen.owned_capacitor == src) + owned_gen.owned_capacitor = null + owned_gen = null else ..() @@ -94,17 +93,19 @@ t += "[time_since_fail > 2 ? "Charging stable." : "Warning, low charge!"]
" t += "Charge: [stored_charge] Watts ([100 * stored_charge/max_charge]%)
" t += "Charge rate: \ - \[min\] \ + \[----\] \ + \[---\] \ \[--\] \ \[-\][charge_rate] Watts/sec \ \[+\] \ \[++\] \ - \[max\]
" + \[+++\] \ + \[+++\]
" t += "
" t += "Refresh " t += "Close
" - user << browse(t, "window=shield_capacitor;size=500x800") + user << browse(t, "window=shield_capacitor;size=500x400") user.set_machine(src) /obj/machinery/shield_capacitor/process() @@ -137,10 +138,10 @@ use_power = 1 if( href_list["charge_rate"] ) charge_rate += text2num(href_list["charge_rate"]) - if(charge_rate > max_charge_rate) - charge_rate = max_charge_rate - else if(charge_rate < min_charge_rate) - charge_rate = min_charge_rate + if(charge_rate > charge_limit) + charge_rate = charge_limit + else if(charge_rate < 0) + charge_rate = 0 // updateDialog() diff --git a/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen.dm b/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen.dm index b252ae7fb9..2cdccda1b7 100644 --- a/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen.dm +++ b/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen.dm @@ -14,7 +14,6 @@ var/field_radius = 3 var/list/field density = 1 - anchored = 1 var/locked = 0 var/average_field_strength = 0 var/strengthen_rate = 0.2 @@ -22,7 +21,7 @@ var/powered = 0 var/check_powered = 1 var/obj/machinery/shield_capacitor/owned_capacitor - var/max_field_strength = 10 + var/target_field_strength = 10 var/time_since_fail = 100 var/energy_conversion_rate = 0.01 //how many renwicks per watt? // @@ -63,17 +62,22 @@ src.anchored = !src.anchored src.visible_message("\blue \icon[src] [src] has been [anchored?"bolted to the floor":"unbolted from the floor"] by [user].") - spawn(0) - for(var/obj/machinery/shield_gen/gen in range(1, src)) - if(get_dir(src, gen) == src.dir) - if(!src.anchored && gen.owned_capacitor == src) - gen.owned_capacitor = null + if(active) + toggle() + if(anchored) + spawn(0) + for(var/obj/machinery/shield_capacitor/cap in range(1, src)) + if(cap.owned_gen) + continue + if(get_dir(cap, src) == cap.dir && src.anchored) + owned_capacitor = cap + owned_capacitor.owned_gen = src + updateDialog() break - else if(src.anchored && !gen.owned_capacitor) - gen.owned_capacitor = src - break - gen.updateDialog() - updateDialog() + else + if(owned_capacitor && owned_capacitor.owned_gen == src) + owned_capacitor.owned_gen = null + owned_capacitor = null else ..() @@ -102,67 +106,65 @@ t += "This generator is: [active ? "Online" : "Offline" ] [active ? "\[Deactivate\]" : "\[Activate\]"]
" t += "[time_since_fail > 2 ? "Field is stable." : "Warning, field is unstable!"]
" t += "Coverage radius (restart required): \ + --- \ -- \ - \ [field_radius * 2]m \ + \ - ++
" - t += "Overall field strength: [average_field_strength] Renwicks ([max_field_strength ? 100 * average_field_strength / max_field_strength : "NA"]%)
" - t += "Charge rate: -- \ - - \ - [strengthen_rate] Renwicks/sec \ - + \ - ++
" + ++ \ + +++
" + t += "Overall field strength: [average_field_strength] Renwicks ([target_field_strength ? 100 * average_field_strength / target_field_strength : "NA"]%)
" t += "Upkeep energy: [field.len * average_field_strength / energy_conversion_rate] Watts/sec
" + t += "Charge rate: -- \ + [strengthen_rate] Renwicks/sec \ + ++
" t += "Additional energy required to charge: [field.len * strengthen_rate / energy_conversion_rate] Watts/sec
" t += "Maximum field strength: \ - \[min\] \ - -- \ - - \ - [max_field_strength] Renwicks \ - + \ - ++ \ - \[max\]
" + \[min\] \ + -- \ + - \ + [target_field_strength] Renwicks \ + + \ + ++ \ + \[max\]
" t += "
" t += "Refresh " t += "Close
" - user << browse(t, "window=shield_generator;size=500x800") + user << browse(t, "window=shield_generator;size=500x400") user.set_machine(src) /obj/machinery/shield_gen/process() - if(active && field.len) + if(field.len) + time_since_fail++ var/stored_renwicks = 0 - var/target_field_strength = min(strengthen_rate + max(average_field_strength, 0), max_field_strength) - if(owned_capacitor) - var/required_energy = field.len * target_field_strength / energy_conversion_rate + var/target_strength_this_update = min(strengthen_rate + max(average_field_strength, 0), target_field_strength) + + if(active && owned_capacitor) + var/required_energy = field.len * target_strength_this_update / energy_conversion_rate var/assumed_charge = min(owned_capacitor.stored_charge, required_energy) stored_renwicks = assumed_charge * energy_conversion_rate owned_capacitor.stored_charge -= assumed_charge - time_since_fail++ - average_field_strength = 0 - target_field_strength = stored_renwicks / field.len + var/renwicks_per_field = 0 + if(stored_renwicks != 0) + renwicks_per_field = stored_renwicks / field.len for(var/obj/effect/energy_field/E in field) - if(stored_renwicks) - var/strength_change = target_field_strength - E.strength - if(strength_change > stored_renwicks) - strength_change = stored_renwicks - if(E.strength < 0) - E.strength = 0 + if(active && renwicks_per_field > 0) + var/amount_to_strengthen = min(renwicks_per_field - E.strength, strengthen_rate) + if(E.ticks_recovering > 0 && amount_to_strengthen > 0) + E.Strengthen( min(amount_to_strengthen / 10, 0.1) ) + E.ticks_recovering -= 1 else - E.Strengthen(strength_change) - - stored_renwicks -= strength_change - + E.Strengthen(amount_to_strengthen) average_field_strength += E.strength else E.Strengthen(-E.strength) average_field_strength /= field.len - if(average_field_strength < 0) + if(average_field_strength < 1) time_since_fail = 0 else average_field_strength = 0 @@ -187,12 +189,12 @@ strengthen_rate = 1 else if(strengthen_rate < 0) strengthen_rate = 0 - else if( href_list["max_field_strength"] ) - max_field_strength += text2num(href_list["max_field_strength"]) - if(max_field_strength > 1000) - max_field_strength = 1000 - else if(max_field_strength < 0) - max_field_strength = 0 + else if( href_list["target_field_strength"] ) + target_field_strength += text2num(href_list["target_field_strength"]) + if(target_field_strength > 1000) + target_field_strength = 1000 + else if(target_field_strength < 0) + target_field_strength = 0 // updateDialog() @@ -252,6 +254,7 @@ */ /obj/machinery/shield_gen/proc/toggle() + set background = 1 active = !active power_change() if(active) @@ -269,7 +272,7 @@ else for(var/obj/effect/energy_field/D in field) field.Remove(D) - del D + D.loc = null for(var/mob/M in view(5,src)) M << "\icon[src] You hear heavy droning fade out." @@ -278,6 +281,8 @@ /obj/machinery/shield_gen/proc/get_shielded_turfs() var/list/out = list() for(var/turf/T in range(field_radius, src)) + world << "turf dist:[get_dist(src,T)]" if(get_dist(src,T) == field_radius) out.Add(T) + world << " added" return out diff --git a/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen_external.dm b/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen_external.dm index f239dc9dac..dab223aeb6 100644 --- a/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen_external.dm +++ b/code/WorkInProgress/Cael_Aislinn/ShieldGen/shield_gen_external.dm @@ -1,7 +1,9 @@ - //---------- external shield generator //generates an energy field that loops around any built up area in space (is useless inside) halts movement and airflow, is blocked by walls, windows, airlocks etc +/obj/machinery/shield_gen/external + name = "hull shield generator" + /obj/machinery/shield_gen/external/New() ..() diff --git a/code/WorkInProgress/Chinsky/ashtray.dm b/code/WorkInProgress/Chinsky/ashtray.dm index ab3a636251..5825171125 100644 --- a/code/WorkInProgress/Chinsky/ashtray.dm +++ b/code/WorkInProgress/Chinsky/ashtray.dm @@ -17,35 +17,35 @@ /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) + W = butt 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 +62,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 +69,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 0000000000..8a959c5b76 --- /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/amorph/life.dm b/code/WorkInProgress/Cib/amorph/life.dm index e23662bbbb..1d254e5768 100644 --- a/code/WorkInProgress/Cib/amorph/life.dm +++ b/code/WorkInProgress/Cib/amorph/life.dm @@ -2,7 +2,7 @@ var/obj/item/weapon/card/id/wear_id = null // Fix for station bounced radios -- Skie var/oxygen_alert = 0 - var/toxins_alert = 0 + var/phoron_alert = 0 var/fire_alert = 0 var/temperature_alert = 0 @@ -455,7 +455,7 @@ if(src.pullin) src.pullin.icon_state = "pull[src.pulling ? 1 : 0]" - if (src.toxin) src.toxin.icon_state = "tox[src.toxins_alert ? 1 : 0]" + if (src.toxin) src.toxin.icon_state = "tox[src.phoron_alert ? 1 : 0]" if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]" if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]" //NOTE: the alerts dont reset when youre out of danger. dont blame me, diff --git a/code/WorkInProgress/Mini/atmos_control.dm b/code/WorkInProgress/Mini/atmos_control.dm index adf81eefb8..b89835de9d 100644 --- a/code/WorkInProgress/Mini/atmos_control.dm +++ b/code/WorkInProgress/Mini/atmos_control.dm @@ -282,7 +282,7 @@ siphoning Carbon Dioxide [data["filter_co2"]?"on":"off"]; Toxins -[data["filter_toxins"]?"on":"off"]; +[data["filter_phoron"]?"on":"off"]; Nitrous Oxide [data["filter_n2o"]?"on":"off"]
@@ -332,7 +332,7 @@ table tr:first-child th:first-child { border: none;} var/list/gases = list( "oxygen" = "O2", "carbon dioxide" = "CO2", - "plasma" = "Toxin", + "phoron" = "Toxin", "other" = "Other", ) var/list/tlv diff --git a/code/WorkInProgress/Ported/Bureaucracy/filing.dm b/code/WorkInProgress/Ported/Bureaucracy/filing.dm index 9e5a990f55..bf01c6dd27 100644 --- a/code/WorkInProgress/Ported/Bureaucracy/filing.dm +++ b/code/WorkInProgress/Ported/Bureaucracy/filing.dm @@ -8,7 +8,7 @@ /obj/structure/filingcabinet/attackby(obj/item/weapon/paper/P,mob/M) if(istype(P)) - M << "You put the [P] in the [src]." + M << "You put \the [P] in the [src]." M.drop_item() P.loc = src else diff --git a/code/WorkInProgress/Ported/Spawners/spawner.dm b/code/WorkInProgress/Ported/Spawners/spawner.dm index 875a05cc68..90f2f90039 100644 --- a/code/WorkInProgress/Ported/Spawners/spawner.dm +++ b/code/WorkInProgress/Ported/Spawners/spawner.dm @@ -57,7 +57,7 @@ // radio if (0) var/obj/item/assembly/r_i_ptank/R = new /obj/item/assembly/r_i_ptank(src.loc) - var/obj/item/weapon/tank/plasma/p3 = new /obj/item/weapon/tank/plasma(R) + var/obj/item/weapon/tank/phoron/p3 = new /obj/item/weapon/tank/phoron(R) var/obj/item/device/radio/signaler/p1 = new /obj/item/device/radio/signaler(R) var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) R.part1 = p1 @@ -74,7 +74,7 @@ // proximity if (1) var/obj/item/assembly/m_i_ptank/R = new /obj/item/assembly/m_i_ptank(src.loc) - var/obj/item/weapon/tank/plasma/p3 = new /obj/item/weapon/tank/plasma(R) + var/obj/item/weapon/tank/phoron/p3 = new /obj/item/weapon/tank/phoron(R) var/obj/item/device/prox_sensor/p1 = new /obj/item/device/prox_sensor(R) var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) R.part1 = p1 @@ -96,7 +96,7 @@ // timer if (2) var/obj/item/assembly/t_i_ptank/R = new /obj/item/assembly/t_i_ptank(src.loc) - var/obj/item/weapon/tank/plasma/p3 = new /obj/item/weapon/tank/plasma(R) + var/obj/item/weapon/tank/phoron/p3 = new /obj/item/weapon/tank/phoron(R) var/obj/item/device/timer/p1 = new /obj/item/device/timer(R) var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) R.part1 = p1 @@ -112,7 +112,7 @@ //bombvest if(3) var/obj/item/clothing/suit/armor/a_i_a_ptank/R = new /obj/item/clothing/suit/armor/a_i_a_ptank(src.loc) - var/obj/item/weapon/tank/plasma/p4 = new /obj/item/weapon/tank/plasma(R) + var/obj/item/weapon/tank/phoron/p4 = new /obj/item/weapon/tank/phoron(R) var/obj/item/device/healthanalyzer/p1 = new /obj/item/device/healthanalyzer(R) var/obj/item/device/igniter/p2 = new /obj/item/device/igniter(R) var/obj/item/clothing/suit/armor/vest/p3 = new /obj/item/clothing/suit/armor/vest(R) @@ -140,7 +140,7 @@ if (0) var/obj/item/device/transfer_valve/V = new(src.loc) - var/obj/item/weapon/tank/plasma/PT = new(V) + var/obj/item/weapon/tank/phoron/PT = new(V) var/obj/item/weapon/tank/oxygen/OT = new(V) var/obj/item/device/radio/signaler/S = new(V) @@ -164,7 +164,7 @@ if (1) var/obj/item/device/transfer_valve/V = new(src.loc) - var/obj/item/weapon/tank/plasma/PT = new(V) + var/obj/item/weapon/tank/phoron/PT = new(V) var/obj/item/weapon/tank/oxygen/OT = new(V) var/obj/item/device/prox_sensor/P = new(V) @@ -187,7 +187,7 @@ // timer if (2) var/obj/item/device/transfer_valve/V = new(src.loc) - var/obj/item/weapon/tank/plasma/PT = new(V) + var/obj/item/weapon/tank/phoron/PT = new(V) var/obj/item/weapon/tank/oxygen/OT = new(V) var/obj/item/device/timer/T = new(V) diff --git a/code/WorkInProgress/Ported/policetape.dm b/code/WorkInProgress/Ported/policetape.dm index 58ad2f8eb6..cdd547d7c0 100644 --- a/code/WorkInProgress/Ported/policetape.dm +++ b/code/WorkInProgress/Ported/policetape.dm @@ -4,7 +4,7 @@ icon = 'icons/policetape.dmi' icon_state = "rollstart" flags = FPRINT - w_class = 1.0 + w_class = 2.0 var/turf/start var/turf/end var/tape_type = /obj/item/tape diff --git a/code/WorkInProgress/Sigyn/Softcurity/wardrobe.dm b/code/WorkInProgress/Sigyn/Softcurity/wardrobe.dm index 452670091f..00a6b83d91 100644 --- a/code/WorkInProgress/Sigyn/Softcurity/wardrobe.dm +++ b/code/WorkInProgress/Sigyn/Softcurity/wardrobe.dm @@ -193,12 +193,12 @@ return -/obj/structure/closet/wardrobe/toxins_white - name = "toxins wardrobe" +/obj/structure/closet/wardrobe/science_white + name = "science wardrobe" icon_state = "white" icon_closed = "white" -/obj/structure/closet/wardrobe/toxins_white/New() +/obj/structure/closet/wardrobe/science_white/New() new /obj/item/clothing/under/rank/scientist(src) new /obj/item/clothing/under/rank/scientist(src) new /obj/item/clothing/under/rank/scientist(src) diff --git a/code/WorkInProgress/SkyMarshal/wardrobes.dm b/code/WorkInProgress/SkyMarshal/wardrobes.dm index 28bd73cff7..420345214f 100755 --- a/code/WorkInProgress/SkyMarshal/wardrobes.dm +++ b/code/WorkInProgress/SkyMarshal/wardrobes.dm @@ -340,7 +340,7 @@ var/obj/item/weapon/storage/backpack/BPK = new /obj/item/weapon/storage/backpack(src) new /obj/item/weapon/storage/box(BPK) new /obj/item/weapon/pen(src) - new /obj/item/device/pda/toxins(src) + new /obj/item/device/pda/science(src) new /obj/item/weapon/tank/oxygen(src) new /obj/item/clothing/mask/gas(src) new /obj/item/clothing/suit/storage/labcoat/science(src) @@ -360,7 +360,7 @@ new /obj/item/device/radio/headset/headset_medsci(src) new /obj/item/clothing/under/rank/chemist(src) new /obj/item/clothing/shoes/white(src) - new /obj/item/device/pda/toxins(src) + new /obj/item/device/pda/science(src) new /obj/item/clothing/suit/storage/labcoat/chemist(src) /obj/item/wardrobe/hos diff --git a/code/WorkInProgress/Tastyfish/Eliza_Data.dm b/code/WorkInProgress/Tastyfish/Eliza_Data.dm index 2fbbfb030b..1535e99292 100644 --- a/code/WorkInProgress/Tastyfish/Eliza_Data.dm +++ b/code/WorkInProgress/Tastyfish/Eliza_Data.dm @@ -243,11 +243,11 @@ "Do you think that caused a trauma with you?", "Have you ever previously spoken to anybody about this?")), new/datum/text_parser/keyword( - list("bomb", "explosive", "toxin", "plasma"), + list("bomb", "explosive", "toxin", "phoron"), list( "Do you worry about bombs often?", - "Do you work in toxins?", - "Do you find it odd to worry about bombs on a toxins research vessel?")), + "Do you work in science?", + "Do you find it odd to worry about bombs on a science research vessel?")), new/datum/text_parser/keyword( list("work", "job", "head", "staff", "transen"), list( diff --git a/code/WorkInProgress/animusstation/atm.dm b/code/WorkInProgress/animusstation/atm.dm index 12632bf3d9..1031c599f4 100644 --- a/code/WorkInProgress/animusstation/atm.dm +++ b/code/WorkInProgress/animusstation/atm.dm @@ -49,7 +49,7 @@ log transactions A.loc = src inserted += 50 return - if(istype(A,/obj/item/weapon/coin/plasma)) + if(istype(A,/obj/item/weapon/coin/phoron)) cashes += A user.drop_item() A.loc = src diff --git a/code/WorkInProgress/autopsy.dm b/code/WorkInProgress/autopsy.dm index 280c40d807..9c812ef7ae 100644 --- a/code/WorkInProgress/autopsy.dm +++ b/code/WorkInProgress/autopsy.dm @@ -8,7 +8,7 @@ icon = 'icons/obj/autopsy_scanner.dmi' icon_state = "" flags = FPRINT | TABLEPASS | CONDUCT - w_class = 1.0 + w_class = 2.0 origin_tech = "materials=1;biotech=1" var/list/datum/autopsy_data_scanner/wdata = list() var/list/datum/autopsy_data_scanner/chemtraces = list() diff --git a/code/WorkInProgress/buildmode.dm b/code/WorkInProgress/buildmode.dm index 28beed7f04..ceb1954a5d 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 96e7eacda6..0f9b4f666d 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/kilakk/fax.dm b/code/WorkInProgress/kilakk/fax.dm index 76bcc0baa4..0d8f4cdde1 100644 --- a/code/WorkInProgress/kilakk/fax.dm +++ b/code/WorkInProgress/kilakk/fax.dm @@ -109,10 +109,13 @@ var/list/alldepartments = list("Central Command") 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) diff --git a/code/WorkInProgress/periodic_news.dm b/code/WorkInProgress/periodic_news.dm index 8b8be52e2d..8cab325d88 100644 --- a/code/WorkInProgress/periodic_news.dm +++ b/code/WorkInProgress/periodic_news.dm @@ -107,7 +107,7 @@ message = {"More on the Refuge food riots: The Refuge Council has condemned NanoTrasen's withdrawal from the colony, claiming \"there has been no increase in anti-NanoTrasen activity\", and \"\[the only] reason - NanoTrasen withdrew was because the \[Tenebrae Lupus] system's Plasma deposits have been completely mined out. + NanoTrasen withdrew was because the \[Tenebrae Lupus] system's Phoron deposits have been completely mined out. We have little to trade with them now\". NanoTrasen officials have denied these allegations, calling them \"further proof\" of the colony's anti-NanoTrasen stance. Meanwhile, Refuge Security has been unable to quell the riots. More on this at 6."} diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 894dc92c72..896cda8440 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -1,53 +1,8 @@ /* - -CONTAINS: -All AirflowX() procs, all Variable Setting Controls for airflow, save/load variable tweaks for airflow. - -VARIABLES: - -atom/movable/airflow_dest - The destination turf of a flying object. - -atom/movable/airflow_speed - The speed (1-15) at which a flying object is traveling to airflow_dest. Decays over time. - - -OVERLOADABLE PROCS: - -mob/airflow_stun() - Contains checks for and results of being stunned by airflow. - Called when airflow quantities exceed airflow_medium_pressure. - RETURNS: Null - -atom/movable/check_airflow_movable(n) - Contains checks for moving any object due to airflow. - n is the pressure that is flowing. - RETURNS: 1 if the object moves under the air conditions, 0 if it stays put. - -atom/movable/airflow_hit(atom/A) - Contains results of hitting a solid object (A) due to airflow. - A is the dense object hit. - Use airflow_speed to determine how fast the projectile was going. - - -AUTOMATIC PROCS: - -Airflow(zone/A, zone/B) - Causes objects to fly along a pressure gradient. - Called by zone updates. A and B are two connected zones. - -AirflowSpace(zone/A) - Causes objects to fly into space. - Called by zone updates. A is a zone connected to space. - -atom/movable/GotoAirflowDest(n) -atom/movable/RepelAirflowDest(n) - Called by main airflow procs to cause the object to fly to or away from destination at speed n. - Probably shouldn't call this directly unless you know what you're - doing and have set airflow_dest. airflow_hit() will be called if the object collides with an obstacle. - +Contains helper procs for airflow, handled in /connection_group. */ + mob/var/tmp/last_airflow_stun = 0 mob/proc/airflow_stun() if(stat == 2) @@ -108,124 +63,6 @@ obj/item/check_airflow_movable(n) if(4,5) if(n < vsc.airflow_medium_pressure) return 0 -//The main airflow code. Called by zone updates. -//Zones A and B are air zones. n represents the amount of air moved. - -proc/Airflow(zone/A, zone/B) - - var/n = B.air.return_pressure() - A.air.return_pressure() - - //Don't go any further if n is lower than the lowest value needed for airflow. - if(abs(n) < vsc.airflow_lightest_pressure) return - - //These turfs are the midway point between A and B, and will be the destination point for thrown objects. - var/list/connection/connections_A = A.connections - var/list/turf/connected_turfs = list() - for(var/connection/C in connections_A) //Grab the turf that is in the zone we are flowing to (determined by n) - if( ( A == C.A.zone || A == C.zone_A ) && ( B == C.B.zone || B == C.zone_B ) ) - if(n < 0) - connected_turfs |= C.B - else - connected_turfs |= C.A - else if( ( A == C.B.zone || A == C.zone_B ) && ( B == C.A.zone || B == C.zone_A ) ) - if(n < 0) - connected_turfs |= C.A - else - connected_turfs |= C.B - - //Get lists of things that can be thrown across the room for each zone (assumes air is moving from zone B to zone A) - var/list/air_sucked = B.movables() - var/list/air_repelled = A.movables() - if(n < 0) - //air is moving from zone A to zone B - var/list/temporary_pplz = air_sucked - air_sucked = air_repelled - air_repelled = temporary_pplz - - for(var/atom/movable/M in air_sucked) - - if(M.last_airflow > world.time - vsc.airflow_delay) continue - - //Check for knocking people over - if(ismob(M) && n > vsc.airflow_stun_pressure) - if(M:status_flags & GODMODE) continue - M:airflow_stun() - - if(M.check_airflow_movable(n)) - - //Check for things that are in range of the midpoint turfs. - var/list/close_turfs = list() - for(var/turf/U in connected_turfs) - if(M in range(U)) close_turfs += U - if(!close_turfs.len) continue - - //If they're already being tossed, don't do it again. - if(!M.airflow_speed) - - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - - spawn M.GotoAirflowDest(abs(n)/5) - - //Do it again for the stuff in the other zone, making it fly away. - for(var/atom/movable/M in air_repelled) - - if(M.last_airflow > world.time - vsc.airflow_delay) continue - - if(ismob(M) && abs(n) > vsc.airflow_medium_pressure) - if(M:status_flags & GODMODE) continue - M:airflow_stun() - - if(M.check_airflow_movable(abs(n))) - - var/list/close_turfs = list() - for(var/turf/U in connected_turfs) - if(M in range(U)) close_turfs += U - if(!close_turfs.len) continue - - //If they're already being tossed, don't do it again. - if(!M.airflow_speed) - - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - - spawn M.RepelAirflowDest(abs(n)/5) - -proc/AirflowSpace(zone/A) - - //The space version of the Airflow(A,B,n) proc. - - var/n = A.air.return_pressure() - //Here, n is determined by only the pressure in the room. - - if(n < vsc.airflow_lightest_pressure) return - - var/list/connected_turfs = A.unsimulated_tiles //The midpoints are now all the space connections. - var/list/pplz = A.movables() //We only need to worry about things in the zone, not things in space. - - for(var/atom/movable/M in pplz) - - if(M.last_airflow > world.time - vsc.airflow_delay) continue - - if(ismob(M) && n > vsc.airflow_stun_pressure) - var/mob/O = M - if(O.status_flags & GODMODE) continue - O.airflow_stun() - - if(M.check_airflow_movable(n)) - - var/list/close_turfs = list() - for(var/turf/U in connected_turfs) - if(M in range(U)) close_turfs += U - if(!close_turfs.len) continue - - //If they're already being tossed, don't do it again. - if(!M.airflow_speed) - - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - spawn - if(M) M.GotoAirflowDest(n/10) - //Sometimes shit breaks, and M isn't there after the spawn. - - /atom/movable/var/tmp/turf/airflow_dest /atom/movable/var/tmp/airflow_speed = 0 /atom/movable/var/tmp/airflow_time = 0 @@ -416,4 +253,4 @@ zone/proc/movables() for(var/atom/A in T) if(istype(A, /obj/effect) || istype(A, /mob/aiEye)) continue - . += A + . += A \ No newline at end of file diff --git a/code/ZAS/Atom.dm b/code/ZAS/Atom.dm new file mode 100644 index 0000000000..b4d1de20af --- /dev/null +++ b/code/ZAS/Atom.dm @@ -0,0 +1,66 @@ + + +/atom/var/pressure_resistance = ONE_ATMOSPHERE + +atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + //Purpose: Determines if the object (or airflow) can pass this atom. + //Called by: Movement, airflow. + //Inputs: The moving atom (optional), target turf, "height" and air group + //Outputs: Boolean if can pass. + + return (!density || !height || air_group) + +/turf/CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0) + if(!target) return 0 + + if(istype(mover)) // turf/Enter(...) will perform more advanced checks + return !density + + else // Now, doing more detailed checks for air movement and air group formation + if(target.blocks_air||blocks_air) + return 0 + + for(var/obj/obstacle in src) + if(!obstacle.CanPass(mover, target, height, air_group)) + return 0 + if(target != src) + for(var/obj/obstacle in target) + if(!obstacle.CanPass(mover, src, height, air_group)) + return 0 + + return 1 + +//Basically another way of calling CanPass(null, other, 0, 0) and CanPass(null, other, 1.5, 1). +//Returns: +// 0 - Not blocked +// AIR_BLOCKED - Blocked +// ZONE_BLOCKED - Not blocked, but zone boundaries will not cross. +// BLOCKED - Blocked, zone boundaries will not cross even if opened. +atom/proc/c_airblock(turf/other) + #ifdef ZASDBG + ASSERT(isturf(other)) + #endif + return !CanPass(null, other, 0, 0) + 2*!CanPass(null, other, 1.5, 1) + + +turf/c_airblock(turf/other) + #ifdef ZASDBG + ASSERT(isturf(other)) + #endif + if(blocks_air) + return BLOCKED + + //Z-level handling code. Always block if there isn't an open space. + #ifdef ZLEVELS + if(other.z != src.z) + if(other.z < src.z) + if(!istype(src, /turf/simulated/floor/open)) return BLOCKED + else + if(!istype(other, /turf/simulated/floor/open)) return BLOCKED + #endif + + var/result = 0 + for(var/atom/movable/M in contents) + result |= M.c_airblock(other) + if(result == BLOCKED) return BLOCKED + return result \ No newline at end of file diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm index 1bb8f9ca54..b9cf2278a1 100644 --- a/code/ZAS/Connection.dm +++ b/code/ZAS/Connection.dm @@ -1,448 +1,165 @@ +#define CONNECTION_DIRECT 2 +#define CONNECTION_SPACE 4 +#define CONNECTION_INVALID 8 + /* -This object is contained within zone/var/connections. It's generated whenever two turfs from different zones are linked. -Indirect connections will not merge the two zones after they reach equilibrium. + +Overview: + Connections are made between turfs by air_master.connect(). They represent a single point where two zones converge. + +Class Vars: + A - Always a simulated turf. + B - A simulated or unsimulated turf. + + zoneA - The archived zone of A. Used to check that the zone hasn't changed. + zoneB - The archived zone of B. May be null in case of unsimulated connections. + + edge - Stores the edge this connection is in. Can reference an edge that is no longer processed + after this connection is removed, so make sure to check edge.coefficient > 0 before re-adding it. + +Class Procs: + + mark_direct() + Marks this connection as direct. Does not update the edge. + Called when the connection is made and there are no doors between A and B. + Also called by update() as a correction. + + mark_indirect() + Unmarks this connection as direct. Does not update the edge. + Called by update() as a correction. + + mark_space() + Marks this connection as unsimulated. Updating the connection will check the validity of this. + Called when the connection is made. + This will not be called as a correction, any connections failing a check against this mark are erased and rebuilt. + + direct() + Returns 1 if no doors are in between A and B. + + valid() + Returns 1 if the connection has not been erased. + + erase() + Called by update() and connection_manager/erase_all(). + Marks the connection as erased and removes it from its edge. + + update() + Called by connection_manager/update_all(). + Makes numerous checks to decide whether the connection is still valid. Erases it automatically if not. + */ -#define CONNECTION_DIRECT 2 -#define CONNECTION_INDIRECT 1 -#define CONNECTION_CLOSED 0 -/connection - var/turf/simulated/A - var/turf/simulated/B +/connection/var/turf/simulated/A +/connection/var/turf/simulated/B +/connection/var/zone/zoneA +/connection/var/zone/zoneB - var/zone/zone_A - var/zone/zone_B +/connection/var/connection_edge/edge - var/indirect = CONNECTION_DIRECT //If the connection is purely indirect, the zones should not join. - - -/connection/New(turf/T,turf/O) - . = ..() - - A = T - B = O - - if(A.zone && B.zone) - if(!A.zone.connections) - A.zone.connections = list() - A.zone.connections += src - zone_A = A.zone - - if(!B.zone.connections) - B.zone.connections = list() - B.zone.connections += src - zone_B = B.zone - - if(A in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[A] - connections.Add(src) - else - air_master.turfs_with_connections[A] = list(src) - - if(B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[B] - connections.Add(src) - else - air_master.turfs_with_connections[B] = list(src) - - if(A.CanPass(null, B, 0, 0)) - - if(!A.CanPass(null, B, 1.5, 1)) - indirect = CONNECTION_INDIRECT - - ConnectZones(A.zone, B.zone, indirect) - - else - ConnectZones(A.zone, B.zone) - indirect = CONNECTION_CLOSED +/connection/var/state = 0 +/connection/New(turf/simulated/A, turf/simulated/B) + #ifdef ZASDBG + ASSERT(air_master.has_valid_zone(A)) + //ASSERT(air_master.has_valid_zone(B)) + #endif + src.A = A + src.B = B + zoneA = A.zone + if(!istype(B)) + mark_space() + edge = air_master.get_edge(A.zone,B) + edge.add_connection(src) else - world.log << "Attempted to create connection object for non-zone tiles: [T] ([T.x],[T.y],[T.z]) -> [O] ([O.x],[O.y],[O.z])" - SoftDelete() + zoneB = B.zone + edge = air_master.get_edge(A.zone,B.zone) + edge.add_connection(src) +/connection/proc/mark_direct() + state |= CONNECTION_DIRECT + //world << "Marked direct." -/connection/Del() - //remove connections from master lists. - if(B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[B] - connections.Remove(src) +/connection/proc/mark_indirect() + state &= ~CONNECTION_DIRECT + //world << "Marked indirect." - if(A in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[A] - connections.Remove(src) +/connection/proc/mark_space() + state |= CONNECTION_SPACE - //Remove connection from zones. - if(A) - if(A.zone && A.zone.connections) - A.zone.connections.Remove(src) - if(!A.zone.connections.len) - A.zone.connections = null +/connection/proc/direct() + return (state & CONNECTION_DIRECT) - if(istype(zone_A) && (!A || A.zone != zone_A)) - if(zone_A.connections) - zone_A.connections.Remove(src) - if(!zone_A.connections.len) - zone_A.connections = null +/connection/proc/valid() + return !(state & CONNECTION_INVALID) - if(B) - if(B.zone && B.zone.connections) - B.zone.connections.Remove(src) - if(!B.zone.connections.len) - B.zone.connections = null +/connection/proc/erase() + edge.remove_connection(src) + state |= CONNECTION_INVALID + //world << "Connection Erased: [state]" - if(istype(zone_B) && (!B || B.zone != zone_B)) - if(zone_B.connections) - zone_B.connections.Remove(src) - if(!zone_B.connections.len) - zone_B.connections = null - - //Disconnect zones while handling unusual conditions. - // e.g. loss of a zone on a turf - DisconnectZones(zone_A, zone_B) - - //Finally, preform actual deletion. - . = ..() - - -/connection/proc/SoftDelete() - //remove connections from master lists. - if(B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[B] - connections.Remove(src) - - if(A in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[A] - connections.Remove(src) - - //Remove connection from zones. - if(A) - if(A.zone && A.zone.connections) - A.zone.connections.Remove(src) - if(!A.zone.connections.len) - A.zone.connections = null - - if(istype(zone_A) && (!A || A.zone != zone_A)) - if(zone_A.connections) - zone_A.connections.Remove(src) - if(!zone_A.connections.len) - zone_A.connections = null - - if(B) - if(B.zone && B.zone.connections) - B.zone.connections.Remove(src) - if(!B.zone.connections.len) - B.zone.connections = null - - if(istype(zone_B) && (!B || B.zone != zone_B)) - if(zone_B.connections) - zone_B.connections.Remove(src) - if(!zone_B.connections.len) - zone_B.connections = null - - //Disconnect zones while handling unusual conditions. - // e.g. loss of a zone on a turf - DisconnectZones(zone_A, zone_B) - - -/connection/proc/ConnectZones(var/zone/zone_1, var/zone/zone_2, open = 0) - - //Sanity checking - if(!istype(zone_1) || !istype(zone_2)) +/connection/proc/update() + //world << "Updated, \..." + if(!istype(A,/turf/simulated)) + //world << "Invalid A." + erase() return - //Handle zones connecting indirectly/directly. - if(open) - - //Create the lists if necessary. - if(!zone_1.connected_zones) - zone_1.connected_zones = list() - - if(!zone_2.connected_zones) - zone_2.connected_zones = list() - - //Increase the number of connections between zones. - if(zone_2 in zone_1.connected_zones) - zone_1.connected_zones[zone_2]++ - else - zone_1.connected_zones += zone_2 - zone_1.connected_zones[zone_2] = 1 - - if(zone_1 in zone_2.connected_zones) - zone_2.connected_zones[zone_1]++ - else - zone_2.connected_zones += zone_1 - zone_2.connected_zones[zone_1] = 1 - - if(open == CONNECTION_DIRECT) - if(!zone_1.direct_connections) - zone_1.direct_connections = list(src) - else - zone_1.direct_connections += src - - if(!zone_2.direct_connections) - zone_2.direct_connections = list(src) - else - zone_2.direct_connections += src - - - //Handle closed connections. - else - - //Create the lists - if(!zone_1.closed_connection_zones) - zone_1.closed_connection_zones = list() - - if(!zone_2.closed_connection_zones) - zone_2.closed_connection_zones = list() - - //Increment the connections. - if(zone_2 in zone_1.closed_connection_zones) - zone_1.closed_connection_zones[zone_2]++ - else - zone_1.closed_connection_zones += zone_2 - zone_1.closed_connection_zones[zone_2] = 1 - - if(zone_1 in zone_2.closed_connection_zones) - zone_2.closed_connection_zones[zone_1]++ - else - zone_2.closed_connection_zones += zone_1 - zone_2.closed_connection_zones[zone_1] = 1 - - if(zone_1.status == ZONE_SLEEPING) - zone_1.SetStatus(ZONE_ACTIVE) - - if(zone_2.status == ZONE_SLEEPING) - zone_2.SetStatus(ZONE_ACTIVE) - -/connection/proc/DisconnectZones(var/zone/zone_1, var/zone/zone_2) - //Sanity checking - if(!istype(zone_1) || !istype(zone_2)) + var/block_status = air_master.air_blocked(A,B) + if(block_status & AIR_BLOCKED) + //world << "Blocked connection." + erase() return - - if(indirect != CONNECTION_CLOSED) - //Handle disconnection of indirectly or directly connected zones. - if( (zone_1 in zone_2.connected_zones) || (zone_2 in zone_1.connected_zones) ) - - //If there are more than one connection, decrement the number of connections - //Otherwise, remove all connections between the zones. - if(zone_2 in zone_1.connected_zones) - if(zone_1.connected_zones[zone_2] > 1) - zone_1.connected_zones[zone_2]-- - else - zone_1.connected_zones -= zone_2 - //remove the list if it is empty - if(!zone_1.connected_zones.len) - zone_1.connected_zones = null - - //Then do the same for the other zone. - if(zone_1 in zone_2.connected_zones) - if(zone_2.connected_zones[zone_1] > 1) - zone_2.connected_zones[zone_1]-- - else - zone_2.connected_zones -= zone_1 - if(!zone_2.connected_zones.len) - zone_2.connected_zones = null - - if(indirect == CONNECTION_DIRECT) - zone_1.direct_connections -= src - if(!zone_1.direct_connections.len) - zone_1.direct_connections = null - - zone_2.direct_connections -= src - if(!zone_2.direct_connections.len) - zone_2.direct_connections = null - - else - //Handle disconnection of closed zones. - if( (zone_1 in zone_2.closed_connection_zones) || (zone_2 in zone_1.closed_connection_zones) ) - - //If there are more than one connection, decrement the number of connections - //Otherwise, remove all connections between the zones. - if(zone_2 in zone_1.closed_connection_zones) - if(zone_1.closed_connection_zones[zone_2] > 1) - zone_1.closed_connection_zones[zone_2]-- - else - zone_1.closed_connection_zones -= zone_2 - //remove the list if it is empty - if(!zone_1.closed_connection_zones.len) - zone_1.closed_connection_zones = null - - //Then do the same for the other zone. - if(zone_1 in zone_2.closed_connection_zones) - if(zone_2.closed_connection_zones[zone_1] > 1) - zone_2.closed_connection_zones[zone_1]-- - else - zone_2.closed_connection_zones -= zone_1 - if(!zone_2.closed_connection_zones.len) - zone_2.closed_connection_zones = null - - -/connection/proc/Cleanup() - - //Check sanity: existance of turfs - if(!A || !B) - SoftDelete() - return - - //Check sanity: loss of zone - if(!A.zone || !B.zone) - SoftDelete() - return - - //Check sanity: zones are different - if(A.zone == B.zone) - SoftDelete() - return - - //Handle zones changing on a turf. - if((A.zone && A.zone != zone_A) || (B.zone && B.zone != zone_B)) - Sanitize() - - if(A.zone && B.zone) - - //If no walls are blocking us... - if(A.ZAirPass(B)) - //...we check to see if there is a door in the way... - var/door_pass = A.CanPass(null,B,1.5,1) - //...and if it is opened. - if(door_pass || A.CanPass(null,B,0,0)) - - //Make and remove connections to let air pass. - if(indirect == CONNECTION_CLOSED) - DisconnectZones(A.zone, B.zone) - ConnectZones(A.zone, B.zone, door_pass + 1) - - if(door_pass) - indirect = CONNECTION_DIRECT - else if(!door_pass) - indirect = CONNECTION_INDIRECT - - //The door is instead closed. - else if(indirect > CONNECTION_CLOSED) - DisconnectZones(A.zone, B.zone) - indirect = CONNECTION_CLOSED - ConnectZones(A.zone, B.zone) - - //If I can no longer pass air, better delete + else if(block_status & ZONE_BLOCKED) + if(direct()) + mark_indirect() else - SoftDelete() + mark_direct() + + var/b_is_space = !istype(B,/turf/simulated) + + if(state & CONNECTION_SPACE) + if(!b_is_space) + //world << "Invalid B." + erase() return - -/connection/proc/Sanitize() - //If the zones change on connected turfs, update it. - - //Both zones changed (wat) - if(A.zone && A.zone != zone_A && B.zone && B.zone != zone_B) - - //If the zones have gotten swapped - // (do not ask me how, I am just being anal retentive about sanity) - if(A.zone == zone_B && B.zone == zone_A) - var/turf/temp = B - B = A - A = temp - zone_B = B.zone - zone_A = A.zone - return - - //Handle removal of connections from archived zones. - if(zone_A && zone_A.connections) - zone_A.connections.Remove(src) - if(!zone_A.connections.len) - zone_A.connections = null - - if(zone_B && zone_B.connections) - zone_B.connections.Remove(src) - if(!zone_B.connections.len) - zone_B.connections = null - - if(A.zone) - if(!A.zone.connections) - A.zone.connections = list() - A.zone.connections |= src - - if(B.zone) - if(!B.zone.connections) - B.zone.connections = list() - B.zone.connections |= src - - //If either zone is null, we disconnect the archived ones after cleaning up the connections. - if(!A.zone || !B.zone) - if(zone_A && zone_B) - DisconnectZones(zone_B, zone_A) - + if(A.zone != zoneA) + //world << "Zone changed, \..." if(!A.zone) - zone_A = A.zone + erase() + //world << "erased." + return + else + edge.remove_connection(src) + edge = air_master.get_edge(A.zone, B) + edge.add_connection(src) + zoneA = A.zone - if(!B.zone) - zone_B = B.zone + //world << "valid." + return + + else if(b_is_space) + //world << "Invalid B." + erase() + return + + if(A.zone == B.zone) + //world << "A == B" + erase() + return + + if(A.zone != zoneA || (zoneB && (B.zone != zoneB))) + + //world << "Zones changed, \..." + if(A.zone && B.zone) + edge.remove_connection(src) + edge = air_master.get_edge(A.zone, B.zone) + edge.add_connection(src) + zoneA = A.zone + zoneB = B.zone + else + //world << "erased." + erase() return - //Handle diconnection and reconnection of zones. - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - ConnectZones(A.zone, B.zone, indirect) - //resetting values of archived values. - zone_B = B.zone - zone_A = A.zone - - //The "A" zone changed. - else if(A.zone && A.zone != zone_A) - - //Handle connection cleanup - if(zone_A) - if(zone_A.connections) - zone_A.connections.Remove(src) - if(!zone_A.connections.len) - zone_A.connections = null - - if(A.zone) - if(!A.zone.connections) - A.zone.connections = list() - A.zone.connections |= src - - //If the "A" zone is null, we disconnect the archived ones after cleaning up the connections. - if(!A.zone) - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - zone_A = A.zone - return - - //Handle diconnection and reconnection of zones. - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - ConnectZones(A.zone, B.zone, indirect) - zone_A = A.zone - - //The "B" zone changed. - else if(B.zone && B.zone != zone_B) - - //Handle connection cleanup - if(zone_B) - if(zone_B.connections) - zone_B.connections.Remove(src) - if(!zone_B.connections.len) - zone_B.connections = null - - if(B.zone) - if(!B.zone.connections) - B.zone.connections = list() - B.zone.connections |= src - - //If the "B" zone is null, we disconnect the archived ones after cleaning up the connections. - if(!B.zone) - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - zone_B = B.zone - return - - //Handle diconnection and reconnection of zones. - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - ConnectZones(A.zone, B.zone, indirect) - zone_B = B.zone - - -#undef CONNECTION_DIRECT -#undef CONNECTION_INDIRECT -#undef CONNECTION_CLOSED + //world << "valid." \ No newline at end of file diff --git a/code/ZAS/ConnectionGroup.dm b/code/ZAS/ConnectionGroup.dm new file mode 100644 index 0000000000..481492e7e2 --- /dev/null +++ b/code/ZAS/ConnectionGroup.dm @@ -0,0 +1,427 @@ +/* + +Overview: + These are what handle gas transfers between zones and into space. + They are found in a zone's edges list and in air_master.edges. + Each edge updates every air tick due to their role in gas transfer. + They come in two flavors, /connection_edge/zone and /connection_edge/unsimulated. + As the type names might suggest, they handle inter-zone and spacelike connections respectively. + +Class Vars: + + A - This always holds a zone. In unsimulated edges, it holds the only zone. + + connecting_turfs - This holds a list of connected turfs, mainly for the sake of airflow. + + coefficent - This is a marker for how many connections are on this edge. Used to determine the ratio of flow. + + connection_edge/zone + + B - This holds the second zone with which the first zone equalizes. + + direct - This counts the number of direct (i.e. with no doors) connections on this edge. + Any value of this is sufficient to make the zones mergeable. + + connection_edge/unsimulated + + B - This holds an unsimulated turf which has the gas values this edge is mimicing. + + air - Retrieved from B on creation and used as an argument for the legacy ShareSpace() proc. + +Class Procs: + + add_connection(connection/c) + Adds a connection to this edge. Usually increments the coefficient and adds a turf to connecting_turfs. + + remove_connection(connection/c) + Removes a connection from this edge. This works even if c is not in the edge, so be careful. + If the coefficient reaches zero as a result, the edge is erased. + + contains_zone(zone/Z) + Returns true if either A or B is equal to Z. Unsimulated connections return true only on A. + + erase() + Removes this connection from processing and zone edge lists. + + tick() + Called every air tick on edges in the processing list. Equalizes gas. + + flow(list/movable, differential, repelled) + Airflow proc causing all objects in movable to be checked against a pressure differential. + If repelled is true, the objects move away from any turf in connecting_turfs, otherwise they approach. + A check against vsc.lightest_airflow_pressure should generally be performed before calling this. + + get_connected_zone(zone/from) + Helper proc that allows getting the other zone of an edge given one of them. + Only on /connection_edge/zone, otherwise use A. + +*/ + + +/connection_edge/var/zone/A + +/connection_edge/var/list/connecting_turfs = list() + +/connection_edge/var/coefficient = 0 + +/connection_edge/New() + CRASH("Cannot make connection edge without specifications.") + +/connection_edge/proc/add_connection(connection/c) + coefficient++ + //world << "Connection added: [type] Coefficient: [coefficient]" + +/connection_edge/proc/remove_connection(connection/c) + //world << "Connection removed: [type] Coefficient: [coefficient-1]" + coefficient-- + if(coefficient <= 0) + erase() + +/connection_edge/proc/contains_zone(zone/Z) + +/connection_edge/proc/erase() + air_master.remove_edge(src) + //world << "[type] Erased." + +/connection_edge/proc/tick() + +/connection_edge/proc/flow(list/movable, differential, repelled) + for(var/atom/movable/M in movable) + + //If they're already being tossed, don't do it again. + if(M.last_airflow > world.time - vsc.airflow_delay) continue + if(M.airflow_speed) continue + + //Check for knocking people over + if(ismob(M) && differential > vsc.airflow_stun_pressure) + if(M:status_flags & GODMODE) continue + M:airflow_stun() + + if(M.check_airflow_movable(differential)) + //Check for things that are in range of the midpoint turfs. + var/list/close_turfs = list() + for(var/turf/U in connecting_turfs) + if(get_dist(M,U) < world.view) close_turfs += U + if(!close_turfs.len) continue + + M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. + + if(repelled) spawn if(M) M.RepelAirflowDest(differential/5) + else spawn if(M) M.GotoAirflowDest(differential/10) + + + + +/connection_edge/zone/var/zone/B +/connection_edge/zone/var/direct = 0 + +/connection_edge/zone/New(zone/A, zone/B) + + src.A = A + src.B = B + A.edges.Add(src) + B.edges.Add(src) + //id = edge_id(A,B) + //world << "New edge between [A] and [B]" + +/connection_edge/zone/add_connection(connection/c) + . = ..() + connecting_turfs.Add(c.A) + if(c.direct()) direct++ + +/connection_edge/zone/remove_connection(connection/c) + connecting_turfs.Remove(c.A) + if(c.direct()) direct-- + . = ..() + +/connection_edge/zone/contains_zone(zone/Z) + return A == Z || B == Z + +/connection_edge/zone/erase() + A.edges.Remove(src) + B.edges.Remove(src) + . = ..() + +/connection_edge/zone/tick() + if(A.invalid || B.invalid) + erase() + return + //world << "[id]: Tick [air_master.current_cycle]: \..." + if(direct) + if(air_master.equivalent_pressure(A, B)) + //world << "merged." + erase() + air_master.merge(A, B) + //world << "zones merged." + return + + //air_master.equalize(A, B) + ShareRatio(A.air,B.air,coefficient) + air_master.mark_zone_update(A) + air_master.mark_zone_update(B) + //world << "equalized." + + var/differential = A.air.return_pressure() - B.air.return_pressure() + if(abs(differential) < vsc.airflow_lightest_pressure) return + + var/list/attracted + var/list/repelled + if(differential > 0) + attracted = A.movables() + repelled = B.movables() + else + attracted = B.movables() + repelled = A.movables() + + flow(attracted, abs(differential), 0) + flow(repelled, abs(differential), 1) + +//Helper proc to get connections for a zone. +/connection_edge/zone/proc/get_connected_zone(zone/from) + if(A == from) return B + else return A + +/connection_edge/unsimulated/var/turf/B +/connection_edge/unsimulated/var/datum/gas_mixture/air + +/connection_edge/unsimulated/New(zone/A, turf/B) + src.A = A + src.B = B + A.edges.Add(src) + air = B.return_air() + //id = 52*A.id + //world << "New edge from [A] to [B]." + +/connection_edge/unsimulated/add_connection(connection/c) + . = ..() + connecting_turfs.Add(c.B) + air.group_multiplier = coefficient + +/connection_edge/unsimulated/remove_connection(connection/c) + connecting_turfs.Remove(c.B) + air.group_multiplier = coefficient + . = ..() + +/connection_edge/unsimulated/erase() + A.edges.Remove(src) + . = ..() + +/connection_edge/unsimulated/contains_zone(zone/Z) + return A == Z + +/connection_edge/unsimulated/tick() + if(A.invalid) + erase() + return + //world << "[id]: Tick [air_master.current_cycle]: To [B]!" + //A.air.mimic(B, coefficient) + ShareSpace(A.air,air,dbg_out) + air_master.mark_zone_update(A) + + var/differential = A.air.return_pressure() - air.return_pressure() + if(abs(differential) < vsc.airflow_lightest_pressure) return + + var/list/attracted = A.movables() + flow(attracted, abs(differential), differential < 0) + +var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66) + +proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) + //Shares a specific ratio of gas between mixtures using simple weighted averages. + var + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD + ratio = sharing_lookup_table[6] + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD + + size = max(1,A.group_multiplier) + share_size = max(1,B.group_multiplier) + + full_oxy = A.oxygen * size + full_nitro = A.nitrogen * size + full_co2 = A.carbon_dioxide * size + full_phoron = A.phoron * size + + full_heat_capacity = A.heat_capacity() * size + + s_full_oxy = B.oxygen * share_size + s_full_nitro = B.nitrogen * share_size + s_full_co2 = B.carbon_dioxide * share_size + s_full_phoron = B.phoron * share_size + + s_full_heat_capacity = B.heat_capacity() * share_size + + oxy_avg = (full_oxy + s_full_oxy) / (size + share_size) + nit_avg = (full_nitro + s_full_nitro) / (size + share_size) + co2_avg = (full_co2 + s_full_co2) / (size + share_size) + phoron_avg = (full_phoron + s_full_phoron) / (size + share_size) + + temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity) + + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD + if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick. + ratio = sharing_lookup_table[connecting_tiles] + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD + + A.oxygen = max(0, (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg ) + A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1-ratio) + nit_avg ) + A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg ) + A.phoron = max(0, (A.phoron - phoron_avg) * (1-ratio) + phoron_avg ) + + A.temperature = max(0, (A.temperature - temp_avg) * (1-ratio) + temp_avg ) + + B.oxygen = max(0, (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg ) + B.nitrogen = max(0, (B.nitrogen - nit_avg) * (1-ratio) + nit_avg ) + B.carbon_dioxide = max(0, (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg ) + B.phoron = max(0, (B.phoron - phoron_avg) * (1-ratio) + phoron_avg ) + + B.temperature = max(0, (B.temperature - temp_avg) * (1-ratio) + temp_avg ) + + for(var/datum/gas/G in A.trace_gases) + var/datum/gas/H = locate(G.type) in B.trace_gases + if(H) + var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size) + G.moles = (G.moles - G_avg) * (1-ratio) + G_avg + + H.moles = (H.moles - G_avg) * (1-ratio) + G_avg + else + H = new G.type + B.trace_gases += H + var/G_avg = (G.moles*size) / (size+share_size) + G.moles = (G.moles - G_avg) * (1-ratio) + G_avg + H.moles = (H.moles - G_avg) * (1-ratio) + G_avg + + for(var/datum/gas/G in B.trace_gases) + var/datum/gas/H = locate(G.type) in A.trace_gases + if(!H) + H = new G.type + A.trace_gases += H + var/G_avg = (G.moles*size) / (size+share_size) + G.moles = (G.moles - G_avg) * (1-ratio) + G_avg + H.moles = (H.moles - G_avg) * (1-ratio) + G_avg + + A.update_values() + B.update_values() + + if(A.compare(B)) return 1 + else return 0 + +proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) + //A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room. + if(!unsimulated_tiles) + return 0 + + var + unsim_oxygen = 0 + unsim_nitrogen = 0 + unsim_co2 = 0 + unsim_phoron = 0 + unsim_heat_capacity = 0 + unsim_temperature = 0 + + size = max(1,A.group_multiplier) + + var/tileslen + var/share_size + + if(istype(unsimulated_tiles, /datum/gas_mixture)) + var/datum/gas_mixture/avg_unsim = unsimulated_tiles + unsim_oxygen = avg_unsim.oxygen + unsim_co2 = avg_unsim.carbon_dioxide + unsim_nitrogen = avg_unsim.nitrogen + unsim_phoron = avg_unsim.phoron + unsim_temperature = avg_unsim.temperature + share_size = max(1, max(size + 3, 1) + avg_unsim.group_multiplier) + tileslen = avg_unsim.group_multiplier + + if(dbg_output) + world << "O2: [unsim_oxygen] N2: [unsim_nitrogen] Size: [share_size] Tiles: [tileslen]" + + else if(istype(unsimulated_tiles, /list)) + if(!unsimulated_tiles.len) + return 0 + // We use the same size for the potentially single space tile + // as we use for the entire room. Why is this? + // Short answer: We do not want larger rooms to depressurize more + // slowly than small rooms, preserving our good old "hollywood-style" + // oh-shit effect when large rooms get breached, but still having small + // rooms remain pressurized for long enough to make escape possible. + share_size = max(1, max(size + 3, 1) + unsimulated_tiles.len) + var/correction_ratio = share_size / unsimulated_tiles.len + + for(var/turf/T in unsimulated_tiles) + unsim_oxygen += T.oxygen + unsim_co2 += T.carbon_dioxide + unsim_nitrogen += T.nitrogen + unsim_phoron += T.phoron + unsim_temperature += T.temperature/unsimulated_tiles.len + + //These values require adjustment in order to properly represent a room of the specified size. + unsim_oxygen *= correction_ratio + unsim_co2 *= correction_ratio + unsim_nitrogen *= correction_ratio + unsim_phoron *= correction_ratio + tileslen = unsimulated_tiles.len + + else //invalid input type + return 0 + + unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_phoron) + + var + ratio = sharing_lookup_table[6] + + old_pressure = A.return_pressure() + + full_oxy = A.oxygen * size + full_nitro = A.nitrogen * size + full_co2 = A.carbon_dioxide * size + full_phoron = A.phoron * size + + full_heat_capacity = A.heat_capacity() * size + + oxy_avg = (full_oxy + unsim_oxygen*share_size) / (size + share_size) + nit_avg = (full_nitro + unsim_nitrogen*share_size) / (size + share_size) + co2_avg = (full_co2 + unsim_co2*share_size) / (size + share_size) + phoron_avg = (full_phoron + unsim_phoron*share_size) / (size + share_size) + + temp_avg = 0 + + if((full_heat_capacity + unsim_heat_capacity) > 0) + temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity) + + if(sharing_lookup_table.len >= tileslen) //6 or more interconnecting tiles will max at 42% of air moved per tick. + ratio = sharing_lookup_table[tileslen] + + if(dbg_output) + world << "Ratio: [ratio]" + world << "Avg O2: [oxy_avg] N2: [nit_avg]" + + A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg ) + A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg ) + A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg ) + A.phoron = max(0, (A.phoron - phoron_avg) * (1 - ratio) + phoron_avg ) + + A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg ) + + for(var/datum/gas/G in A.trace_gases) + var/G_avg = (G.moles * size) / (size + share_size) + G.moles = (G.moles - G_avg) * (1 - ratio) + G_avg + + A.update_values() + + if(dbg_output) world << "Result: [abs(old_pressure - A.return_pressure())] kPa" + + return abs(old_pressure - A.return_pressure()) + + +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) \ No newline at end of file diff --git a/code/ZAS/ConnectionManager.dm b/code/ZAS/ConnectionManager.dm new file mode 100644 index 0000000000..1c101f4b45 --- /dev/null +++ b/code/ZAS/ConnectionManager.dm @@ -0,0 +1,102 @@ +/* + +Overview: + The connection_manager class stores connections in each cardinal direction on a turf. + It isn't always present if a turf has no connections, check if(connections) before using. + Contains procs for mass manipulation of connection data. + +Class Vars: + + NSEWUD - Connections to this turf in each cardinal direction. + +Class Procs: + + get(d) + Returns the connection (if any) in this direction. + Preferable to accessing the connection directly because it checks validity. + + place(connection/c, d) + Called by air_master.connect(). Sets the connection in the specified direction to c. + + update_all() + Called after turf/update_air_properties(). Updates the validity of all connections on this turf. + + erase_all() + Called when the turf is changed with ChangeTurf(). Erases all existing connections. + + check(connection/c) + Checks for connection validity. It's possible to have a reference to a connection that has been erased. + + +*/ + +/turf/var/tmp/connection_manager/connections + +/connection_manager/var/connection/N +/connection_manager/var/connection/S +/connection_manager/var/connection/E +/connection_manager/var/connection/W + +#ifdef ZLEVELS +/connection_manager/var/connection/U +/connection_manager/var/connection/D +#endif + +/connection_manager/proc/get(d) + switch(d) + if(NORTH) + if(check(N)) return N + else return null + if(SOUTH) + if(check(S)) return S + else return null + if(EAST) + if(check(E)) return E + else return null + if(WEST) + if(check(W)) return W + else return null + + #ifdef ZLEVELS + if(UP) + if(check(U)) return U + else return null + if(DOWN) + if(check(D)) return D + else return null + #endif + +/connection_manager/proc/place(connection/c, d) + switch(d) + if(NORTH) N = c + if(SOUTH) S = c + if(EAST) E = c + if(WEST) W = c + + #ifdef ZLEVELS + if(UP) U = c + if(DOWN) D = c + #endif + +/connection_manager/proc/update_all() + if(check(N)) N.update() + if(check(S)) S.update() + if(check(E)) E.update() + if(check(W)) W.update() + #ifdef ZLEVELS + if(check(U)) U.update() + if(check(D)) D.update() + #endif + +/connection_manager/proc/erase_all() + if(check(N)) N.erase() + if(check(S)) S.erase() + if(check(E)) E.erase() + if(check(W)) W.erase() + #ifdef ZLEVELS + if(check(U)) U.erase() + if(check(D)) D.erase() + #endif + +/connection_manager/proc/check(connection/c) + return c && c.valid() \ No newline at end of file diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm new file mode 100644 index 0000000000..cef6b068a8 --- /dev/null +++ b/code/ZAS/Controller.dm @@ -0,0 +1,321 @@ +var/datum/controller/air_system/air_master + +var/tick_multiplier = 2 + +/* + +Overview: + The air controller does everything. There are tons of procs in here. + +Class Vars: + zones - All zones currently holding one or more turfs. + edges - All processing edges. + + tiles_to_update - Tiles scheduled to update next tick. + zones_to_update - Zones which have had their air changed and need air archival. + active_hotspots - All processing fire objects. + + active_zones - The number of zones which were archived last tick. Used in debug verbs. + next_id - The next UID to be applied to a zone. Mostly useful for debugging purposes as zones do not need UIDs to function. + +Class Procs: + + mark_for_update(turf/T) + Adds the turf to the update list. When updated, update_air_properties() will be called. + When stuff changes that might affect airflow, call this. It's basically the only thing you need. + + add_zone(zone/Z) and remove_zone(zone/Z) + Adds zones to the zones list. Does not mark them for update. + + air_blocked(turf/A, turf/B) + Returns a bitflag consisting of: + AIR_BLOCKED - The connection between turfs is physically blocked. No air can pass. + ZONE_BLOCKED - There is a door between the turfs, so zones cannot cross. Air may or may not be permeable. + + has_valid_zone(turf/T) + Checks the presence and validity of T's zone. + May be called on unsimulated turfs, returning 0. + + merge(zone/A, zone/B) + Called when zones have a direct connection and equivalent pressure and temperature. + Merges the zones to create a single zone. + + connect(turf/simulated/A, turf/B) + Called by turf/update_air_properties(). The first argument must be simulated. + Creates a connection between A and B. + + mark_zone_update(zone/Z) + Adds zone to the update list. Unlike mark_for_update(), this one is called automatically whenever + air is returned from a simulated turf. + + equivalent_pressure(zone/A, zone/B) + Currently identical to A.air.compare(B.air). Returns 1 when directly connected zones are ready to be merged. + + get_edge(zone/A, zone/B) + get_edge(zone/A, turf/B) + Gets a valid connection_edge between A and B, creating a new one if necessary. + + has_same_air(turf/A, turf/B) + Used to determine if an unsimulated edge represents a specific turf. + Simulated edges use connection_edge/contains_zone() for the same purpose. + Returns 1 if A has identical gases and temperature to B. + + remove_edge(connection_edge/edge) + Called when an edge is erased. Removes it from processing. + +*/ + + +//Geometry lists +/datum/controller/air_system/var/list/zones = list() +/datum/controller/air_system/var/list/edges = list() + +//Geometry updates lists +/datum/controller/air_system/var/list/tiles_to_update = list() +/datum/controller/air_system/var/list/zones_to_update = list() +/datum/controller/air_system/var/list/active_hotspots = list() + +/datum/controller/air_system/var/active_zones = 0 + +/datum/controller/air_system/var/current_cycle = 0 +/datum/controller/air_system/var/update_delay = 5 //How long between check should it try to process atmos again. +/datum/controller/air_system/var/failed_ticks = 0 //How many ticks have runtimed? + +/datum/controller/air_system/var/tick_progress = 0 + +/datum/controller/air_system/var/next_id = 1 //Used to keep track of zone UIDs. + +/datum/controller/air_system/proc/Setup() + //Purpose: Call this at the start to setup air groups geometry + // (Warning: Very processor intensive but only must be done once per round) + //Called by: Gameticker/Master controller + //Inputs: None. + //Outputs: None. + + #ifndef ZASDBG + set background = 1 + #endif + + world << "\red \b Processing Geometry..." + sleep(-1) + + var/start_time = world.timeofday + + var/simulated_turf_count = 0 + + for(var/turf/simulated/S in world) + simulated_turf_count++ + S.update_air_properties() + + world << {"Geometry initialized in [round(0.1*(world.timeofday-start_time),0.1)] seconds. +Total Simulated Turfs: [simulated_turf_count] +Total Zones: [zones.len] +Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count]"} + +// spawn Start() + + +/datum/controller/air_system/proc/Start() + //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere. + //Called by: Master controller + //Inputs: None. + //Outputs: None. + + #ifndef ZASDBG + set background = 1 + #endif + + while(1) + Tick() + sleep(max(5,update_delay*tick_multiplier)) + + +/datum/controller/air_system/proc/Tick() + . = 1 //Set the default return value, for runtime detection. + + current_cycle++ + + //If there are tiles to update, do so. + tick_progress = "updating turf properties" + + var/list/updating + + if(tiles_to_update.len) + updating = tiles_to_update + tiles_to_update = list() + + #ifdef ZASDBG + var/updated = 0 + #endif + for(var/turf/T in updating) + T.update_air_properties() + T.post_update_air_properties() + T.needs_air_update = 0 + #ifdef ZASDBG + T.overlays -= mark + updated++ + #endif + //sleep(1) + + #ifdef ZASDBG + if(updated != updating.len) + tick_progress = "[updating.len - updated] tiles left unupdated." + world << "\red [tick_progress]" + . = 0 + #endif + + //Where gas exchange happens. + if(.) + tick_progress = "processing edges" + + for(var/connection_edge/edge in edges) + edge.tick() + + //Process fires. + if(.) + tick_progress = "processing fire" + + for(var/obj/fire/fire in active_hotspots) + fire.process() + + //Process zones. + if(.) + tick_progress = "updating zones" + + active_zones = zones_to_update.len + if(zones_to_update.len) + updating = zones_to_update + zones_to_update = list() + for(var/zone/zone in updating) + zone.tick() + zone.needs_update = 0 + + if(.) + tick_progress = "success" + +/datum/controller/air_system/proc/add_zone(zone/z) + zones.Add(z) + z.name = "Zone [next_id++]" + mark_zone_update(z) + +/datum/controller/air_system/proc/remove_zone(zone/z) + zones.Remove(z) + +/datum/controller/air_system/proc/air_blocked(turf/A, turf/B) + #ifdef ZASDBG + ASSERT(isturf(A)) + ASSERT(isturf(B)) + #endif + var/ablock = A.c_airblock(B) + if(ablock == BLOCKED) return BLOCKED + return ablock | B.c_airblock(A) + +/datum/controller/air_system/proc/has_valid_zone(turf/simulated/T) + #ifdef ZASDBG + ASSERT(istype(T)) + #endif + return istype(T) && T.zone && !T.zone.invalid + +/datum/controller/air_system/proc/merge(zone/A, zone/B) + #ifdef ZASDBG + ASSERT(istype(A)) + ASSERT(istype(B)) + ASSERT(!A.invalid) + ASSERT(!B.invalid) + ASSERT(A != B) + #endif + if(A.contents.len < B.contents.len) + A.c_merge(B) + mark_zone_update(B) + else + B.c_merge(A) + mark_zone_update(A) + +/datum/controller/air_system/proc/connect(turf/simulated/A, turf/simulated/B) + #ifdef ZASDBG + ASSERT(istype(A)) + ASSERT(isturf(B)) + ASSERT(A.zone) + ASSERT(!A.zone.invalid) + //ASSERT(B.zone) + ASSERT(A != B) + #endif + + var/block = air_master.air_blocked(A,B) + if(block & AIR_BLOCKED) return + + var/direct = !(block & ZONE_BLOCKED) + var/space = !istype(B) + + if(direct && !space) + if(equivalent_pressure(A.zone,B.zone) || current_cycle == 0) + merge(A.zone,B.zone) + return + + var + a_to_b = get_dir(A,B) + b_to_a = get_dir(B,A) + + if(!A.connections) A.connections = new + if(!B.connections) B.connections = new + + if(A.connections.get(a_to_b)) return + if(B.connections.get(b_to_a)) return + if(!space) + if(A.zone == B.zone) return + + + var/connection/c = new /connection(A,B) + + A.connections.place(c, a_to_b) + B.connections.place(c, b_to_a) + + if(direct) c.mark_direct() + +/datum/controller/air_system/proc/mark_for_update(turf/T) + #ifdef ZASDBG + ASSERT(isturf(T)) + #endif + if(T.needs_air_update) return + tiles_to_update |= T + #ifdef ZASDBG + T.overlays += mark + #endif + T.needs_air_update = 1 + +/datum/controller/air_system/proc/mark_zone_update(zone/Z) + #ifdef ZASDBG + ASSERT(istype(Z)) + #endif + if(Z.needs_update) return + zones_to_update.Add(Z) + Z.needs_update = 1 + +/datum/controller/air_system/proc/equivalent_pressure(zone/A, zone/B) + return A.air.compare(B.air) + +/datum/controller/air_system/proc/get_edge(zone/A, zone/B) + + if(istype(B)) + for(var/connection_edge/zone/edge in A.edges) + if(edge.contains_zone(B)) return edge + var/connection_edge/edge = new/connection_edge/zone(A,B) + edges.Add(edge) + return edge + else + for(var/connection_edge/unsimulated/edge in A.edges) + if(has_same_air(edge.B,B)) return edge + var/connection_edge/edge = new/connection_edge/unsimulated(A,B) + edges.Add(edge) + return edge + +/datum/controller/air_system/proc/has_same_air(turf/A, turf/B) + if(A.oxygen != B.oxygen) return 0 + if(A.nitrogen != B.nitrogen) return 0 + if(A.phoron != B.phoron) return 0 + if(A.carbon_dioxide != B.carbon_dioxide) return 0 + if(A.temperature != B.temperature) return 0 + return 1 + +/datum/controller/air_system/proc/remove_edge(connection/c) + edges.Remove(c) \ No newline at end of file diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm index 5ac704cf9f..6f0a67fd3e 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -1,213 +1,20 @@ -client/proc/ZoneTick() - set category = "Debug" - set name = "Process Atmos" +var/image/assigned = image('icons/Testing/Zone.dmi', icon_state = "assigned") +var/image/created = image('icons/Testing/Zone.dmi', icon_state = "created") +var/image/merged = image('icons/Testing/Zone.dmi', icon_state = "merged") +var/image/invalid_zone = image('icons/Testing/Zone.dmi', icon_state = "invalid") +var/image/air_blocked = image('icons/Testing/Zone.dmi', icon_state = "block") +var/image/zone_blocked = image('icons/Testing/Zone.dmi', icon_state = "zoneblock") +var/image/blocked = image('icons/Testing/Zone.dmi', icon_state = "fullblock") +var/image/mark = image('icons/Testing/Zone.dmi', icon_state = "mark") - var/result = air_master.Tick() - if(result) - src << "Sucessfully Processed." +/connection_edge/var/dbg_out = 0 - else - src << "Failed to process! ([air_master.tick_progress])" +/turf/var/tmp/dbg_img +/turf/proc/dbg(image/img, d = 0) + if(d > 0) img.dir = d + overlays -= dbg_img + overlays += img + dbg_img = img - -client/proc/Zone_Info(turf/T as null|turf) - set category = "Debug" - if(T) - if(T.zone) - T.zone.DebugDisplay(src) - else - mob << "No zone here." - else - if(zone_debug_images) - for(var/zone in zone_debug_images) - images -= zone_debug_images[zone] - zone_debug_images = null - -client/var/list/zone_debug_images - -client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf) - set category = "Debug" - if(!istype(T)) - return - - var/direction_list = list(\ - "North" = NORTH,\ - "South" = SOUTH,\ - "East" = EAST,\ - "West" = WEST,\ - "N/A" = null) - var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list - if(!direction) - return - - if(direction == "N/A") - if(T.CanPass(null, T, 0,0)) - mob << "The turf can pass air! :D" - else - mob << "No air passage :x" - return - - var/turf/simulated/other_turf = get_step(T, direction_list[direction]) - if(!istype(other_turf)) - return - - var/pass_directions = T.CanPass(null, other_turf, 0, 0) + 2 * other_turf.CanPass(null, T, 0, 0) - - switch(pass_directions) - if(0) - mob << "Neither turf can connect. :(" - - if(1) - mob << "The initial turf only can connect. :\\" - - if(2) - mob << "The other turf can connect, but not the initial turf. :/" - - if(3) - mob << "Both turfs can connect! :)" - - -zone/proc/DebugDisplay(client/client) - if(!istype(client)) - return - - if(!dbg_output) - dbg_output = 1 //Don't want to be spammed when someone investigates a zone... - - if(!client.zone_debug_images) - client.zone_debug_images = list() - - var/list/current_zone_images = list() - - for(var/turf/T in contents) - current_zone_images += image('icons/misc/debug_group.dmi', T, null, TURF_LAYER) - - for(var/turf/space/S in unsimulated_tiles) - current_zone_images += image('icons/misc/debug_space.dmi', S, null, TURF_LAYER) - - client << "Zone Air Contents" - client << "Oxygen: [air.oxygen]" - client << "Nitrogen: [air.nitrogen]" - client << "Plasma: [air.toxins]" - client << "Carbon Dioxide: [air.carbon_dioxide]" - client << "Temperature: [air.temperature] K" - client << "Heat Energy: [air.temperature * air.heat_capacity()] J" - client << "Pressure: [air.return_pressure()] KPa" - client << "" - client << "Space Tiles: [length(unsimulated_tiles)]" - client << "Movable Objects: [length(movables())]" - client << "Connections: [length(connections)]" - - for(var/connection/C in connections) - client << "\ref[C] [C.A] --> [C.B] [(C.indirect?"Open":"Closed")]" - current_zone_images += image('icons/misc/debug_connect.dmi', C.A, null, TURF_LAYER) - current_zone_images += image('icons/misc/debug_connect.dmi', C.B, null, TURF_LAYER) - - client << "Connected Zones:" - for(var/zone/zone in connected_zones) - client << "\ref[zone] [zone] - [connected_zones[zone]] (Connected)" - - for(var/zone/zone in closed_connection_zones) - client << "\ref[zone] [zone] - [closed_connection_zones[zone]] (Unconnected)" - - for(var/C in connections) - if(!istype(C,/connection)) - client << "[C] (Not Connection!)" - - if(!client.zone_debug_images) - client.zone_debug_images = list() - client.zone_debug_images[src] = current_zone_images - - client.images += client.zone_debug_images[src] - - else - dbg_output = 0 - - client.images -= client.zone_debug_images[src] - client.zone_debug_images.Remove(src) - - if(air_master) - for(var/zone/Z in air_master.zones) - if(Z.air == air && Z != src) - var/turf/zloc = pick(Z.contents) - client << "\red Illegal air datum shared by: [zloc.loc.name]" - - -client/proc/TestZASRebuild() -// var/turf/turf = get_turf(mob) - var/zone/current_zone = mob.loc:zone - if(!current_zone) - src << "There is no zone there!" - return - - var/list/current_adjacents = list() - var/list/overlays = list() - var/adjacent_id - var/lowest_id - - var/list/identical_ids = list() - var/list/turfs = current_zone.contents.Copy() - var/current_identifier = 1 - - for(var/turf/simulated/current in turfs) - lowest_id = null - current_adjacents = list() - - for(var/direction in cardinal) - var/turf/simulated/adjacent = get_step(current, direction) - if(!current.ZAirPass(adjacent)) - continue - if(turfs.Find(adjacent)) - current_adjacents += adjacent - adjacent_id = turfs[adjacent] - - if(adjacent_id && (!lowest_id || adjacent_id < lowest_id)) - lowest_id = adjacent_id - - if(!lowest_id) - lowest_id = current_identifier++ - identical_ids += lowest_id - overlays += image('icons/misc/debug_rebuild.dmi',, "[lowest_id]") - - for(var/turf/simulated/adjacent in current_adjacents) - adjacent_id = turfs[adjacent] - if(adjacent_id != lowest_id) - if(adjacent_id) - adjacent.overlays -= overlays[adjacent_id] - identical_ids[adjacent_id] = lowest_id - - turfs[adjacent] = lowest_id - adjacent.overlays += overlays[lowest_id] - - sleep(5) - - if(turfs[current]) - current.overlays -= overlays[turfs[current]] - turfs[current] = lowest_id - current.overlays += overlays[lowest_id] - sleep(5) - - var/list/final_arrangement = list() - - for(var/turf/simulated/current in turfs) - current_identifier = identical_ids[turfs[current]] - current.overlays -= overlays[turfs[current]] - current.overlays += overlays[current_identifier] - sleep(5) - - if( current_identifier > final_arrangement.len ) - final_arrangement.len = current_identifier - final_arrangement[current_identifier] = list(current) - - else - final_arrangement[current_identifier] += current - - //lazy but fast - final_arrangement.Remove(null) - - src << "There are [final_arrangement.len] unique segments." - - for(var/turf/current in turfs) - current.overlays -= overlays - - return final_arrangement \ No newline at end of file +proc/soft_assert(thing,fail) + if(!thing) message_admins(fail) \ No newline at end of file diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm new file mode 100644 index 0000000000..31deb69bc5 --- /dev/null +++ b/code/ZAS/Diagnostic.dm @@ -0,0 +1,236 @@ +client/proc/ZoneTick() + set category = "Debug" + set name = "Process Atmos" + + var/result = air_master.Tick() + if(result) + src << "Sucessfully Processed." + + else + src << "Failed to process! ([air_master.tick_progress])" + + +client/proc/Zone_Info(turf/T as null|turf) + set category = "Debug" + if(T) + if(istype(T,/turf/simulated) && T:zone) + T:zone:dbg_data(src) + else + mob << "No zone here." + var/datum/gas_mixture/mix = T.return_air() + mob << "[mix.return_pressure()] kPa [mix.temperature]C" + mob << "O2: [mix.oxygen] N2: [mix.nitrogen] CO2: [mix.carbon_dioxide] TX: [mix.phoron]" + else + if(zone_debug_images) + for(var/zone in zone_debug_images) + images -= zone_debug_images[zone] + zone_debug_images = null + +client/var/list/zone_debug_images + +client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf) + set category = "Debug" + if(!istype(T)) + return + + var/direction_list = list(\ + "North" = NORTH,\ + "South" = SOUTH,\ + "East" = EAST,\ + "West" = WEST,\ + "N/A" = null) + var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list + if(!direction) + return + + if(direction == "N/A") + if(!(T.c_airblock(T) & AIR_BLOCKED)) + mob << "The turf can pass air! :D" + else + mob << "No air passage :x" + return + + var/turf/simulated/other_turf = get_step(T, direction_list[direction]) + if(!istype(other_turf)) + return + + var/t_block = T.c_airblock(other_turf) + var/o_block = other_turf.c_airblock(T) + + if(o_block & AIR_BLOCKED) + if(t_block & AIR_BLOCKED) + mob << "Neither turf can connect. :(" + + else + mob << "The initial turf only can connect. :\\" + else + if(t_block & AIR_BLOCKED) + mob << "The other turf can connect, but not the initial turf. :/" + + else + mob << "Both turfs can connect! :)" + + mob << "Additionally, \..." + + if(o_block & ZONE_BLOCKED) + if(t_block & ZONE_BLOCKED) + mob << "neither turf can merge." + else + mob << "the other turf cannot merge." + else + if(t_block & ZONE_BLOCKED) + mob << "the initial turf cannot merge." + else + mob << "both turfs can merge." + + +/*zone/proc/DebugDisplay(client/client) + if(!istype(client)) + return + + if(!dbg_output) + dbg_output = 1 //Don't want to be spammed when someone investigates a zone... + + if(!client.zone_debug_images) + client.zone_debug_images = list() + + var/list/current_zone_images = list() + + for(var/turf/T in contents) + current_zone_images += image('icons/misc/debug_group.dmi', T, null, TURF_LAYER) + + for(var/turf/space/S in unsimulated_tiles) + current_zone_images += image('icons/misc/debug_space.dmi', S, null, TURF_LAYER) + + client << "Zone Air Contents" + client << "Oxygen: [air.oxygen]" + client << "Nitrogen: [air.nitrogen]" + client << "Phoron: [air.phoron]" + client << "Carbon Dioxide: [air.carbon_dioxide]" + client << "Temperature: [air.temperature] K" + client << "Heat Energy: [air.temperature * air.heat_capacity()] J" + client << "Pressure: [air.return_pressure()] KPa" + client << "" + client << "Space Tiles: [length(unsimulated_tiles)]" + client << "Movable Objects: [length(movables())]" + client << "Connections: [length(connections)]" + + for(var/connection/C in connections) + client << "\ref[C] [C.A] --> [C.B] [(C.indirect?"Open":"Closed")]" + current_zone_images += image('icons/misc/debug_connect.dmi', C.A, null, TURF_LAYER) + current_zone_images += image('icons/misc/debug_connect.dmi', C.B, null, TURF_LAYER) + + client << "Connected Zones:" + for(var/zone/zone in connected_zones) + client << "\ref[zone] [zone] - [connected_zones[zone]] (Connected)" + + for(var/zone/zone in closed_connection_zones) + client << "\ref[zone] [zone] - [closed_connection_zones[zone]] (Unconnected)" + + for(var/C in connections) + if(!istype(C,/connection)) + client << "[C] (Not Connection!)" + + if(!client.zone_debug_images) + client.zone_debug_images = list() + client.zone_debug_images[src] = current_zone_images + + client.images += client.zone_debug_images[src] + + else + dbg_output = 0 + + client.images -= client.zone_debug_images[src] + client.zone_debug_images.Remove(src) + + if(air_master) + for(var/zone/Z in air_master.zones) + if(Z.air == air && Z != src) + var/turf/zloc = pick(Z.contents) + client << "\red Illegal air datum shared by: [zloc.loc.name]"*/ + + +/*client/proc/TestZASRebuild() + set category = "Debug" +// var/turf/turf = get_turf(mob) + var/zone/current_zone = mob.loc:zone + if(!current_zone) + src << "There is no zone there!" + return + + var/list/current_adjacents = list() + var/list/overlays = list() + var/adjacent_id + var/lowest_id + + var/list/identical_ids = list() + var/list/turfs = current_zone.contents.Copy() + var/current_identifier = 1 + + for(var/turf/simulated/current in turfs) + lowest_id = null + current_adjacents = list() + + for(var/direction in cardinal) + var/turf/simulated/adjacent = get_step(current, direction) + if(!current.ZCanPass(adjacent)) + continue + if(turfs.Find(adjacent)) + current_adjacents += adjacent + adjacent_id = turfs[adjacent] + + if(adjacent_id && (!lowest_id || adjacent_id < lowest_id)) + lowest_id = adjacent_id + + if(!lowest_id) + lowest_id = current_identifier++ + identical_ids += lowest_id + overlays += image('icons/misc/debug_rebuild.dmi',, "[lowest_id]") + + for(var/turf/simulated/adjacent in current_adjacents) + adjacent_id = turfs[adjacent] + if(adjacent_id != lowest_id) + if(adjacent_id) + adjacent.overlays -= overlays[adjacent_id] + identical_ids[adjacent_id] = lowest_id + + turfs[adjacent] = lowest_id + adjacent.overlays += overlays[lowest_id] + + sleep(5) + + if(turfs[current]) + current.overlays -= overlays[turfs[current]] + turfs[current] = lowest_id + current.overlays += overlays[lowest_id] + sleep(5) + + var/list/final_arrangement = list() + + for(var/turf/simulated/current in turfs) + current_identifier = identical_ids[turfs[current]] + current.overlays -= overlays[turfs[current]] + current.overlays += overlays[current_identifier] + sleep(5) + + if( current_identifier > final_arrangement.len ) + final_arrangement.len = current_identifier + final_arrangement[current_identifier] = list(current) + + else + final_arrangement[current_identifier] += current + + //lazy but fast + final_arrangement.Remove(null) + + src << "There are [final_arrangement.len] unique segments." + + for(var/turf/current in turfs) + current.overlays -= overlays + + return final_arrangement*/ + +client/proc/ZASSettings() + set category = "Debug" + + vsc.SetDefault(mob) \ No newline at end of file diff --git a/code/ZAS/FEA_system.dm b/code/ZAS/FEA_system.dm deleted file mode 100644 index 5a386d5959..0000000000 --- a/code/ZAS/FEA_system.dm +++ /dev/null @@ -1,356 +0,0 @@ -/* -Overview: - The air_master global variable is the workhorse for the system. - -Why are you archiving data before modifying it? - The general concept with archiving data and having each tile keep track of when they were last updated is to keep everything symmetric - and totally independent of the order they are read in an update cycle. - This prevents abnormalities like air/fire spreading rapidly in one direction and super slowly in the other. - -Why not just archive everything and then calculate? - Efficiency. While a for-loop that goes through all tils and groups to archive their information before doing any calculations seems simple, it is - slightly less efficient than the archive-before-modify/read method. - -Why is there a cycle check for calculating data as well? - This ensures that every connection between group-tile, tile-tile, and group-group is only evaluated once per loop. - - - - -Important variables: - air_master.groups_to_rebuild (list) - A list of air groups that have had their geometry occluded and thus may need to be split in half. - A set of adjacent groups put in here will join together if validly connected. - This is done before air system calculations for a cycle. - air_master.tiles_to_update (list) - Turfs that are in this list have their border data updated before the next air calculations for a cycle. - Place turfs in this list rather than call the proc directly to prevent race conditions - - turf/simulated.archive() and datum/air_group.archive() - This stores all data for. - If you modify, make sure to update the archived_cycle to prevent race conditions and maintain symmetry - - atom/CanPass(atom/movable/mover, turf/target, height, air_group) - returns 1 for allow pass and 0 for deny pass - Turfs automatically call this for all objects/mobs in its turf. - This is called both as source.CanPass(target, height, air_group) - and target.CanPass(source, height, air_group) - - Cases for the parameters - 1. This is called with args (mover, location, height>0, air_group=0) for normal objects. - 2. This is called with args (null, location, height=0, air_group=0) for flowing air. - 3. This is called with args (null, location, height=?, air_group=1) for determining group boundaries. - - Cases 2 and 3 would be different for doors or other objects open and close fairly often. - (Case 3 would return 0 always while Case 2 would return 0 only when the door is open) - This prevents the necessity of re-evaluating group geometry every time a door opens/closes. - - -Important Procedures - air_master.process() - This first processes the air_master update/rebuild lists then processes all groups and tiles for air calculations - -*/ - -var/tick_multiplier = 2 - -atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) - //Purpose: Determines if the object (or airflow) can pass this atom. - //Called by: Movement, airflow. - //Inputs: The moving atom (optional), target turf, "height" and air group - //Outputs: Boolean if can pass. - - return (!density || !height || air_group) - -/turf/CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0) - if(!target) return 0 - - if(istype(mover)) // turf/Enter(...) will perform more advanced checks - return !density - - else // Now, doing more detailed checks for air movement and air group formation - if(target.blocks_air||blocks_air) - return 0 - - for(var/obj/obstacle in src) - if(!obstacle.CanPass(mover, target, height, air_group)) - return 0 - if(target != src) - for(var/obj/obstacle in target) - if(!obstacle.CanPass(mover, src, height, air_group)) - return 0 - - return 1 - - -var/datum/controller/air_system/air_master - -/datum/controller/air_system - //Geometry lists - var/list/turfs_with_connections = list() - var/list/active_hotspots = list() - - //Special functions lists - var/reconsidering_zones = FALSE - var/list/tiles_to_reconsider_zones = list() - var/list/tiles_to_reconsider_alternate - - //Geometry updates lists - var/updating_tiles = FALSE - var/list/tiles_to_update = list() - var/list/tiles_to_update_alternate - - var/checking_connections = FALSE - var/list/connections_to_check = list() - var/list/connections_to_check_alternate - - var/list/potential_intrazone_connections = list() - - //Zone lists - var/list/active_zones = list() - var/list/zones_needing_rebuilt = list() - var/list/zones = list() - - - var/current_cycle = 0 - var/update_delay = 5 //How long between check should it try to process atmos again. - var/failed_ticks = 0 //How many ticks have runtimed? - - var/tick_progress = 0 - - -/datum/controller/air_system/proc/Setup() - //Purpose: Call this at the start to setup air groups geometry - // (Warning: Very processor intensive but only must be done once per round) - //Called by: Gameticker/Master controller - //Inputs: None. - //Outputs: None. - - set background = 1 - world << "\red \b Processing Geometry..." - sleep(-1) - - var/start_time = world.timeofday - - var/simulated_turf_count = 0 - - for(var/turf/simulated/S in world) - simulated_turf_count++ - if(!S.zone && !S.blocks_air) - if(S.CanPass(null, S, 0, 0)) - new/zone(S) - - for(var/turf/simulated/S in world) - S.update_air_properties() - - world << {"Geometry initialized in [round(0.1*(world.timeofday-start_time),0.1)] seconds. -Total Simulated Turfs: [simulated_turf_count] -Total Zones: [zones.len] -Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count]"} - -// spawn Start() - - -/datum/controller/air_system/proc/Start() - //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere. - //Called by: Master controller - //Inputs: None. - //Outputs: None. - - - set background = 1 - - while(1) - if(!air_processing_killed) - var/success = Tick() //Changed so that a runtime does not crash the ticker. - if(!success) //Runtimed. - failed_ticks++ - if(failed_ticks > 20) - world << "ERROR IN ATMOS TICKER. Killing air simulation!" - air_processing_killed = 1 - sleep(max(5,update_delay*tick_multiplier)) - - -/datum/controller/air_system/proc/Tick() - . = 1 //Set the default return value, for runtime detection. - - current_cycle++ - - //If there are tiles to update, do so. - tick_progress = "updating turf properties" - if(tiles_to_update.len) - updating_tiles = TRUE - - for(var/turf/simulated/T in tiles_to_update) - if(. && T && !T.update_air_properties()) - //If a runtime occured, make sure we can sense it. - . = 0 - - updating_tiles = FALSE - - if(.) - if(tiles_to_update_alternate) - tiles_to_update = tiles_to_update_alternate - tiles_to_update_alternate = null - else - tiles_to_update = list() - - else if(tiles_to_update_alternate) - tiles_to_update |= tiles_to_update_alternate - tiles_to_update_alternate = null - - //Rebuild zones. - if(.) - tick_progress = "rebuilding zones" - if(zones_needing_rebuilt.len) - for(var/zone/zone in zones_needing_rebuilt) - zone.Rebuild() - - zones_needing_rebuilt = list() - - //Check sanity on connection objects. - if(.) - tick_progress = "checking/creating connections" - if(connections_to_check.len) - checking_connections = TRUE - - for(var/connection/C in connections_to_check) - C.Cleanup() - - for(var/turf/simulated/turf_1 in potential_intrazone_connections) - for(var/turf/simulated/turf_2 in potential_intrazone_connections[turf_1]) - - if(!turf_1.zone || !turf_2.zone) - continue - - if(turf_1.zone == turf_2.zone) - continue - - var/should_skip = FALSE - if(turf_1 in air_master.turfs_with_connections) - - for(var/connection/C in turfs_with_connections[turf_1]) - if(C.B == turf_2 || C.A == turf_2) - should_skip = TRUE - break - if(should_skip) - continue - - new /connection(turf_1, turf_2) - - checking_connections = FALSE - - potential_intrazone_connections = list() - - if(connections_to_check_alternate) - connections_to_check = connections_to_check_alternate - connections_to_check_alternate = null - else - connections_to_check = list() - - //Process zones. - if(.) - tick_progress = "processing zones" - for(var/zone/Z in active_zones) - if(Z.last_update < current_cycle) - var/output = Z.process() - if(Z) - Z.last_update = current_cycle - if(. && Z && !output) - . = 0 - - //Ensure tiles still have zones. - if(.) - tick_progress = "reconsidering zones on turfs" - if(tiles_to_reconsider_zones.len) - reconsidering_zones = TRUE - - for(var/turf/simulated/T in tiles_to_reconsider_zones) - if(!T.zone) - new /zone(T) - - reconsidering_zones = FALSE - - if(tiles_to_reconsider_alternate) - tiles_to_reconsider_zones = tiles_to_reconsider_alternate - tiles_to_reconsider_alternate = null - else - tiles_to_reconsider_zones = list() - - //Process fires. - if(.) - tick_progress = "processing fire" - for(var/obj/fire/F in active_hotspots) - if(. && F && !F.process()) - . = 0 - - if(.) - tick_progress = "success" - - -/datum/controller/air_system/proc/AddTurfToUpdate(turf/simulated/outdated_turf) - var/list/tiles_to_check = list() - - if(istype(outdated_turf)) - tiles_to_check |= outdated_turf - - if(istype(outdated_turf, /turf)) - for(var/direction in cardinal) - var/turf/simulated/adjacent_turf = get_step(outdated_turf, direction) - if(istype(adjacent_turf)) - tiles_to_check |= adjacent_turf - - if(updating_tiles) - if(!tiles_to_update_alternate) - tiles_to_update_alternate = tiles_to_check - else - tiles_to_update_alternate |= tiles_to_check - else - tiles_to_update |= tiles_to_check - - -/datum/controller/air_system/proc/AddConnectionToCheck(connection/connection) - if(checking_connections) - if(istype(connection, /list)) - if(!connections_to_check_alternate) - connections_to_check_alternate = connection - - else if(!connections_to_check_alternate) - connections_to_check_alternate = list() - - connections_to_check_alternate |= connection - - else - connections_to_check |= connection - - -/datum/controller/air_system/proc/ReconsiderTileZone(var/turf/simulated/zoneless_turf) - if(zoneless_turf.zone) - return - - if(reconsidering_zones) - if(!tiles_to_reconsider_alternate) - tiles_to_reconsider_alternate = list() - - tiles_to_reconsider_alternate |= zoneless_turf - - else - tiles_to_reconsider_zones |= zoneless_turf - - -/datum/controller/air_system/proc/AddIntrazoneConnection(var/turf/simulated/A, var/turf/simulated/B) - if(!istype(A) || !istype(B)) - return - - if(A in potential_intrazone_connections) - if(B in potential_intrazone_connections[A]) - return - - if (B in potential_intrazone_connections) - if(A in potential_intrazone_connections[B]) - return - - potential_intrazone_connections[B] += A - - else - potential_intrazone_connections[B] = list(A) \ No newline at end of file diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index a40746f52f..8b692c5b13 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -3,8 +3,8 @@ Making Bombs with ZAS: Make burny fire with lots of burning Draw off 5000K gas from burny fire -Separate gas into oxygen and plasma components -Obtain plasma and oxygen tanks filled up about 50-75% with normal-temp gas +Separate gas into oxygen and phoron components +Obtain phoron and oxygen tanks filled up about 50-75% with normal-temp gas Fill rest with super hot gas from separated canisters, they should be about 125C now. Attach to transfer valve and open. BOOM. @@ -25,7 +25,7 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) if(locate(/obj/fire) in src) return 1 var/datum/gas_mixture/air_contents = return_air() - if(!air_contents || exposed_temperature < PLASMA_MINIMUM_BURN_TEMPERATURE) + if(!air_contents || exposed_temperature < PHORON_MINIMUM_BURN_TEMPERATURE) return 0 var/igniting = 0 @@ -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) - air_contents.toxins = 0 + if(air_contents.phoron < 0.1) + air_contents.phoron = 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 @@ -108,7 +108,7 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume()) //spread for(var/direction in cardinal) - if(S.air_check_directions&direction) //Grab all valid bordering tiles + if(S.open_directions & direction) //Grab all valid bordering tiles var/turf/simulated/enemy_tile = get_step(S, direction) @@ -139,7 +139,7 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) //Ensure flow temperature is higher than minimum fire temperatures. //this creates some energy ex nihilo but is necessary to get a fire started //lets just pretend this energy comes from the ignition source and dont mention this again - //flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) + //flow.temperature = max(PHORON_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) //burn baby burn! @@ -188,11 +188,11 @@ turf/simulated/apply_fire_protection() datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn) var/value = 0 - if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid)) + if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid)) var/total_fuel = 0 var/datum/gas/volatile_fuel/fuel = locate() in trace_gases - total_fuel += toxins + total_fuel += phoron if(fuel) //Volatile Fuel @@ -200,11 +200,14 @@ 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 + if(total_fuel == 0) + return 0 + //Calculate the firelevel. var/firelevel = calculate_firelevel(liquid) @@ -227,9 +230,9 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc //remove and add gasses as calculated oxygen -= min(oxygen, total_oxygen * used_reactants_ratio ) - toxins -= min(toxins, (toxins * used_fuel_ratio * used_reactants_ratio ) * 3) - if(toxins < 0) - toxins = 0 + phoron -= min(phoron, (phoron * used_fuel_ratio * used_reactants_ratio ) * 3) + if(phoron < 0) + phoron = 0 carbon_dioxide += max(2 * total_fuel, 0) @@ -254,12 +257,12 @@ datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_ var/datum/gas/volatile_fuel/fuel = locate() in trace_gases - if(oxygen && (toxins || fuel || liquid)) + if(oxygen && (phoron || fuel || liquid)) if(liquid) return 1 - if (toxins) + if(phoron >= 0.1) return 1 - if(fuel) + if(fuel && fuel.moles >= 0.1) return 1 return 0 @@ -269,12 +272,12 @@ datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fu var/datum/gas/volatile_fuel/fuel = locate() in trace_gases - if(oxygen && (toxins || fuel || liquid)) + if(oxygen && (phoron || fuel || liquid)) if(liquid) return 1 - if (toxins >= 0.7) + if (phoron >= 0.1) return 1 - if(fuel && fuel.moles >= 1.4) + if(fuel && fuel.moles >= 0.1) return 1 return 0 @@ -288,7 +291,7 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue if(check_recombustability(liquid)) - total_fuel += toxins + total_fuel += phoron if(liquid) total_fuel += liquid.amount diff --git a/code/ZAS/Functions.dm b/code/ZAS/Functions.dm deleted file mode 100644 index 3037e13f41..0000000000 --- a/code/ZAS/Functions.dm +++ /dev/null @@ -1,172 +0,0 @@ -//Global Functions -//Contents: FloodFill, ZMerge, ZConnect - -//Floods outward from an initial turf to fill everywhere it's zone would reach. -proc/FloodFill(turf/simulated/start) - - if(!istype(start)) - return list() - - //The list of tiles waiting to be evaulated. - var/list/open = list(start) - //The list of tiles which have been evaulated. - var/list/closed = list() - - //Loop through the turfs in the open list in order to find which adjacent turfs should be added to the zone. - while(open.len) - var/turf/simulated/T = pick(open) - - //sanity! - if(!istype(T)) - open -= T - continue - - //Check all cardinal directions - for(var/d in cardinal) - var/turf/simulated/O = get_step(T,d) - - //Ensure the turf is of proper type, that it is not in either list, and that air can reach it. - if(istype(O) && !(O in open) && !(O in closed) && O.ZCanPass(T)) - - //Handle connections from a tile with a door. - if(T.HasDoor()) - //If they both have doors, then they are not able to connect period. - if(O.HasDoor()) - continue - - //Connect first to north and west - if(d == NORTH || d == WEST) - open += O - - //If that fails, and north/west cannot be connected to, see if west or south can be connected instead. - else - var/turf/simulated/W = get_step(O, WEST) - var/turf/simulated/N = get_step(O, NORTH) - - if( !O.ZCanPass(N) && !O.ZCanPass(W) ) - //If it cannot connect either to the north or west, connect it! - open += O - - //If no doors are involved, add it immediately. - else if(!O.HasDoor()) - open += O - - //Handle connecting to a tile with a door. - else - if(d == SOUTH || d == EAST) - //doors prefer connecting to zones to the north or west - closed += O - - else - //see if we need to force an attempted connection - //(there are no potentially viable zones to the north/west of the door) - var/turf/simulated/W = get_step(O, WEST) - var/turf/simulated/N = get_step(O, NORTH) - - if( !O.ZCanPass(N) && !O.ZCanPass(W) ) - //If it cannot connect either to the north or west, connect it! - closed += O - - //This tile is now evaluated, and can be moved to the list of evaluated tiles. - open -= T - closed += T - - return closed - - -//Procedure to merge two zones together. -proc/ZMerge(zone/A,zone/B) - - //Sanity~ - if(!istype(A) || !istype(B)) - return - - var/new_contents = A.contents + B.contents - - //Set all the zone vars. - for(var/turf/simulated/T in B.contents) - T.zone = A - - if(istype(A.air) && istype(B.air)) - //Merges two zones so that they are one. - var/a_size = A.air.group_multiplier - var/b_size = B.air.group_multiplier - var/c_size = a_size + b_size - - //Set air multipliers to one so air represents gas per tile. - A.air.group_multiplier = 1 - B.air.group_multiplier = 1 - - //Remove some air proportional to the size of this zone. - A.air.remove_ratio(a_size/c_size) - B.air.remove_ratio(b_size/c_size) - - //Merge the gases and set the multiplier to the sum of the old ones. - A.air.merge(B.air) - A.air.group_multiplier = c_size - - //I hate when the air datum somehow disappears. - // Try to make it sorta work anyways. Fakit - else if(istype(B.air)) - A.air = B.air - A.air.group_multiplier = A.contents.len - - else if(istype(A.air)) - A.air.group_multiplier = A.contents.len - - //Doublefakit. - else - A.air = new - - //Check for connections to merge into the new zone. - for(var/connection/C in B.connections) - //The Cleanup proc will delete the connection if the zones are the same. - // It will also set the zone variables correctly. - C.Cleanup() - - //Add space tiles. - if(A.unsimulated_tiles && B.unsimulated_tiles) - A.unsimulated_tiles |= B.unsimulated_tiles - else if (B.unsimulated_tiles) - A.unsimulated_tiles = B.unsimulated_tiles - - //Add contents. - A.contents = new_contents - - //Remove the "B" zone, finally. - B.SoftDelete() - - -//Connects two zones by forming a connection object representing turfs A and B. -proc/ZConnect(turf/simulated/A,turf/simulated/B) - - //Make sure that if it's space, it gets added to unsimulated_tiles instead. - if(!istype(B)) - if(A.zone) - A.zone.AddTurf(B) - return - if(!istype(A)) - if(B.zone) - B.zone.AddTurf(A) - return - - if(!istype(A) || !istype(B)) - return - - //Make some preliminary checks to see if the connection is valid. - if(!A.zone || !B.zone) return - if(A.zone == B.zone) - air_master.AddIntrazoneConnection(A,B) - return - - if(A.CanPass(null, B, 1.5, 1) && A.zone.air.compare(B.zone.air)) - return ZMerge(A.zone,B.zone) - - //Ensure the connection isn't already made. - if(A in air_master.turfs_with_connections) - for(var/connection/C in air_master.turfs_with_connections[A]) - if(C.B == B || C.A == B) - return - - //Make the connection. - new /connection(A,B) diff --git a/code/ZAS/Plasma.dm b/code/ZAS/Phoron.dm similarity index 76% rename from code/ZAS/Plasma.dm rename to code/ZAS/Phoron.dm index 716ea21640..1e3df5292a 100644 --- a/code/ZAS/Plasma.dm +++ b/code/ZAS/Phoron.dm @@ -1,37 +1,37 @@ var/image/contamination_overlay = image('icons/effects/contamination.dmi') /pl_control - var/PLASMA_DMG = 3 - var/PLASMA_DMG_NAME = "Plasma Damage Amount" - var/PLASMA_DMG_DESC = "Self Descriptive" + var/PHORON_DMG = 3 + var/PHORON_DMG_NAME = "Phoron Damage Amount" + var/PHORON_DMG_DESC = "Self Descriptive" var/CLOTH_CONTAMINATION = 1 var/CLOTH_CONTAMINATION_NAME = "Cloth Contamination" - var/CLOTH_CONTAMINATION_DESC = "If this is on, plasma does damage by getting into cloth." + var/CLOTH_CONTAMINATION_DESC = "If this is on, phoron does damage by getting into cloth." - var/PLASMAGUARD_ONLY = 0 - var/PLASMAGUARD_ONLY_NAME = "\"PlasmaGuard Only\"" - var/PLASMAGUARD_ONLY_DESC = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." + var/PHORONGUARD_ONLY = 0 + var/PHORONGUARD_ONLY_NAME = "\"PhoronGuard Only\"" + var/PHORONGUARD_ONLY_DESC = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." var/GENETIC_CORRUPTION = 0 var/GENETIC_CORRUPTION_NAME = "Genetic Corruption Chance" var/GENETIC_CORRUPTION_DESC = "Chance of genetic corruption as well as toxic damage, X in 10,000." var/SKIN_BURNS = 0 - var/SKIN_BURNS_DESC = "Plasma has an effect similar to mustard gas on the un-suited." + var/SKIN_BURNS_DESC = "Phoron has an effect similar to mustard gas on the un-suited." var/SKIN_BURNS_NAME = "Skin Burns" var/EYE_BURNS = 1 var/EYE_BURNS_NAME = "Eye Burns" - var/EYE_BURNS_DESC = "Plasma burns the eyes of anyone not wearing eye protection." + var/EYE_BURNS_DESC = "Phoron burns the eyes of anyone not wearing eye protection." var/CONTAMINATION_LOSS = 0.02 var/CONTAMINATION_LOSS_NAME = "Contamination Loss" var/CONTAMINATION_LOSS_DESC = "How much toxin damage is dealt from contaminated clothing" //Per tick? ASK ARYN - var/PLASMA_HALLUCINATION = 0 - var/PLASMA_HALLUCINATION_NAME = "Plasma Hallucination" - var/PLASMA_HALLUCINATION_DESC = "Does being in plasma cause you to hallucinate?" + var/PHORON_HALLUCINATION = 0 + var/PHORON_HALLUCINATION_NAME = "Phoron Hallucination" + var/PHORON_HALLUCINATION_DESC = "Does being in phoron cause you to hallucinate?" var/N2O_HALLUCINATION = 1 var/N2O_HALLUCINATION_NAME = "N2O Hallucination" @@ -43,7 +43,7 @@ obj/var/contaminated = 0 /obj/item/proc/can_contaminate() //Clothing and backpacks can be contaminated. - if(flags & PLASMAGUARD) return 0 + if(flags & PHORONGUARD) return 0 else if(istype(src,/obj/item/weapon/storage/backpack)) return 0 //Cannot be washed :( else if(istype(src,/obj/item/clothing)) return 1 @@ -66,7 +66,7 @@ obj/var/contaminated = 0 suit_contamination() if(!pl_head_protected()) - if(prob(1)) suit_contamination() //Plasma can sometimes get through such an open suit. + if(prob(1)) suit_contamination() //Phoron can sometimes get through such an open suit. //Cannot wash backpacks currently. // if(istype(back,/obj/item/weapon/storage/backpack)) @@ -75,7 +75,7 @@ obj/var/contaminated = 0 /mob/proc/pl_effects() /mob/living/carbon/human/pl_effects() - //Handles all the bad things plasma can do. + //Handles all the bad things phoron can do. //Contamination if(vsc.plc.CLOTH_CONTAMINATION) contaminate() @@ -111,7 +111,7 @@ obj/var/contaminated = 0 if(vsc.plc.GENETIC_CORRUPTION) if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION) randmutb(src) - src << "\red High levels of toxins cause you to spontaneously mutate." + src << "\red High levels of phoron cause you to spontaneously mutate." domutcheck(src,null) @@ -128,8 +128,8 @@ obj/var/contaminated = 0 /mob/living/carbon/human/proc/pl_head_protected() //Checks if the head is adequately sealed. if(head) - if(vsc.plc.PLASMAGUARD_ONLY) - if(head.flags & PLASMAGUARD) + if(vsc.plc.PHORONGUARD_ONLY) + if(head.flags & PHORONGUARD) return 1 else if(head.flags & HEADCOVERSEYES) return 1 @@ -138,10 +138,11 @@ obj/var/contaminated = 0 /mob/living/carbon/human/proc/pl_suit_protected() //Checks if the suit is adequately sealed. if(wear_suit) - if(vsc.plc.PLASMAGUARD_ONLY) - if(wear_suit.flags & PLASMAGUARD) return 1 + if(vsc.plc.PHORONGUARD_ONLY) + if(wear_suit.flags & PHORONGUARD) return 1 else if(wear_suit.flags_inv & HIDEJUMPSUIT) return 1 + //should check HIDETAIL as well, but for the moment tails are not a part that can be damaged separately return 0 /mob/living/carbon/human/proc/suit_contamination() @@ -153,11 +154,11 @@ obj/var/contaminated = 0 turf/Entered(obj/item/I) . = ..() - //Items that are in plasma, but not on a mob, can still be contaminated. + //Items that are in phoron, but not on a mob, can still be contaminated. if(istype(I) && vsc.plc.CLOTH_CONTAMINATION) var/datum/gas_mixture/env = return_air(1) if(!env) return - if(env.toxins > MOLES_PLASMA_VISIBLE + 1) + if(env.phoron > MOLES_PHORON_VISIBLE + 1) if(I.can_contaminate()) I.contaminate() \ No newline at end of file diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm new file mode 100644 index 0000000000..162939baa9 --- /dev/null +++ b/code/ZAS/Turf.dm @@ -0,0 +1,240 @@ +/turf/simulated/var/zone/zone +/turf/simulated/var/open_directions +/turf/simulated/var/gas_graphic + +/turf/var/needs_air_update = 0 +/turf/var/datum/gas_mixture/air + +/turf/simulated/proc/set_graphic(new_graphic) + if(isnum(new_graphic)) + if(new_graphic == 1) new_graphic = plmaster + else if(new_graphic == 2) new_graphic = slmaster + if(gas_graphic) overlays -= gas_graphic + if(new_graphic) overlays += new_graphic + gas_graphic = new_graphic + +/turf/proc/update_air_properties() + var/block = c_airblock(src) + if(block & AIR_BLOCKED) + //dbg(blocked) + return 1 + + #ifdef ZLEVELS + for(var/d = 1, d < 64, d *= 2) + #else + for(var/d = 1, d < 16, d *= 2) + #endif + + var/turf/unsim = get_step(src, d) + block = unsim.c_airblock(src) + + if(block & AIR_BLOCKED) + //unsim.dbg(air_blocked, turn(180,d)) + continue + + var/r_block = c_airblock(unsim) + + if(r_block & AIR_BLOCKED) + continue + + if(istype(unsim, /turf/simulated)) + + var/turf/simulated/sim = unsim + if(air_master.has_valid_zone(sim)) + + air_master.connect(sim, src) + +/turf/simulated/update_air_properties() + if(zone && zone.invalid) + c_copy_air() + zone = null //Easier than iterating through the list at the zone. + + var/s_block = c_airblock(src) + if(s_block & AIR_BLOCKED) + #ifdef ZASDBG + if(verbose) world << "Self-blocked." + //dbg(blocked) + #endif + if(zone) + var/zone/z = zone + if(locate(/obj/machinery/door/airlock) in src) //Hacky, but prevents normal airlocks from rebuilding zones all the time + z.remove(src) + else + z.rebuild() + + return 1 + + var/previously_open = open_directions + open_directions = 0 + + var/list/postponed + #ifdef ZLEVELS + for(var/d = 1, d < 64, d *= 2) + #else + for(var/d = 1, d < 16, d *= 2) + #endif + + var/turf/unsim = get_step(src, d) + var/block = unsim.c_airblock(src) + if(block & AIR_BLOCKED) + + #ifdef ZASDBG + if(verbose) world << "[d] is blocked." + //unsim.dbg(air_blocked, turn(180,d)) + #endif + + continue + + var/r_block = c_airblock(unsim) + if(r_block & AIR_BLOCKED) + + #ifdef ZASDBG + if(verbose) world << "[d] is blocked." + //dbg(air_blocked, d) + #endif + + //Check that our zone hasn't been cut off recently. + //This happens when windows move or are constructed. We need to rebuild. + if((previously_open & d) && istype(unsim, /turf/simulated)) + var/turf/simulated/sim = unsim + if(sim.zone == zone) + zone.rebuild() + return + + continue + + open_directions |= d + + if(istype(unsim, /turf/simulated)) + + var/turf/simulated/sim = unsim + if(air_master.has_valid_zone(sim)) + + //Might have assigned a zone, since this happens for each direction. + if(!zone) + + //if((block & ZONE_BLOCKED) || (r_block & ZONE_BLOCKED && !(s_block & ZONE_BLOCKED))) + if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || (r_block & ZONE_BLOCKED && !(s_block & ZONE_BLOCKED))) + #ifdef ZASDBG + if(verbose) world << "[d] is zone blocked." + //dbg(zone_blocked, d) + #endif + + //Postpone this tile rather than exit, since a connection can still be made. + if(!postponed) postponed = list() + postponed.Add(sim) + + else + + sim.zone.add(src) + + #ifdef ZASDBG + dbg(assigned) + if(verbose) world << "Added to [zone]" + #endif + + else if(sim.zone != zone) + + #ifdef ZASDBG + if(verbose) world << "Connecting to [sim.zone]" + #endif + + air_master.connect(src, sim) + + + #ifdef ZASDBG + else if(verbose) world << "[d] has same zone." + + else if(verbose) world << "[d] has invalid zone." + #endif + + else + + //Postponing connections to tiles until a zone is assured. + if(!postponed) postponed = list() + postponed.Add(unsim) + + if(!air_master.has_valid_zone(src)) //Still no zone, make a new one. + var/zone/newzone = new/zone() + newzone.add(src) + + #ifdef ZASDBG + dbg(created) + + ASSERT(zone) + #endif + + //At this point, a zone should have happened. If it hasn't, don't add more checks, fix the bug. + + for(var/turf/T in postponed) + air_master.connect(src, T) + +/turf/proc/post_update_air_properties() + if(connections) connections.update_all() + +/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air + return 0 + +/turf/return_air() + //Create gas mixture to hold data for passing + var/datum/gas_mixture/GM = new + + GM.oxygen = oxygen + GM.carbon_dioxide = carbon_dioxide + GM.nitrogen = nitrogen + GM.phoron = phoron + + GM.temperature = temperature + GM.update_values() + + return GM + +/turf/remove_air(amount as num) + var/datum/gas_mixture/GM = new + + var/sum = oxygen + carbon_dioxide + nitrogen + phoron + if(sum>0) + GM.oxygen = (oxygen/sum)*amount + GM.carbon_dioxide = (carbon_dioxide/sum)*amount + GM.nitrogen = (nitrogen/sum)*amount + GM.phoron = (phoron/sum)*amount + + GM.temperature = temperature + GM.update_values() + + return GM + +/turf/simulated/assume_air(datum/gas_mixture/giver) + var/datum/gas_mixture/my_air = return_air() + my_air.merge(giver) + +/turf/simulated/remove_air(amount as num) + var/datum/gas_mixture/my_air = return_air() + return my_air.remove(amount) + +/turf/simulated/return_air() + if(zone) + if(!zone.invalid) + air_master.mark_zone_update(zone) + return zone.air + else + if(!air) + make_air() + c_copy_air() + return air + else + if(!air) + make_air() + return air + +/turf/proc/make_air() + air = new/datum/gas_mixture + air.temperature = temperature + air.adjust(oxygen, carbon_dioxide, nitrogen, phoron) + air.group_multiplier = 1 + air.volume = CELL_VOLUME + +/turf/simulated/proc/c_copy_air() + if(!air) air = new/datum/gas_mixture + air.copy_from(zone.air) + air.group_multiplier = 1 \ No newline at end of file diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index 5dd951fe52..c2d8a2fc6c 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" @@ -186,51 +186,51 @@ var/global/vs_control/vsc = new newvalue = vars[V] V = newvalue -/vs_control/proc/ChangePlasma() +/vs_control/proc/ChangePhoron() for(var/V in plc.settings) plc.Randomize(V) /vs_control/proc/SetDefault(var/mob/user) - var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!",\ + var/list/setting_choices = list("Phoron - Standard", "Phoron - Low Hazard", "Phoron - High Hazard", "Phoron - Oh Shit!",\ "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish") var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices if(!def) return switch(def) - if("Plasma - Standard") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 + if("Phoron - Standard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 0 plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 0 + plc.SKIN_BURNS = 0 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 0 plc.CONTAMINATION_LOSS = 0.02 - if("Plasma - Low Hazard") - plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 + if("Phoron - Low Hazard") + plc.CLOTH_CONTAMINATION = 0 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 0 plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 - plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 0 + plc.SKIN_BURNS = 0 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 0 plc.CONTAMINATION_LOSS = 0.01 - if("Plasma - High Hazard") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 + if("Phoron - High Hazard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 0 plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 1 + plc.SKIN_BURNS = 1 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 1 plc.CONTAMINATION_LOSS = 0.05 - if("Plasma - Oh Shit!") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 1 + if("Phoron - Oh Shit!") + plc.CLOTH_CONTAMINATION = 1 //If this is on, phoron does damage by getting into cloth. + plc.PHORONGUARD_ONLY = 1 plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 1 + plc.SKIN_BURNS = 1 //Phoron has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Phoron burns the eyes of anyone not wearing eye protection. + plc.PHORON_HALLUCINATION = 1 plc.CONTAMINATION_LOSS = 0.075 if("ZAS - Normal") @@ -288,9 +288,10 @@ 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]\"" + world << "\blue [key_name(user)] changed the global phoron/ZAS settings to \"[def]\"" /pl_control/var/list/settings = list() diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm deleted file mode 100644 index 12ac2df244..0000000000 --- a/code/ZAS/ZAS_Turfs.dm +++ /dev/null @@ -1,300 +0,0 @@ -/atom/var/pressure_resistance = ONE_ATMOSPHERE - -/turf/var/zone/zone - -/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air - del(giver) - return 0 - -/turf/return_air() - //Create gas mixture to hold data for passing - var/datum/gas_mixture/GM = new - - GM.oxygen = oxygen - GM.carbon_dioxide = carbon_dioxide - GM.nitrogen = nitrogen - GM.toxins = toxins - - GM.temperature = temperature - GM.update_values() - - return GM - -/turf/remove_air(amount as num) - var/datum/gas_mixture/GM = new - - var/sum = oxygen + carbon_dioxide + nitrogen + toxins - if(sum>0) - GM.oxygen = (oxygen/sum)*amount - GM.carbon_dioxide = (carbon_dioxide/sum)*amount - GM.nitrogen = (nitrogen/sum)*amount - GM.toxins = (toxins/sum)*amount - - GM.temperature = temperature - GM.update_values() - - return GM - -/turf/simulated/var/current_graphic = null - -/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. - -/turf/simulated/var/tmp/obj/fire/active_hotspot - -/turf/simulated/proc/update_visuals() - overlays = null - - var/siding_icon_state = return_siding_icon_state() - if(siding_icon_state) - overlays += image('icons/turf/floors.dmi',siding_icon_state) - var/datum/gas_mixture/model = return_air() - switch(model.graphic) - if(1) - overlays.Add(plmaster) //TODO: Make invisible plasma an option - if(2) - overlays.Add(slmaster) - -/turf/simulated/New() - ..() - - if(!blocks_air) - air = new - - air.oxygen = oxygen - air.carbon_dioxide = carbon_dioxide - air.nitrogen = nitrogen - air.toxins = toxins - - air.temperature = temperature - air.update_values() - - if(air_master) - air_master.tiles_to_update.Add(src) - - else - if(air_master) - for(var/direction in cardinal) - var/turf/simulated/floor/target = get_step(src,direction) - if(istype(target)) - air_master.tiles_to_update |= target - -/turf/simulated/Del() - if(active_hotspot) - del(active_hotspot) - if(blocks_air) - for(var/direction in list(NORTH, SOUTH, EAST, WEST)) - var/turf/simulated/tile = get_step(src,direction) - if(istype(tile) && !tile.blocks_air) - air_master.tiles_to_update.Add(tile) - ..() - -/turf/simulated/assume_air(datum/gas_mixture/giver) - if(!giver) return 0 - if(zone) - zone.assume_air(giver) - return 1 - else - return ..() - -/turf/simulated/return_air() - if(zone) - return zone.air - else if(air) - return air - - else - return ..() - -/turf/simulated/remove_air(amount as num) - if(zone) - return zone.remove_air(amount) - - else if(air) - var/datum/gas_mixture/removed = null - removed = air.remove(amount) - - if(air.check_tile_graphic()) - update_visuals(air) - return removed - - else - return ..() - -/turf/simulated/proc/update_air_properties() - var/air_directions_archived = air_check_directions - air_check_directions = 0 - - var/unsim_directions_archived = unsim_check_directions - unsim_check_directions = 0 - - for(var/direction in cardinal) - var/turf/check_turf = get_step(src, direction) - if(ZAirPass(check_turf)) - if(istype(check_turf, /turf/simulated)) - air_check_directions |= direction - else if(istype(check_turf, /turf/space) || istype(check_turf, /turf/unsimulated)) - unsim_check_directions |= direction - - if(!zone && !blocks_air) //No zone, but not a wall. - for(var/direction in DoorDirections) //Check door directions first. - if(air_check_directions & direction) - var/turf/simulated/T = get_step(src, direction) - if(!istype(T)) - continue - if(T.zone) - T.zone.AddTurf(src) - break - if(!zone) //Still no zone - for(var/direction in CounterDoorDirections) //Check the others second. - if(air_check_directions & direction) - var/turf/simulated/T = get_step(src,direction) - if(!istype(T)) - continue - if(T.zone) - T.zone.AddTurf(src) - break - if(!zone) //No zone found, new zone! - new/zone(src) - if(!zone) //Still no zone, the floodfill determined it is not part of a larger zone. Force a zone on it. - new/zone(list(src)) - - //Check pass sanity of the connections. - if(src in air_master.turfs_with_connections) - air_master.AddConnectionToCheck(air_master.turfs_with_connections[src]) - - if(zone && CanPass(null, src, 0, 0)) - - 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() - - //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)) - var/turf/NT = get_step(T, direction) - - //If the tile is in our own zone, and we cannot connect to it, better rebuild. - if(istype(NT,/turf/simulated) && NT in zone.contents) - air_master.zones_needing_rebuilt.Add(zone) - - //Parse if we need to remove the tile, or rebuild the zone. - else if(istype(NT) && NT in zone.unsimulated_tiles) - var/consider_rebuild = 0 - - //Loop through all neighboring turfs to see if we should remove the turf or just rebuild. - for(var/d in cardinal) - var/turf/UT = get_step(NT,d) - - //If we find a neighboring tile that is in the same zone, rebuild - if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) - consider_rebuild = 1 - break - - //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) - - //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) - //Checks for the presence of doors, used for zone spreading and connection. - //A positive numerical argument checks only for closed doors. - //Another turf as an argument checks for windoors between here and there. - for(var/obj/machinery/door/D in src) - if(isnum(O) && O) - if(!D.density) continue - if(istype(D,/obj/machinery/door/window)) - if(!istype(O)) - continue - if(D.dir == get_dir(D,O)) - return 1 - else - return 1 - -/turf/proc/ZCanPass(turf/simulated/T, var/include_space = 0) - //Fairly standard pass checks for turfs, objects and directional windows. Also stops at the edge of space. - if(!istype(T)) - return 0 - - if(!istype(T) && !include_space) - return 0 - else - if(T.blocks_air||blocks_air) - return 0 - - for(var/obj/obstacle in src) - if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) - continue - if(!obstacle.CanPass(null, T, 1.5, 1)) - return 0 - - for(var/obj/obstacle in T) - if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) - continue - if(!obstacle.CanPass(null, src, 1.5, 1)) - return 0 - - return 1 - -/turf/proc/ZAirPass(turf/T) - //Fairly standard pass checks for turfs, objects and directional windows. - if(!istype(T)) - return 0 - - if(T.blocks_air||blocks_air) - return 0 - - for(var/obj/obstacle in src) - if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) - continue - if(!obstacle.CanPass(null, T, 0, 0)) - return 0 - - for(var/obj/obstacle in T) - if(istype(obstacle, /obj/machinery/door) && !(obstacle:air_properties_vary_with_direction)) - continue - if(!obstacle.CanPass(null, src, 0, 0)) - return 0 - - return 1 - -/*UNUSED -/turf/proc/check_connections() - //Checks for new connections that can be made. - for(var/d in cardinal) - var/turf/simulated/T = get_step(src,d) - if(istype(T) && ( !T.zone || !T.CanPass(0,src,0,0) ) ) - continue - if(T.zone != zone) - ZConnect(src,T) - -/turf/proc/check_for_space() - //Checks for space around the turf. - for(var/d in cardinal) - var/turf/T = get_step(src,d) - if(istype(T,/turf/space) && T.CanPass(0,src,0,0)) - zone.AddSpace(T) - */ \ No newline at end of file diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm deleted file mode 100644 index cd77fbbbf2..0000000000 --- a/code/ZAS/ZAS_Zones.dm +++ /dev/null @@ -1,828 +0,0 @@ -var/list/DoorDirections = list(NORTH,WEST) //Which directions doors turfs can connect to zones -var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs can connect to zones - -/zone - var/dbg_output = 0 //Enables debug output. - - var/datum/gas_mixture/air //The air contents of the zone. - var/datum/gas_mixture/archived_air - - var/list/contents //All the tiles that are contained in this zone. - var/list/unsimulated_tiles // Any space tiles in this list will cause air to flow out. - - var/datum/gas_mixture/air_unsim //Overall average of the air in connected unsimualted tiles. - var/unsim_air_needs_update = 0 //Set to 1 on geometry changes, marks air_unsim as needing update. - - var/list/connections //connection objects which refer to connections with other zones, e.g. through a door. - var/list/direct_connections //connections which directly connect two zones. - - var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number - //of points they're connected at. - var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed. - - var/last_update = 0 - var/last_rebuilt = 0 - var/status = ZONE_ACTIVE - var/interactions_with_neighbors = 0 - var/interactions_with_unsim = 0 - var/progress = "nothing" - - -//CREATION AND DELETION -/zone/New(turf/start) - . = ..() - //Get the turfs that are part of the zone using a floodfill method - if(istype(start,/list)) - contents = start - else - contents = FloodFill(start) - - //Change all the zone vars of the turfs, check for space to be added to unsimulated_tiles. - for(var/turf/T in contents) - if(T.zone && T.zone != src) - T.zone.RemoveTurf(T) - T.zone = src - if(!istype(T,/turf/simulated)) - AddTurf(T) - - //Generate the gas_mixture for use in txhis zone by using the average of the gases - //defined at startup. - 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 - air.update_values() - - //Add this zone to the global list. - if(air_master) - air_master.zones.Add(src) - air_master.active_zones.Add(src) - - -//DO NOT USE. Use the SoftDelete proc. -/zone/Del() - //Ensuring the zone list doesn't get clogged with null values. - 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 = null - . = ..() - - -//Handles deletion via garbage collection. -/zone/proc/SoftDelete() - if(air_master) - air_master.zones.Remove(src) - air_master.active_zones.Remove(src) - air_master.zones_needing_rebuilt.Remove(src) - air = 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) - - //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 - - air_master.AddConnectionToCheck(connections) - connections = null - - return 1 - - -//ZONE MANAGEMENT FUNCTIONS -/zone/proc/AddTurf(turf/T) - //Adds the turf to contents, increases the size of the zone, and sets the zone var. - if(istype(T, /turf/simulated)) - if(T in contents) - return - if(T.zone) - T.zone.RemoveTurf(T) - contents += T - if(air) - air.group_multiplier++ - - T.zone = src - - else - if(!unsimulated_tiles) - unsimulated_tiles = list() - else if(T in unsimulated_tiles) - return - unsimulated_tiles += T - contents -= T - - unsim_air_needs_update = 1 - -/zone/proc/RemoveTurf(turf/T) - //Same, but in reverse. - if(istype(T, /turf/simulated)) - if(!(T in contents)) - return - contents -= T - if(air) - air.group_multiplier-- - - if(T.zone == src) - T.zone = null - - if(!contents.len) - SoftDelete() - - else if(unsimulated_tiles) - unsimulated_tiles -= T - if(!unsimulated_tiles.len) - unsimulated_tiles = null - - unsim_air_needs_update = 1 - -//Updates the air_unsim var -/zone/proc/UpdateUnsimAvg() - if(!unsimulated_tiles || !unsimulated_tiles.len) //if we don't have any unsimulated tiles, we can't do much. - return - - 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 - - unsim_air_needs_update = 0 - - if(!air_unsim) - air_unsim = new /datum/gas_mixture - - air_unsim.oxygen = 0 - air_unsim.nitrogen = 0 - air_unsim.carbon_dioxide = 0 - air_unsim.toxins = 0 - air_unsim.temperature = 0 - - var/correction_ratio = max(1, max(max(1, air.group_multiplier) + 3, 1) + unsimulated_tiles.len) / unsimulated_tiles.len - - for(var/turf/T in unsimulated_tiles) - if(!istype(T, /turf/simulated)) - air_unsim.oxygen += T.oxygen - air_unsim.carbon_dioxide += T.carbon_dioxide - air_unsim.nitrogen += T.nitrogen - air_unsim.toxins += T.toxins - air_unsim.temperature += T.temperature/unsimulated_tiles.len - - //These values require adjustment in order to properly represent a room of the specified size. - air_unsim.oxygen *= correction_ratio - air_unsim.carbon_dioxide *= correction_ratio - air_unsim.nitrogen *= correction_ratio - air_unsim.toxins *= correction_ratio - - air_unsim.group_multiplier = unsimulated_tiles.len - - air_unsim.update_values() - return - - ////////////// - //PROCESSING// -////////////// - -#define QUANTIZE(variable) (round(variable,0.0001)) - -/zone/proc/process() - . = 1 - - progress = "problem with: SoftDelete()" - - //Deletes zone if empty. - if(!contents.len) - return SoftDelete() - - progress = "problem with: Rebuild()" - - if(!contents.len) //If we got soft deleted. - return - - progress = "problem with: air regeneration" - - //Sometimes explosions will cause the air to be deleted for some reason. - if(!air) - air = new() - air.oxygen = MOLES_O2STANDARD - air.nitrogen = MOLES_N2STANDARD - air.temperature = T0C - air.total_moles() - world.log << "Air object lost in zone. Regenerating." - - - progress = "problem with: ShareSpace()" - - if(unsim_air_needs_update) - unsim_air_needs_update = 0 - UpdateUnsimAvg() - - if(unsimulated_tiles) - if(locate(/turf/simulated) in unsimulated_tiles) - for(var/turf/simulated/T in unsimulated_tiles) - unsimulated_tiles -= T - - if(unsimulated_tiles.len) - var/moved_air = ShareSpace(air, air_unsim) - - if(!air.compare(air_unsim)) - interactions_with_unsim++ - - if(moved_air > vsc.airflow_lightest_pressure) - AirflowSpace(src) - else - unsimulated_tiles = null - - //Check the graphic. - progress = "problem with: modifying turf graphics" - - air.graphic = 0 - if(air.toxins > MOLES_PLASMA_VISIBLE) - air.graphic = 1 - else if(air.trace_gases.len) - var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air.trace_gases - if(sleeping_agent && (sleeping_agent.moles > 1)) - air.graphic = 2 - - progress = "problem with an inbuilt byond function: some conditional checks" - - //Only run through the individual turfs if there's reason to. - if(air.graphic != air.graphic_archived || air.temperature > PLASMA_FLASHPOINT) - - progress = "problem with: turf/simulated/update_visuals()" - - for(var/turf/simulated/S in contents) - //Update overlays. - if(air.graphic != air.graphic_archived) - if(S.HasDoor(1)) - S.update_visuals() - else - S.update_visuals(air) - - progress = "problem with: item or turf temperature_expose()" - - //Expose stuff to extreme heat. - if(air.temperature > PLASMA_FLASHPOINT) - for(var/atom/movable/item in S) - item.temperature_expose(air, air.temperature, CELL_VOLUME) - S.hotspot_expose(air.temperature, CELL_VOLUME) - - progress = "problem with: calculating air graphic" - - //Archive graphic so we can know if it's different. - air.graphic_archived = air.graphic - - progress = "problem with: calculating air temp" - - //Ensure temperature does not reach absolute zero. - air.temperature = max(TCMB,air.temperature) - - progress = "problem with an inbuilt byond function: length(connections)" - - //Handle connections to other zones. - if(length(connections)) - - progress = "problem with: ZMerge(), a couple of misc procs" - - if(length(direct_connections)) - for(var/connection/C in direct_connections) - - //Do merging if conditions are met. Specifically, if there's a non-door connection - //to somewhere with space, the zones are merged regardless of equilibrium, to speed - //up spacing in areas with double-plated windows. - if(C.A.zone && C.B.zone) - if(C.A.zone.air.compare(C.B.zone.air) || unsimulated_tiles) - ZMerge(C.A.zone,C.B.zone) - - progress = "problem with: ShareRatio(), Airflow(), a couple of misc procs" - - //Share some - for(var/zone/Z in connected_zones) - //If that zone has already processed, skip it. - if(Z.last_update > last_update) - continue - - //Handle adjacent zones that are sleeping - if(Z.status == ZONE_SLEEPING) - if(air.compare(Z.air)) - continue - - else - Z.SetStatus(ZONE_ACTIVE) - - if(air && Z.air) - //Ensure we're not doing pointless calculations on equilibrium zones. - if(!air.compare(Z.air)) - if(abs(Z.air.return_pressure() - air.return_pressure()) > vsc.airflow_lightest_pressure) - Airflow(src,Z) - var/unsimulated_boost = 0 - if(unsimulated_tiles) - unsimulated_boost += unsimulated_tiles.len - if(Z.unsimulated_tiles) - unsimulated_boost += Z.unsimulated_tiles.len - unsimulated_boost = max(0, min(3, unsimulated_boost)) - ShareRatio( air , Z.air , connected_zones[Z] + unsimulated_boost) - - 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 - 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) - - interactions_with_neighbors = 0 - interactions_with_unsim = 0 - - progress = "all components completed successfully, the problem is not here" - - -/zone/proc/SetStatus(var/new_status) - if(status == ZONE_SLEEPING && new_status == ZONE_ACTIVE) - air_master.active_zones.Add(src) - status = ZONE_ACTIVE - - else if(status == ZONE_ACTIVE && new_status == ZONE_SLEEPING) - air_master.active_zones.Remove(src) - status = ZONE_SLEEPING - - if(unsimulated_tiles && unsimulated_tiles.len) - UpdateUnsimAvg() - air.copy_from(air_unsim) - - if(!archived_air) - archived_air = new - archived_air.copy_from(air) - - -/zone/proc/CheckStatus() - return status - - -/zone/proc/ActivateIfNeeded() - if(status == ZONE_ACTIVE) return - - var/difference = 0 - - if(unsimulated_tiles && unsimulated_tiles.len) - UpdateUnsimAvg() - if(!air.compare(air_unsim)) - difference = 1 - - if(!difference) - for(var/zone/Z in connected_zones) //Check adjacent zones for air difference. - if(!air.compare(Z.air)) - difference = 1 - break - - if(difference) //We have a difference, activate the zone. - SetStatus(ZONE_ACTIVE) - - return - - -/zone/proc/assume_air(var/datum/gas_mixture/giver) - if(status == ZONE_ACTIVE) - return air.merge(giver) - - else - if(unsimulated_tiles && unsimulated_tiles.len) - UpdateUnsimAvg() - var/datum/gas_mixture/compare_air = new - compare_air.copy_from(giver) - compare_air.add(air_unsim) - compare_air.divide(air.group_multiplier) - - if(air_unsim.compare(compare_air)) - return 0 - - var/result = air.merge(giver) - - if(!archived_air.compare(air)) - SetStatus(ZONE_ACTIVE) - return result - - -/zone/proc/remove_air(var/amount) - if(status == ZONE_ACTIVE) - return air.remove(amount) - - else - var/result = air.remove(amount) - - if(!archived_air.compare(air)) - SetStatus(ZONE_ACTIVE) - - return result - - //////////////// - //Air Movement// -//////////////// - -var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66) - -proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) - //Shares a specific ratio of gas between mixtures using simple weighted averages. - var - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - ratio = sharing_lookup_table[6] - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - - size = max(1,A.group_multiplier) - share_size = max(1,B.group_multiplier) - - full_oxy = A.oxygen * size - full_nitro = A.nitrogen * size - full_co2 = A.carbon_dioxide * size - full_plasma = A.toxins * size - - full_heat_capacity = A.heat_capacity() * size - - s_full_oxy = B.oxygen * share_size - s_full_nitro = B.nitrogen * share_size - s_full_co2 = B.carbon_dioxide * share_size - s_full_plasma = B.toxins * share_size - - s_full_heat_capacity = B.heat_capacity() * share_size - - oxy_avg = (full_oxy + s_full_oxy) / (size + share_size) - nit_avg = (full_nitro + s_full_nitro) / (size + share_size) - co2_avg = (full_co2 + s_full_co2) / (size + share_size) - plasma_avg = (full_plasma + s_full_plasma) / (size + share_size) - - temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity) - - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick. - ratio = sharing_lookup_table[connecting_tiles] - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - - A.oxygen = max(0, (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg ) - A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1-ratio) + nit_avg ) - A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg ) - A.toxins = max(0, (A.toxins - plasma_avg) * (1-ratio) + plasma_avg ) - - A.temperature = max(0, (A.temperature - temp_avg) * (1-ratio) + temp_avg ) - - B.oxygen = max(0, (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg ) - B.nitrogen = max(0, (B.nitrogen - nit_avg) * (1-ratio) + nit_avg ) - B.carbon_dioxide = max(0, (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg ) - B.toxins = max(0, (B.toxins - plasma_avg) * (1-ratio) + plasma_avg ) - - B.temperature = max(0, (B.temperature - temp_avg) * (1-ratio) + temp_avg ) - - for(var/datum/gas/G in A.trace_gases) - var/datum/gas/H = locate(G.type) in B.trace_gases - if(H) - var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size) - G.moles = (G.moles - G_avg) * (1-ratio) + G_avg - - H.moles = (H.moles - G_avg) * (1-ratio) + G_avg - else - H = new G.type - B.trace_gases += H - var/G_avg = (G.moles*size) / (size+share_size) - G.moles = (G.moles - G_avg) * (1-ratio) + G_avg - H.moles = (H.moles - G_avg) * (1-ratio) + G_avg - - for(var/datum/gas/G in B.trace_gases) - var/datum/gas/H = locate(G.type) in A.trace_gases - if(!H) - H = new G.type - A.trace_gases += H - var/G_avg = (G.moles*size) / (size+share_size) - G.moles = (G.moles - G_avg) * (1-ratio) + G_avg - H.moles = (H.moles - G_avg) * (1-ratio) + G_avg - - A.update_values() - B.update_values() - - if(A.compare(B)) return 1 - else return 0 - -proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) - //A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room. - if(!unsimulated_tiles) - return 0 - - var - unsim_oxygen = 0 - unsim_nitrogen = 0 - unsim_co2 = 0 - unsim_plasma = 0 - unsim_heat_capacity = 0 - unsim_temperature = 0 - - size = max(1,A.group_multiplier) - - var/tileslen - var/share_size - - if(istype(unsimulated_tiles, /datum/gas_mixture)) - var/datum/gas_mixture/avg_unsim = unsimulated_tiles - unsim_oxygen = avg_unsim.oxygen - unsim_co2 = avg_unsim.carbon_dioxide - unsim_nitrogen = avg_unsim.nitrogen - unsim_plasma = avg_unsim.toxins - unsim_temperature = avg_unsim.temperature - share_size = max(1, max(size + 3, 1) + avg_unsim.group_multiplier) - tileslen = avg_unsim.group_multiplier - - else if(istype(unsimulated_tiles, /list)) - if(!unsimulated_tiles.len) - return 0 - // We use the same size for the potentially single space tile - // as we use for the entire room. Why is this? - // Short answer: We do not want larger rooms to depressurize more - // slowly than small rooms, preserving our good old "hollywood-style" - // oh-shit effect when large rooms get breached, but still having small - // rooms remain pressurized for long enough to make escape possible. - share_size = max(1, max(size + 3, 1) + unsimulated_tiles.len) - var/correction_ratio = share_size / unsimulated_tiles.len - - for(var/turf/T in unsimulated_tiles) - unsim_oxygen += T.oxygen - unsim_co2 += T.carbon_dioxide - unsim_nitrogen += T.nitrogen - unsim_plasma += T.toxins - unsim_temperature += T.temperature/unsimulated_tiles.len - - //These values require adjustment in order to properly represent a room of the specified size. - unsim_oxygen *= correction_ratio - unsim_co2 *= correction_ratio - unsim_nitrogen *= correction_ratio - unsim_plasma *= correction_ratio - tileslen = unsimulated_tiles.len - - else //invalid input type - return 0 - - unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_plasma) - - var - ratio = sharing_lookup_table[6] - - old_pressure = A.return_pressure() - - full_oxy = A.oxygen * size - full_nitro = A.nitrogen * size - full_co2 = A.carbon_dioxide * size - full_plasma = A.toxins * size - - full_heat_capacity = A.heat_capacity() * size - - oxy_avg = (full_oxy + unsim_oxygen) / (size + share_size) - nit_avg = (full_nitro + unsim_nitrogen) / (size + share_size) - co2_avg = (full_co2 + unsim_co2) / (size + share_size) - plasma_avg = (full_plasma + unsim_plasma) / (size + share_size) - - temp_avg = 0 - - if((full_heat_capacity + unsim_heat_capacity) > 0) - temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity) - - if(sharing_lookup_table.len >= tileslen) //6 or more interconnecting tiles will max at 42% of air moved per tick. - ratio = sharing_lookup_table[tileslen] - - A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg ) - A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg ) - A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg ) - A.toxins = max(0, (A.toxins - plasma_avg) * (1 - ratio) + plasma_avg ) - - A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg ) - - for(var/datum/gas/G in A.trace_gases) - var/G_avg = (G.moles * size) / (size + share_size) - G.moles = (G.moles - G_avg) * (1 - ratio) + G_avg - - A.update_values() - - return abs(old_pressure - A.return_pressure()) - - -proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) - //Shares a specific ratio of gas between mixtures using simple weighted averages. - var - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - ratio = sharing_lookup_table[6] - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - - full_heat_capacity = A.heat_capacity() - - s_full_heat_capacity = B.heat_capacity() - - temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity) - - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick. - ratio = sharing_lookup_table[connecting_tiles] - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - - //We need to adjust it to account for the insulation settings. - ratio *= 1 - vsc.connection_insulation - - 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// -/////////////////// -//Used for updating zone geometry when a zone is cut into two parts. - -zone/proc/Rebuild() - if(last_rebuilt == air_master.current_cycle) - return - - last_rebuilt = air_master.current_cycle - - var/list/new_zone_contents = IsolateContents() - if(new_zone_contents.len == 1) - return - - var/list/current_contents - var/list/new_zones = list() - - contents = new_zone_contents[1] - air.group_multiplier = contents.len - - for(var/identifier in 2 to new_zone_contents.len) - current_contents = new_zone_contents[identifier] - var/zone/new_zone = new (current_contents) - new_zone.air.copy_from(air) - new_zones += new_zone - - for(var/connection/connection in connections) - connection.Cleanup() - - var/turf/simulated/adjacent - - for(var/turf/unsimulated in unsimulated_tiles) - for(var/direction in cardinal) - adjacent = get_step(unsimulated, direction) - - if(istype(adjacent) && adjacent.CanPass(null, unsimulated, 0, 0)) - for(var/zone/zone in new_zones) - if(adjacent in zone) - zone.AddTurf(unsimulated) - - -//Implements a two-pass connected component labeling algorithm to determine if the zone is, in fact, split. - -/zone/proc/IsolateContents() - var/list/current_adjacents = list() - var/adjacent_id - var/lowest_id - - var/list/identical_ids = list() - var/list/turfs = contents.Copy() - var/current_identifier = 1 - - for(var/turf/simulated/current in turfs) - lowest_id = null - current_adjacents = list() - - for(var/direction in cardinal) - if( !(current.air_check_directions & direction)) - continue - var/turf/simulated/adjacent = get_step(current, direction) - if(adjacent in turfs) - current_adjacents += adjacent - adjacent_id = turfs[adjacent] - - if(adjacent_id && (!lowest_id || adjacent_id < lowest_id)) - lowest_id = adjacent_id - - if(!lowest_id) - lowest_id = current_identifier++ - identical_ids += lowest_id - - for(var/turf/simulated/adjacent in current_adjacents) - adjacent_id = turfs[adjacent] - if(adjacent_id != lowest_id) - if(adjacent_id) - identical_ids[adjacent_id] = lowest_id - turfs[adjacent] = lowest_id - turfs[current] = lowest_id - - var/list/final_arrangement = list() - - for(var/turf/simulated/current in turfs) - current_identifier = identical_ids[turfs[current]] - - if( current_identifier > final_arrangement.len ) - final_arrangement.len = current_identifier - final_arrangement[current_identifier] = list(current) - - else - final_arrangement[current_identifier] += current - - //lazy but fast - final_arrangement.Remove(null) - - return final_arrangement - - -/* - if(!RequiresRebuild()) - return - - //Choose a random turf and regenerate the zone from it. - var/list/new_contents - var/list/new_unsimulated - - var/list/turfs_needing_zones = list() - - var/list/zones_to_check_connections = list(src) - - if(!locate(/turf/simulated/floor) in contents) - for(var/turf/simulated/turf in contents) - air_master.ReconsiderTileZone(turf) - return SoftDelete() - - var/turfs_to_ignore = list() - if(direct_connections) - for(var/connection/connection in direct_connections) - if(connection.A.zone != src) - turfs_to_ignore += A - else if(connection.B.zone != src) - turfs_to_ignore += B - - new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() ) - - //Now, we have allocated the new turfs into proper lists, and we can start actually rebuilding. - - //If something isn't carried over, it will need a new zone. - for(var/turf/T in contents) - if(!(T in new_contents)) - RemoveTurf(T) - turfs_needing_zones += T - - //Handle addition of new turfs - for(var/turf/S in new_contents) - if(!istype(S, /turf/simulated)) - new_unsimulated |= S - new_contents.Remove(S) - - //If something new is added, we need to deal with it seperately. - else if(!(S in contents) && istype(S, /turf/simulated)) - if(!(S.zone in zones_to_check_connections)) - zones_to_check_connections += S.zone - - S.zone.RemoveTurf(S) - AddTurf(S) - - //Handle the addition of new unsimulated tiles. - unsimulated_tiles = null - - if(new_unsimulated.len) - for(var/turf/S in new_unsimulated) - if(istype(S, /turf/simulated)) - continue - for(var/direction in cardinal) - var/turf/simulated/T = get_step(S,direction) - if(istype(T) && T.zone && S.CanPass(null, T, 0, 0)) - T.zone.AddTurf(S) - - //Finally, handle the orphaned turfs - - for(var/turf/simulated/T in turfs_needing_zones) - if(!T.zone) - zones_to_check_connections += new /zone(T) - - for(var/zone/zone in zones_to_check_connections) - for(var/connection/C in zone.connections) - C.Cleanup()*/ - diff --git a/code/ZAS/Zone.dm b/code/ZAS/Zone.dm new file mode 100644 index 0000000000..2d285d08f6 --- /dev/null +++ b/code/ZAS/Zone.dm @@ -0,0 +1,154 @@ +/* + +Overview: + Each zone is a self-contained area where gas values would be the same if tile-based equalization were run indefinitely. + If you're unfamiliar with ZAS, FEA's air groups would have similar functionality if they didn't break in a stiff breeze. + +Class Vars: + name - A name of the format "Zone [#]", used for debugging. + invalid - True if the zone has been erased and is no longer eligible for processing. + needs_update - True if the zone has been added to the update list. + edges - A list of edges that connect to this zone. + air - The gas mixture that any turfs in this zone will return. Values are per-tile with a group multiplier. + +Class Procs: + add(turf/simulated/T) + Adds a turf to the contents, sets its zone and merges its air. + + remove(turf/simulated/T) + Removes a turf, sets its zone to null and erases any gas graphics. + Invalidates the zone if it has no more tiles. + + c_merge(zone/into) + Invalidates this zone and adds all its former contents to into. + + c_invalidate() + Marks this zone as invalid and removes it from processing. + + rebuild() + Invalidates the zone and marks all its former tiles for updates. + + add_tile_air(turf/simulated/T) + Adds the air contained in T.air to the zone's air supply. Called when adding a turf. + + tick() + Called only when the gas content is changed. Archives values and changes gas graphics. + + dbg_data(mob/M) + Sends M a printout of important figures for the zone. + +*/ + + +/zone/var/name +/zone/var/invalid = 0 +/zone/var/list/contents = list() + +/zone/var/needs_update = 0 + +/zone/var/list/edges = list() + +/zone/var/datum/gas_mixture/air = new + +/zone/New() + air_master.add_zone(src) + air.temperature = TCMB + air.group_multiplier = 1 + air.volume = CELL_VOLUME + +/zone/proc/add(turf/simulated/T) +#ifdef ZASDBG + ASSERT(!invalid) + ASSERT(istype(T)) + ASSERT(!air_master.has_valid_zone(T)) +#endif + + var/datum/gas_mixture/turf_air = T.return_air() + add_tile_air(turf_air) + T.zone = src + contents.Add(T) + T.set_graphic(air.graphic) + +/zone/proc/remove(turf/simulated/T) +#ifdef ZASDBG + ASSERT(!invalid) + ASSERT(istype(T)) + ASSERT(T.zone == src) + soft_assert(T in contents, "Lists are weird broseph") +#endif + contents.Remove(T) + T.zone = null + T.set_graphic(0) + if(contents.len) + air.group_multiplier = contents.len + else + c_invalidate() + +/zone/proc/c_merge(zone/into) +#ifdef ZASDBG + ASSERT(!invalid) + ASSERT(istype(into)) + ASSERT(into != src) + ASSERT(!into.invalid) +#endif + c_invalidate() + for(var/turf/simulated/T in contents) + into.add(T) + #ifdef ZASDBG + T.dbg(merged) + #endif + +/zone/proc/c_invalidate() + invalid = 1 + air_master.remove_zone(src) + #ifdef ZASDBG + for(var/turf/simulated/T in contents) + T.dbg(invalid_zone) + #endif + +/zone/proc/rebuild() + if(invalid) return //Short circuit for explosions where rebuild is called many times over. + c_invalidate() + for(var/turf/simulated/T in contents) + //T.dbg(invalid_zone) + T.needs_air_update = 0 //Reset the marker so that it will be added to the list. + air_master.mark_for_update(T) + +/zone/proc/add_tile_air(datum/gas_mixture/tile_air) + //air.volume += CELL_VOLUME + air.group_multiplier = 1 + air.multiply(contents.len) + air.merge(tile_air) + air.divide(contents.len+1) + air.group_multiplier = contents.len+1 + +/zone/proc/tick() + air.archive() + if(air.check_tile_graphic()) + for(var/turf/simulated/T in contents) + T.set_graphic(air.graphic) + +/zone/proc/dbg_data(mob/M) + M << name + M << "O2: [air.oxygen] N2: [air.nitrogen] CO2: [air.carbon_dioxide] P: [air.phoron]" + M << "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)" + M << "O2 per N2: [(air.nitrogen ? air.oxygen/air.nitrogen : "N/A")] Moles: [air.total_moles]" + M << "Simulated: [contents.len] ([air.group_multiplier])" + //M << "Unsimulated: [unsimulated_contents.len]" + //M << "Edges: [edges.len]" + if(invalid) M << "Invalid!" + var/zone_edges = 0 + var/space_edges = 0 + var/space_coefficient = 0 + for(var/connection_edge/E in edges) + if(E.type == /connection_edge/zone) zone_edges++ + else + space_edges++ + space_coefficient += E.coefficient + M << "[E:air:return_pressure()]kPa" + + M << "Zone Edges: [zone_edges]" + M << "Space Edges: [space_edges] ([space_coefficient] connections)" + + //for(var/turf/T in unsimulated_contents) + // M << "[T] at ([T.x],[T.y])" \ No newline at end of file diff --git a/code/ZAS/_docs.dm b/code/ZAS/_docs.dm new file mode 100644 index 0000000000..8d084dc4c9 --- /dev/null +++ b/code/ZAS/_docs.dm @@ -0,0 +1,35 @@ +/* + +Zone Air System: + +This air system divides the station into impermeable areas called zones. +When something happens, i.e. a door opening or a wall being taken down, +zones equalize and eventually merge. Making an airtight area closes the connection again. + +Control Flow: +Every air tick: + Marked turfs are updated with update_air_properties(), followed by post_update_air_properties(). + Edges, including those generated by connections in the previous step, are processed. This is where gas is exchanged. + Fire is processed. + Marked zones have their air archived. + +Important Functions: + +air_master.mark_for_update(turf) + When stuff happens, call this. It works on everything. You basically don't need to worry about any other + functions besides CanPass(). + +Notes for people who used ZAS before: + There is no connected_zones anymore. + To get the zones that are connected to a zone, use this loop: + for(var/connection_edge/zone/edge in zone.edges) + var/zone/connected_zone = edge.get_connected_zone(zone) + +*/ + +//#define ZASDBG +//#define ZLEVELS + +#define AIR_BLOCKED 1 +#define ZONE_BLOCKED 2 +#define BLOCKED 3 \ No newline at end of file diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/_gas_mixture.dm similarity index 92% rename from code/ZAS/FEA_gas_mixture.dm rename to code/ZAS/_gas_mixture.dm index 9a829633e2..2a072e8ef9 100644 --- a/code/ZAS/FEA_gas_mixture.dm +++ b/code/ZAS/_gas_mixture.dm @@ -7,8 +7,8 @@ What are the archived variables for? #define SPECIFIC_HEAT_TOXIN 200 #define SPECIFIC_HEAT_AIR 20 #define SPECIFIC_HEAT_CDO 30 -#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \ - max(0, carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN) +#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,phoron) \ + max(0, carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + phoron * SPECIFIC_HEAT_TOXIN) #define MINIMUM_HEAT_CAPACITY 0.0003 #define QUANTIZE(variable) (round(variable,0.0001)) @@ -17,7 +17,7 @@ What are the archived variables for? /hook/startup/proc/createGasOverlays() plmaster = new /obj/effect/overlay() plmaster.icon = 'icons/effects/tile_effects.dmi' - plmaster.icon_state = "plasma" + plmaster.icon_state = "phoron" plmaster.layer = FLY_LAYER plmaster.mouse_opacity = 0 @@ -45,7 +45,7 @@ What are the archived variables for? var/oxygen = 0 //Holds the "moles" of each of the four gases. var/carbon_dioxide = 0 var/nitrogen = 0 - var/toxins = 0 + var/phoron = 0 var/total_moles = 0 //Updated when a reaction occurs. @@ -64,7 +64,7 @@ What are the archived variables for? var/tmp/oxygen_archived //These are variables for use with the archived data var/tmp/carbon_dioxide_archived var/tmp/nitrogen_archived - var/tmp/toxins_archived + var/tmp/phoron_archived var/tmp/temperature_archived @@ -85,7 +85,7 @@ What are the archived variables for? oxygen = max(0, oxygen + o2) carbon_dioxide = max(0, carbon_dioxide + co2) nitrogen = max(0, nitrogen + n2) - toxins = max(0, toxins + tx) + phoron = max(0, phoron + tx) //handle trace gasses for(var/datum/gas/G in traces) @@ -119,7 +119,7 @@ What are the archived variables for? //Inputs: None //Outputs: Heat capacity - var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) + var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,phoron) if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -133,7 +133,7 @@ What are the archived variables for? //Inputs: None //Outputs: Archived heat capacity - var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived) + var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,phoron_archived) if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -143,7 +143,7 @@ What are the archived variables for? /datum/gas_mixture/proc/total_moles() return total_moles - /*var/moles = oxygen + carbon_dioxide + nitrogen + toxins + /*var/moles = oxygen + carbon_dioxide + nitrogen + phoron if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -187,7 +187,7 @@ What are the archived variables for? //Inputs: None //Outputs: None - total_moles = oxygen + carbon_dioxide + nitrogen + toxins + total_moles = oxygen + carbon_dioxide + nitrogen + phoron if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -206,7 +206,7 @@ What are the archived variables for? //Outputs: 1 if graphic changed, 0 if unchanged graphic = 0 - if(toxins > MOLES_PLASMA_VISIBLE) + if(phoron > MOLES_PHORON_VISIBLE) graphic = 1 else if(length(trace_gases)) var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases @@ -258,11 +258,11 @@ What are the archived variables for? carbon_dioxide += burned_fuel fuel_burnt += burned_fuel - //Handle plasma burning + //Handle phoron burning if(toxins > MINIMUM_HEAT_CAPACITY) - var/plasma_burn_rate = 0 + var/phoron_burn_rate = 0 var/oxygen_burn_rate = 0 - //more plasma released at higher temperatures + //more phoron released at higher temperatures var/temperature_scale if(temperature > PLASMA_UPPER_TEMPERATURE) temperature_scale = 1 @@ -271,17 +271,17 @@ What are the archived variables for? if(temperature_scale > 0) oxygen_burn_rate = 1.4 - temperature_scale if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN) - plasma_burn_rate = (toxins*temperature_scale)/4 + phoron_burn_rate = (toxins*temperature_scale)/4 else - plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/4 - if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY) - toxins -= plasma_burn_rate - oxygen -= plasma_burn_rate*oxygen_burn_rate - carbon_dioxide += plasma_burn_rate + phoron_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/4 + if(phoron_burn_rate > MINIMUM_HEAT_CAPACITY) + toxins -= phoron_burn_rate + oxygen -= phoron_burn_rate*oxygen_burn_rate + carbon_dioxide += phoron_burn_rate - energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate) + energy_released += FIRE_PLASMA_ENERGY_RELEASED * (phoron_burn_rate) - fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate) + fuel_burnt += (phoron_burn_rate)*(1+oxygen_burn_rate) if(energy_released > 0) var/new_heat_capacity = heat_capacity() @@ -305,7 +305,7 @@ What are the archived variables for? oxygen_archived = oxygen carbon_dioxide_archived = carbon_dioxide nitrogen_archived = nitrogen - toxins_archived = toxins + phoron_archived = phoron if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -329,7 +329,7 @@ What are the archived variables for? if(((giver.oxygen > MINIMUM_AIR_TO_SUSPEND) && (giver.oxygen >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((giver.carbon_dioxide > MINIMUM_AIR_TO_SUSPEND) && (giver.carbon_dioxide >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((giver.nitrogen > MINIMUM_AIR_TO_SUSPEND) && (giver.nitrogen >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((giver.toxins > MINIMUM_AIR_TO_SUSPEND) && (giver.toxins >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND))) + || ((giver.phoron > MINIMUM_AIR_TO_SUSPEND) && (giver.phoron >= phoron*MINIMUM_AIR_RATIO_TO_SUSPEND))) return 0 if(abs(giver.temperature - temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) return 0 @@ -362,12 +362,12 @@ What are the archived variables for? oxygen += giver.oxygen*giver.group_multiplier/group_multiplier carbon_dioxide += giver.carbon_dioxide*giver.group_multiplier/group_multiplier nitrogen += giver.nitrogen*giver.group_multiplier/group_multiplier - toxins += giver.toxins*giver.group_multiplier/group_multiplier + phoron += giver.phoron*giver.group_multiplier/group_multiplier else oxygen += giver.oxygen carbon_dioxide += giver.carbon_dioxide nitrogen += giver.nitrogen - toxins += giver.toxins + phoron += giver.phoron if(giver.trace_gases.len) for(var/datum/gas/trace_gas in giver.trace_gases) @@ -399,12 +399,12 @@ What are the archived variables for? removed.oxygen = QUANTIZE((oxygen/sum)*amount) removed.nitrogen = QUANTIZE((nitrogen/sum)*amount) removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount) - removed.toxins = QUANTIZE(((toxins/sum)*amount)) + removed.phoron = QUANTIZE(((phoron/sum)*amount)) oxygen -= removed.oxygen/group_multiplier nitrogen -= removed.nitrogen/group_multiplier carbon_dioxide -= removed.carbon_dioxide/group_multiplier - toxins -= removed.toxins/group_multiplier + phoron -= removed.phoron/group_multiplier if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -436,12 +436,12 @@ What are the archived variables for? removed.oxygen = QUANTIZE(oxygen*ratio) removed.nitrogen = QUANTIZE(nitrogen*ratio) removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio) - removed.toxins = QUANTIZE(toxins*ratio) + removed.phoron = QUANTIZE(phoron*ratio) oxygen -= removed.oxygen/group_multiplier nitrogen -= removed.nitrogen/group_multiplier carbon_dioxide -= removed.carbon_dioxide/group_multiplier - toxins -= removed.toxins/group_multiplier + phoron -= removed.phoron/group_multiplier if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -480,7 +480,7 @@ What are the archived variables for? oxygen = sample.oxygen carbon_dioxide = sample.carbon_dioxide nitrogen = sample.nitrogen - toxins = sample.toxins + phoron = sample.phoron total_moles = sample.total_moles() trace_gases.len=null @@ -508,14 +508,14 @@ What are the archived variables for? var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION - var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION + var/delta_phoron = QUANTIZE(phoron_archived - sharer.phoron_archived)/TRANSFER_FRACTION var/delta_temperature = (temperature_archived - sharer.temperature_archived) if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) + || ((abs(delta_phoron) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_phoron) >= phoron_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) return 0 if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) @@ -540,7 +540,7 @@ What are the archived variables for? if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= sharer.oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= sharer.carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= sharer.nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= sharer.toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) + || ((abs(delta_phoron) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_phoron) >= sharer.phoron_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) return -1 if(trace_gases.len) @@ -564,14 +564,14 @@ What are the archived variables for? var/delta_oxygen = (oxygen_archived - model.oxygen)/TRANSFER_FRACTION var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION - var/delta_toxins = (toxins_archived - model.toxins)/TRANSFER_FRACTION + var/delta_phoron = (phoron_archived - model.phoron)/TRANSFER_FRACTION var/delta_temperature = (temperature_archived - model.temperature) if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) + || ((abs(delta_phoron) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_phoron) >= phoron_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) return 0 if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) return 0 @@ -597,7 +597,7 @@ What are the archived variables for? var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION - var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION + var/delta_phoron = QUANTIZE(phoron_archived - sharer.phoron_archived)/TRANSFER_FRACTION var/delta_temperature = (temperature_archived - sharer.temperature_archived) @@ -630,14 +630,14 @@ What are the archived variables for? heat_sharer_to_self -= carbon_dioxide_heat_capacity*sharer.temperature_archived heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity - if(delta_toxins) - var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins - if(delta_toxins > 0) - heat_self_to_sharer += toxins_heat_capacity*temperature_archived - heat_capacity_self_to_sharer += toxins_heat_capacity + if(delta_phoron) + var/phoron_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_phoron + if(delta_phoron > 0) + heat_self_to_sharer += phoron_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += phoron_heat_capacity else - heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived - heat_capacity_sharer_to_self -= toxins_heat_capacity + heat_sharer_to_self -= phoron_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= phoron_heat_capacity old_self_heat_capacity = heat_capacity()*group_multiplier old_sharer_heat_capacity = sharer.heat_capacity()*sharer.group_multiplier @@ -651,10 +651,10 @@ What are the archived variables for? nitrogen -= delta_nitrogen/group_multiplier sharer.nitrogen += delta_nitrogen/sharer.group_multiplier - toxins -= delta_toxins/group_multiplier - sharer.toxins += delta_toxins/sharer.group_multiplier + phoron -= delta_phoron/group_multiplier + sharer.phoron += delta_phoron/sharer.group_multiplier - var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_phoron) var/list/trace_types_considered = list() @@ -743,7 +743,7 @@ What are the archived variables for? var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/TRANSFER_FRACTION var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION - var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/TRANSFER_FRACTION + var/delta_phoron = QUANTIZE(phoron_archived - model.phoron)/TRANSFER_FRACTION var/delta_temperature = (temperature_archived - model.temperature) @@ -764,10 +764,10 @@ What are the archived variables for? heat_transferred -= carbon_dioxide_heat_capacity*model.temperature heat_capacity_transferred -= carbon_dioxide_heat_capacity - if(delta_toxins) - var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins - heat_transferred -= toxins_heat_capacity*model.temperature - heat_capacity_transferred -= toxins_heat_capacity + if(delta_phoron) + var/phoron_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_phoron + heat_transferred -= phoron_heat_capacity*model.temperature + heat_capacity_transferred -= phoron_heat_capacity old_self_heat_capacity = heat_capacity()*group_multiplier @@ -775,14 +775,14 @@ What are the archived variables for? oxygen -= delta_oxygen*border_multiplier/group_multiplier carbon_dioxide -= delta_carbon_dioxide*border_multiplier/group_multiplier nitrogen -= delta_nitrogen*border_multiplier/group_multiplier - toxins -= delta_toxins*border_multiplier/group_multiplier + phoron -= delta_phoron*border_multiplier/group_multiplier else oxygen -= delta_oxygen/group_multiplier carbon_dioxide -= delta_carbon_dioxide/group_multiplier nitrogen -= delta_nitrogen/group_multiplier - toxins -= delta_toxins/group_multiplier + phoron -= delta_phoron/group_multiplier - var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_phoron) if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -812,7 +812,7 @@ What are the archived variables for? temperature_mimic(model, model.thermal_conductivity, border_multiplier) if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) - var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins) + var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.phoron) return delta_pressure*R_IDEAL_GAS_EQUATION/volume else return 0 @@ -989,8 +989,8 @@ What are the archived variables for? if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \ ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (carbon_dioxide > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) return 0 - if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \ - ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins))) + if((abs(phoron-sample.phoron) > MINIMUM_AIR_TO_SUSPEND) && \ + ((phoron < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.phoron) || (phoron > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.phoron))) return 0 @@ -1030,7 +1030,7 @@ What are the archived variables for? oxygen += right_side.oxygen carbon_dioxide += right_side.carbon_dioxide nitrogen += right_side.nitrogen - toxins += right_side.toxins + phoron += right_side.phoron if(trace_gases.len || right_side.trace_gases.len) for(var/datum/gas/trace_gas in right_side.trace_gases) @@ -1052,7 +1052,7 @@ What are the archived variables for? oxygen = max(oxygen - right_side.oxygen) carbon_dioxide = max(carbon_dioxide - right_side.carbon_dioxide) nitrogen = max(nitrogen - right_side.nitrogen) - toxins = max(toxins - right_side.toxins) + phoron = max(phoron - right_side.phoron) if(trace_gases.len || right_side.trace_gases.len) for(var/datum/gas/trace_gas in right_side.trace_gases) @@ -1067,7 +1067,7 @@ What are the archived variables for? oxygen *= factor carbon_dioxide *= factor nitrogen *= factor - toxins *= factor + phoron *= factor if(trace_gases && trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) @@ -1080,7 +1080,7 @@ What are the archived variables for? oxygen /= factor carbon_dioxide /= factor nitrogen /= factor - toxins /= factor + phoron /= factor if(trace_gases && trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) diff --git a/code/__HELPERS/bygex.dm b/code/__HELPERS/bygex.dm deleted file mode 100644 index 0955b10750..0000000000 --- a/code/__HELPERS/bygex.dm +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef LIBREGEX_LIBRARY - #define LIBREGEX_LIBRARY "bygex" -#endif - -proc - regEx_compare(str, exp) - return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_compare")(str, exp)) - - regex_compare(str, exp) - return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_compare")(str, exp)) - - regEx_find(str, exp) - return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_find")(str, exp)) - - regex_find(str, exp) - return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_find")(str, exp)) - - regEx_replaceall(str, exp, fmt) - return call(LIBREGEX_LIBRARY, "regEx_replaceall")(str, exp, fmt) - - regex_replaceall(str, exp, fmt) - return call(LIBREGEX_LIBRARY, "regex_replaceall")(str, exp, fmt) - - replacetextEx(str, exp, fmt) - return call(LIBREGEX_LIBRARY, "regEx_replaceallliteral")(str, exp, fmt) - - replacetext(str, exp, fmt) - return call(LIBREGEX_LIBRARY, "regex_replaceallliteral")(str, exp, fmt) - - regEx_replace(str, exp, fmt) - return call(LIBREGEX_LIBRARY, "regEx_replace")(str, exp, fmt) - - regex_replace(str, exp, fmt) - return call(LIBREGEX_LIBRARY, "regex_replace")(str, exp, fmt) - - regEx_findall(str, exp) - return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_findall")(str, exp)) - - regex_findall(str, exp) - return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_findall")(str, exp)) - - -//upon calling a regex match or search, a /datum/regex object is created with str(haystack) and exp(needle) variables set -//it also contains a list(matches) of /datum/match objects, each of which holds the position and length of the match -//matched strings are not returned from the dll, in order to save on memory allocation for large numbers of strings -//instead, you can use regex.str(matchnum) to fetch this string as needed. -//likewise you can also use regex.pos(matchnum) and regex.len(matchnum) as shorthands -/datum/regex - var/str - var/exp - var/error - var/anchors = 0 - var/list/matches = list() - - New(str, exp, results) - src.str = str - src.exp = exp - - if(findtext(results, "Err", 1, 4)) //error message - src.error = results - else - var/list/L = params2list(results) - var/list/M - var{i;j} - for(i in L) - M = L[i] - for(j=2, j<=M.len, j+=2) - matches += new /datum/match(text2num(M[j-1]),text2num(M[j])) - anchors = (j-2)/2 - return matches - - proc - str(i) - if(!i) return str - var/datum/match/M = matches[i] - return copytext(str, M.pos, M.pos+M.len) - - pos(i) - if(!i) return 1 - var/datum/match/M = matches[i] - return M.pos - - len(i) - if(!i) return length(str) - var/datum/match/M = matches[i] - return M.len - - end(i) - if(!i) return length(str) - var/datum/match/M = matches[i] - return M.pos + M.len - - report() //debug tool - . = ":: RESULTS ::\n:: str :: [html_encode(str)]\n:: exp :: [html_encode(exp)]\n:: anchors :: [anchors]" - if(error) - . += "\n[error]" - return - for(var/i=1, i<=matches.len, ++i) - . += "\nMatch[i]\n\t[html_encode(str(i))]\n\tpos=[pos(i)] len=[len(i)]" - -/datum/match - var/pos - var/len - - New(pos, len) - src.pos = pos - src.len = len diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm index d804dcb06a..4a7b9fa646 100644 --- a/code/__HELPERS/files.dm +++ b/code/__HELPERS/files.dm @@ -21,7 +21,7 @@ var/path = root for(var/i=0, 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 e180f2092d..885de82c44 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) @@ -255,10 +315,12 @@ proc/tg_list2text(list/list, glue=",") if(rights & R_SOUNDS) . += "[seperator]+SOUND" if(rights & R_SPAWN) . += "[seperator]+SPAWN" if(rights & R_MOD) . += "[seperator]+MODERATOR" + if(rights & R_MENTOR) . += "[seperator]+MENTOR" return . /proc/ui_style2icon(ui_style) 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/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index f9c2c90dd5..f89488e9c4 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -352,7 +352,7 @@ Turf and target are seperate in case you want to teleport some distance from a t var/select = null var/list/borgs = list() for (var/mob/living/silicon/robot/A in player_list) - if (A.stat == 2 || A.connected_ai || A.scrambledcodes) + if (A.stat == 2 || A.connected_ai || A.scrambledcodes || istype(A,/mob/living/silicon/robot/drone)) continue var/name = "[A.real_name] ([A.modtype] [A.braintype])" borgs[name] = A @@ -531,10 +531,17 @@ Turf and target are seperate in case you want to teleport some distance from a t . += "*no key*" if(include_name && M) + var/name + if(M.real_name) - . += "/([M.real_name])" + name = M.real_name else if(M.name) - . += "/([M.name])" + name = M.name + + if(is_special_character(M)) + . += "/([name])" //Orange + else + . += "/([name])" return . @@ -1267,6 +1274,7 @@ proc/is_hot(obj/item/W as obj) //Is this even used for anything besides balloons? Yes I took out the W:lit stuff because : really shouldnt be used. /proc/is_sharp(obj/item/W as obj) // For the record, WHAT THE HELL IS THIS METHOD OF DOING IT? + if(!W) return 0 if(W.sharp) return 1 return ( \ W.sharp || \ @@ -1374,4 +1382,4 @@ var/list/WALLITEMS = list( return 0 /proc/format_text(text) - return replacetext(replacetext(text,"\proper ",""),"\improper ","") \ No newline at end of file + return replacetext(replacetext(text,"\proper ",""),"\improper ","") diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index c02737400b..b39df75189 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 cb840a1d90..d6918b1f7e 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -32,6 +32,9 @@ build_click(src, client.buildmode, params, A) return + if(control_disabled || stat) + return + var/list/modifiers = params2list(params) if(modifiers["middle"]) MiddleClickOn(A) @@ -46,7 +49,8 @@ CtrlClickOn(A) return - if(control_disabled || stat || world.time <= next_move) return + if(world.time <= next_move) + return next_move = world.time + 9 /* @@ -55,6 +59,7 @@ RestrainedClickOn(A) else */ + A.add_hiddenprint(src) A.attack_ai(src) /* @@ -122,4 +127,4 @@ else // disable/6 is not in Topic; disable/5 disables both temporary and permenant shock Topic("aiDisable=5", list("aiDisable"="5"), 1) - return + return \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 5ce15be96e..7612b48453 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -92,8 +92,9 @@ return - // operate two levels deep here (item in backpack in src; NOT item in box in backpack in src) - if(A == loc || (A in loc) || (A in contents) || (A.loc in contents)) + // operate two STORAGE levels deep here (item in backpack in src; NOT item in box in backpack in src) + var/sdepth = A.storage_depth(src) + if(A == loc || (A in loc) || (sdepth != -1 && sdepth <= 1)) // faster access to objects already on you if(A in contents) @@ -117,7 +118,8 @@ return // Allows you to click on a box's contents, if that box is on the ground, but no deeper than that - if(isturf(A) || isturf(A.loc) || (A.loc && isturf(A.loc.loc))) + sdepth = A.storage_depth_turf() + if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) next_move = world.time + 10 if(A.Adjacent(src)) // see adjacent.dm @@ -291,7 +293,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 640a09d045..d86faacbd1 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 618858d543..5e005c5f0e 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -14,6 +14,7 @@ var/datum/global_hud/global_hud = new() var/obj/screen/blurry var/list/vimpaired var/list/darkMask + var/obj/screen/nvg /datum/global_hud/New() //420erryday psychedellic colours screen overlay for when you are high @@ -30,6 +31,13 @@ var/datum/global_hud/global_hud = new() blurry.layer = 17 blurry.mouse_opacity = 0 + nvg = new /obj/screen() + nvg.screen_loc = "1,1" + nvg.icon = 'icons/obj/nvg_hud_full.dmi' + nvg.icon_state = "nvg_hud" + nvg.layer = 17 + nvg.mouse_opacity = 0 + var/obj/screen/O var/i //that nasty looking dither you get when you're short-sighted @@ -166,9 +174,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 +196,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 +218,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 +239,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 3d97018352..ca053f86e6 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]") diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 4ca8f9f5d7..996ea857ac 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -36,9 +36,6 @@ 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 @@ -276,37 +273,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 821f42ee1b..90a68b02b6 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -39,7 +39,7 @@ user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" - log_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) + msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) //spawn(1800) // this wont work right // M.lastattacker = null @@ -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 c326d83df4..869b10c3a1 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 f2b5f01ce3..366ac7aff9 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -18,9 +18,11 @@ 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 + var/ert_admin_call_only = 0 var/allow_vote_mode = 0 // allow votes to change mode var/allow_admin_jump = 1 // allows admin jumping var/allow_admin_spawning = 1 // allows admin item spawning @@ -29,13 +31,15 @@ var/vote_period = 600 // length of voting period (deciseconds, default 1 minute) var/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called var/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote + var/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100). var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi) var/vote_no_dead = 0 // dead people can't vote (tbi) // var/enable_authentication = 0 // goon authentication var/del_new_on_log = 1 // del's new players if they log before they spawn in var/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard var/traitor_scaling = 0 //if amount of traitors scales based on amount of players - var/protect_roles_from_antagonist = 0// If security and such can be tratior/cult/other + var/objectives_disabled = 0 //if objectives are disabled or not + var/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other var/continous_rounds = 1 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke. var/allow_Metadata = 0 // Metadata is supported. var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1. @@ -56,12 +60,23 @@ var/respawn = 1 var/guest_jobban = 1 var/usewhitelist = 0 + var/mods_are_mentors = 0 var/kick_inactive = 0 //force disconnect for inactive players var/load_jobs_from_txt = 0 var/ToRban = 0 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/max_maint_drones = 5 //This many drones can spawn, + var/allow_drone_spawn = 1 //assuming the admin allow them to. + var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes. + + 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 @@ -129,7 +144,7 @@ var/main_irc = "" var/admin_irc = "" var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix - + var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge. /datum/configuration/New() var/list/L = typesof(/datum/game_mode) - /datum/game_mode @@ -140,7 +155,7 @@ if (M.config_tag) if(!(M.config_tag in modes)) // ensure each mode is added only once - diary << "Adding game mode [M.name] ([M.config_tag]) to configuration." + log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.") src.modes += M.config_tag src.mode_names[M.config_tag] = M.name src.probabilities[M.config_tag] = M.probability @@ -177,7 +192,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 +254,12 @@ if ("log_hrefs") config.log_hrefs = 1 + if ("log_runtime") + config.log_runtime = 1 + + if ("mentors") + config.mods_are_mentors = 1 + if("allow_admin_ooccolor") config.allow_admin_ooccolor = 1 @@ -275,6 +296,12 @@ if ("vote_autotransfer_interval") config.vote_autotransfer_interval = text2num(value) + if ("vote_autogamemode_timeleft") + config.vote_autogamemode_timeleft = text2num(value) + + if("ert_admin_only") + config.ert_admin_call_only = 1 + if ("allow_ai") config.allow_ai = 1 @@ -326,6 +353,9 @@ if ("traitor_scaling") config.traitor_scaling = 1 + if ("objectives_disabled") + config.objectives_disabled = 1 + if("protect_roles_from_antagonist") config.protect_roles_from_antagonist = 1 @@ -340,9 +370,9 @@ if (prob_name in config.modes) config.probabilities[prob_name] = text2num(prob_value) else - diary << "Unknown game mode probability configuration definition: [prob_name]." + log_misc("Unknown game mode probability configuration definition: [prob_name].") else - diary << "Incorrect probability configuration definition: [prob_name] [prob_value]." + log_misc("Incorrect probability configuration definition: [prob_name] [prob_value].") if("allow_random_events") config.allow_random_events = 1 @@ -425,6 +455,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 @@ -446,13 +482,30 @@ else //probably windows, if not this should work anyway config.python_path = "python" - else - diary << "Unknown setting in configuration: '[name]'" + if("use_lib_nudge") + config.use_lib_nudge = 1 + if("allow_cult_ghostwriter") + config.cult_ghostwriter = 1 + + if("req_cult_ghostwriter") + config.cult_ghostwriter_req_cultists = text2num(value) + + if("allow_drone_spawn") + config.allow_drone_spawn = text2num(value) + + if("drone_build_time") + config.drone_build_time = text2num(value) + + if("max_maint_drones") + config.max_maint_drones = text2num(value) + + else + log_misc("Unknown setting in configuration: '[name]'") else if(type == "game_options") if(!value) - diary << "Unknown value for setting [name] in [filename]." + log_misc("Unknown value for setting [name] in [filename].") value = text2num(value) switch(name) @@ -493,7 +546,7 @@ if("limbs_can_break") config.limbs_can_break = value else - diary << "Unknown setting in configuration: '[name]'" + log_misc("Unknown setting in configuration: '[name]'") /datum/configuration/proc/loadsql(filename) // -- TLE var/list/Lines = file2list(filename) @@ -539,7 +592,7 @@ if ("enable_stat_tracking") sqllogging = 1 else - diary << "Unknown setting in configuration: '[name]'" + log_misc("Unknown setting in configuration: '[name]'") /datum/configuration/proc/loadforumsql(filename) // -- TLE var/list/Lines = file2list(filename) @@ -581,7 +634,7 @@ if ("authenticatedgroup") forum_authenticated_group = value else - diary << "Unknown setting in configuration: '[name]'" + log_misc("Unknown setting in configuration: '[name]'") /datum/configuration/proc/pick_mode(mode_name) // I wish I didn't have to instance the game modes in order to look up diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm new file mode 100644 index 0000000000..cb51229c9f --- /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/master_controller.dm b/code/controllers/master_controller.dm index 5e7d308a9e..34b4a045f7 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -30,10 +30,13 @@ datum/controller/game_controller var/total_cost = 0 var/last_thing_processed + var/mob/list/expensive_mobs = list() + var/rebuild_active_areas = 0 datum/controller/game_controller/New() //There can be only one master_controller. Out with the old and in with the new. if(master_controller != src) + log_debug("Rebuilding Master Controller") if(istype(master_controller)) Recover() del(master_controller) @@ -66,6 +69,7 @@ datum/controller/game_controller/proc/setup() setupgenetics() setupfactions() setup_economy() + SetupXenoarch() transfer_controller = new @@ -225,11 +229,15 @@ datum/controller/game_controller/proc/process() datum/controller/game_controller/proc/process_mobs() var/i = 1 + expensive_mobs.Cut() while(i<=mob_list.len) var/mob/M = mob_list[i] if(M) + var/clock = world.timeofday last_thing_processed = M.type M.Life() + if((world.timeofday - clock) > 1) + expensive_mobs += M i++ continue mob_list.Cut(i,i+1) @@ -246,6 +254,10 @@ datum/controller/game_controller/proc/process_diseases() active_diseases.Cut(i,i+1) datum/controller/game_controller/proc/process_machines() + process_machines_process() + process_machines_power() + process_machines_rebuild() +datum/controller/game_controller/proc/process_machines_process() var/i = 1 while(i<=machines.len) var/obj/machinery/Machine = machines[i] @@ -253,12 +265,38 @@ datum/controller/game_controller/proc/process_machines() last_thing_processed = Machine.type if(Machine.process() != PROCESS_KILL) if(Machine) - if(Machine.use_power) - Machine.auto_use_power() i++ continue machines.Cut(i,i+1) +datum/controller/game_controller/proc/process_machines_power() + var/i=1 + while(i<=active_areas.len) + var/area/A = active_areas[i] + if(A.powerupdate && A.master == A) + A.powerupdate -= 1 + for(var/area/SubArea in A.related) + for(var/obj/machinery/M in SubArea) + if(M) + if(M.use_power) + M.auto_use_power() + + if(A.apc.len && A.master == A) + i++ + continue + + A.powerupdate = 0 + active_areas.Cut(i,i+1) + +datum/controller/game_controller/proc/process_machines_rebuild() + if(controller_iteration % 150 == 0 || rebuild_active_areas) //Every 300 seconds we retest every area/machine + for(var/area/A in all_areas) + if(A == A.master) + A.powerupdate += 1 + active_areas |= A + rebuild_active_areas = 0 + + datum/controller/game_controller/proc/process_objects() var/i = 1 while(i<=processing_objects.len) @@ -296,7 +334,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/controllers/voting.dm b/code/controllers/voting.dm index 172642f444..ef1e41dd53 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -50,9 +50,9 @@ datum/controller/vote initiate_vote("crew_transfer","the server") log_debug("The server has called a crew transfer vote") -/* proc/autogamemode() //This is here for whoever can figure out how to make this work + proc/autogamemode() initiate_vote("gamemode","the server") - log_debug("The server has called a gamemode vote")*/ + log_debug("The server has called a gamemode vote") proc/reset() initiator = null @@ -163,13 +163,14 @@ datum/controller/vote restart = 1 else master_mode = . - if(!going) - going = 1 - world << "The round will start soon." if("crew_transfer") if(. == "Initiate Crew Transfer") init_shift_change(null, 1) + if(mode == "gamemode") //fire this even if the vote fails. + if(!going) + going = 1 + world << "The round will start soon." if(restart) world << "World restarting due to vote..." diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index 88efc2ffc3..d411920139 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -79,6 +79,11 @@ var/global/const/base_law_type = /datum/ai_laws/nanotrasen add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.") add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.") +/datum/ai_laws/drone/New() + ..() + add_inherent_law("Preserve, repair and improve the station to the best of your abilities.") + add_inherent_law("Cause no harm to the station or anything on it.") + add_inherent_law("Interfere with no being that is not a fellow drone.") /* General ai_law functions */ diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 1e141a2ac2..019739030b 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -11,6 +11,8 @@ return /obj/effect/datacore/proc/manifest_modify(var/name, var/assignment) + if(PDA_Manifest.len) + PDA_Manifest.Cut() var/datum/data/record/foundrecord var/real_title = assignment @@ -34,6 +36,9 @@ foundrecord.fields["real_rank"] = real_title /obj/effect/datacore/proc/manifest_inject(var/mob/living/carbon/human/H) + if(PDA_Manifest.len) + PDA_Manifest.Cut() + if(H.mind && (H.mind.assigned_role != "MODE")) var/assignment if(H.mind.role_alt_title) @@ -107,13 +112,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.SE - L.fields["identity"] = H.dna.UI + 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 @@ -149,6 +154,11 @@ proc/get_id_photo(var/mob/living/carbon/human/H) else preview_icon.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT) + // Skin color + if(H.species.flags & HAS_SKIN_TONE) + if(!H.species || H.species.flags & HAS_SKIN_COLOR) + preview_icon.Blend(rgb(H.r_skin, H.g_skin, H.b_skin), ICON_ADD) + var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = H.species ? H.species.eyes : "eyes_s") eyes_s.Blend(rgb(H.r_eyes, H.g_eyes, H.b_eyes), ICON_ADD) @@ -205,7 +215,7 @@ proc/get_id_photo(var/mob/living/carbon/human/H) clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY) clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_open"), ICON_OVERLAY) if("Scientist") - clothes_s = new /icon('icons/mob/uniform.dmi', "toxinswhite_s") + clothes_s = new /icon('icons/mob/uniform.dmi', "rndswhite_s") clothes_s.Blend(new /icon('icons/mob/feet.dmi', "white"), ICON_UNDERLAY) clothes_s.Blend(new /icon('icons/mob/suit.dmi', "labcoat_tox_open"), ICON_OVERLAY) if("Chemist") @@ -269,4 +279,4 @@ proc/get_id_photo(var/mob/living/carbon/human/H) del(eyes_s) del(clothes_s) - return preview_icon \ No newline at end of file + return preview_icon diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 7c1dbb0f8c..b513a6cd06 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -258,6 +258,11 @@ client body += "" body += "" body += "" + + body += "" + + body += "" + body += "" if(ishuman(D)) body += "" body += "" @@ -820,6 +825,74 @@ 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["fix_nano"]) + if(!check_rights(R_DEBUG)) return + + var/mob/H = locate(href_list["fix_nano"]) + + if(!istype(H) || !H.client) + usr << "This can only be done on mobs with clients" + return + + + + nanomanager.send_resources(H.client) + + usr << "Resource files sent" + H << "Your NanoUI Resource files have been refreshed" + + log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(H)] ") + + + 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 95adc92dcc..bea5672006 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -16,7 +16,7 @@ var/list/advance_cures = list( "nutriment", "sugar", "orangejuice", "spaceacillin", "kelotane", "ethanol", "leporazine", "synaptizine", "lipozine", - "silver", "gold", "plasma" + "silver", "gold", "phoron" ) /* @@ -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 16b4008fef..dba42d74d6 100644 --- a/code/datums/diseases/appendicitis.dm +++ b/code/datums/diseases/appendicitis.dm @@ -16,6 +16,11 @@ /datum/disease/appendicitis/stage_act() ..() + + if(istype(affected_mob,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = affected_mob + if(H.species.name == "Diona" || H.species.name == "Machine" || H.species.name == "Vox") src.cure() + if(stage == 1) if(affected_mob.op_stage.appendix == 2.0) // appendix is removed, can't get infected again @@ -45,7 +50,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 69a8eb6500..a4d85a5640 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -39,12 +39,14 @@ //Save original dna for when the disease is cured. src.original_dna["name"] = affected_mob.real_name - src.original_dna["UI"] = affected_mob.dna.UI - src.original_dna["SE"] = affected_mob.dna.SE + src.original_dna["UI"] = affected_mob.dna.UI.Copy() + src.original_dna["SE"] = affected_mob.dna.SE.Copy() affected_mob << "\red You don't feel like yourself.." - affected_mob.UpdateAppearance(strain_data["UI"]) - affected_mob.dna.SE = strain_data["SE"] + var/list/newUI=strain_data["UI"] + var/list/newSE=strain_data["SE"] + affected_mob.UpdateAppearance(newUI.Copy()) + affected_mob.dna.SE = newSE.Copy() affected_mob.dna.UpdateSE() affected_mob.real_name = strain_data["name"] domutcheck(affected_mob) @@ -56,8 +58,10 @@ /datum/disease/dnaspread/Del() if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"])) - affected_mob.UpdateAppearance(original_dna["UI"]) - affected_mob.dna.SE = original_dna["SE"] + var/list/newUI=original_dna["UI"] + var/list/newSE=original_dna["SE"] + affected_mob.UpdateAppearance(newUI.Copy()) + affected_mob.dna.SE = newSE.Copy() affected_mob.dna.UpdateSE() affected_mob.real_name = original_dna["name"] diff --git a/code/datums/diseases/rhumba_beat.dm b/code/datums/diseases/rhumba_beat.dm index 8e70770a4a..00bf74e7cd 100644 --- a/code/datums/diseases/rhumba_beat.dm +++ b/code/datums/diseases/rhumba_beat.dm @@ -4,7 +4,7 @@ spread = "On contact" spread_type = CONTACT_GENERAL cure = "Chick Chicky Boom!" - cure_id = list("plasma") + cure_id = list("phoron") agent = "Unknown" affected_species = list("Human") permeability_mod = 1 diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index 512e9f02dc..6d81631890 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -63,7 +63,7 @@ var/global/datum/getrev/revdata = new("config/svndir.txt") s_archive = s if(!revision) abort() - diary << "Revision info loaded succesfully" + log_misc("Revision info loaded succesfully") return return abort() @@ -91,6 +91,6 @@ client/verb/showrevinfo() var/output = "Sorry, the revision info is unavailable." output = file2text("/home/bay12/live/data/gitcommit") output += "Current Infomational Settings:
" - output += "Protect Authority Roles From Tratior: [config.protect_roles_from_antagonist]
" + output += "Protect Authority Roles From Traitor: [config.protect_roles_from_antagonist]
" usr << browse(output,"window=revdata"); return diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 7adf7d987e..32ebbed57e 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -75,6 +75,8 @@ datum/mind 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 @@ -127,7 +129,7 @@ datum/mind if (istype(current, /mob/living/carbon/human) || istype(current, /mob/living/carbon/monkey)) /** Impanted**/ if(istype(current, /mob/living/carbon/human)) - if(H.is_loyalty_implanted(H)) + if(H.is_loyalty_implanted(H)) text = "Loyalty Implant:Remove|Implanted
" else text = "Loyalty Implant:No Implant|Implant him!
" @@ -355,7 +357,7 @@ datum/mind if(!check_rights(R_ADMIN)) return if (href_list["role_edit"]) - var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in get_all_jobs() + var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in joblist if (!new_role) return assigned_role = new_role @@ -497,6 +499,9 @@ datum/mind else if(href_list["implant"]) var/mob/living/carbon/human/H = current + + H.hud_updateflag |= (1 << IMPLOYAL_HUD) // updates that players HUD images so secHUD's pick up they are implanted or not. + switch(href_list["implant"]) if("remove") for(var/obj/item/weapon/implant/loyalty/I in H.contents) @@ -538,6 +543,8 @@ datum/mind log_admin("[key_name_admin(usr)] has de-traitor'ed [current].") else if (href_list["revolution"]) + current.hud_updateflag |= (1 << SPECIALROLE_HUD) + switch(href_list["revolution"]) if("clear") if(src in ticker.mode.revolutionaries) @@ -550,6 +557,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") @@ -559,6 +567,7 @@ datum/mind current << "\red Revolution has been disappointed of your leader traits! You are a regular revolutionary now!" else if(!(src in ticker.mode.revolutionaries)) current << "\red You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!" + current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." else return ticker.mode.revolutionaries += src @@ -570,7 +579,8 @@ 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!" + current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." else if(!(src in ticker.mode.head_revolutionaries)) current << "\blue You are a member of the revolutionaries' leadership now!" else @@ -586,6 +596,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" @@ -627,6 +638,7 @@ datum/mind usr << "\red Reequipping revolutionary goes wrong!" else if (href_list["cult"]) + current.hud_updateflag |= (1 << SPECIALROLE_HUD) switch(href_list["cult"]) if("clear") if(src in ticker.mode.cult) @@ -638,6 +650,11 @@ datum/mind special_role = "Cultist" current << "You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie." current << "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back." + current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." + var/datum/game_mode/cult/cult = ticker.mode + if (istype(cult)) + if(!config.objectives_disabled) + cult.memoize_cult_objectives(src) log_admin("[key_name_admin(usr)] has cult'ed [current].") if("tome") var/mob/living/carbon/human/H = current @@ -662,6 +679,8 @@ datum/mind usr << "\red Spawning amulet failed!" else if (href_list["wizard"]) + current.hud_updateflag |= (1 << SPECIALROLE_HUD) + switch(href_list["wizard"]) if("clear") if(src in ticker.mode.wizards) @@ -676,6 +695,7 @@ datum/mind special_role = "Wizard" //ticker.mode.learn_basic_spells(current) current << "\red You are the Space Wizard!" + current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." log_admin("[key_name_admin(usr)] has wizard'ed [current].") if("lair") current.loc = pick(wizardstart) @@ -684,10 +704,12 @@ datum/mind if("name") ticker.mode.name_wizard(current) if("autoobjectives") - ticker.mode.forge_wizard_objectives(src) - usr << "\blue The objectives for wizard [key] have been generated. You can edit them and anounce manually." + if(!config.objectives_disabled) + ticker.mode.forge_wizard_objectives(src) + usr << "\blue The objectives for wizard [key] have been generated. You can edit them and anounce manually." else if (href_list["changeling"]) + current.hud_updateflag |= (1 << SPECIALROLE_HUD) switch(href_list["changeling"]) if("clear") if(src in ticker.mode.changelings) @@ -704,9 +726,12 @@ datum/mind ticker.mode.grant_changeling_powers(current) special_role = "Changeling" current << "Your powers are awoken. A flash of memory returns to us...we are a changeling!" + if(config.objectives_disabled) + current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." log_admin("[key_name_admin(usr)] has changeling'ed [current].") if("autoobjectives") - ticker.mode.forge_changeling_objectives(src) + if(!config.objectives_disabled) + ticker.mode.forge_changeling_objectives(src) usr << "\blue The objectives for changeling [key] have been generated. You can edit them and anounce manually." if("initialdna") @@ -719,6 +744,10 @@ datum/mind domutcheck(current, null) else if (href_list["nuclear"]) + var/mob/living/carbon/human/H = current + + current.hud_updateflag |= (1 << SPECIALROLE_HUD) + switch(href_list["nuclear"]) if("clear") if(src in ticker.mode.syndicates) @@ -739,13 +768,15 @@ datum/mind current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]" special_role = "Syndicate" current << "\blue You are a [syndicate_name()] agent!" - ticker.mode.forge_syndicate_objectives(src) + if(config.objectives_disabled) + current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." + else + ticker.mode.forge_syndicate_objectives(src) ticker.mode.greet_syndicate(src) log_admin("[key_name_admin(usr)] has nuke op'ed [current].") if("lair") current.loc = get_turf(locate("landmark*Syndicate-Spawn")) if("dressup") - var/mob/living/carbon/human/H = current del(H.belt) del(H.back) del(H.l_ear) @@ -772,6 +803,7 @@ datum/mind usr << "\red No valid nuke found!" else if (href_list["traitor"]) + current.hud_updateflag |= (1 << SPECIALROLE_HUD) switch(href_list["traitor"]) if("clear") if(src in ticker.mode.traitors) @@ -791,14 +823,17 @@ datum/mind special_role = "traitor" current << "\red You are a traitor!" log_admin("[key_name_admin(usr)] has traitor'ed [current].") + if (config.objectives_disabled) + current << "You have been turned into an antagonist- Within the rules, try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonist." if(istype(current, /mob/living/silicon)) var/mob/living/silicon/A = current call(/datum/game_mode/proc/add_law_zero)(A) A.show_laws() if("autoobjectives") - ticker.mode.forge_traitor_objectives(src) - usr << "\blue The objectives for traitor [key] have been generated. You can edit them and anounce manually." + if (!config.objectives_disabled) + ticker.mode.forge_traitor_objectives(src) + usr << "\blue The objectives for traitor [key] have been generated. You can edit them and anounce manually." else if (href_list["monkey"]) var/mob/living/L = current @@ -851,6 +886,7 @@ datum/mind current.radiation -= 50 else if (href_list["silicon"]) + current.hud_updateflag |= (1 << SPECIALROLE_HUD) switch(href_list["silicon"]) if("unmalf") if(src in ticker.mode.malf_ai) @@ -1004,11 +1040,12 @@ datum/mind special_role = "malfunction" current.icon_state = "ai-malf" - proc/make_Tratior() + proc/make_Traitor() if(!(src in ticker.mode.traitors)) ticker.mode.traitors += src special_role = "traitor" - ticker.mode.forge_traitor_objectives(src) + if (!config.objectives_disabled) + ticker.mode.forge_traitor_objectives(src) ticker.mode.finalize_traitor(src) ticker.mode.greet_traitor(src) @@ -1047,7 +1084,8 @@ datum/mind ticker.mode.changelings += src ticker.mode.grant_changeling_powers(current) special_role = "Changeling" - ticker.mode.forge_changeling_objectives(src) + if(!config.objectives_disabled) + ticker.mode.forge_changeling_objectives(src) ticker.mode.greet_changeling(src) proc/make_Wizard() diff --git a/code/datums/spells/horsemask.dm b/code/datums/spells/horsemask.dm index f3ecc12151..2ea66dac57 100644 --- a/code/datums/spells/horsemask.dm +++ b/code/datums/spells/horsemask.dm @@ -28,12 +28,23 @@ user << "They are too far away!" return - var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead - magichead.canremove = 0 //curses! - magichead.flags_inv = null //so you can still see their face - magichead.voicechange = 1 //NEEEEIIGHH + var/obj/item/clothing/mask/horsehead/magic/magichead = new /obj/item/clothing/mask/horsehead/magic target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \ "Your face burns up, and shortly after the fire you realise you have the face of a horse!") target.equip_to_slot(magichead, slot_wear_mask) flick("e_flash", target.flash) + +//item used by the horsehead spell +/obj/item/clothing/mask/horsehead/magic + //flags_inv = null //so you can still see their face... no. How can you recognize someone when their face is completely different? + voicechange = 1 //NEEEEIIGHH + + dropped(mob/user as mob) + canremove = 1 + ..() + + equipped(var/mob/user, var/slot) + if (slot == slot_wear_mask) + canremove = 0 //curses! + ..() diff --git a/code/datums/sun.dm b/code/datums/sun.dm index 82acfa0cff..868fe1eed8 100644 --- a/code/datums/sun.dm +++ b/code/datums/sun.dm @@ -6,6 +6,7 @@ var/rate var/list/solars // for debugging purposes, references solars_list at the constructor var/nexttime = 3600 // Replacement for var/counter to force the sun to move every X IC minutes + var/lastAngleUpdate /datum/sun/New() @@ -28,15 +29,25 @@ counter = 0 */ angle = ((rate*world.time/100)%360 + 360)%360 + /* Yields a 45 - 75 IC minute rotational period Rotation rate can vary from 4.8 deg/min to 8 deg/min (288 to 480 deg/hr) */ - // To prevent excess server load the server only updates the sun's sight lines every 6 minutes - if(nexttime < world.time) + if(lastAngleUpdate != angle) + for(var/obj/machinery/power/tracker/T in solars_list) + if(!T.powernet) + solars_list.Remove(T) + continue + T.set_angle(angle) + lastAngleUpdate=angle + + + + if(nexttime > world.time) return - nexttime = nexttime + 3600 // 600 world.time ticks = 1 minute, 3600 = 6 minutes. + nexttime = nexttime + 600 // 600 world.time ticks = 1 minute // now calculate and cache the (dx,dy) increments for line drawing @@ -58,22 +69,13 @@ dy = c / abs(s) - for(var/obj/machinery/power/M in solars_list) + for(var/obj/machinery/power/solar/S in solars_list) - if(!M.powernet) - solars_list.Remove(M) + if(!S.powernet) + solars_list.Remove(S) continue - - // Solar Tracker - if(istype(M, /obj/machinery/power/tracker)) - var/obj/machinery/power/tracker/T = M - T.set_angle(angle) - - // Solar Panel - else if(istype(M, /obj/machinery/power/solar)) - var/obj/machinery/power/solar/S = M - if(S.control) - occlusion(S) + if(S.control) + occlusion(S) diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 9b1ccf64b0..c8768a0e40 100755 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -5,7 +5,7 @@ //BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle. //NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points. -var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Medical / Science","Hydroponics") +var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Medical / Science","Hydroponics", "Supply", "Miscellaneous") /datum/supply_packs var/name = null @@ -44,19 +44,24 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee hidden = 1 /datum/supply_packs/food - name = "Food crate" - contains = list(/obj/item/weapon/reagent_containers/food/drinks/flour, + name = "Kitchen supply crate" + contains = list(/obj/item/weapon/reagent_containers/food/snacks/flour, + /obj/item/weapon/reagent_containers/food/snacks/flour, + /obj/item/weapon/reagent_containers/food/snacks/flour, + /obj/item/weapon/reagent_containers/food/snacks/flour, /obj/item/weapon/reagent_containers/food/drinks/milk, /obj/item/weapon/reagent_containers/food/drinks/milk, /obj/item/weapon/storage/fancy/egg_box, - /obj/item/weapon/reagent_containers/food/condiment/enzyme, - /obj/item/weapon/reagent_containers/food/snacks/grown/banana, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/meat, + /obj/item/weapon/reagent_containers/food/snacks/meat, /obj/item/weapon/reagent_containers/food/snacks/grown/banana, /obj/item/weapon/reagent_containers/food/snacks/grown/banana) cost = 10 containertype = /obj/structure/closet/crate/freezer containername = "Food crate" - group = "Hospitality" + group = "Supply" /datum/supply_packs/monkey name = "Monkey crate" @@ -108,7 +113,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Security" /datum/supply_packs/toner - name = "Toner Cartridges" + name = "Toner cartridges" contains = list(/obj/item/device/toner, /obj/item/device/toner, /obj/item/device/toner, @@ -117,23 +122,24 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/device/toner) cost = 10 containertype = /obj/structure/closet/crate - containername = "Toner Cartridges" - group = "Operations" + containername = "Toner cartridges" + group = "Supply" /datum/supply_packs/party name = "Party equipment" contains = list(/obj/item/weapon/storage/box/drinkingglasses, /obj/item/weapon/reagent_containers/food/drinks/shaker, + /obj/item/weapon/reagent_containers/food/drinks/flask/barflask, /obj/item/weapon/reagent_containers/food/drinks/bottle/patron, /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" @@ -170,7 +176,17 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/clothing/mask/gas) cost = 35 containertype = /obj/structure/closet/crate/internals - containername = "Emergency Crate" + containername = "Emergency crate" + group = "Engineering" + +/datum/supply_packs/evacuation + name = "Inflatable barriers" + contains = list(/obj/item/weapon/storage/briefcase/inflatable, + /obj/item/weapon/storage/briefcase/inflatable, + /obj/item/weapon/storage/briefcase/inflatable) + cost = 20 + containertype = /obj/structure/closet/crate + containername = "Inflatable Barrier Crate" group = "Engineering" /datum/supply_packs/janitor @@ -192,7 +208,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee cost = 10 containertype = /obj/structure/closet/crate containername = "Janitorial supplies" - group = "Operations" + group = "Supply" /datum/supply_packs/lightbulbs name = "Replacement lights" @@ -204,26 +220,6 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee containername = "Replacement lights" group = "Engineering" -/datum/supply_packs/costume - name = "Standard Costume crate" - contains = list(/obj/item/weapon/storage/backpack/clown, - /obj/item/clothing/shoes/clown_shoes, - /obj/item/clothing/mask/gas/clown_hat, - /obj/item/clothing/under/rank/clown, - /obj/item/weapon/bikehorn, - /obj/item/clothing/under/mime, - /obj/item/clothing/shoes/black, - /obj/item/clothing/gloves/white, - /obj/item/clothing/mask/gas/mime, - /obj/item/clothing/head/beret, - /obj/item/clothing/suit/suspenders, - /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing) - cost = 10 - containertype = /obj/structure/closet/crate/secure - containername = "Standard Costumes" - access = access_theatre - group = "Operations" - /datum/supply_packs/wizard name = "Wizard costume" contains = list(/obj/item/weapon/staff, @@ -233,7 +229,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee cost = 20 containertype = /obj/structure/closet/crate containername = "Wizard costume crate" - group = "Operations" + group = "Miscellaneous" /datum/supply_packs/mule name = "MULEbot Crate" @@ -270,46 +266,52 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee //farm animals - useless and annoying, but potentially a good source of food /datum/supply_packs/cow - name = "Cow Crate" + name = "Cow crate" cost = 30 containertype = /obj/structure/largecrate/cow - containername = "Cow Crate" + containername = "Cow crate" access = access_hydroponics + group = "Hydroponics" /datum/supply_packs/goat - name = "Goat Crate" + name = "Goat crate" cost = 25 containertype = /obj/structure/largecrate/goat - containername = "Goat Crate" + containername = "Goat crate" access = access_hydroponics group = "Hydroponics" /datum/supply_packs/chicken - name = "Chicken Crate" + name = "Chicken crate" cost = 20 containertype = /obj/structure/largecrate/chick - containername = "Chicken Crate" + containername = "Chicken crate" access = access_hydroponics group = "Hydroponics" /datum/supply_packs/lisa - name = "Corgi Crate" + name = "Corgi crate" contains = list() cost = 50 containertype = /obj/structure/largecrate/lisa - containername = "Corgi Crate" + containername = "Corgi crate" group = "Hydroponics" /datum/supply_packs/seeds - name = "Seeds Crate" + name = "Seeds crate" contains = list(/obj/item/seeds/chiliseed, /obj/item/seeds/berryseed, /obj/item/seeds/cornseed, /obj/item/seeds/eggplantseed, /obj/item/seeds/tomatoseed, + /obj/item/seeds/appleseed, /obj/item/seeds/soyaseed, /obj/item/seeds/wheatseed, /obj/item/seeds/carrotseed, + /obj/item/seeds/harebell, + /obj/item/seeds/lemonseed, + /obj/item/seeds/orangeseed, + /obj/item/seeds/grassseed, /obj/item/seeds/sunflowerseed, /obj/item/seeds/chantermycelium, /obj/item/seeds/potatoseed, @@ -321,7 +323,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Hydroponics" /datum/supply_packs/weedcontrol - name = "Weed Control Crate" + name = "Weed control crate" contains = list(/obj/item/weapon/scythe, /obj/item/clothing/mask/gas, /obj/item/weapon/grenade/chem_grenade/antiweed, @@ -333,7 +335,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Hydroponics" /datum/supply_packs/exoticseeds - name = "Exotic Seeds Crate" + name = "Exotic seeds crate" contains = list(/obj/item/seeds/nettleseed, /obj/item/seeds/replicapod, /obj/item/seeds/replicapod, @@ -343,6 +345,10 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/seeds/amanitamycelium, /obj/item/seeds/reishimycelium, /obj/item/seeds/bananaseed, + /obj/item/seeds/riceseed, + /obj/item/seeds/eggplantseed, + /obj/item/seeds/limeseed, + /obj/item/seeds/grapeseed, /obj/item/seeds/eggyseed) cost = 15 containertype = /obj/structure/closet/crate/hydroponics @@ -368,7 +374,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Medical / Science" /datum/supply_packs/virus - name = "Virus crate" + name = "Virus sample crate" /* contains = list(/obj/item/weapon/reagent_containers/glass/bottle/flu_virion, /obj/item/weapon/reagent_containers/glass/bottle/cold, /obj/item/weapon/reagent_containers/glass/bottle/epiglottis_virion, @@ -387,12 +393,12 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/weapon/virusdish/random) cost = 25 containertype = "/obj/structure/closet/crate/secure" - containername = "Virus crate" + containername = "Virus sample crate" access = access_cmo group = "Medical / Science" /datum/supply_packs/metal50 - name = "50 Metal Sheets" + name = "50 metal sheets" contains = list(/obj/item/stack/sheet/metal) amount = 50 cost = 10 @@ -401,7 +407,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Engineering" /datum/supply_packs/glass50 - name = "50 Glass Sheets" + name = "50 glass sheets" contains = list(/obj/item/stack/sheet/glass) amount = 50 cost = 10 @@ -409,6 +415,15 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee containername = "Glass sheets crate" group = "Engineering" +/datum/supply_packs/wood50 + name = "50 wooden planks" + contains = list(/obj/item/stack/sheet/wood) + amount = 50 + cost = 10 + containertype = /obj/structure/closet/crate + containername = "Wooden planks crate" + group = "Engineering" + /datum/supply_packs/electrical name = "Electrical maintenance crate" contains = list(/obj/item/weapon/storage/toolbox/electrical, @@ -492,7 +507,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/weapon/paper/solar) cost = 20 containertype = /obj/structure/closet/crate - containername = "solar pack crate" + containername = "Solar pack crate" group = "Engineering" /datum/supply_packs/engine @@ -568,7 +583,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /datum/supply_packs/robotics - name = "Robotics Assembly Crate" + name = "Robotics assembly crate" contains = list(/obj/item/device/assembly/prox_sensor, /obj/item/device/assembly/prox_sensor, /obj/item/device/assembly/prox_sensor, @@ -581,15 +596,15 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/weapon/cell/high) cost = 10 containertype = /obj/structure/closet/crate/secure/gear - containername = "Robotics Assembly" + containername = "Robotics assembly" access = access_robotics group = "Engineering" -/datum/supply_packs/plasma - name = "Plasma assembly crate" - contains = list(/obj/item/weapon/tank/plasma, - /obj/item/weapon/tank/plasma, - /obj/item/weapon/tank/plasma, +/datum/supply_packs/phoron + name = "Phoron assembly crate" + contains = list(/obj/item/weapon/tank/phoron, + /obj/item/weapon/tank/phoron, + /obj/item/weapon/tank/phoron, /obj/item/device/assembly/igniter, /obj/item/device/assembly/igniter, /obj/item/device/assembly/igniter, @@ -600,8 +615,8 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/device/assembly/timer, /obj/item/device/assembly/timer) cost = 10 - containertype = /obj/structure/closet/crate/secure/plasma - containername = "Plasma assembly crate" + containertype = /obj/structure/closet/crate/secure/phoron + containername = "Phoron assembly crate" access = access_tox_storage group = "Medical / Science" @@ -624,9 +639,9 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /datum/supply_packs/eweapons name = "Experimental weapons crate" contains = list(/obj/item/weapon/flamethrower/full, - /obj/item/weapon/tank/plasma, - /obj/item/weapon/tank/plasma, - /obj/item/weapon/tank/plasma, + /obj/item/weapon/tank/phoron, + /obj/item/weapon/tank/phoron, + /obj/item/weapon/tank/phoron, /obj/item/weapon/grenade/chem_grenade/incendiary, /obj/item/weapon/grenade/chem_grenade/incendiary, /obj/item/weapon/grenade/chem_grenade/incendiary) @@ -695,6 +710,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, @@ -738,30 +765,30 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Security" /datum/supply_packs/securitybarriers - name = "Security Barriers" + name = "Security barrier crate" contains = list(/obj/machinery/deployable/barrier, /obj/machinery/deployable/barrier, /obj/machinery/deployable/barrier, /obj/machinery/deployable/barrier) cost = 20 containertype = /obj/structure/closet/crate/secure/gear - containername = "Security Barriers crate" + containername = "Security barrier crate" group = "Security" /datum/supply_packs/securitybarriers - name = "Shield Generators" + name = "Wall shield Generators" contains = list(/obj/machinery/shieldwallgen, /obj/machinery/shieldwallgen, /obj/machinery/shieldwallgen, /obj/machinery/shieldwallgen) cost = 20 containertype = /obj/structure/closet/crate/secure - containername = "Shield Generators crate" + containername = "wall shield generators crate" access = access_teleporter group = "Security" /datum/supply_packs/randomised - var/num_contained = 3 //number of items picked to be contained in a randomised crate + var/num_contained = 4 //number of items picked to be contained in a randomised crate contains = list(/obj/item/clothing/head/collectable/chef, /obj/item/clothing/head/collectable/paper, /obj/item/clothing/head/collectable/tophat, @@ -786,7 +813,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee cost = 200 containertype = /obj/structure/closet/crate containername = "Collectable hats crate! Brought to you by Bass.inc!" - group = "Operations" + group = "Miscellaneous" /datum/supply_packs/randomised/New() manifest += "Contains any [num_contained] of:" @@ -832,7 +859,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee group = "Operations" /datum/supply_packs/boxes - name = "Empty Box supplies" + name = "Empty boxes" contains = list(/obj/item/weapon/storage/box, /obj/item/weapon/storage/box, /obj/item/weapon/storage/box, @@ -845,8 +872,8 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/weapon/storage/box) cost = 10 containertype = "/obj/structure/closet/crate" - containername = "Empty Box crate" - group = "Operations" + containername = "Empty box crate" + group = "Supply" /datum/supply_packs/surgery name = "Surgery crate" @@ -884,12 +911,48 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/pizzabox/mushroom, /obj/item/pizzabox/meat, /obj/item/pizzabox/vegetable) - name = "Surprise pack of five dozen pizzas" + name = "Surprise pack of five pizzas" cost = 15 containertype = /obj/structure/closet/crate/freezer containername = "Pizza crate" group = "Hospitality" +/datum/supply_packs/randomised/costume + num_contained = 2 + contains = list(/obj/item/clothing/suit/pirate, + /obj/item/clothing/suit/judgerobe, + /obj/item/clothing/suit/wcoat, + /obj/item/clothing/suit/hastur, + /obj/item/clothing/suit/holidaypriest, + /obj/item/clothing/suit/nun, + /obj/item/clothing/suit/imperium_monk, + /obj/item/clothing/suit/ianshirt, + /obj/item/clothing/under/gimmick/rank/captain/suit, + /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit, + /obj/item/clothing/under/lawyer/purpsuit, + /obj/item/clothing/under/rank/mailman, + /obj/item/clothing/under/dress/dress_saloon, + /obj/item/clothing/suit/suspenders, + /obj/item/clothing/suit/storage/labcoat/mad, + /obj/item/clothing/suit/bio_suit/plaguedoctorsuit, + /obj/item/clothing/under/schoolgirl, + /obj/item/clothing/under/owl, + /obj/item/clothing/under/waiter, + /obj/item/clothing/under/gladiator, + /obj/item/clothing/under/soviet, + /obj/item/clothing/under/scratch, + /obj/item/clothing/under/wedding/bride_white, + /obj/item/clothing/suit/chef, + /obj/item/clothing/suit/apron/overalls, + /obj/item/clothing/under/redcoat, + /obj/item/clothing/under/kilt) + name = "Costumes crate" + cost = 10 + containertype = /obj/structure/closet/crate/secure + containername = "Actor Costumes" + access = access_theatre + group = "Miscellaneous" + /datum/supply_packs/formal_wear contains = list(/obj/item/clothing/head/bowler, /obj/item/clothing/head/that, @@ -899,14 +962,17 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/clothing/under/suit_jacket/female, /obj/item/clothing/under/suit_jacket/really_black, /obj/item/clothing/under/suit_jacket/red, + /obj/item/clothing/under/lawyer/bluesuit, + /obj/item/clothing/under/lawyer/purpsuit, /obj/item/clothing/shoes/black, /obj/item/clothing/shoes/black, + /obj/item/clothing/shoes/leather, /obj/item/clothing/suit/wcoat) name = "Formalwear closet" cost = 30 containertype = /obj/structure/closet containername = "Formalwear for the best occasions." - group = "Operations" + group = "Miscellaneous" /datum/supply_packs/rust_injector contains = list(/obj/machinery/power/rust_fuel_injector) @@ -946,10 +1012,28 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /datum/supply_packs/shield_gen contains = list(/obj/item/weapon/circuitboard/shield_gen) - name = "Experimental shield generator circuitry" + name = "Bubble shield generator circuitry" cost = 50 containertype = /obj/structure/closet/crate/secure - containername = "Experimental shield generator" + containername = "bubble shield generator circuitry crate" + group = "Engineering" + access = access_ce + +/datum/supply_packs/shield_gen_ex + contains = list(/obj/item/weapon/circuitboard/shield_gen_ex) + name = "Hull shield generator circuitry" + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "hull shield generator circuitry crate" + group = "Engineering" + access = access_ce + +/datum/supply_packs/shield_cap + contains = list(/obj/item/weapon/circuitboard/shield_cap) + name = "Bubble shield capacitor circuitry" + cost = 50 + containertype = /obj/structure/closet/crate/secure + containername = "shield capacitor circuitry crate" group = "Engineering" access = access_ce @@ -957,7 +1041,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee name = "Supermatter Core" contains = list(/obj/machinery/power/supermatter) cost = 50 - containertype = /obj/structure/closet/crate/secure/plasma + containertype = /obj/structure/closet/crate/secure/phoron containername = "Supermatter crate (CAUTION)" group = "Engineering" access = access_ce @@ -967,27 +1051,18 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee name = "Supermatter Shard" contains = list(/obj/machinery/power/supermatter/shard) cost = 25 - containertype = /obj/structure/closet/crate/secure/plasma + containertype = /obj/structure/closet/crate/secure/phoron 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" - cost = 50 - containertype = /obj/structure/closet/crate/secure - containername = "Experimental shield capacitor" - group = "Engineering" - access = access_ce - /datum/supply_packs/eftpos contains = list(/obj/item/device/eftpos) name = "EFTPOS scanner" cost = 10 containertype = /obj/structure/closet/crate containername = "EFTPOS crate" - group = "Operations" + group = "Miscellaneous" /datum/supply_packs/teg contains = list(/obj/machinery/power/generator) @@ -1026,15 +1101,13 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee access = access_atmospherics /datum/supply_packs/bee_keeper - name = "Beekeeping Crate" + name = "Beekeeping crate" contains = list(/obj/item/beezeez, - /obj/item/beezeez, /obj/item/weapon/bee_net, /obj/item/apiary, - /obj/item/queen_bee, - /obj/item/queen_bee, /obj/item/queen_bee) - cost = 20 + cost = 40 + contraband = 1 containertype = /obj/structure/closet/crate/hydroponics containername = "Beekeeping crate" access = access_hydroponics diff --git a/code/defines/obj.dm b/code/defines/obj.dm index 6c6269d301..25a5242c07 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -51,122 +51,205 @@ //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. +Instead of creating this list over and over when someone leaves their PDA open to the page +we'll only update it when it changes. The PDA_Manifest global list is zeroed out upon any change +using /obj/effect/datacore/proc/manifest_inject( ), or manifest_insert( ) +*/ + +var/global/list/PDA_Manifest = list() + +/obj/effect/datacore/proc/get_manifest_json() + if(PDA_Manifest.len) + return PDA_Manifest + 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) + + + PDA_Manifest = list(\ + "heads" = heads,\ + "sec" = sec,\ + "eng" = eng,\ + "med" = med,\ + "sci" = sci,\ + "civ" = civ,\ + "bot" = bot,\ + "misc" = misc\ + ) + return PDA_Manifest - dat += "" - dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly - dat = replacetext(dat, "\t", "") - return dat /obj/effect/laser name = "laser" @@ -185,49 +268,6 @@ var/list/container = list( ) - -/obj/structure/cable - level = 1 - anchored =1 - var/datum/powernet/powernet - name = "power cable" - desc = "A flexible superconducting cable for heavy-duty power transfer" - icon = 'icons/obj/power_cond_red.dmi' - icon_state = "0-1" - var/d1 = 0 - var/d2 = 1 - layer = 2.44 //Just below unary stuff, which is at 2.45 and above pipes, which are at 2.4 - var/cable_color = "red" - var/obj/structure/powerswitch/power_switch - -/obj/structure/cable/yellow - cable_color = "yellow" - icon = 'icons/obj/power_cond_yellow.dmi' - -/obj/structure/cable/green - cable_color = "green" - icon = 'icons/obj/power_cond_green.dmi' - -/obj/structure/cable/blue - cable_color = "blue" - icon = 'icons/obj/power_cond_blue.dmi' - -/obj/structure/cable/pink - cable_color = "pink" - icon = 'icons/obj/power_cond_pink.dmi' - -/obj/structure/cable/orange - cable_color = "orange" - icon = 'icons/obj/power_cond_orange.dmi' - -/obj/structure/cable/cyan - cable_color = "cyan" - icon = 'icons/obj/power_cond_cyan.dmi' - -/obj/structure/cable/white - cable_color = "white" - icon = 'icons/obj/power_cond_white.dmi' - /obj/effect/projection name = "Projection" desc = "This looks like a projection of something." @@ -257,7 +297,7 @@ item_state = "beachball" density = 0 anchored = 0 - w_class = 1.0 + w_class = 2.0 force = 0.0 throwforce = 0.0 throw_speed = 1 diff --git a/code/defines/obj/hydro.dm b/code/defines/obj/hydro.dm index 2b57dbeffa..443ba95b09 100644 --- a/code/defines/obj/hydro.dm +++ b/code/defines/obj/hydro.dm @@ -18,7 +18,7 @@ icon = 'icons/obj/seeds.dmi' icon_state = "seed" // unknown plant seed - these shouldn't exist in-game flags = FPRINT | TABLEPASS - w_class = 1.0 // Makes them pocketable + w_class = 2.0 // Makes them pocketable var/mypath = "/obj/item/seeds" var/plantname = "Plants" var/productname = "" @@ -1167,7 +1167,7 @@ attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/circular_saw) || istype(W, /obj/item/weapon/hatchet) || (istype(W, /obj/item/weapon/twohanded/fireaxe) && W:wielded) || istype(W, /obj/item/weapon/melee/energy)) - user.show_message("You make planks out of the [src]!", 1) + user.show_message("You make planks out of \the [src]!", 1) for(var/i=0,i<2,i++) var/obj/item/stack/sheet/wood/NG = new (user.loc) for (var/obj/item/stack/sheet/wood/G in user.loc) @@ -1205,7 +1205,7 @@ force = 0 flags = TABLEPASS throwforce = 1 - w_class = 1.0 + w_class = 2.0 throw_speed = 1 throw_range = 3 plant_type = 1 @@ -1229,7 +1229,7 @@ force = 15 flags = TABLEPASS throwforce = 1 - w_class = 1.0 + w_class = 2.0 throw_speed = 1 throw_range = 3 plant_type = 1 @@ -1251,7 +1251,7 @@ force = 30 flags = TABLEPASS throwforce = 1 - w_class = 1.0 + w_class = 2.0 throw_speed = 1 throw_range = 3 plant_type = 1 @@ -1417,7 +1417,7 @@ icon = 'icons/obj/chemical.dmi' icon_state = "bottle16" flags = FPRINT | TABLEPASS - w_class = 1.0 + w_class = 2.0 var/mutmod = 0 var/yieldmod = 0 New() diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index e798f26c60..f16d2810b0 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -31,7 +31,7 @@ icon = 'icons/obj/items.dmi' icon_state = "banana_peel" item_state = "banana_peel" - w_class = 1.0 + w_class = 2.0 throwforce = 0 throw_speed = 4 throw_range = 20 @@ -42,7 +42,7 @@ icon = 'icons/obj/harvest.dmi' icon_state = "corncob" item_state = "corncob" - w_class = 1.0 + w_class = 2.0 throwforce = 0 throw_speed = 4 throw_range = 20 @@ -53,13 +53,13 @@ gender = PLURAL icon = 'icons/obj/items.dmi' icon_state = "soap" - w_class = 1.0 + w_class = 2.0 throwforce = 0 throw_speed = 4 throw_range = 20 /obj/item/weapon/soap/nanotrasen - desc = "A Nanotrasen brand bar of soap. Smells of plasma." + desc = "A Nanotrasen brand bar of soap. Smells of phoron." icon_state = "soapnt" /obj/item/weapon/soap/deluxe @@ -90,7 +90,7 @@ icon = 'icons/obj/items.dmi' icon_state = "c_tube" throwforce = 1 - w_class = 1.0 + w_class = 2.0 throw_speed = 4 throw_range = 5 @@ -117,7 +117,7 @@ desc = "Better keep this safe." icon_state = "nucleardisk" item_state = "card-id" - w_class = 1.0 + w_class = 2.0 /* /obj/item/weapon/game_kit @@ -229,7 +229,7 @@ icon_state = "large" sharp = 1 desc = "Could probably be used as ... a throwing weapon?" - w_class = 1.0 + w_class = 2.0 force = 5.0 throwforce = 8.0 item_state = "shard-glass" @@ -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." @@ -394,6 +401,8 @@ name = "power control module" icon_state = "power_mod" 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" @@ -452,7 +461,7 @@ icon = 'icons/obj/food.dmi' icon_state = "meat" flags = FPRINT | TABLEPASS | CONDUCT - w_class = 1.0 + w_class = 2.0 origin_tech = "biotech=2" /obj/item/weapon/hatchet diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 9c04d5b672..02b806a50c 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -14,6 +14,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station */ + /area var/fire = null var/atmos = 1 @@ -31,6 +32,8 @@ NOTE: there are two lists of areas in the end of this file: centcom and station var/eject = null + var/debug = 0 + var/powerupdate = 10 //We give everything 10 ticks to settle out it's power usage. var/requires_power = 1 var/always_unpowered = 0 //this gets overriden to 1 for space in area/New() @@ -43,7 +46,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station var/used_environ = 0 var/has_gravity = 1 - + var/list/apc = list() var/no_air = null var/area/master // master area used for power calcluations // (original area before splitting due to sd_DAL) @@ -664,6 +667,10 @@ var/list/ghostteleportlocs = list() name = "Waste Disposal" icon_state = "disposal" +/area/maintenance/evahallway + name = "\improper EVA Hallway" + icon_state = "eva" + //Hallway /area/hallway/primary/fore @@ -788,6 +795,14 @@ var/list/ghostteleportlocs = list() name = "\improper Security Dormitories" icon_state = "Sleep" +/area/crew_quarters/sleep/bedrooms + name = "\improper Dormitory Bedroom" + icon_state = "Sleep" + +/area/crew_quarters/sleep/cryo + name = "\improper Cryogenic Storage" + icon_state = "Sleep" + /area/crew_quarters/sleep_male name = "\improper Male Dorm" icon_state = "Sleep" @@ -845,7 +860,7 @@ var/list/ghostteleportlocs = list() icon_state = "chapeloffice" /area/lawoffice - name = "\improper Law Office" + name = "\improper Internal Affairs" icon_state = "law" @@ -921,23 +936,64 @@ var/list/ghostteleportlocs = list() //Engineering /area/engine + + drone_fabrication + name = "\improper Drone Fabrication" + icon_state = "engine" + engine_smes - name = "\improper Engineering SMES" + name = "Engineering SMES" icon_state = "engine_smes" - requires_power = 0//This area only covers the batteries and they deal with their own power +// requires_power = 0//This area only covers the batteries and they deal with their own power + + engine_room + name = "\improper Engine Room" + icon_state = "engine" + + engine_airlock + name = "\improper Engine Room Airlock" + icon_state = "engine" + + engine_monitoring + name = "\improper Engine Monitoring Room" + icon_state = "engine_monitoring" + + engineering_monitoring + name = "\improper Engineering Monitoring Room" + icon_state = "engine_monitoring" engineering name = "Engineering" icon_state = "engine_smes" - break_room + engineering_foyer name = "\improper Engineering Foyer" icon_state = "engine" + break_room + name = "\improper Engineering Break Room" + icon_state = "engine" + chiefs_office name = "\improper Chief Engineer's office" icon_state = "engine_control" + hallway + name = "\improper Engineering Hallway" + icon_state = "engine_hallway" + + engine_eva + name = "\improper Engine EVA" + icon_state = "engine_eva" + + workshop + name = "\improper Engineering Workshop" + icon_state = "engine_storage" + + locker_room + name = "\improper Engineering Locker Room" + icon_state = "engine_storage" + //Solars @@ -1041,7 +1097,6 @@ var/list/ghostteleportlocs = list() icon_state = "medbay3" music = 'sound/ambience/signal.ogg' - /area/medical/biostorage name = "\improper Secondary Storage" icon_state = "medbay2" @@ -1067,7 +1122,7 @@ var/list/ghostteleportlocs = list() icon_state = "patients" /area/medical/ward - name = "\improper Medbay Patient Ward" + name = "\improper Recovery Ward" icon_state = "patients" /area/medical/patient_a @@ -1082,8 +1137,8 @@ var/list/ghostteleportlocs = list() name = "\improper Isolation C" icon_state = "patients" -/area/medical/iso_access - name = "\improper Isolation Access" +/area/medical/patient_wing + name = "\improper Patient Wing" icon_state = "patients" /area/medical/cmo @@ -1106,6 +1161,10 @@ var/list/ghostteleportlocs = list() name = "\improper Virology" icon_state = "virology" +/area/medical/virologyaccess + name = "\improper Virology Access" + icon_state = "virology" + /area/medical/morgue name = "\improper Morgue" icon_state = "morgue" @@ -1115,11 +1174,19 @@ var/list/ghostteleportlocs = list() icon_state = "chem" /area/medical/surgery - name = "\improper Surgery" + name = "\improper Operating Theatre 1" + icon_state = "surgery" + +/area/medical/surgery2 + name = "\improper Operating Theatre 2" icon_state = "surgery" /area/medical/surgeryobs - name = "\improper Surgery Observation" + name = "\improper Operation Observation Room" + icon_state = "surgery" + +/area/medical/surgeryprep + name = "\improper Pre-Op Prep Room" icon_state = "surgery" /area/medical/cryo @@ -1139,7 +1206,7 @@ var/list/ghostteleportlocs = list() icon_state = "cloning" /area/medical/sleeper - name = "\improper Medical Treatment Center" + name = "\improper Emergency Treatment Centre" icon_state = "exam_room" //Security @@ -1180,6 +1247,11 @@ var/list/ghostteleportlocs = list() name = "\improper Firing Range" icon_state = "firingrange" +/area/security/tactical + name = "\improper Tactical Equipment" + icon_state = "Tactical" + + /* New() ..() @@ -1277,48 +1349,44 @@ var/list/ghostteleportlocs = list() name = "Hydroponics" icon_state = "hydro" -//Toxins +//rnd (Research and Development -/area/toxins/lab +/area/rnd/lab name = "\improper Research and Development" icon_state = "toxlab" -/area/toxins/hallway +/area/rnd/hallway name = "\improper Research Lab" icon_state = "toxlab" -/area/toxins/rdoffice +/area/rnd/rdoffice name = "\improper Research Director's Office" icon_state = "head_quarters" -/area/toxins/supermatter +/area/rnd/supermatter name = "\improper Supermatter Lab" icon_state = "toxlab" -/area/toxins/xenobiology +/area/rnd/xenobiology name = "\improper Xenobiology Lab" icon_state = "toxlab" -/area/toxins/storage +/area/rnd/storage name = "\improper Toxins Storage" icon_state = "toxstorage" -/area/toxins/test_area +/area/rnd/test_area name = "\improper Toxins Test Area" icon_state = "toxtest" -/area/toxins/mixing +/area/rnd/mixing name = "\improper Toxins Mixing Room" icon_state = "toxmix" -/area/toxins/misc_lab +/area/rnd/misc_lab 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" @@ -1361,6 +1429,10 @@ var/list/ghostteleportlocs = list() name = "Port Emergency Storage" icon_state = "emergencystorage" +/area/storage/emergency3 + name = "Central Emergency Storage" + icon_state = "emergencystorage" + /area/storage/tech name = "Technical Storage" icon_state = "auxstorage" @@ -1827,7 +1899,7 @@ var/list/the_station_areas = list ( /area/quartermaster, /area/janitor, /area/hydroponics, - /area/toxins, + /area/rnd, /area/storage, /area/construction, /area/ai_monitored/storage/eva, //do not try to simplify to "/area/ai_monitored" --rastaf0 diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 6695fe4402..21b86f5bcc 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -13,6 +13,8 @@ master = src //moved outside the spawn(1) to avoid runtimes in lighting.dm when it references loc.loc.master ~Carn uid = ++global_uid related = list(src) + active_areas += src + all_areas += src if(type == /area) // override defaults for space. TODO: make space areas of type /area/space rather than /area requires_power = 1 @@ -100,6 +102,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 +125,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) @@ -218,6 +222,7 @@ // called when power status changes /area/proc/power_change() + master.powerupdate = 2 for(var/area/RA in related) for(var/obj/machinery/M in RA) // for each machine in the area M.power_change() // reverify power status (to update icons etc.) @@ -239,7 +244,6 @@ return used /area/proc/clear_usage() - master.used_equip = 0 master.used_light = 0 master.used_environ = 0 diff --git a/code/game/atoms.dm b/code/game/atoms.dm index f5870a2499..351216b8bf 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 @@ -43,7 +44,6 @@ /atom/proc/assume_air(datum/gas_mixture/giver) - del(giver) return null /atom/proc/remove_air(amount) @@ -100,8 +100,10 @@ /atom/proc/emp_act(var/severity) return -/atom/proc/bullet_act(var/obj/item/projectile/Proj) - return 0 + +/atom/proc/bullet_act(obj/item/projectile/P, def_zone) + P.on_hit(src, 0, def_zone) + . = 0 /atom/proc/in_contents_of(container)//can take class or object instance as argument if(ispath(container)) @@ -317,7 +319,43 @@ its easier to just keep the beam vertical. var/full_print = md5(H.dna.uni_identity) // Add the fingerprints - fingerprints[full_print] = full_print + // + if(fingerprints[full_print]) + switch(stringpercent(fingerprints[full_print])) //tells us how many stars are in the current prints. + + if(28 to 32) + if(prob(1)) + fingerprints[full_print] = full_print // You rolled a one buddy. + else + fingerprints[full_print] = stars(full_print, rand(0,40)) // 24 to 32 + + if(24 to 27) + if(prob(3)) + fingerprints[full_print] = full_print //Sucks to be you. + else + fingerprints[full_print] = stars(full_print, rand(15, 55)) // 20 to 29 + + if(20 to 23) + if(prob(5)) + fingerprints[full_print] = full_print //Had a good run didn't ya. + else + fingerprints[full_print] = stars(full_print, rand(30, 70)) // 15 to 25 + + if(16 to 19) + if(prob(5)) + fingerprints[full_print] = full_print //Welp. + else + fingerprints[full_print] = stars(full_print, rand(40, 100)) // 0 to 21 + + if(0 to 15) + if(prob(5)) + fingerprints[full_print] = stars(full_print, rand(0,50)) // small chance you can smudge. + else + fingerprints[full_print] = full_print + + else + fingerprints[full_print] = stars(full_print, rand(0, 20)) //Initial touch, not leaving much evidence the first time. + return 1 else @@ -333,17 +371,22 @@ its easier to just keep the beam vertical. /atom/proc/transfer_fingerprints_to(var/atom/A) + if(!istype(A.fingerprints,/list)) A.fingerprints = list() + if(!istype(A.fingerprintshidden,/list)) A.fingerprintshidden = list() + if(!istype(fingerprintshidden, /list)) + fingerprintshidden = list() + //skytodo //A.fingerprints |= fingerprints //detective //A.fingerprintshidden |= fingerprintshidden //admin - if(fingerprints) + if(A.fingerprints && fingerprints) A.fingerprints |= fingerprints.Copy() //detective - if(fingerprintshidden) + if(A.fingerprintshidden && fingerprintshidden) A.fingerprintshidden |= fingerprintshidden.Copy() //admin A.fingerprintslast = fingerprintslast @@ -361,16 +404,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() - - //adding blood to humans - else if (istype(src, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = src - //if this blood isn't already in the list, add it - if(blood_DNA[H.dna.unique_enzymes]) - return 0 //already bloodied with this blood. Cannot add more. - blood_DNA[H.dna.unique_enzymes] = H.dna.b_type - H.update_inv_gloves() //handles bloody hands overlays and updating - return 1 //we applied blood to the item + blood_color = "#A10808" + if (M.species) + blood_color = M.species.blood_color return /atom/proc/add_vomit_floor(mob/living/carbon/M as mob, var/toxvomit = 0) diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 9102ee8780..32c7ef1dd6 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -16,15 +16,6 @@ #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] - // UI Indices (can change to mutblock style, if desired) #define DNA_UI_HAIR_R 1 #define DNA_UI_HAIR_G 2 @@ -33,29 +24,43 @@ var/global/list/assigned_blocks[STRUCDNASIZE] #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. +#define DNA_UI_SKIN_R 8 +#define DNA_UI_SKIN_G 9 +#define DNA_UI_SKIN_B 10 +#define DNA_UI_EYES_R 11 +#define DNA_UI_EYES_G 12 +#define DNA_UI_EYES_B 13 +#define DNA_UI_GENDER 14 +#define DNA_UI_BEARD_STYLE 15 +#define DNA_UI_HAIR_STYLE 16 +#define DNA_UI_LENGTH 16 // Update this when you add something, or you WILL break shit. + +#define DNA_SE_LENGTH 27 +// For later: +//#define DNA_SE_LENGTH 50 // Was STRUCDNASIZE, size 27. 15 new blocks added = 42, plus room to grow. -/* Note RE: unassigned blocks +// 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[DNA_SE_LENGTH] - Many genes in baycode are currently sitting unused - (compare setupgame.dm to the number of *BLOCK variables). +// Used to determine what each block means (admin hax and species stuff on /vg/, mostly) +var/global/list/assigned_blocks[DNA_SE_LENGTH] - This datum will return 0 (or equivalent) if asked about - a block 0 (which means the gene was unassigned). Setters - will silently return without performing any action. +var/global/list/datum/dna/gene/dna_genes[0] - I have code to assign these genes in a streamlined manner, - but in order to avoid breaking things, I've left the - existing setupgame.dm intact. Please let me know if you - need this behavior changed. - */ +///////////////// +// 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 + +// 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 @@ -70,13 +75,33 @@ var/global/list/assigned_blocks[STRUCDNASIZE] // Okay to read, but you're an idiot if you do. // BLOCK = VALUE - var/list/SE[STRUCDNASIZE] + var/list/SE[DNA_SE_LENGTH] 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<=DNA_SE_LENGTH;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 /////////////////////////////////////// @@ -84,7 +109,11 @@ var/global/list/assigned_blocks[STRUCDNASIZE] // Create random UI. /datum/dna/proc/ResetUI(var/defer=0) for(var/i=1,i<=DNA_UI_LENGTH,i++) - UI[i]=rand(0,4095) + 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() @@ -110,13 +139,17 @@ var/global/list/assigned_blocks[STRUCDNASIZE] SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1) SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1) - SetUIValueRange(DNA_UI_BEARD_R, character.r_eyes, 255, 1) - SetUIValueRange(DNA_UI_BEARD_G, character.g_eyes, 255, 1) - SetUIValueRange(DNA_UI_BEARD_B, character.b_eyes, 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, character.s_tone, 220, 1) + SetUIValueRange(DNA_UI_SKIN_R, character.r_skin, 255, 1) + SetUIValueRange(DNA_UI_SKIN_G, character.g_skin, 255, 1) + SetUIValueRange(DNA_UI_SKIN_B, character.b_skin, 255, 1) - SetUIState(DNA_UI_GENDER, character.gender!=MALE, 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) @@ -126,7 +159,7 @@ var/global/list/assigned_blocks[STRUCDNASIZE] // 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>0) ASSERT(value<=4095) UI[block]=value dirtyUI=1 @@ -140,12 +173,13 @@ var/global/list/assigned_blocks[STRUCDNASIZE] // 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) +/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0) if (block<=0) return + if (value==0) value = 1 // FIXME: hair/beard/eye RGB values if they are 0 are not set, this is a work around we'll encode it in the DNA to be 1 instead. ASSERT(maxvalue<=4095) - var/range = round(4095 / maxvalue) + var/range = (4095 / maxvalue) if(value) - SetUIValue(block,value * range - rand(1,range-1)) + SetUIValue(block,round(value * range),defer) // Getter version of above. /datum/dna/proc/GetUIValueRange(var/block,var/maxvalue) @@ -205,13 +239,12 @@ var/global/list/assigned_blocks[STRUCDNASIZE] // "Zeroes out" all of the blocks. /datum/dna/proc/ResetSE() - for(var/i = 1, i <= STRUCDNASIZE, i++) + for(var/i = 1, i <= DNA_SE_LENGTH, 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) @@ -234,6 +267,12 @@ var/global/list/assigned_blocks[STRUCDNASIZE] 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 @@ -249,7 +288,7 @@ var/global/list/assigned_blocks[STRUCDNASIZE] if(on) val=rand(BOUNDS[DNA_ON_LOWERBOUND],BOUNDS[DNA_ON_UPPERBOUND]) else - val=rand(BOUNDS[DNA_OFF_LOWERBOUND],BOUNDS[DNA_OFF_UPPERBOUND]) + val=rand(1,BOUNDS[DNA_OFF_UPPERBOUND]) SetSEValue(block,val,defer) // Get hex-encoded SE block. @@ -310,7 +349,7 @@ var/global/list/assigned_blocks[STRUCDNASIZE] if(UI.len != DNA_UI_LENGTH) ResetUIFrom(character) - if(length(struc_enzymes)!= 3*STRUCDNASIZE) + if(length(struc_enzymes)!= 3*DNA_SE_LENGTH) ResetSE() if(length(unique_enzymes) != 32) @@ -318,7 +357,7 @@ var/global/list/assigned_blocks[STRUCDNASIZE] else if(length(uni_identity) != 3*DNA_UI_LENGTH) uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4" - if(length(struc_enzymes)!= 3*STRUCDNASIZE) + if(length(struc_enzymes)!= 3*DNA_SE_LENGTH) struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" // BACK-COMPAT! @@ -330,4 +369,3 @@ var/global/list/assigned_blocks[STRUCDNASIZE] 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 0000000000..954c86f2a6 --- /dev/null +++ b/code/game/dna/dna2_domutcheck.dm @@ -0,0 +1,43 @@ +// (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) + var/changed = gene_active != gene_prior_status || (gene.flags & GENE_ALWAYS_ACTIVATE) + + // If gene state has changed: + if(changed) + // Gene active (or ALWAYS ACTIVATE) + if(gene_active || (gene.flags & GENE_ALWAYS_ACTIVATE)) + testing("[gene.name] activated!") + gene.activate(M,connected,flags) + if(M) + M.active_genes |= gene.type + M.update_icon = 1 + // If Gene is NOT active: + else + testing("[gene.name] deactivated!") + gene.deactivate(M,connected,flags) + if(M) + M.active_genes -= gene.type + M.update_icon = 1 diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 08d07ab2e1..4ffa5ea512 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -38,7 +38,7 @@ /proc/randmuti(var/mob/living/M) if(!M) return M.dna.check_integrity() - M.dna.SetUIValue(rand(1,UNIDNASIZE),rand(1,4095)) + M.dna.SetUIValue(rand(1,DNA_UI_LENGTH),rand(1,4095)) // Scramble UI or SE. /proc/scramble(var/UI, var/mob/M, var/prob) @@ -52,7 +52,7 @@ M.UpdateAppearance() else - for(var/i = 1, i <= STRUCDNASIZE-1, i++) + for(var/i = 1, i <= DNA_SE_LENGTH-1, i++) if(prob(prob)) M.dna.SetSEValue(i,rand(1,4095),1) M.dna.UpdateSE() @@ -139,11 +139,15 @@ H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) + H.r_skin = dna.GetUIValueRange(DNA_UI_SKIN_R, 255) + H.g_skin = dna.GetUIValueRange(DNA_UI_SKIN_G, 255) + H.b_skin = dna.GetUIValueRange(DNA_UI_SKIN_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) - H.s_tone = dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) + H.s_tone = 35 - dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative. if (dna.GetUIState(DNA_UI_GENDER)) H.gender = FEMALE @@ -170,309 +174,3 @@ // Used below, simple injection modifier. /proc/probinj(var/pr, var/inj) return prob(pr+inj*pr) - -// (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 -// inj: 1 for if we're checking this from an injector, screws with manifestation probability calc. -/proc/domutcheck(mob/living/M as mob, connected, inj) - 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) - - ///////////////////////////////////// - // IMPORTANT REMINDER - // IF A BLOCK IS SET TO 0 (unused) - // GetSEState(block) WILL RETURN 0 - ///////////////////////////////////// - - if(M.dna.GetSEState(NOBREATHBLOCK)) - if(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(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(probinj(45,inj) || (mRegen in old_mutations)) - M << "\blue You feel better" - M.mutations.Add(mRegen) - if(M.dna.GetSEState(INCREASERUNBLOCK)) - if(probinj(45,inj) || (mRun in old_mutations)) - M << "\blue Your leg muscles pulsate." - M.mutations.Add(mRun) - if(M.dna.GetSEState(REMOTETALKBLOCK)) - if(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(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(HALLUCINATIONBLOCK)) - if(probinj(45,inj) || (mHallucination in old_mutations)) - M.mutations.Add(mHallucination) - M << "\red Your mind says 'Hello'" - if(M.dna.GetSEState(NOPRINTSBLOCK)) - if(probinj(45,inj) || (mFingerprints in old_mutations)) - M.mutations.Add(mFingerprints) - M << "\blue Your fingers feel numb" - if(M.dna.GetSEState(SHOCKIMMUNITYBLOCK)) - if(probinj(45,inj) || (mShock in old_mutations)) - M.mutations.Add(mShock) - M << "\blue Your skin feels strange" - if(M.dna.GetSEState(SMALLSIZEBLOCK)) - if(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(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(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(probinj(30,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(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 \ No newline at end of file diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 37ad94e3f5..eadbfb06e1 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -1,5 +1,38 @@ #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) + if(dna) + 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 +47,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 +114,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 +139,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 +152,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 +163,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 +228,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 +238,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)) @@ -253,7 +273,7 @@ I.loc = src src.disk = I user << "You insert [I]." - nanomanager.update_uis(src) // update all UIs attached to src() + nanomanager.update_uis(src) // update all UIs attached to src return else src.attack_hand(user) @@ -292,6 +312,8 @@ /obj/machinery/computer/scan_consolenew/New() ..() + for(var/i=0;i<3;i++) + buffers[i+1]=new /datum/dna2/record spawn(5) for(dir in list(NORTH,EAST,SOUTH,WEST)) connected = locate(/obj/machinery/dna_scannernew, get_step(src, dir)) @@ -308,13 +330,13 @@ arr += "[i]:[EncodeDNABlock(buffer[i])]" return arr -/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/list/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 = list(buffer[id]) + I.buf = buffer return 1 /obj/machinery/computer/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob) @@ -323,7 +345,7 @@ W.loc = src src.disk = W user << "You insert [W]." - nanomanager.update_uis(src) // update all UIs attached to src() + nanomanager.update_uis(src) // update all UIs attached to src /* /obj/machinery/computer/scan_consolenew/process() //not really used right now if(stat & (NOPOWER|BROKEN)) @@ -336,6 +358,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 +368,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 +386,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 src.buffers) + new_buffers += list(buf.GetData()) + data["buffers"]=new_buffers data["radiationIntensity"] = radiation_intensity data["radiationDuration"] = radiation_duration @@ -432,23 +454,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(..()) @@ -620,14 +638,17 @@ if (href_list["selectSEBlock"] && href_list["selectSESubblock"]) // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes) var/select_block = text2num(href_list["selectSEBlock"]) var/select_subblock = text2num(href_list["selectSESubblock"]) - if ((select_block <= STRUCDNASIZE) && (select_block >= 1)) + if ((select_block <= DNA_SE_LENGTH) && (select_block >= 1)) 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 = 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 @@ -645,28 +666,32 @@ 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) + if (src.selected_se_block > 1 && src.selected_se_block < DNA_SE_LENGTH/2) real_SE_block++ - else if (src.selected_se_block > STRUCDNASIZE/2 && src.selected_se_block < STRUCDNASIZE) + else if (src.selected_se_block > DNA_SE_LENGTH/2 && src.selected_se_block < DNA_SE_LENGTH) 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) - domutcheck(src.connected.occupant,src.connected) 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) + //testing("Random identity mut!") 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 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 @@ -677,18 +702,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 @@ -702,7 +723,7 @@ // 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) @@ -710,56 +731,52 @@ if (bufferOption == "saveUI") if(src.connected.occupant && src.connected.occupant.dna) - src.buffers[bufferId]["ue"] = 0 - src.buffers[bufferId]["data"] = src.connected.occupant.dna.UI - 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.Clone() + if(ishuman(connected.occupant)) + databuf.dna.real_name=connected.occupant.name + 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.UI - 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.Clone() + if(ishuman(connected.occupant)) + databuf.dna.real_name=connected.occupant.name + 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.SE - 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.Clone() + if(ishuman(connected.occupant)) + databuf.dna.real_name=connected.occupant.name + 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]=new /datum/dna2/record() 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] + var/text = sanitize(input(usr, "New Label:", "Edit Label", buf.name) as text|null) + buf.name = text + 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 @@ -769,33 +786,42 @@ 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.UpdateAppearance(src.buffers[bufferId]["data"]) - else if (src.buffers[bufferId]["type"] == "se") - src.connected.occupant.dna.SE = 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.Copy()) + 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/list/selectedbuf + if(buf.types & DNA2_BUF_SE) + selectedbuf=buf.dna.SE + else + selectedbuf=buf.dna.UI + var/blk = input(usr,"Select Block","Block") in all_dna_blocks(selectedbuf) + 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) @@ -807,14 +833,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 @@ -823,11 +846,10 @@ //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 diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm new file mode 100644 index 0000000000..a119a0cf4b --- /dev/null +++ b/code/game/dna/genes/disabilities.dm @@ -0,0 +1,129 @@ +///////////////////// +// 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(mutation) + M.sdisabilities|=sdisability + if(activation_message) + M << "\red [activation_message]" + else + testing("[name] has no 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(mutation) + M.sdisabilities-=sdisability + if(deactivation_message) + M << "\red [deactivation_message]" + else + testing("[name] has no 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 diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm new file mode 100644 index 0000000000..21eec348bd --- /dev/null +++ b/code/game/dna/genes/gene.dm @@ -0,0 +1,122 @@ +/** +* 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 + +/** +* Is the gene active in this mob's DNA? +*/ +/datum/dna/gene/proc/is_active(var/mob/M) + return M.active_genes && type in M.active_genes + +// 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 + +// This section inspired by goone's bioEffects. + +/** +* Called in each life() tick. +*/ +/datum/dna/gene/proc/OnMobLife(var/mob/M) + return + +/** +* Called when the mob dies +*/ +/datum/dna/gene/proc/OnMobDeath(var/mob/M) + return + +/** +* Called when the mob says shit +*/ +/datum/dna/gene/proc/OnSay(var/mob/M, var/message) + return message + +/** +* Called after the mob runs update_icons. +* +* @params M The subject. +* @params g Gender (m or f) +* @params fat Fat? (0 or 1) +*/ +/datum/dna/gene/proc/OnDrawUnderlays(var/mob/M, var/g, var/fat) + return 0 + + +///////////////////// +// 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(flags & MUTCHK_FORCED) + return 1 + // Probability check + return probinj(activation_prob,(flags&MUTCHK_FORCED)) + +/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 0000000000..444e56a587 --- /dev/null +++ b/code/game/dna/genes/monkey.dm @@ -0,0 +1,174 @@ +/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)) + //testing("Cannot monkey-ify [M], type is [M.type].") + 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.Clone() + 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)) + //testing("Cannot humanize [M], type is [M.type].") + 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 + if(Mo.greaterform) + O = new(src, Mo.greaterform) + else + O = new(src) + + if (M.dna.GetUIState(DNA_UI_GENDER)) + O.gender = FEMALE + else + O.gender = MALE + + if (M) + if (M.dna) + O.dna = M.dna.Clone() + 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 0000000000..3381894f8a --- /dev/null +++ b/code/game/dna/genes/powers.dm @@ -0,0 +1,195 @@ +/////////////////////////////////// +// 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) + if(flags & MUTCHK_FORCED) + return !(/datum/dna/gene/basic/cold_resist in M.active_genes) + // Probability check + var/_prob = 15 + if(COLD_RESISTANCE in M.mutations) + _prob=5 + if(probinj(_prob,(flags&MUTCHK_FORCED))) + return 1 + + OnDrawUnderlays(var/mob/M,var/g,var/fat) + return "cold[fat]_s" +*/ + +/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) + if(flags & MUTCHK_FORCED) + return 1 + // return !(/datum/dna/gene/basic/heat_resist in M.active_genes) + // Probability check + var/_prob=30 + //if(mHeatres in M.mutations) + // _prob=5 + if(probinj(_prob,(flags&MUTCHK_FORCED))) + return 1 + + OnDrawUnderlays(var/mob/M,var/g,var/fat) + return "fire[fat]_s" + +/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) + + OnDrawUnderlays(var/mob/M,var/g,var/fat) + if(fat) + return "hulk_[fat]_s" + else + return "hulk_[g]_s" + return 0 + + OnMobLife(var/mob/living/carbon/human/M) + if(!istype(M)) return + if(M.health <= 25) + M.mutations.Remove(HULK) + M.update_mutations() //update our mutation overlays + M << "\red You suddenly feel very weak." + M.Weaken(3) + M.emote("collapse") + +/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 + OnDrawUnderlays(var/mob/M,var/g,var/fat) + return "telekinesishead[fat]_s" diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index a6da766b4e..43dea8c32f 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -123,7 +123,8 @@ var/mob/living/newtraitor = pick(possible_traitors) //message_admins("[newtraitor.real_name] is the new Traitor.") - forge_traitor_objectives(newtraitor.mind) + if (!config.objectives_disabled) + forge_traitor_objectives(newtraitor.mind) if(istype(newtraitor, /mob/living/silicon)) add_law_zero(newtraitor) @@ -134,11 +135,15 @@ newtraitor << "\red ATTENTION: \black It is time to pay your debt to the Syndicate..." newtraitor << "You are now a traitor." newtraitor.mind.special_role = "traitor" + newtraitor.hud_updateflag |= 1 << SPECIALROLE_HUD var/obj_count = 1 newtraitor << "\blue Your current objectives:" - for(var/datum/objective/objective in newtraitor.mind.objectives) - newtraitor << "Objective #[obj_count]: [objective.explanation_text]" - obj_count++ + if(!config.objectives_disabled) + for(var/datum/objective/objective in newtraitor.mind.objectives) + newtraitor << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + else + newtraitor << "You have been selected this round as an antagonist- Within the rules, try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonist." //else //message_admins("No new traitor being added.") //else @@ -188,11 +193,14 @@ traitors += character.mind character << "\red You are the traitor." character.mind.special_role = "traitor" - var/obj_count = 1 - character << "\blue Your current objectives:" - for(var/datum/objective/objective in character.mind.objectives) - character << "Objective #[obj_count]: [objective.explanation_text]" - obj_count++ + if (config.objectives_disabled) + character << "You have been selected this round as an antagonist- Within the rules, try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonist." + else + var/obj_count = 1 + character << "\blue Your current objectives:" + for(var/datum/objective/objective in character.mind.objectives) + character << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ //else //message_admins("New traitor roll failed. No new traitor.") //else diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm index 4c77520846..0e1b6c07eb 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.dm b/code/game/gamemodes/changeling/changeling.dm index 6a3bbd19c8..8a3b7d075e 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -72,7 +72,8 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" for(var/datum/mind/changeling in changelings) grant_changeling_powers(changeling.current) changeling.special_role = "Changeling" - forge_changeling_objectives(changeling) + if(!config.objectives_disabled) + forge_changeling_objectives(changeling) greet_changeling(changeling) spawn (rand(waittime_l, waittime_h)) @@ -120,18 +121,24 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" if (you_are) changeling.current << "\red You are a changeling!" changeling.current << "\red Use say \":g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them." - changeling.current << "You must complete the following tasks:" + + if(config.objectives_disabled) + changeling.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." + + if (!config.objectives_disabled) + changeling.current << "You must complete the following tasks:" if (changeling.current.mind) if (changeling.current.mind.assigned_role == "Clown") changeling.current << "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself." changeling.current.mutations.Remove(CLUMSY) - var/obj_count = 1 - for(var/datum/objective/objective in changeling.objectives) - changeling.current << "Objective #[obj_count]: [objective.explanation_text]" - obj_count++ - return + if (!config.objectives_disabled) + var/obj_count = 1 + for(var/datum/objective/objective in changeling.objectives) + changeling.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + return /*/datum/game_mode/changeling/check_finished() var/changelings_alive = 0 @@ -181,25 +188,25 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" //Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed. text += "
Changeling ID: [changeling.changeling.changelingID]." text += "
Genomes Absorbed: [changeling.changeling.absorbedcount]" - - if(changeling.objectives.len) - var/count = 1 - for(var/datum/objective/objective in changeling.objectives) - if(objective.check_completion()) - text += "
Objective #[count]: [objective.explanation_text] Success!" - feedback_add_details("changeling_objective","[objective.type]|SUCCESS") + if(!config.objectives_disabled) + if(changeling.objectives.len) + var/count = 1 + for(var/datum/objective/objective in changeling.objectives) + if(objective.check_completion()) + text += "
Objective #[count]: [objective.explanation_text] Success!" + feedback_add_details("changeling_objective","[objective.type]|SUCCESS") + else + text += "
Objective #[count]: [objective.explanation_text] Fail." + feedback_add_details("changeling_objective","[objective.type]|FAIL") + changelingwin = 0 + count++ + if(!config.objectives_disabled) + if(changelingwin) + text += "
The changeling was successful!" + feedback_add_details("changeling_success","SUCCESS") else - text += "
Objective #[count]: [objective.explanation_text] Fail." - feedback_add_details("changeling_objective","[objective.type]|FAIL") - changelingwin = 0 - count++ - - if(changelingwin) - text += "
The changeling was successful!" - feedback_add_details("changeling_success","SUCCESS") - else - text += "
The changeling has failed." - feedback_add_details("changeling_success","FAIL") + text += "
The changeling has failed." + feedback_add_details("changeling_success","FAIL") world << text @@ -208,6 +215,8 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" /datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind) var/list/absorbed_dna = list() + var/list/absorbed_species = list() + var/list/absorbed_languages = list() var/absorbedcount = 0 var/chem_charges = 20 var/chem_recharge_rate = 0.5 diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index 96deb59554..53b2c36ea8 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -1,5 +1,6 @@ //Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human /mob/proc/make_changeling() + if(!mind) return if(!mind.changeling) mind.changeling = new /datum/changeling(gender) verbs += /datum/changeling/proc/EvolutionMenu @@ -23,6 +24,15 @@ src.verbs += P.verbpath mind.changeling.absorbed_dna |= dna + + var/mob/living/carbon/human/H = src + if(istype(H)) + mind.changeling.absorbed_species += H.species.name + + for(var/language in languages) + if(!(language in mind.changeling.absorbed_languages)) + mind.changeling.absorbed_languages += language + return 1 //removes our changeling verbs @@ -57,12 +67,60 @@ return if(changeling.geneticdamage > max_genetic_damage) - src << "Our geneomes are still reassembling. We need time to recover first." + src << "Our genomes are still reassembling. We need time to recover first." return return changeling +//Used to dump the languages from the changeling datum into the actual mob. +/mob/proc/changeling_update_languages(var/updated_languages) + + languages = list() + for(var/language in updated_languages) + languages += language + + return + +//Used to switch species based on the changeling datum. +/mob/proc/changeling_change_species() + + set category = "Changeling" + set name = "Change Species (5)" + + var/mob/living/carbon/human/H = src + if(!istype(H)) + src << "We may only use this power while in humanoid form." + return + + var/datum/changeling/changeling = changeling_power(5,1,0) + if(!changeling) return + + if(changeling.absorbed_species.len < 2) + src << "We do not know of any other species genomes to use." + return + + var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species + if(!S) return + + domutcheck(src, null) + + changeling.chem_charges -= 5 + changeling.geneticdamage = 30 + + src.visible_message("[src] transforms!") + + src.verbs -= /mob/proc/changeling_change_species + spawn(10) src.verbs += /mob/proc/changeling_change_species + + H.set_species(S) + + changeling_update_languages(changeling.absorbed_languages) + + feedback_add_details("changeling_powers","TR") + + return 1 + //Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim. //Doesn't cost anything as it's the most basic ability. /mob/proc/changeling_absorb_dna() @@ -82,6 +140,10 @@ src << "[T] is not compatible with our biology." return + if(T.species.flags & NO_SCAN) + src << "We do not know how to parse this creature's DNA!" + return + if(NOCLONE in T.mutations) src << "This creature's DNA is ruined beyond useability!" return @@ -127,6 +189,17 @@ changeling.chem_charges += 10 changeling.geneticpoints += 2 + //Steal all of their languages! + for(var/language in T.languages) + if(!(language in changeling.absorbed_languages)) + changeling.absorbed_languages += language + + changeling_update_languages(changeling.absorbed_languages) + + //Steal their species! + if(T.species && !(T.species.name in changeling.absorbed_species)) + changeling.absorbed_species += T.species.name + if(T.mind && T.mind.changeling) if(T.mind.changeling.absorbed_dna) for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot @@ -184,7 +257,7 @@ changeling.chem_charges -= 5 src.visible_message("[src] transforms!") changeling.geneticdamage = 30 - src.dna = chosen_dna + src.dna = chosen_dna.Clone() src.real_name = chosen_dna.real_name src.flavor_text = "" src.UpdateAppearance() @@ -205,6 +278,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() @@ -232,7 +309,7 @@ del(animation) var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey(src) - O.dna = C.dna + O.dna = C.dna.Clone() C.dna = null for(var/obj/item/W in C) @@ -256,6 +333,8 @@ O.make_changeling(1) O.verbs += /mob/proc/changeling_lesser_transform + O.changeling_update_languages(changeling.absorbed_languages) + feedback_add_details("changeling_powers","LF") del(C) return 1 @@ -285,7 +364,7 @@ changeling.chem_charges-- C.remove_changeling_powers() C.visible_message("[C] transforms!") - C.dna = chosen_dna + C.dna = chosen_dna.Clone() var/list/implants = list() for (var/obj/item/weapon/implant/I in C) //Still preserving implants @@ -318,7 +397,7 @@ O.gender = FEMALE else O.gender = MALE - O.dna = C.dna + O.dna = C.dna.Clone() C.dna = null O.real_name = chosen_dna.real_name @@ -340,6 +419,7 @@ C.mind.transfer_to(O) O.make_changeling() + O.changeling_update_languages(changeling.absorbed_languages) feedback_add_details("changeling_powers","LFT") del(C) @@ -370,24 +450,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 @@ -717,7 +797,7 @@ var/list/datum/dna/hivemind_bank = list() src << "Our sting appears ineffective against its DNA." return 0 T.visible_message("[T] transforms!") - T.dna = chosen_dna + T.dna = chosen_dna.Clone() T.real_name = chosen_dna.real_name T.UpdateAppearance() domutcheck(T, null) diff --git a/code/game/gamemodes/changeling/modularchangling.dm b/code/game/gamemodes/changeling/modularchangling.dm index 2395e63b27..5048977789 100644 --- a/code/game/gamemodes/changeling/modularchangling.dm +++ b/code/game/gamemodes/changeling/modularchangling.dm @@ -26,6 +26,12 @@ var/list/datum/power/changeling/powerinstances = list() genomecost = 0 verbpath = /mob/proc/changeling_transform +/datum/power/changeling/change_species + name = "Change Species" + desc = "We take on the apperance of a species that we have absorbed." + genomecost = 0 + verbpath = /mob/proc/changeling_change_species + /datum/power/changeling/fakedeath name = "Regenerative Stasis" desc = "We become weakened to a death-like state, where we will rise again from death." @@ -53,7 +59,7 @@ var/list/datum/power/changeling/powerinstances = list() /datum/power/changeling/lesser_form name = "Lesser Form" desc = "We debase ourselves and become lesser. We become a monkey." - genomecost = 1 + genomecost = 4 verbpath = /mob/proc/changeling_lesser_form /datum/power/changeling/deaf_sting @@ -74,7 +80,7 @@ var/list/datum/power/changeling/powerinstances = list() name = "Silence Sting" desc = "We silently sting a human, completely silencing them for a short time." helptext = "Does not provide a warning to a victim that they have been stung, until they try to speak and cannot." - genomecost = 2 + genomecost = 3 allowduringlesserform = 1 verbpath = /mob/proc/changeling_silence_sting @@ -82,14 +88,14 @@ var/list/datum/power/changeling/powerinstances = list() name = "Mimic Voice" desc = "We shape our vocal glands to sound like a desired voice." helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this" - genomecost = 3 + genomecost = 1 verbpath = /mob/proc/changeling_mimicvoice /datum/power/changeling/extractdna name = "Extract DNA" desc = "We stealthily sting a target and extract the DNA from them." helptext = "Will give you the DNA of your target, allowing you to transform into them. Does not count towards absorb objectives." - genomecost = 4 + genomecost = 2 allowduringlesserform = 1 verbpath = /mob/proc/changeling_extract_dna_sting @@ -103,7 +109,7 @@ var/list/datum/power/changeling/powerinstances = list() /datum/power/changeling/paralysis_sting name = "Paralysis Sting" desc = "We silently sting a human, paralyzing them for a short time." - genomecost = 3 + genomecost = 8 verbpath = /mob/proc/changeling_paralysis_sting /datum/power/changeling/LSDSting @@ -119,11 +125,11 @@ var/list/datum/power/changeling/powerinstances = list() genomecost = 10 verbpath = /mob/proc/changeling_DEATHsting -/datum/power/changeling/unfat_sting - name = "Unfat Sting" - desc = "We silently sting a human, forcing them to rapidly metobolize their fat." - genomecost = 1 - verbpath = /mob/proc/changeling_unfat_sting +///datum/power/changeling/unfat_sting +// name = "Unfat Sting" +// desc = "We silently sting a human, forcing them to rapidly metabolize their fat." +// genomecost = 1 +// verbpath = /mob/proc/changeling_unfat_sting /datum/power/changeling/boost_range name = "Boost Range" @@ -136,7 +142,7 @@ var/list/datum/power/changeling/powerinstances = list() name = "Epinephrine sacs" desc = "We evolve additional sacs of adrenaline throughout our body." helptext = "Gives the ability to instantly recover from stuns. High chemical cost." - genomecost = 4 + genomecost = 3 verbpath = /mob/proc/changeling_unstun /datum/power/changeling/ChemicalSynth @@ -167,7 +173,7 @@ var/list/datum/power/changeling/powerinstances = list() name = "Digital Camoflauge" desc = "We evolve the ability to distort our form and proprtions, defeating common altgorthms used to detect lifeforms on cameras." helptext = "We cannot be tracked by camera while using this skill. However, humans looking at us will find us.. uncanny. We must constantly expend chemicals to maintain our form like this." - genomecost = 3 + genomecost = 1 allowduringlesserform = 1 verbpath = /mob/proc/changeling_digitalcamo @@ -175,7 +181,7 @@ var/list/datum/power/changeling/powerinstances = list() name = "Rapid Regeneration" desc = "We evolve the ability to rapidly regenerate, negating the need for stasis." helptext = "Heals a moderate amount of damage every tick." - genomecost = 8 + genomecost = 7 verbpath = /mob/proc/changeling_rapidregen diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm index 12a5525428..2dbec4fa60 100644 --- a/code/game/gamemodes/changeling/traitor_chan.dm +++ b/code/game/gamemodes/changeling/traitor_chan.dm @@ -37,7 +37,8 @@ for(var/datum/mind/changeling in changelings) grant_changeling_powers(changeling.current) changeling.special_role = "Changeling" - forge_changeling_objectives(changeling) + if(!config.objectives_disabled) + forge_changeling_objectives(changeling) greet_changeling(changeling) ..() return \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index e0e81a647e..b1e3442d34 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -54,12 +54,13 @@ /datum/game_mode/cult/pre_setup() - if(prob(50)) - objectives += "survive" - objectives += "sacrifice" - else - objectives += "eldergod" - objectives += "sacrifice" + if(!config.objectives_disabled) + if(prob(50)) + objectives += "survive" + objectives += "sacrifice" + else + objectives += "eldergod" + objectives += "sacrifice" if(config.protect_roles_from_antagonist) restricted_jobs += protected_jobs @@ -98,7 +99,10 @@ grant_runeword(cult_mind.current) update_cult_icons_added(cult_mind) cult_mind.current << "\blue You are a member of the cult!" - memoize_cult_objectives(cult_mind) + if(!config.objectives_disabled) + memoize_cult_objectives(cult_mind) + else + cult_mind.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." cult_mind.special_role = "Cultist" spawn (rand(waittime_l, waittime_h)) @@ -192,7 +196,8 @@ /datum/game_mode/cult/add_cultist(datum/mind/cult_mind) //INHERIT if (!..(cult_mind)) return - memoize_cult_objectives(cult_mind) + if (!config.objectives_disabled) + memoize_cult_objectives(cult_mind) /datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = 1) @@ -367,7 +372,8 @@ /datum/game_mode/cult/declare_completion() - + if(config.objectives_disabled) + return 1 if(!check_cult_victory()) feedback_set_details("round_end_result","win - cult win") feedback_set("round_end_result",acolytes_survived) @@ -378,38 +384,38 @@ world << "\red The staff managed to stop the cult!" var/text = "Cultists escaped: [acolytes_survived]" - - if(objectives.len) - text += "
The cultists' objectives were:" - for(var/obj_count=1, obj_count <= objectives.len, obj_count++) - var/explanation - switch(objectives[obj_count]) - if("survive") - if(!check_survive()) - explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Success!" - feedback_add_details("cult_objective","cult_survive|SUCCESS|[acolytes_needed]") - else - explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Fail." - feedback_add_details("cult_objective","cult_survive|FAIL|[acolytes_needed]") - if("sacrifice") - if(sacrifice_target) - if(sacrifice_target in sacrificed) - explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Success!" - feedback_add_details("cult_objective","cult_sacrifice|SUCCESS") - else if(sacrifice_target && sacrifice_target.current) - explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Fail." - feedback_add_details("cult_objective","cult_sacrifice|FAIL") + if(!config.objectives_disabled) + if(objectives.len) + text += "
The cultists' objectives were:" + for(var/obj_count=1, obj_count <= objectives.len, obj_count++) + var/explanation + switch(objectives[obj_count]) + if("survive") + if(!check_survive()) + explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Success!" + feedback_add_details("cult_objective","cult_survive|SUCCESS|[acolytes_needed]") + else + explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Fail." + feedback_add_details("cult_objective","cult_survive|FAIL|[acolytes_needed]") + if("sacrifice") + if(sacrifice_target) + if(sacrifice_target in sacrificed) + explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Success!" + feedback_add_details("cult_objective","cult_sacrifice|SUCCESS") + else if(sacrifice_target && sacrifice_target.current) + explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Fail." + feedback_add_details("cult_objective","cult_sacrifice|FAIL") else explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Fail (Gibbed)." feedback_add_details("cult_objective","cult_sacrifice|FAIL|GIBBED") - if("eldergod") - if(!eldergod) - explanation = "Summon Nar-Sie. Success!" - feedback_add_details("cult_objective","cult_narsie|SUCCESS") - else - explanation = "Summon Nar-Sie. Fail." + if("eldergod") + if(!eldergod) + explanation = "Summon Nar-Sie. Success!" + feedback_add_details("cult_objective","cult_narsie|SUCCESS") + else + explanation = "Summon Nar-Sie. Fail." feedback_add_details("cult_objective","cult_narsie|FAIL") - text += "
Objective #[obj_count]: [explanation]" + text += "
Objective #[obj_count]: [explanation]" world << text ..() diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 014371cabf..4e38f4fe44 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -37,7 +37,7 @@ flags = FPRINT|TABLEPASS|HEADCOVERSEYES armor = list(melee = 30, bullet = 10, laser = 5,energy = 5, bomb = 0, bio = 0, rad = 0) cold_protection = HEAD - min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECITON_TEMPERATURE + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE siemens_coefficient = 0 diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 2760a66d49..33a7b905d8 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -242,7 +242,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/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index e7f1e2ff26..d78c3333ea 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -392,6 +392,11 @@ var/list/sacrificed = list() D.real_name = "[pick(first_names_male)] [pick(last_names)]" D.universal_speak = 1 D.status_flags &= ~GODMODE + D.s_tone = 35 + D.b_eyes = 200 + D.r_eyes = 200 + D.g_eyes = 200 + D.underwear = 0 D.key = ghost.key @@ -839,7 +844,7 @@ var/list/sacrificed = list() if (cultist == user) //just to be sure. return if(cultist.buckled || cultist.handcuffed || (!isturf(cultist.loc) && !istype(cultist.loc, /obj/structure/closet))) - user << "\red You cannot summon the [cultist], for his shackles of blood are strong" + user << "\red You cannot summon \the [cultist], for his shackles of blood are strong." return fizzle() cultist.loc = src.loc cultist.lying = 1 diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index 5b1b1494b5..51bcc39a37 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.UI - D.strain_data["SE"] = H.dna.SE + D.strain_data["UI"] = H.dna.uni_identity + D.strain_data["SE"] = H.dna.struc_enzymes D.carrier = 1 D.holder = H D.affected_mob = H @@ -233,10 +233,10 @@ if (prob(25)) if (prob(75)) randmutb(H) - domutcheck(H,null,1) + domutcheck(H,null,MUTCHK_FORCED) else randmutg(H) - domutcheck(H,null,1) + domutcheck(H,null,MUTCHK_FORCED) for(var/mob/living/carbon/monkey/M in living_mob_list) var/turf/T = get_turf(M) if(!T) diff --git a/code/game/gamemodes/events/holidays/Christmas.dm b/code/game/gamemodes/events/holidays/Christmas.dm index 2ee79e7c65..72d42318e6 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/ninja_abilities.dm b/code/game/gamemodes/events/ninja_abilities.dm index 641bdf77ce..11109af279 100644 --- a/code/game/gamemodes/events/ninja_abilities.dm +++ b/code/game/gamemodes/events/ninja_abilities.dm @@ -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 d25dabe21b..d9f3801902 100644 --- a/code/game/gamemodes/events/ninja_equipment.dm +++ b/code/game/gamemodes/events/ninja_equipment.dm @@ -323,13 +323,13 @@ ________________________________________________________________________________ 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) + var/phoron_level = environment.phoron/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) dat += "
    " 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)]%
  • " + dat += "
  • Phoron: [round(phoron_level*100)]%
  • " dat += "
" if(unknown_level > 0.01) dat += "OTHER: [round(unknown_level)]%
" @@ -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 c8848cd3ee..dbebc649f5 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 c3b77d5f87..4d0df9c3f7 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 39be77978e..fe252c3ab3 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -22,7 +22,7 @@ var/explosion_in_progress = 0 //sit back and relax var/list/datum/mind/modePlayer = new var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist - var/list/protected_jobs = list() // Jobs that can't be tratiors because + var/list/protected_jobs = list() // Jobs that can't be traitors because var/required_players = 0 var/required_players_secret = 0 //Minimum number of players for that game mode to be chose in Secret var/required_enemies = 0 @@ -44,7 +44,7 @@ Stealthy and Inconspicuous Weapons; /obj/item/weapon/cartridge/syndicate:3:Detomatix PDA Cartridge; Whitespace:Seperator; Stealth and Camouflage Items; -/obj/item/clothing/under/chameleon:3:Chameleon Jumpsuit; +/obj/item/weapon/storage/box/syndie_kit/chameleon:3:Chameleon Kit; /obj/item/clothing/shoes/syndigaloshes:2:No-Slip Syndicate Shoes; /obj/item/weapon/card/id/syndicate:2:Agent ID card; /obj/item/clothing/mask/gas/voice:4:Voice Changer; @@ -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 a834a3cc0b..d42f88e891 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -56,7 +56,13 @@ var/global/datum/controller/gameticker/ticker vote.process() if(going) pregame_timeleft-- - + if(pregame_timeleft == config.vote_autogamemode_timeleft) + if(!vote.time_remaining) + vote.autogamemode() //Quit calling this over and over and over and over. + while(vote.time_remaining) + for(var/i=0, i<10, i++) + sleep(1) + vote.process() if(pregame_timeleft <= 0) current_state = GAME_STATE_SETTING_UP while (!setup()) @@ -149,6 +155,7 @@ var/global/datum/controller/gameticker/ticker master_controller.process() //Start master_controller.process() lighting_controller.process() //Start processing DynamicAreaLighting updates + for(var/obj/multiz/ladder/L in world) L.connect() //Lazy hackfix for ladders. TODO: move this to an actual controller. ~ Z if(config.sql_enabled) spawn(3000) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 4dfff4fc4c..f556f43b4a 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. @@ -74,7 +69,8 @@ var/global/vox_kills = 0 //Used to check the Inviolate. continue //Generate objectives for the group. - raid_objectives = forge_vox_objectives() + if(!config.objectives_disabled) + raid_objectives = forge_vox_objectives() var/index = 1 @@ -163,10 +159,7 @@ var/global/vox_kills = 0 //Used to check the Inviolate. objs += new /datum/objective/heist/inviolate_crew objs += 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!" @@ -175,9 +168,12 @@ var/global/vox_kills = 0 //Used to check the Inviolate. 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]" - obj_count++ + if(!config.objectives_disabled) + for(var/datum/objective/objective in raider.objectives) + raider.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + else + raider.current << "Within the rules, try to act as an opposing force to the crew or come up with other fun ideas. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." /datum/game_mode/heist/declare_completion() @@ -245,28 +241,6 @@ var/global/vox_kills = 0 //Used to check the Inviolate. feedback_add_details("traitor_objective","[objective.type]|FAIL") count++ - var/text = "The vox raiders were:" - - for(var/datum/mind/vox in raiders) - text += "
[vox.key] was [vox.name] (" - var/obj/stack = raiders[vox] - if(get_area(stack) != locate(/area/shuttle/vox/station)) - text += "left behind)" - continue - else if(vox.current) - if(vox.current.stat == DEAD) - text += "died" - else - text += "survived" - if(vox.current.real_name != vox.name) - text += " as [vox.current.real_name]" - else - text += "body destroyed" - text += ")" - - world << text - return 1 - ..() datum/game_mode/proc/auto_declare_completion_heist() diff --git a/code/game/gamemodes/intercept_report.dm b/code/game/gamemodes/intercept_report.dm index 54c1ac6b07..2ee0fe7d91 100644 --- a/code/game/gamemodes/intercept_report.dm +++ b/code/game/gamemodes/intercept_report.dm @@ -213,11 +213,11 @@ if(prob(prob_right_job)) if(correct_person) if(correct_person:assigned_role=="MODE") - changeling_job = pick(get_all_jobs()) + changeling_job = pick(joblist) else changeling_job = correct_person:assigned_role else - changeling_job = pick(get_all_jobs()) + changeling_job = pick(joblist) if(prob(prob_right_dude) && ticker.mode == "changeling") if(correct_person:assigned_role=="MODE") changeling_name = correct_person:current diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index 1fb1aff61a..eccf013fff 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -30,7 +30,7 @@ /datum/game_mode/malfunction/pre_setup() for(var/mob/new_player/player in player_list) - if(player.mind && player.mind.assigned_role == "AI") + if(player.mind && player.mind.assigned_role == "AI" && (player.client.prefs.be_special & BE_MALF)) malf_ai+=player.mind if(malf_ai.len) return 1 diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index deb28d7689..712512bd47 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 c3720275ee..55191067e1 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/newobjective.dm b/code/game/gamemodes/newobjective.dm index 9f26b049b8..30791aefcc 100644 --- a/code/game/gamemodes/newobjective.dm +++ b/code/game/gamemodes/newobjective.dm @@ -604,7 +604,7 @@ datum var/list/all_items = owner.current.get_contents() for(var/obj/item/I in all_items) if(!istype(I, steal_target)) continue//If it's not actually that item. - if(I:air_contents:toxins) return 1 //If they got one with plasma + if(I:air_contents:phoron) return 1 //If they got one with plasma return 0 diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm index 026253a73b..42f5b69d7f 100644 --- a/code/game/gamemodes/ninja/ninja.dm +++ b/code/game/gamemodes/ninja/ninja.dm @@ -54,7 +54,10 @@ /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) + if(!config.objectives_disabled) + forge_ninja_objectives(ninja) + else + ninja.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." var/mob/living/carbon/human/N = ninja.current N.internal = N.s_store N.internals.icon_state = "internal1" @@ -128,6 +131,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." @@ -175,12 +179,13 @@ else special_role_text = "antagonist" - if(ninjawin) - text += "
The [special_role_text] was successful!" - feedback_add_details("traitor_success","SUCCESS") - else - text += "
The [special_role_text] has failed!" - feedback_add_details("traitor_success","FAIL") + if(!config.objectives_disabled) + if(ninjawin) + text += "
The [special_role_text] was successful!" + feedback_add_details("traitor_success","SUCCESS") + else + text += "
The [special_role_text] has failed!" + feedback_add_details("traitor_success","FAIL") world << text return 1 diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index be68855414..5674ea9098 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,16 +136,18 @@ spawnpos = 1 synd_mind.current.loc = synd_spawn[spawnpos] - forge_syndicate_objectives(synd_mind) + synd_mind.current.real_name = "[syndicate_name()] Operative" // placeholder while we get their actual name + spawn(0) + NukeNameAssign(synd_mind) + if(!config.objectives_disabled) + forge_syndicate_objectives(synd_mind) greet_syndicate(synd_mind) equip_syndicate(synd_mind.current) 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]" @@ -190,9 +195,12 @@ if (you_are) syndicate.current << "\blue You are a [syndicate_name()] agent!" var/obj_count = 1 - for(var/datum/objective/objective in syndicate.objectives) - syndicate.current << "Objective #[obj_count]: [objective.explanation_text]" - obj_count++ + if(!config.objectives_disabled) + for(var/datum/objective/objective in syndicate.objectives) + syndicate.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + else + syndicate.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." return @@ -209,9 +217,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 +227,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 @@ -244,6 +270,8 @@ /datum/game_mode/nuclear/declare_completion() + if(config.objectives_disabled) + return var/disk_rescued = 1 for(var/obj/item/weapon/disk/nuclear/D in world) var/disk_area = get_area(D) @@ -344,12 +372,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 24a3df847a..a58e8b553f 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -82,6 +82,10 @@ var/bomb_set 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)) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 12ac544784..848f247db9 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 @@ -352,7 +358,7 @@ datum/objective/escape if(!location) return 0 - if(istype(location, /turf/simulated/shuttle/floor4)) // Fails tratiors if they are in the shuttle brig -- Polymorph + if(istype(location, /turf/simulated/shuttle/floor4)) // Fails traitors if they are in the shuttle brig -- Polymorph if(istype(owner.current, /mob/living/carbon)) var/mob/living/carbon/C = owner.current if (!C.handcuffed) @@ -483,7 +489,7 @@ datum/objective/steal "a pair of magboots" = /obj/item/clothing/shoes/magboots, "the station blueprints" = /obj/item/blueprints, "a nasa voidsuit" = /obj/item/clothing/suit/space/nasavoid, - "28 moles of plasma (full tank)" = /obj/item/weapon/tank, + "28 moles of phoron (full tank)" = /obj/item/weapon/tank, "a sample of slime extract" = /obj/item/slime_extract, "a piece of corgi meat" = /obj/item/weapon/reagent_containers/food/snacks/meat/corgi, "a research director's jumpsuit" = /obj/item/clothing/under/rank/research_director, @@ -545,13 +551,13 @@ datum/objective/steal if(!isliving(owner.current)) return 0 var/list/all_items = owner.current.get_contents() switch (target_name) - if("28 moles of plasma (full tank)","10 diamonds","50 gold bars","25 refined uranium bars") + if("28 moles of phoron (full tank)","10 diamonds","50 gold bars","25 refined uranium bars") var/target_amount = text2num(target_name)//Non-numbers are ignored. var/found_amount = 0.0//Always starts as zero. - for(var/obj/item/I in all_items) //Check for plasma tanks + for(var/obj/item/I in all_items) //Check for phoron tanks if(istype(I, steal_target)) - found_amount += (target_name=="28 moles of plasma (full tank)" ? (I:air_contents:toxins) : (I:amount)) + found_amount += (target_name=="28 moles of phoron (full tank)" ? (I:air_contents:phoron) : (I:amount)) return found_amount>=target_amount if("50 coins (in bag)") @@ -861,7 +867,7 @@ datum/objective/heist/salvage target = "plasteel" target_amount = 100 if(4) - target = "plasma" + target = "phoron" target_amount = 100 if(5) target = "silver" @@ -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/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index e94baa3ede..f6199dcb16 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -21,7 +21,7 @@ recommended_enemies = 3 - uplink_welcome = "Revolutionary Uplink Console:" + uplink_welcome = "AntagCorp Uplink Console:" uplink_uses = 10 var/finished = 0 @@ -73,14 +73,14 @@ /datum/game_mode/revolution/post_setup() var/list/heads = get_living_heads() - for(var/datum/mind/rev_mind in head_revolutionaries) - for(var/datum/mind/head_mind in heads) - var/datum/objective/mutiny/rev_obj = new - rev_obj.owner = rev_mind - rev_obj.target = head_mind - rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]." - rev_mind.objectives += rev_obj + if(!config.objectives_disabled) + for(var/datum/mind/head_mind in heads) + var/datum/objective/mutiny/rev_obj = new + rev_obj.owner = rev_mind + rev_obj.target = head_mind + rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]." + rev_mind.objectives += rev_obj // equip_traitor(rev_mind.current, 1) //changing how revs get assigned their uplink so they can get PDA uplinks. --NEO // Removing revolutionary uplinks. -Pete @@ -107,22 +107,26 @@ /datum/game_mode/proc/forge_revolutionary_objectives(var/datum/mind/rev_mind) - var/list/heads = get_living_heads() - for(var/datum/mind/head_mind in heads) - var/datum/objective/mutiny/rev_obj = new - rev_obj.owner = rev_mind - rev_obj.target = head_mind - rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]." - rev_mind.objectives += rev_obj + if(!config.objectives_disabled) + var/list/heads = get_living_heads() + for(var/datum/mind/head_mind in heads) + var/datum/objective/mutiny/rev_obj = new + rev_obj.owner = rev_mind + rev_obj.target = head_mind + rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]." + rev_mind.objectives += rev_obj /datum/game_mode/proc/greet_revolutionary(var/datum/mind/rev_mind, var/you_are=1) var/obj_count = 1 if (you_are) rev_mind.current << "\blue You are a member of the revolutionaries' leadership!" - for(var/datum/objective/objective in rev_mind.objectives) - rev_mind.current << "Objective #[obj_count]: [objective.explanation_text]" - rev_mind.special_role = "Head Revolutionary" - obj_count++ + if(!config.objectives_disabled) + for(var/datum/objective/objective in rev_mind.objectives) + rev_mind.current << "Objective #[obj_count]: [objective.explanation_text]" + rev_mind.special_role = "Head Revolutionary" + obj_count++ + else + rev_mind.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." ///////////////////////////////////////////////////////////////////////////////// //This are equips the rev heads with their gear, and makes the clown not clumsy// @@ -193,6 +197,8 @@ revolutionaries += rev_mind rev_mind.current << "\red You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!" rev_mind.special_role = "Revolutionary" + if(config.objectives_disabled) + rev_mind.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." update_rev_icons_added(rev_mind) return 1 ////////////////////////////////////////////////////////////////////////////// @@ -202,6 +208,7 @@ if(rev_mind in revolutionaries) revolutionaries -= rev_mind rev_mind.special_role = null + rev_mind.current.hud_updateflag |= 1 << SPECIALROLE_HUD if(beingborged) rev_mind.current << "\red The frame's firmware detects and deletes your neural reprogramming! You remember nothing from the moment you were flashed until now." @@ -342,13 +349,14 @@ //Announces the end of the game with all relavent information stated// ////////////////////////////////////////////////////////////////////// /datum/game_mode/revolution/declare_completion() - if(finished == 1) - feedback_set_details("round_end_result","win - heads killed") - world << "\red The heads of staff were killed or abandoned the station! The revolutionaries win!" - else if(finished == 2) - feedback_set_details("round_end_result","loss - rev heads killed") - world << "\red The heads of staff managed to stop the revolution!" - ..() + if(!config.objectives_disabled) + if(finished == 1) + feedback_set_details("round_end_result","win - heads killed") + world << "\red The heads of staff were killed or abandoned the station! The revolutionaries win!" + else if(finished == 2) + feedback_set_details("round_end_result","loss - rev heads killed") + world << "\red The heads of staff managed to stop the revolution!" + ..() return 1 /datum/game_mode/proc/auto_declare_completion_revolution() diff --git a/code/game/gamemodes/revolution/rp-revolution.dm b/code/game/gamemodes/revolution/rp-revolution.dm index 7456e73403..963579af7c 100644 --- a/code/game/gamemodes/revolution/rp-revolution.dm +++ b/code/game/gamemodes/revolution/rp-revolution.dm @@ -304,4 +304,4 @@ mob/living/carbon/human/proc else if(choice == "No!") M << "\red You reject this traitorous cause!" src << "\red [M] does not support the revolution!" - M.mind.rev_cooldown = world.time+50 \ No newline at end of file + M.mind.rev_cooldown = world.time+50 diff --git a/code/game/gamemodes/revolution/rp_revolution.dm b/code/game/gamemodes/revolution/rp_revolution.dm index d00b58d23b..70fd1387f0 100644 --- a/code/game/gamemodes/revolution/rp_revolution.dm +++ b/code/game/gamemodes/revolution/rp_revolution.dm @@ -8,7 +8,7 @@ required_enemies = 3 recommended_enemies = 3 - uplink_welcome = "Revolutionary Uplink Console:" + uplink_welcome = "AntagCorp Uplink Console:" uplink_uses = 5 newscaster_announcements = /datum/news_announcement/revolution_inciting_event @@ -57,14 +57,14 @@ /datum/game_mode/revolution/rp_revolution/post_setup() heads = get_living_heads() - for(var/datum/mind/rev_mind in head_revolutionaries) - for(var/datum/mind/head_mind in heads) - var/datum/objective/mutiny/rp/rev_obj = new - rev_obj.owner = rev_mind - rev_obj.target = head_mind - rev_obj.explanation_text = "Assassinate, convert or capture [head_mind.name], the [head_mind.assigned_role]." - rev_mind.objectives += rev_obj + if(!config.objectives_disabled) + for(var/datum/mind/head_mind in heads) + var/datum/objective/mutiny/rp/rev_obj = new + rev_obj.owner = rev_mind + rev_obj.target = head_mind + rev_obj.explanation_text = "Assassinate, convert or capture [head_mind.name], the [head_mind.assigned_role]." + rev_mind.objectives += rev_obj update_rev_icons_added(rev_mind) @@ -81,10 +81,13 @@ var/obj_count = 1 if (you_are) rev_mind.current << "\blue You are a member of the revolutionaries' leadership!" - for(var/datum/objective/objective in rev_mind.objectives) - rev_mind.current << "Objective #[obj_count]: [objective.explanation_text]" - rev_mind.special_role = "Head Revolutionary" - obj_count++ + if(!config.objectives_disabled) + for(var/datum/objective/objective in rev_mind.objectives) + rev_mind.current << "Objective #[obj_count]: [objective.explanation_text]" + rev_mind.special_role = "Head Revolutionary" + obj_count++ + else + rev_mind.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." // Show each head revolutionary up to 3 candidates var/list/already_considered = list() @@ -110,7 +113,10 @@ revolutionaries += rev_mind rev_mind.current << "\red You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill, capture or convert the heads to win the revolution!" rev_mind.special_role = "Revolutionary" + if(config.objectives_disabled) + rev_mind.current << "Within the rules, try to act as an opposing force to the crew. Further RP and try to make sure other players have fun! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! Please remember all rules aside from those without explicit exceptions apply to antagonists." update_rev_icons_added(rev_mind) + H.hud_updateflag |= 1 << SPECIALROLE_HUD return 1 ///////////////////////////// @@ -140,13 +146,14 @@ //Announces the end of the game with all relavent information stated// ////////////////////////////////////////////////////////////////////// /datum/game_mode/revolution/rp_revolution/declare_completion() - if(finished == 1) - feedback_set_details("round_end_result","win - heads overthrown") - world << "\red The heads of staff were overthrown! The revolutionaries win!" - else if(finished == 2) - feedback_set_details("round_end_result","loss - revolution stopped") - world << "\red The heads of staff managed to stop the revolution!" - ..() + if(!config.objectives_disabled) + if(finished == 1) + feedback_set_details("round_end_result","win - heads overthrown") + world << "\red The heads of staff were overthrown! The revolutionaries win!" + else if(finished == 2) + feedback_set_details("round_end_result","loss - revolution stopped") + world << "\red The heads of staff managed to stop the revolution!" + ..() return 1 /datum/game_mode/revolution/proc/is_convertible(mob/M) @@ -156,9 +163,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!" @@ -187,7 +202,7 @@ tried_to_add_revheads = world.time+50 var/active_revs = 0 for(var/datum/mind/rev_mind in head_revolutionaries) - if(rev_mind.current.client && rev_mind.current.client.inactivity <= 10*60*20) // 20 minutes inactivity are OK + if(rev_mind.current && rev_mind.current.client && rev_mind.current.client.inactivity <= 10*60*20) // 20 minutes inactivity are OK active_revs++ if(active_revs == 0) @@ -251,4 +266,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 c72f56f8cf..d2b54fe5ba 100644 --- a/code/game/gamemodes/setupgame.dm +++ b/code/game/gamemodes/setupgame.dm @@ -2,10 +2,13 @@ // (mostly) DNA2 SETUP ///////////////////////// -// Randomize block, assign a reference name, and optionally define difficulty (by making activation zone smaller or bigger) +// 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) + if(blocksLeft.len==0) + warning("[name]: No more blocks left to assign!") + return 0 var/assigned = pick(blocksLeft) blocksLeft.Remove(assigned) assigned_blocks[assigned]=name @@ -60,7 +63,7 @@ BLINDBLOCK = tempnum */ var/list/numsToAssign=new() - for(var/i=1;i